初始提交:姜十三论坛 Jiang13 Forum

轻量自用论坛,Go 单二进制 + React SPA 内嵌 + SQLite。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
freefire
2026-06-15 21:08:52 +08:00
commit e1c1708715
140 changed files with 16115 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
import { useState } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { notify } from '@/lib/notify';
import { api } from '../api/client';
import { useAuth } from '../hooks/useAuth';
const schema = z.object({
username: z.string().min(1, '请输入用户名'),
password: z.string().min(1, '请输入密码'),
});
type FormValues = z.infer<typeof schema>;
export default function LoginPage() {
const nav = useNavigate();
const { refresh } = useAuth();
const [loading, setLoading] = useState(false);
const form = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues: { username: '', password: '' },
});
const onSubmit = async (values: FormValues) => {
setLoading(true);
try {
await api.login(values.username, values.password);
await refresh();
notify.success('登录成功');
nav('/', { replace: true });
} catch (e: unknown) {
notify.error(e instanceof Error ? e.message : '登录失败');
} finally {
setLoading(false);
}
};
return (
<div className="auth-page">
<div className="auth-box">
<div className="logo-mark"></div>
<h1></h1>
<p className="subtitle"></p>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<Input placeholder="用户名" autoComplete="username" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<Input type="password" placeholder="密码" autoComplete="current-password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full" loading={loading}>
</Button>
</form>
</Form>
<p style={{ textAlign: 'center', marginTop: 16, fontSize: 13, color: 'var(--color-text-3)' }}>
<Link to="/register"></Link>
</p>
</div>
</div>
);
}