Files
senmesh-zc/src/routes/admin/org-account/index.tsx

328 lines
9.8 KiB
TypeScript
Raw Normal View History

import { useState } from "react";
import { createFileRoute } from "@tanstack/react-router";
import { RotateCcw, Search } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { DataTable } from "@/components/data-table";
import { Pagination } from "@/components/pagination";
import { useFetchList } from "./-hooks/useFetchList";
import { useUserStatusActions } from "@/hooks/use-user-status-actions";
import { UserActionConfirmDialog } from "./-components/UserActionConfirmDialog";
import { useUserStore } from "@/stores/user";
import { DateRangePicker } from "@/components/date-range-picker";
export const Route = createFileRoute("/admin/org-account/")({
component: RouteComponent,
});
const initialFilters = {
orgNameLike: "",
usernameLike: "",
realNameLike: "",
phoneLike: "",
enabled: "",
status: "",
createTimeStart: "",
createTimeEnd: "",
};
export function useColumns({
handleEnable,
handleDisable,
handleCancelUser,
}: any) {
const currentUserId = useUserStore((state: any) => state.user?.id);
return [
{
accessorKey: "orgName",
header: "机构名称",
cell: ({ row }: any) => (
<div className="flex items-center gap-1">
<div>{row.getValue("orgName")}</div>
{row.original.administrator && (
<Badge
variant="outline"
className="text-primary border-primary shrink-0"
>
管理员
</Badge>
)}
</div>
),
},
{
accessorKey: "username",
header: "账号",
cell: ({ row }: any) => <div>{row.getValue("username")}</div>,
},
{
accessorKey: "realName",
header: "姓名",
cell: ({ row }: any) => (
<div>{row.getValue("realName") || row.original.nickname || "-"}</div>
),
},
{
accessorKey: "phone",
header: "手机号",
cell: ({ row }: any) => <div>{row.getValue("phone") || "-"}</div>,
},
{
accessorKey: "userType",
header: "用户类型",
cell: ({ row }: any) => (
<div>{row.getValue("userType") === 2 ? "个人用户" : "企业用户"}</div>
),
},
{
accessorKey: "enabled",
header: "启用状态",
cell: ({ row }: any) =>
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) => {
const status = Number(row.getValue("status"));
return (
<div className="text-xs">
{status === 1 ? (
<Badge variant="secondary">待激活</Badge>
) : 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) => {
const record = row.original;
// 已注销或当前登录人自己,不展示操作
if (Number(record.status) === 3 || record.userId === currentUserId) {
return null;
}
return (
<div className="space-x-2">
{record.enabled ? (
<Button
size="sm"
variant="outline"
onClick={() => handleDisable(record)}
>
禁用
</Button>
) : (
<Button
size="sm"
variant="outline"
onClick={() => handleEnable(record)}
>
启用
</Button>
)}
<Button
size="sm"
variant="destructive"
onClick={() => handleCancelUser(record)}
>
注销
</Button>
</div>
);
},
},
];
}
function RouteComponent() {
const [currentEntity, setCurrentEntity] = useState<any>(null);
// 启用(直接操作)
const { enable } = useUserStatusActions({
onSuccess: () => query?.refetch(),
});
const handleEnable = (record: any) => {
enable(record.userId);
};
// 禁用/注销(二次确认)
const [confirmAction, setConfirmAction] = useState<
"disable" | "adminCancel"
>("disable");
const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
const handleDisable = (record: any) => {
setCurrentEntity(record);
setConfirmAction("disable");
setOpenConfirmDialog(true);
};
const handleCancelUser = (record: any) => {
setCurrentEntity(record);
setConfirmAction("adminCancel");
setOpenConfirmDialog(true);
};
const { table, query, search } = useFetchList(() =>
useColumns({
handleEnable,
handleDisable,
handleCancelUser,
}),
);
// 筛选条件(点击查询后生效)
const [filters, setFilters] = useState<any>(initialFilters);
const setFilter = (key: string, value: string) => {
setFilters((prev: any) => ({ ...prev, [key]: value }));
};
const handleSearch = () => {
search({
...filters,
createTimeStart: filters.createTimeStart
? `${filters.createTimeStart} 00:00:00`
: "",
createTimeEnd: filters.createTimeEnd
? `${filters.createTimeEnd} 23:59:59`
: "",
});
};
const handleReset = () => {
setFilters(initialFilters);
search({});
};
return (
<>
<UserActionConfirmDialog
open={openConfirmDialog}
setOpen={setOpenConfirmDialog}
action={confirmAction}
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 flex-wrap items-center gap-2">
<Input
placeholder="机构名称"
className="w-[160px]"
value={filters.orgNameLike}
onChange={(e: any) => setFilter("orgNameLike", e.target.value)}
/>
<Input
placeholder="账号"
className="w-[140px]"
value={filters.usernameLike}
onChange={(e: any) => setFilter("usernameLike", e.target.value)}
/>
<Input
placeholder="真实姓名"
className="w-[120px]"
value={filters.realNameLike}
onChange={(e: any) => setFilter("realNameLike", e.target.value)}
/>
<Input
placeholder="手机号"
className="w-[140px]"
value={filters.phoneLike}
onChange={(e: any) => setFilter("phoneLike", e.target.value)}
/>
<Select
value={filters.enabled || "all"}
onValueChange={(value: string) =>
setFilter("enabled", value === "all" ? "" : value)
}
>
<SelectTrigger className="w-[110px]">
<SelectValue placeholder="启用状态" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">启用状态</SelectItem>
<SelectItem value="true">启用</SelectItem>
<SelectItem value="false">禁用</SelectItem>
</SelectContent>
</Select>
<Select
value={filters.status || "all"}
onValueChange={(value: string) =>
setFilter("status", value === "all" ? "" : value)
}
>
<SelectTrigger className="w-[110px]">
<SelectValue placeholder="用户状态" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">用户状态</SelectItem>
<SelectItem value="1">待激活</SelectItem>
<SelectItem value="2">已激活</SelectItem>
<SelectItem value="3">已注销</SelectItem>
</SelectContent>
</Select>
<div className="flex items-center gap-1 text-sm text-black/60">
创建时间
<DateRangePicker
from={filters.createTimeStart}
to={filters.createTimeEnd}
onChange={(range) => {
setFilter("createTimeStart", range.from ?? "");
setFilter("createTimeEnd", range.to ?? "");
}}
/>
</div>
<Button onClick={handleSearch}>
<Search />
查询
</Button>
<Button variant="outline" onClick={handleReset}>
<RotateCcw />
重置
</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>
</>
);
}