feat: 管理后台增强——用户启停操作、shadcn日期区间/后缀标签组件
1. 用户管理页:新增启用状态列与启用/禁用操作按钮(对接 user/enable|disable) 2. 机构账号/记录查询页:时间区间改用官方 shadcn Range Picker 模式 (Popover+Calendar mode=range 双月面板,新增 components/date-range-picker.tsx) 3. 上传配置页:文件类型限制改为标签式输入(新增 suffix-tag-input.tsx, Badge标签+回车添加+常用后缀快捷点选),替换自由文本框 4. 修复:.env 的 VITE_APP_TITLE 加引号,规避 Bun 1.3.10 env 解析 对行尾多字节中文的截断(标题乱码"森睿智�") 5. 新增共享 hook hooks/use-user-status-actions.ts(从 org-account 迁出) 6. vite 代理保留 本地Docker(localhost:8080)/公司 两种目标,切换注释即可
This commit is contained in:
117
src/components/init-password.tsx
Normal file
117
src/components/init-password.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import { useRouter } from "@tanstack/react-router";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
Form,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormControl,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { initUserPassword } from "@/apis/user";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
import logo from "@/assets/image/logo.png";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
const formSchema = z.object({
|
||||
rePassword: z.string().nonempty({
|
||||
message: "确认密码不能为空",
|
||||
}),
|
||||
password: z.string().nonempty({
|
||||
message: "密码不能为空",
|
||||
}),
|
||||
});
|
||||
|
||||
const title = import.meta.env.VITE_APP_TITLE;
|
||||
|
||||
export function InitPassword() {
|
||||
const router = useRouter();
|
||||
const user = useUserStore((state) => state.user);
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
password: "",
|
||||
rePassword: "",
|
||||
},
|
||||
});
|
||||
|
||||
const { mutateAsync, isPending } = useMutation({
|
||||
mutationFn: initUserPassword,
|
||||
onSuccess() {
|
||||
router.navigate({ to: "/", replace: true });
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = (values: z.infer<typeof formSchema>) => {
|
||||
toast.promise(mutateAsync({ ...values, username: user?.username }), {
|
||||
loading: "提交中...",
|
||||
success: "设置成功",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen box-border">
|
||||
<div>
|
||||
<div className="flex justify-center items-center mb-4 gap-2">
|
||||
<img
|
||||
src={logo}
|
||||
alt=""
|
||||
className="size-12 object-contain rounded-full bg-white overflow-hidden"
|
||||
/>
|
||||
<div className="text-3xl">{title}</div>
|
||||
</div>
|
||||
<div className="w-[480px] p-10 bg-white rounded-xl">
|
||||
<div className="text-center text-2xl">设置密码</div>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="space-y-8 mt-12"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>密码</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="密码" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="rePassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>确认密码</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder="确认密码"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" className="w-full" disabled={isPending}>
|
||||
{isPending && <Spinner />}
|
||||
提交
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user