Files
labelmain-demo/app/management/team/employee/page.tsx
2026-02-27 09:51:33 +08:00

289 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { getUserList, userEditById } from "@/components/label/api/user"
import { User } from "@/components/label/api/user/typing"
import useAuth from "@/components/label/hooks/useAuth"
import { useAllUserStore } from "@/components/label/store/auth"
import {
ActionIcon,
Badge,
Button,
Group,
Paper,
Stack,
Text,
TextInput,
} from "@mantine/core"
import { modals } from "@mantine/modals"
import { notifications } from "@mantine/notifications"
import { IconEdit, IconPlus, IconRefresh, IconSearch, IconUpload } from "@tabler/icons-react"
import { DataTable, DataTableColumn } from "mantine-datatable"
import { useCallback, useEffect, useMemo, useState } from "react"
import CreateUserModal from "./components/CreateUserModal"
import EditUserModal from "./components/EditUserModal"
import ImportModal from "./components/ImportModal"
export default function TeamEmployeePage() {
const { isShow } = useAuth()
const setFlag = useAllUserStore((s) => s.setFlag)
const [name, setName] = useState("")
const [appliedName, setAppliedName] = useState("")
const [records, setRecords] = useState<User.UserInfo[]>([])
const [loading, setLoading] = useState(false)
const [totalItems, setTotalItems] = useState(0)
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(20)
const [createOpened, setCreateOpened] = useState(false)
const [editOpened, setEditOpened] = useState(false)
const [importOpened, setImportOpened] = useState(false)
const [selectedUser, setSelectedUser] = useState<User.UserInfo | null>(null)
const load = useCallback(async () => {
try {
setLoading(true)
const params: User.ListRequest = {
page_number: page,
page_size: pageSize,
}
if (appliedName.trim()) params.name = appliedName.trim()
const res = await getUserList(params)
setRecords(res?.user_list ?? [])
setTotalItems(res?.total_items ?? 0)
} catch (e) {
setRecords([])
setTotalItems(0)
notifications.show({
color: "red",
title: "加载失败",
message: e instanceof Error ? e.message : "请求失败",
})
} finally {
setLoading(false)
}
}, [appliedName, page, pageSize])
useEffect(() => {
queueMicrotask(load)
}, [load])
const columns = useMemo(() => {
const cols: DataTableColumn<User.UserInfo>[] = [
{ accessor: "uid", title: "UID", width: 120, textAlign: "center" },
{ accessor: "name", title: "姓名", width: 120, textAlign: "center" },
{
accessor: "work_status",
title: "状态",
width: 100,
textAlign: "center",
render: (record) =>
record.work_status === 1 ? (
<Badge color="green" variant="light">
</Badge>
) : (
<Badge color="gray" variant="light">
</Badge>
),
},
{
accessor: "group_name",
title: "组织",
width: 180,
textAlign: "center",
},
{
accessor: "base_city",
title: "所在地",
width: 180,
textAlign: "center",
},
{
accessor: "operation",
title: "操作",
width: 220,
textAlign: "center",
render: (record) => (
<Group justify="center" gap={4} wrap="nowrap">
{isShow("edit") ? (
<Button
variant="subtle"
size="compact-xs"
onClick={() => {
modals.openConfirmModal({
title: "重置密码",
centered: true,
children: (
<Text size="sm"> 123456</Text>
),
labels: { confirm: "确定", cancel: "取消" },
onConfirm: async () => {
await userEditById({ password: "123456" }, record.uid)
notifications.show({
color: "green",
title: "操作成功",
message: "已重置密码",
})
},
})
}}>
</Button>
) : null}
{isShow("edit") ? (
<ActionIcon
variant="subtle"
color="blue"
onClick={() => {
setSelectedUser(record)
setEditOpened(true)
}}>
<IconEdit size={16} />
</ActionIcon>
) : null}
</Group>
),
},
]
return cols
}, [isShow])
return (
<Stack w="100%" h="calc(100vh - 56px)" p="md" gap="md">
<Paper
withBorder
p="md"
radius="md"
style={{
borderColor:
"light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
}}>
<Group justify="space-between" wrap="wrap">
<Group>
<TextInput
placeholder="请输入姓名"
size="xs"
radius="xs"
value={name}
onChange={(e) => setName(e.currentTarget.value)}
/>
<Button
size="xs"
radius="xs"
leftSection={<IconSearch size={16} />}
onClick={() => {
setAppliedName(name)
setPage(1)
}}>
</Button>
<Button
variant="default"
size="xs"
radius="xs"
leftSection={<IconRefresh size={16} />}
onClick={() => {
setName("")
setAppliedName("")
setPage(1)
setPageSize(20)
}}>
</Button>
</Group>
<Group>
{isShow("add") ? (
<Button
size="xs"
radius="xs"
leftSection={<IconPlus size={16} />}
onClick={() => setCreateOpened(true)}>
</Button>
) : null}
{isShow("add") ? (
<Button
size="xs"
radius="xs"
variant="default"
leftSection={<IconUpload size={16} />}
onClick={() => setImportOpened(true)}>
</Button>
) : null}
</Group>
</Group>
</Paper>
<Paper
withBorder
p="md"
radius="md"
style={{
borderColor:
"light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
flex: 1,
minHeight: 0,
display: "flex",
}}>
<DataTable<User.UserInfo>
withTableBorder
withRowBorders
fetching={loading}
records={records}
columns={columns}
noRecordsText="暂无数据"
totalRecords={totalItems}
recordsPerPage={pageSize}
page={page}
onPageChange={setPage}
onRecordsPerPageChange={(v) => {
setPageSize(v)
setPage(1)
}}
recordsPerPageOptions={[10, 20, 50, 100]}
scrollAreaProps={{ type: "auto" }}
style={{ width: "100%" }}
/>
</Paper>
<CreateUserModal
opened={createOpened}
onCloseAction={(refresh) => {
setCreateOpened(false)
if (refresh) {
setFlag(true)
load()
}
}}
/>
<ImportModal
opened={importOpened}
onCloseAction={(refresh) => {
setImportOpened(false)
if (refresh) {
setFlag(true)
load()
}
}}
/>
<EditUserModal
opened={editOpened}
data={selectedUser}
onCloseAction={(refresh) => {
setEditOpened(false)
setSelectedUser(null)
if (refresh) {
setFlag(true)
load()
}
}}
/>
</Stack>
)
}