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:
222
src/routes/admin/user/index.tsx
Normal file
222
src/routes/admin/user/index.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { Plus } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DataTable } from "@/components/data-table";
|
||||
import { useFetchList } from "./-hooks/useFetchList";
|
||||
import { useState } from "react";
|
||||
import { EditUserDialog } from "./-components/EditUserDialog";
|
||||
import { CancelUserConfirmDialog } from "./-components/CancelUserConfirmDialog";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Pagination } from "@/components/pagination";
|
||||
import { ResetUserPasswordDialog } from "@/components/reset-user-password-dialog";
|
||||
import { useUserStatusActions } from "@/hooks/use-user-status-actions";
|
||||
|
||||
export const Route = createFileRoute("/admin/user/")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
export function useColumns({
|
||||
handleCancelUser,
|
||||
handleEditUser,
|
||||
handleResetUserPassword,
|
||||
handleEnable,
|
||||
handleDisable,
|
||||
}: any) {
|
||||
return [
|
||||
{
|
||||
accessorKey: "username",
|
||||
header: "用户名",
|
||||
cell: ({ row }: any) => <div>{row.getValue("username")}</div>,
|
||||
},
|
||||
{
|
||||
accessorKey: "realName",
|
||||
header: "姓名",
|
||||
cell: ({ row }: any) => <div>{row.getValue("realName")}</div>,
|
||||
},
|
||||
{
|
||||
accessorKey: "enabled",
|
||||
header: "启用状态",
|
||||
cell: ({ row }: any) =>
|
||||
Number(row.getValue("status")) === 3 ? (
|
||||
<Badge variant="secondary" className="text-red-600">
|
||||
-
|
||||
</Badge>
|
||||
) : row.getValue("enabled") ? (
|
||||
<Badge className="bg-green-500/10 text-green-600">启用</Badge>
|
||||
) : (
|
||||
<Badge className="bg-red-500/10 text-red-500">禁用</Badge>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "状态",
|
||||
cell: ({ row }: any) => (
|
||||
<div className="text-xs">
|
||||
{row.getValue("status") === 1 ? (
|
||||
<Badge variant="secondary">未激活</Badge>
|
||||
) : row.getValue("status") === 2 ? (
|
||||
<Badge variant="secondary" className="text-green-600">
|
||||
已激活
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="secondary" className="text-red-600">
|
||||
已注销
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createTime",
|
||||
header: "创建日期",
|
||||
cell: ({ row }: any) => <div>{row.getValue("createTime")}</div>,
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
enableHiding: false,
|
||||
header: "操作",
|
||||
cell: ({ row }: any) => {
|
||||
if (row.original.parentId === 0) {
|
||||
return null;
|
||||
}
|
||||
const record = row.original;
|
||||
return (
|
||||
<div className="space-x-2">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => handleEditUser(record)}
|
||||
>
|
||||
修改
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => handleResetUserPassword(record)}
|
||||
>
|
||||
重置密码
|
||||
</Button>
|
||||
{Number(record.status) !== 3 && record.enabled && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => handleDisable(record)}
|
||||
>
|
||||
禁用
|
||||
</Button>
|
||||
)}
|
||||
{Number(record.status) !== 3 && !record.enabled && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => handleEnable(record)}
|
||||
>
|
||||
启用
|
||||
</Button>
|
||||
)}
|
||||
{Number(record.status) !== 3 && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
onClick={() => handleCancelUser(record)}
|
||||
>
|
||||
注销
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function RouteComponent() {
|
||||
const [currentEntity, setCurrentEntity] = useState<any>(null);
|
||||
|
||||
// 修改用户
|
||||
const [openEditUserDialog, setOpenEditUserDialog] = useState(false);
|
||||
const handleEditUser = (record?: any) => {
|
||||
setCurrentEntity(record);
|
||||
setOpenEditUserDialog(true);
|
||||
};
|
||||
|
||||
// 重置用户密码
|
||||
const [openResetUserPasswordDialog, setOpenResetUserPasswordDialog] =
|
||||
useState(false);
|
||||
const handleResetUserPassword = (record?: any) => {
|
||||
setCurrentEntity(record);
|
||||
setOpenResetUserPasswordDialog(true);
|
||||
};
|
||||
|
||||
// 注销用户
|
||||
const [openCancelUserConfirmDialog, setOpenCancelUserConfirmDialog] =
|
||||
useState(false);
|
||||
const handleCancelUser = (record?: any) => {
|
||||
setCurrentEntity(record);
|
||||
setOpenCancelUserConfirmDialog(true);
|
||||
};
|
||||
|
||||
// 启用/禁用(禁用走二次确认)
|
||||
const { enable, disable } = useUserStatusActions({
|
||||
onSuccess: () => query?.refetch(),
|
||||
});
|
||||
const handleEnable = (record: any) => {
|
||||
enable(record.id);
|
||||
};
|
||||
const handleDisable = (record: any) => {
|
||||
disable(record.id);
|
||||
};
|
||||
|
||||
const { table, query } = useFetchList(() =>
|
||||
useColumns({
|
||||
handleCancelUser,
|
||||
handleEditUser,
|
||||
handleResetUserPassword,
|
||||
handleEnable,
|
||||
handleDisable,
|
||||
}),
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EditUserDialog
|
||||
open={openEditUserDialog}
|
||||
setOpen={setOpenEditUserDialog}
|
||||
data={currentEntity}
|
||||
refetch={query?.refetch}
|
||||
/>
|
||||
<ResetUserPasswordDialog
|
||||
open={openResetUserPasswordDialog}
|
||||
setOpen={setOpenResetUserPasswordDialog}
|
||||
data={currentEntity}
|
||||
/>
|
||||
<CancelUserConfirmDialog
|
||||
open={openCancelUserConfirmDialog}
|
||||
setOpen={setOpenCancelUserConfirmDialog}
|
||||
data={currentEntity}
|
||||
refetch={query?.refetch}
|
||||
/>
|
||||
<div className="p-4 box-border min-h-full space-y-4">
|
||||
<div>
|
||||
<div className="text-lg">用户管理</div>
|
||||
<div className="text-xs text-black/50">管理单位用户信息</div>
|
||||
</div>
|
||||
<div className="p-4 rounded-lg border bg-white space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button onClick={() => handleEditUser()}>
|
||||
<Plus />
|
||||
新增
|
||||
</Button>
|
||||
</div>
|
||||
<div className="relative overflow-hidden">
|
||||
<DataTable table={table} query={query} />
|
||||
<Pagination
|
||||
table={table}
|
||||
className="justify-end p-2 sticky bottom-0 left-0 right-0 z-10 bg-white"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user