feat: 添加账号支持选择学习平台
账号新增 platform 字段,登录/刷新课程/发现课程按平台分发;同时把 JS 脚本收进 script/(目录规范调整)。
This commit is contained in:
+17
-4
@@ -75,6 +75,7 @@ function accountPayload(account: Account) {
|
||||
return {
|
||||
id: account.id,
|
||||
username: account.username,
|
||||
platform: account.platform || 'guanyixue',
|
||||
note: account.note || '',
|
||||
user: account.user || '',
|
||||
cookies: account.cookies || [],
|
||||
@@ -93,6 +94,9 @@ export default function App() {
|
||||
const [accounts, setAccounts] = useState<Account[]>([])
|
||||
const accountsRef = useRef(accounts)
|
||||
const [platforms, setPlatforms] = useState<Record<string, string>>({ guanyixue: '莞易学' })
|
||||
const [platformList, setPlatformList] = useState<PlatformInfo[]>([
|
||||
{ id: 'guanyixue', label: '莞易学' },
|
||||
])
|
||||
const [offline, setOffline] = useState(false)
|
||||
const [toast, setToast] = useState<ToastState | null>(null)
|
||||
const [pending, setPending] = useState<Record<string, string>>({})
|
||||
@@ -193,9 +197,12 @@ export default function App() {
|
||||
useEffect(() => {
|
||||
api<{ platforms: PlatformInfo[] }>('/api/platforms')
|
||||
.then((response) => {
|
||||
const list = response.platforms || []
|
||||
if (!list.length) return
|
||||
setPlatformList(list)
|
||||
const map: Record<string, string> = {}
|
||||
for (const platform of response.platforms || []) map[platform.id] = platform.label
|
||||
if (Object.keys(map).length) setPlatforms(map)
|
||||
for (const platform of list) map[platform.id] = platform.label
|
||||
setPlatforms(map)
|
||||
})
|
||||
.catch(() => {})
|
||||
}, [])
|
||||
@@ -366,7 +373,10 @@ export default function App() {
|
||||
try {
|
||||
let response = await api<CoursesResponse>('/api/courses', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ cookies: account.cookies }),
|
||||
body: JSON.stringify({
|
||||
cookies: account.cookies,
|
||||
platform: account.platform || 'guanyixue',
|
||||
}),
|
||||
})
|
||||
if (!response.ok && response.code === 'session_expired') {
|
||||
notify({ message: '会话已失效,正在自动重新登录…' })
|
||||
@@ -578,6 +588,7 @@ export default function App() {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
username: data.username,
|
||||
platform: data.platform,
|
||||
password: data.password,
|
||||
note: data.note,
|
||||
cookies: [],
|
||||
@@ -621,7 +632,8 @@ export default function App() {
|
||||
}
|
||||
|
||||
function platformLabel(account: Account) {
|
||||
const id = (account.courses || []).find((course) => course.platform)?.platform
|
||||
const id =
|
||||
account.platform || (account.courses || []).find((course) => course.platform)?.platform
|
||||
return (id && platforms[id]) || '莞易学'
|
||||
}
|
||||
|
||||
@@ -749,6 +761,7 @@ export default function App() {
|
||||
|
||||
<AddAccountDialog
|
||||
open={dialog?.type === 'add'}
|
||||
platforms={platformList}
|
||||
onClose={() => setDialog(null)}
|
||||
onSubmit={addAccount}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { ChevronDown, GraduationCap } from 'lucide-react'
|
||||
|
||||
import type { PlatformInfo } from '../types'
|
||||
import { Modal } from './ui/Modal'
|
||||
import { Button } from './ui/Button'
|
||||
import { inputCls } from '../lib/utils'
|
||||
@@ -8,20 +10,24 @@ export interface NewAccount {
|
||||
username: string
|
||||
password: string
|
||||
note: string
|
||||
platform: string
|
||||
}
|
||||
|
||||
export function AddAccountDialog({
|
||||
open,
|
||||
platforms,
|
||||
onClose,
|
||||
onSubmit,
|
||||
}: {
|
||||
open: boolean
|
||||
platforms: PlatformInfo[]
|
||||
onClose: () => void
|
||||
onSubmit: (account: NewAccount) => Promise<void>
|
||||
}) {
|
||||
const [username, setUsername] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [note, setNote] = useState('')
|
||||
const [platform, setPlatform] = useState(platforms[0]?.id || 'guanyixue')
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
|
||||
@@ -30,9 +36,10 @@ export function AddAccountDialog({
|
||||
setUsername('')
|
||||
setPassword('')
|
||||
setNote('')
|
||||
setPlatform(platforms[0]?.id || 'guanyixue')
|
||||
setError('')
|
||||
setSaving(false)
|
||||
}, [open])
|
||||
}, [open, platforms])
|
||||
|
||||
async function submit() {
|
||||
if (!username.trim() || !password) {
|
||||
@@ -42,7 +49,7 @@ export function AddAccountDialog({
|
||||
setSaving(true)
|
||||
setError('')
|
||||
try {
|
||||
await onSubmit({ username: username.trim(), password, note: note.trim() })
|
||||
await onSubmit({ username: username.trim(), password, note: note.trim(), platform })
|
||||
onClose()
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : String(err))
|
||||
@@ -69,6 +76,27 @@ export function AddAccountDialog({
|
||||
}
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="mb-1.5 block text-[12px] font-medium text-slate-600">学习平台</label>
|
||||
<div className="relative">
|
||||
<GraduationCap className="pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-slate-400" />
|
||||
<select
|
||||
className={`${inputCls} appearance-none pl-8 pr-8`}
|
||||
value={platform}
|
||||
onChange={(event) => setPlatform(event.target.value)}
|
||||
>
|
||||
{platforms.map((item) => (
|
||||
<option key={item.id} value={item.id}>
|
||||
{item.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown className="pointer-events-none absolute right-2.5 top-1/2 size-3.5 -translate-y-1/2 text-slate-400" />
|
||||
</div>
|
||||
<p className="mt-1.5 text-[11px] leading-relaxed text-slate-400">
|
||||
选「莞易学」后,后台会自动识别旧版 / 新版课程页并按对应实现学习;后续新增的平台会出现在这里。
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="mb-1.5 block text-[12px] font-medium text-slate-600">登录账号</label>
|
||||
<input
|
||||
|
||||
@@ -47,6 +47,7 @@ export function QuizDialog({
|
||||
try {
|
||||
const body: Record<string, unknown> = {
|
||||
cookies: account.cookies,
|
||||
platform: account.platform || 'guanyixue',
|
||||
plan_id: course.plan_id,
|
||||
project_id: course.project_id,
|
||||
name: course.name || '',
|
||||
|
||||
@@ -37,6 +37,7 @@ export interface RunState {
|
||||
export interface Account {
|
||||
id: string
|
||||
username: string
|
||||
platform?: string
|
||||
note?: string
|
||||
user?: string
|
||||
cookies: Cookie[]
|
||||
|
||||
Reference in New Issue
Block a user