- Add active: state feedback to all buttons across the app - Fix cache clearing to update Zustand store (not just localStorage) - Remove checkboxes from settings cache section, compact layout - Settings page: single outer scroll instead of dual-column scroll - CourseWorkspace: elastic log panel height, work/exam record counts - Integrate WorkList/ExamList types and display in UI - Delete unused CourseList.tsx component - Fix wk.ts: strict equality, remove unused import Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
148 lines
4.6 KiB
TypeScript
148 lines
4.6 KiB
TypeScript
import { For, Show } from "solid-js";
|
||
import Dialog from "~/components/dialog/Dialog";
|
||
import type { CourseKind } from "~/service/wk";
|
||
|
||
type HostOption = {
|
||
label: string;
|
||
host: string;
|
||
};
|
||
|
||
type StatusOption = {
|
||
label: string;
|
||
value: CourseKind;
|
||
};
|
||
|
||
export type LoginForm = {
|
||
username: string;
|
||
password: string;
|
||
token: string;
|
||
status: CourseKind;
|
||
host: string;
|
||
};
|
||
|
||
interface AddAccountDialogProps {
|
||
open: () => boolean;
|
||
onClose: () => void;
|
||
onSubmit: () => void;
|
||
isSubmitting: boolean;
|
||
errorMessage: string;
|
||
form: LoginForm;
|
||
statusOptions: StatusOption[];
|
||
hostOptions: HostOption[];
|
||
updateForm: <K extends keyof LoginForm>(key: K, value: LoginForm[K]) => void;
|
||
}
|
||
|
||
const AddAccountDialog = (props: AddAccountDialogProps) => {
|
||
return (
|
||
<Dialog
|
||
open={props.open}
|
||
onClose={props.onClose}
|
||
title="添加账号"
|
||
widthClass="max-w-2xl"
|
||
footer={
|
||
<>
|
||
<button
|
||
type="button"
|
||
class="rounded-xl border border-zinc-200 px-4 py-2 text-zinc-700 transition hover:bg-zinc-100 active:bg-zinc-200"
|
||
onClick={props.onClose}
|
||
>
|
||
取消
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="rounded-xl bg-cyan-500 px-4 py-2 text-white transition hover:bg-cyan-600 active:bg-cyan-700 disabled:cursor-not-allowed disabled:bg-cyan-300"
|
||
disabled={props.isSubmitting}
|
||
onClick={props.onSubmit}
|
||
>
|
||
{props.isSubmitting ? "登录中..." : "添加"}
|
||
</button>
|
||
</>
|
||
}
|
||
>
|
||
<div class="grid gap-4 md:grid-cols-2">
|
||
<label class="flex flex-col gap-2 text-sm text-zinc-700">
|
||
<span>账号</span>
|
||
<input
|
||
class="rounded-xl border border-zinc-200 bg-zinc-50 px-4 py-3 transition outline-none focus:border-cyan-400 focus:bg-white"
|
||
value={props.form.username}
|
||
onInput={(event) =>
|
||
props.updateForm("username", event.currentTarget.value)
|
||
}
|
||
placeholder="请输入账号"
|
||
/>
|
||
</label>
|
||
|
||
<label class="flex flex-col gap-2 text-sm text-zinc-700">
|
||
<span>密码</span>
|
||
<input
|
||
type="password"
|
||
class="rounded-xl border border-zinc-200 bg-zinc-50 px-4 py-3 transition outline-none focus:border-cyan-400 focus:bg-white"
|
||
value={props.form.password}
|
||
onInput={(event) =>
|
||
props.updateForm("password", event.currentTarget.value)
|
||
}
|
||
placeholder="请输入密码"
|
||
/>
|
||
</label>
|
||
|
||
<label class="flex flex-col gap-2 text-sm text-zinc-700 md:col-span-2">
|
||
<span>Cookie</span>
|
||
<textarea
|
||
class="min-h-28 rounded-xl border border-zinc-200 bg-zinc-50 px-4 py-3 transition outline-none focus:border-cyan-400 focus:bg-white"
|
||
value={props.form.token}
|
||
onInput={(event) =>
|
||
props.updateForm("token", event.currentTarget.value)
|
||
}
|
||
placeholder="可直接粘贴 Cookie 或 token,账号密码与 Cookie 二选一即可"
|
||
/>
|
||
</label>
|
||
|
||
<label class="flex flex-col gap-2 text-sm text-zinc-700">
|
||
<span>状态</span>
|
||
<select
|
||
class="rounded-xl border border-zinc-200 bg-zinc-50 px-4 py-3 transition outline-none focus:border-cyan-400 focus:bg-white"
|
||
value={props.form.status}
|
||
onChange={(event) =>
|
||
props.updateForm(
|
||
"status",
|
||
event.currentTarget.value as CourseKind,
|
||
)
|
||
}
|
||
>
|
||
<For each={props.statusOptions}>
|
||
{(item) => <option value={item.value}>{item.label}</option>}
|
||
</For>
|
||
</select>
|
||
</label>
|
||
|
||
<label class="flex flex-col gap-2 text-sm text-zinc-700">
|
||
<span>Host</span>
|
||
<select
|
||
class="rounded-xl border border-zinc-200 bg-zinc-50 px-4 py-3 transition outline-none focus:border-cyan-400 focus:bg-white"
|
||
value={props.form.host}
|
||
onChange={(event) =>
|
||
props.updateForm("host", event.currentTarget.value)
|
||
}
|
||
>
|
||
<For each={props.hostOptions}>
|
||
{(item) => (
|
||
<option value={item.host}>
|
||
{item.label}({item.host})
|
||
</option>
|
||
)}
|
||
</For>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
|
||
<Show when={props.errorMessage}>
|
||
<div class="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-600">
|
||
{props.errorMessage}
|
||
</div>
|
||
</Show>
|
||
</Dialog>
|
||
);
|
||
};
|
||
|
||
export default AddAccountDialog;
|