311 lines
9.8 KiB
JavaScript
311 lines
9.8 KiB
JavaScript
import React, { useEffect, useMemo, useState } from 'react';
|
||
import { Button, Form, Input, InputNumber, Modal, Popconfirm, Select, Space, Switch, Table, Tag, Typography, message } from 'antd';
|
||
import { DeleteOutlined, EditOutlined, PlusOutlined, ReloadOutlined, AppstoreOutlined } from '@ant-design/icons';
|
||
import { SycmCard } from '../../components/Common';
|
||
import {
|
||
createDepartment,
|
||
deleteDepartment,
|
||
getDepartmentPagePermissions,
|
||
getDepartments,
|
||
updateDepartment,
|
||
updateDepartmentPagePermissions,
|
||
} from '../../api/admin';
|
||
|
||
const { Text } = Typography;
|
||
|
||
const DEPARTMENT_SOURCE_META = {
|
||
dingtalk: { color: 'blue', label: '钉钉同步' },
|
||
hr: { color: 'cyan', label: 'HR同步' },
|
||
local: { color: 'default', label: '本地' },
|
||
};
|
||
|
||
const DepartmentManagement = () => {
|
||
const [departments, setDepartments] = useState([]);
|
||
const [loading, setLoading] = useState(false);
|
||
const [saving, setSaving] = useState(false);
|
||
const [permissionSaving, setPermissionSaving] = useState(false);
|
||
const [modalVisible, setModalVisible] = useState(false);
|
||
const [permissionVisible, setPermissionVisible] = useState(false);
|
||
const [editingDepartment, setEditingDepartment] = useState(null);
|
||
const [permissionDepartment, setPermissionDepartment] = useState(null);
|
||
const [pagePermissions, setPagePermissions] = useState([]);
|
||
const [form] = Form.useForm();
|
||
|
||
const departmentMap = useMemo(() => {
|
||
return departments.reduce((acc, item) => {
|
||
acc[item.id] = item;
|
||
return acc;
|
||
}, {});
|
||
}, [departments]);
|
||
|
||
const fetchDepartments = async () => {
|
||
try {
|
||
setLoading(true);
|
||
const data = await getDepartments();
|
||
setDepartments(Array.isArray(data) ? data : []);
|
||
} catch (error) {
|
||
message.error(error.response?.data?.error || '获取部门列表失败');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
fetchDepartments();
|
||
}, []);
|
||
|
||
const openCreateModal = () => {
|
||
setEditingDepartment(null);
|
||
form.resetFields();
|
||
form.setFieldsValue({
|
||
sort: 0,
|
||
status: 'active',
|
||
});
|
||
setModalVisible(true);
|
||
};
|
||
|
||
const openEditModal = (record) => {
|
||
setEditingDepartment(record);
|
||
form.setFieldsValue({
|
||
name: record.name,
|
||
code: record.code,
|
||
parentId: record.parentId || undefined,
|
||
sort: record.sort,
|
||
status: record.status,
|
||
});
|
||
setModalVisible(true);
|
||
};
|
||
|
||
const handleSave = async () => {
|
||
try {
|
||
const values = await form.validateFields();
|
||
setSaving(true);
|
||
if (editingDepartment) {
|
||
await updateDepartment(editingDepartment.id, values);
|
||
message.success('部门信息已更新');
|
||
} else {
|
||
await createDepartment(values);
|
||
message.success('部门已创建');
|
||
}
|
||
setModalVisible(false);
|
||
fetchDepartments();
|
||
} catch (error) {
|
||
if (!error?.errorFields) {
|
||
message.error(error.response?.data?.error || '保存部门失败');
|
||
}
|
||
} finally {
|
||
setSaving(false);
|
||
}
|
||
};
|
||
|
||
const handleDelete = async (id) => {
|
||
try {
|
||
await deleteDepartment(id);
|
||
message.success('部门已删除');
|
||
fetchDepartments();
|
||
} catch (error) {
|
||
message.error(error.response?.data?.error || '删除部门失败');
|
||
}
|
||
};
|
||
|
||
const openPermissionModal = async (record) => {
|
||
try {
|
||
setPermissionDepartment(record);
|
||
const data = await getDepartmentPagePermissions(record.id);
|
||
setPagePermissions(Array.isArray(data.permissions) ? data.permissions : []);
|
||
setPermissionVisible(true);
|
||
} catch (error) {
|
||
message.error(error.response?.data?.error || '获取部门功能页面失败');
|
||
}
|
||
};
|
||
|
||
const handlePermissionToggle = (pageKey, allowed) => {
|
||
setPagePermissions((prev) =>
|
||
prev.map((item) => (item.pageKey === pageKey ? { ...item, allowed } : item))
|
||
);
|
||
};
|
||
|
||
const handleSavePermissions = async () => {
|
||
if (!permissionDepartment) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
setPermissionSaving(true);
|
||
await updateDepartmentPagePermissions(permissionDepartment.id, {
|
||
permissions: pagePermissions.map((item) => ({
|
||
pageKey: item.pageKey,
|
||
allowed: item.allowed,
|
||
})),
|
||
});
|
||
message.success('部门功能页面权限已更新');
|
||
setPermissionVisible(false);
|
||
} catch (error) {
|
||
message.error(error.response?.data?.error || '更新部门功能页面失败');
|
||
} finally {
|
||
setPermissionSaving(false);
|
||
}
|
||
};
|
||
|
||
const columns = [
|
||
{
|
||
title: '部门名称',
|
||
dataIndex: 'name',
|
||
width: 220,
|
||
},
|
||
{
|
||
title: '编码',
|
||
dataIndex: 'code',
|
||
width: 160,
|
||
},
|
||
{
|
||
title: '上级部门',
|
||
dataIndex: 'parentId',
|
||
width: 180,
|
||
render: (value) => (value && departmentMap[value] ? departmentMap[value].name : '顶级部门'),
|
||
},
|
||
{
|
||
title: '来源',
|
||
dataIndex: 'source',
|
||
width: 120,
|
||
render: (value) => {
|
||
const sourceMeta = DEPARTMENT_SOURCE_META[value] || { color: 'default', label: value || '未知' };
|
||
return <Tag color={sourceMeta.color}>{sourceMeta.label}</Tag>;
|
||
},
|
||
},
|
||
{
|
||
title: '状态',
|
||
dataIndex: 'status',
|
||
width: 120,
|
||
render: (value) => <Tag color={value === 'active' ? 'success' : 'default'}>{value === 'active' ? '启用' : '停用'}</Tag>,
|
||
},
|
||
{
|
||
title: '排序',
|
||
dataIndex: 'sort',
|
||
width: 90,
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'actions',
|
||
width: 260,
|
||
render: (_, record) => {
|
||
return (
|
||
<Space>
|
||
<Button type="link" size="small" icon={<AppstoreOutlined />} onClick={() => openPermissionModal(record)}>
|
||
功能页面
|
||
</Button>
|
||
{record.source === 'local' && (
|
||
<Button type="link" size="small" icon={<EditOutlined />} onClick={() => openEditModal(record)}>
|
||
编辑
|
||
</Button>
|
||
)}
|
||
{record.source === 'local' && (
|
||
<Popconfirm title="确定删除该部门吗?" onConfirm={() => handleDelete(record.id)}>
|
||
<Button type="link" size="small" danger icon={<DeleteOutlined />}>
|
||
删除
|
||
</Button>
|
||
</Popconfirm>
|
||
)}
|
||
{record.source !== 'local' && <Text type="secondary">同步部门</Text>}
|
||
</Space>
|
||
);
|
||
},
|
||
},
|
||
];
|
||
|
||
return (
|
||
<div className="settings-tab-page">
|
||
<SycmCard bodyStyle={{ padding: 16 }}>
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16, flexWrap: 'wrap', gap: 12 }}>
|
||
<Space wrap>
|
||
<Button icon={<ReloadOutlined />} onClick={fetchDepartments}>
|
||
刷新
|
||
</Button>
|
||
<Button type="primary" icon={<PlusOutlined />} onClick={openCreateModal}>
|
||
新增部门
|
||
</Button>
|
||
</Space>
|
||
</div>
|
||
|
||
<Table rowKey="id" columns={columns} dataSource={departments} loading={loading} pagination={false} scroll={{ x: 920 }} />
|
||
</SycmCard>
|
||
|
||
<Modal
|
||
title={editingDepartment ? '编辑部门' : '新增部门'}
|
||
open={modalVisible}
|
||
onCancel={() => setModalVisible(false)}
|
||
onOk={handleSave}
|
||
confirmLoading={saving}
|
||
>
|
||
<Form form={form} layout="vertical" style={{ marginTop: 16 }}>
|
||
<Form.Item label="部门名称" name="name" rules={[{ required: true, message: '请输入部门名称' }]}>
|
||
<Input />
|
||
</Form.Item>
|
||
<Form.Item label="部门编码" name="code" rules={[{ required: true, message: '请输入部门编码' }]}>
|
||
<Input />
|
||
</Form.Item>
|
||
<Form.Item label="上级部门" name="parentId">
|
||
<Select
|
||
allowClear
|
||
placeholder="请选择上级部门"
|
||
options={departments
|
||
.filter((item) => item.source === 'local' && item.id !== editingDepartment?.id)
|
||
.map((item) => ({
|
||
value: item.id,
|
||
label: item.name,
|
||
}))}
|
||
/>
|
||
</Form.Item>
|
||
<Form.Item label="排序" name="sort">
|
||
<InputNumber min={0} style={{ width: '100%' }} />
|
||
</Form.Item>
|
||
<Form.Item label="状态" name="status">
|
||
<Select
|
||
options={[
|
||
{ value: 'active', label: '启用' },
|
||
{ value: 'inactive', label: '停用' },
|
||
]}
|
||
/>
|
||
</Form.Item>
|
||
</Form>
|
||
</Modal>
|
||
|
||
<Modal
|
||
title={permissionDepartment ? `${permissionDepartment.name} - 功能页面权限` : '功能页面权限'}
|
||
open={permissionVisible}
|
||
onCancel={() => setPermissionVisible(false)}
|
||
onOk={handleSavePermissions}
|
||
confirmLoading={permissionSaving}
|
||
width={640}
|
||
>
|
||
<div style={{ marginTop: 12 }}>
|
||
<Text type="secondary">开启后,该部门下的用户在侧边栏中可以看到对应功能页面;管理员角色不受部门侧限制。</Text>
|
||
<div style={{ marginTop: 20, display: 'grid', gap: 12 }}>
|
||
{pagePermissions.map((item) => (
|
||
<div
|
||
key={item.pageKey}
|
||
style={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
padding: '12px 14px',
|
||
borderRadius: 'var(--sycm-radius-lg)',
|
||
background: 'var(--sycm-bg-subtle)',
|
||
}}
|
||
>
|
||
<div>
|
||
<div style={{ fontWeight: 600 }}>{item.pageName}</div>
|
||
<Text type="secondary">{item.path}</Text>
|
||
</div>
|
||
<Switch checked={Boolean(item.allowed)} onChange={(value) => handlePermissionToggle(item.pageKey, value)} />
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default DepartmentManagement;
|