feat: build account dashboard and settings workspace

This commit is contained in:
2026-03-26 23:03:45 +08:00
parent be4bc8a3af
commit 8ee9a696b4
18 changed files with 2468 additions and 54 deletions

View File

@@ -0,0 +1,147 @@
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"
onClick={props.onClose}
>
</button>
<button
type="button"
class="rounded-xl bg-cyan-500 px-4 py-2 text-white transition hover:bg-cyan-600 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;