可正常启用
This commit is contained in:
parent
9975d4508e
commit
6e79e0faac
@ -1,134 +1,163 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Table, Button, Modal, Form, Input, Space, message, Switch, TreeSelect } from 'antd';
|
import { Table, Button, Modal, Form, Input, Space, InputNumber, Switch, TreeSelect, Select } from 'antd';
|
||||||
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||||
import type { DepartmentDTO } from './types';
|
import type { DepartmentResponse } from './types';
|
||||||
import { getDepartmentTree, createDepartment, updateDepartment, deleteDepartment, getNextSort } from './service.ts';
|
import { useTableData } from '@/hooks/useTableData';
|
||||||
|
import type { FixedType } from 'rc-table/lib/interface';
|
||||||
|
import { getDepartmentTree } from './service';
|
||||||
|
import type { UserResponse } from '@/pages/System/User/types';
|
||||||
|
import { getUsers } from './service';
|
||||||
|
|
||||||
const DepartmentPage: React.FC = () => {
|
const DepartmentPage: React.FC = () => {
|
||||||
const [departments, setDepartments] = useState<DepartmentDTO[]>([]);
|
const {
|
||||||
|
list: departments,
|
||||||
|
pagination,
|
||||||
|
loading,
|
||||||
|
loadData: fetchDepartments,
|
||||||
|
handleCreate,
|
||||||
|
handleUpdate,
|
||||||
|
handleDelete
|
||||||
|
} = useTableData({
|
||||||
|
service: {
|
||||||
|
baseUrl: '/api/v1/department'
|
||||||
|
},
|
||||||
|
defaultParams: {
|
||||||
|
sortField: 'createTime',
|
||||||
|
sortOrder: 'descend'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
const [editingDepartment, setEditingDepartment] = useState<DepartmentDTO | null>(null);
|
const [editingDepartment, setEditingDepartment] = useState<DepartmentResponse | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [departmentTree, setDepartmentTree] = useState<DepartmentResponse[]>([]);
|
||||||
|
const [users, setUsers] = useState<UserResponse[]>([]);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
const fetchDepartments = async () => {
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
const data = await getDepartmentTree();
|
|
||||||
setDepartments(data || []);
|
|
||||||
console.log("部门", data);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取部门列表失败:', error);
|
|
||||||
message.error('获取部门列表失败');
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchDepartments();
|
Promise.all([
|
||||||
|
getDepartmentTree().then(setDepartmentTree),
|
||||||
|
getUsers().then(setUsers)
|
||||||
|
]);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
setEditingDepartment(null);
|
setEditingDepartment(null);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
|
|
||||||
|
// 获取当前最大排序值
|
||||||
|
const maxSort = Math.max(0, ...departments.map(dept => dept.sort));
|
||||||
|
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
sort: 0
|
sort: maxSort + 1
|
||||||
});
|
});
|
||||||
setModalVisible(true);
|
setModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (record: DepartmentDTO) => {
|
const handleEdit = (record: DepartmentResponse) => {
|
||||||
setEditingDepartment(record);
|
setEditingDepartment(record);
|
||||||
form.setFieldsValue({
|
form.setFieldsValue(record);
|
||||||
...record,
|
|
||||||
parentId: record.parentId || undefined
|
|
||||||
});
|
|
||||||
setModalVisible(true);
|
setModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (id: number) => {
|
|
||||||
Modal.confirm({
|
|
||||||
title: '确认删除',
|
|
||||||
content: '确定要删除这个部门吗?',
|
|
||||||
onOk: async () => {
|
|
||||||
try {
|
|
||||||
await deleteDepartment(id);
|
|
||||||
message.success('删除成功');
|
|
||||||
fetchDepartments();
|
|
||||||
} catch (error) {
|
|
||||||
message.error('删除失败');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
if (editingDepartment) {
|
if (editingDepartment) {
|
||||||
await updateDepartment(editingDepartment.id, {
|
const success = await handleUpdate(editingDepartment.id, {
|
||||||
...values,
|
...values,
|
||||||
version: editingDepartment.version
|
version: editingDepartment.version
|
||||||
});
|
});
|
||||||
message.success('更新成功');
|
if (success) {
|
||||||
} else {
|
|
||||||
await createDepartment(values);
|
|
||||||
message.success('创建成功');
|
|
||||||
}
|
|
||||||
setModalVisible(false);
|
setModalVisible(false);
|
||||||
fetchDepartments();
|
fetchDepartments();
|
||||||
} catch (error) {
|
getDepartmentTree().then(setDepartmentTree);
|
||||||
message.error('操作失败');
|
}
|
||||||
|
} else {
|
||||||
|
const success = await handleCreate(values);
|
||||||
|
if (success) {
|
||||||
|
setModalVisible(false);
|
||||||
|
fetchDepartments();
|
||||||
|
getDepartmentTree().then(setDepartmentTree);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const handleParentChange = async (value: number | undefined) => {
|
|
||||||
try {
|
|
||||||
const nextSort = await getNextSort(value);
|
|
||||||
form.setFieldValue('sort', nextSort);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取排序号失败:', error);
|
console.error('操作失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '部门名称',
|
title: 'ID',
|
||||||
dataIndex: 'name',
|
dataIndex: 'id',
|
||||||
key: 'name',
|
key: 'id',
|
||||||
width: '25%',
|
width: 60,
|
||||||
|
fixed: 'left' as FixedType,
|
||||||
|
sorter: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '部门编码',
|
title: '部门编码',
|
||||||
dataIndex: 'code',
|
dataIndex: 'code',
|
||||||
key: 'code',
|
key: 'code',
|
||||||
width: '20%',
|
width: 100,
|
||||||
|
sorter: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '部门名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
width: 150,
|
||||||
|
sorter: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '上级部门',
|
||||||
|
dataIndex: 'parentId',
|
||||||
|
key: 'parentId',
|
||||||
|
width: 150,
|
||||||
|
render: (parentId: number) => {
|
||||||
|
const parent = departments.find(dept => dept.id === parentId);
|
||||||
|
return parent?.name || '-';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '部门描述',
|
||||||
|
dataIndex: 'description',
|
||||||
|
key: 'description',
|
||||||
|
width: 200,
|
||||||
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '排序',
|
title: '排序',
|
||||||
dataIndex: 'sort',
|
dataIndex: 'sort',
|
||||||
key: 'sort',
|
key: 'sort',
|
||||||
width: '15%',
|
width: 80,
|
||||||
|
sorter: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '负责人',
|
||||||
|
dataIndex: 'leaderName',
|
||||||
|
key: 'leaderName',
|
||||||
|
width: 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
dataIndex: 'enabled',
|
dataIndex: 'enabled',
|
||||||
key: 'enabled',
|
key: 'enabled',
|
||||||
width: '15%',
|
width: 80,
|
||||||
render: (enabled: boolean) => (
|
render: (enabled: boolean) => (
|
||||||
<Switch checked={enabled} disabled />
|
<Switch checked={enabled} disabled size="small"/>
|
||||||
),
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
width: '25%',
|
width: 160,
|
||||||
render: (_: any, record: DepartmentDTO) => (
|
fixed: 'right' as FixedType,
|
||||||
<Space>
|
render: (_: any, record: DepartmentResponse) => (
|
||||||
|
<Space size={0}>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
|
size="small"
|
||||||
icon={<EditOutlined/>}
|
icon={<EditOutlined/>}
|
||||||
onClick={() => handleEdit(record)}
|
onClick={() => handleEdit(record)}
|
||||||
>
|
>
|
||||||
@ -136,27 +165,19 @@ const DepartmentPage: React.FC = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
|
size="small"
|
||||||
danger
|
danger
|
||||||
icon={<DeleteOutlined/>}
|
icon={<DeleteOutlined/>}
|
||||||
onClick={() => handleDelete(record.id)}
|
onClick={() => handleDelete(record.id)}
|
||||||
disabled={record.parentId === null}
|
disabled={record.children?.length > 0}
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
),
|
)
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const getTreeSelectData = (deps: DepartmentDTO[]): any[] => {
|
|
||||||
return deps.map(dept => ({
|
|
||||||
title: dept.name,
|
|
||||||
value: dept.id,
|
|
||||||
children: dept.children && dept.children.length > 0 ? getTreeSelectData(dept.children) : undefined,
|
|
||||||
disabled: editingDepartment ? dept.id === editingDepartment.id : false
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{padding: '24px'}}>
|
<div style={{padding: '24px'}}>
|
||||||
<div style={{marginBottom: 16}}>
|
<div style={{marginBottom: 16}}>
|
||||||
@ -170,8 +191,8 @@ const DepartmentPage: React.FC = () => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={departments}
|
dataSource={departments}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
defaultExpandAllRows
|
scroll={{x: 1500}}
|
||||||
pagination={false}
|
pagination={pagination}
|
||||||
size="middle"
|
size="middle"
|
||||||
bordered
|
bordered
|
||||||
/>
|
/>
|
||||||
@ -188,6 +209,17 @@ const DepartmentPage: React.FC = () => {
|
|||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
>
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="code"
|
||||||
|
label="部门编码"
|
||||||
|
rules={[
|
||||||
|
{required: true, message: '请输入部门编码'},
|
||||||
|
{pattern: /^[A-Z_]+$/, message: '部门编码只能包含大写字母和下划线'}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入部门编码"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="name"
|
name="name"
|
||||||
label="部门名称"
|
label="部门名称"
|
||||||
@ -195,39 +227,84 @@ const DepartmentPage: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<Input placeholder="请输入部门名称"/>
|
<Input placeholder="请输入部门名称"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
|
||||||
name="code"
|
|
||||||
label="部门编码"
|
|
||||||
rules={[{ required: true, message: '请输入部门编码' }]}
|
|
||||||
>
|
|
||||||
<Input placeholder="请输入部门编码" />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="parentId"
|
name="parentId"
|
||||||
label="上级部门"
|
label="上级部门"
|
||||||
>
|
>
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
treeData={getTreeSelectData(departments)}
|
treeData={departmentTree.map(dept => ({
|
||||||
|
title: dept.name,
|
||||||
|
value: dept.id,
|
||||||
|
children: dept.children?.map(child => ({
|
||||||
|
title: child.name,
|
||||||
|
value: child.id
|
||||||
|
}))
|
||||||
|
}))}
|
||||||
placeholder="请选择上级部门"
|
placeholder="请选择上级部门"
|
||||||
allowClear
|
allowClear
|
||||||
treeDefaultExpandAll
|
treeDefaultExpandAll
|
||||||
onChange={handleParentChange}
|
disabled={editingDepartment?.children?.length > 0}
|
||||||
disabled={editingDepartment?.parentId === null}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="description"
|
||||||
|
label="部门描述"
|
||||||
|
>
|
||||||
|
<Input.TextArea placeholder="请输入部门描述"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="sort"
|
name="sort"
|
||||||
label="排序"
|
label="显示排序"
|
||||||
|
rules={[{required: true, message: '请输入显示排序'}]}
|
||||||
>
|
>
|
||||||
<Input type="number" placeholder="排序号将自动生成" disabled />
|
<InputNumber
|
||||||
|
style={{width: '100%'}}
|
||||||
|
min={0}
|
||||||
|
placeholder="请输入显示排序"
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="leaderId"
|
||||||
|
label="负责人"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder="请选择负责人"
|
||||||
|
allowClear
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="children"
|
||||||
|
onChange={(value, option: any) => {
|
||||||
|
form.setFieldsValue({
|
||||||
|
leaderId: value,
|
||||||
|
leaderName: option?.label
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{users.map(user => (
|
||||||
|
<Select.Option
|
||||||
|
key={user.id}
|
||||||
|
value={user.id}
|
||||||
|
label={user.nickname || user.username}
|
||||||
|
>
|
||||||
|
{user.nickname || user.username}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="leaderName" hidden>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="enabled"
|
name="enabled"
|
||||||
label="状态"
|
label="状态"
|
||||||
valuePropName="checked"
|
valuePropName="checked"
|
||||||
initialValue={true}
|
|
||||||
>
|
>
|
||||||
<Switch />
|
<Switch checkedChildren="启用" unCheckedChildren="禁用"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@ -1,33 +1,30 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
|
import type { Page } from '@/types/base/page';
|
||||||
import type { DepartmentResponse, DepartmentRequest, DepartmentQuery } from './types';
|
import type { DepartmentResponse, DepartmentRequest, DepartmentQuery } from './types';
|
||||||
|
|
||||||
export const getDepartments = async (params?: DepartmentQuery) => {
|
const BASE_URL = '/api/v1/department';
|
||||||
return request.get('/api/v1/department', {
|
|
||||||
params,
|
|
||||||
errorMessage: '获取部门列表失败,请刷新重试'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createDepartment = async (data: DepartmentRequest) => {
|
// 获取部门列表(分页)
|
||||||
return request.post('/api/v1/department', data, {
|
export const getDepartments = (params?: DepartmentQuery) =>
|
||||||
errorMessage: '创建部门失败,请稍后重试'
|
request.get<Page<DepartmentResponse>>(`${BASE_URL}/page`, { params });
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateDepartment = async (id: number, data: DepartmentRequest) => {
|
// 获取部门树
|
||||||
return request.put(`/api/v1/department/${id}`, data, {
|
export const getDepartmentTree = () =>
|
||||||
errorMessage: '更新部门失败,请稍后重试'
|
request.get<DepartmentResponse[]>(`${BASE_URL}/tree`);
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteDepartment = async (id: number) => {
|
// 创建部门
|
||||||
return request.delete(`/api/v1/department/${id}`, {
|
export const createDepartment = (data: DepartmentRequest) =>
|
||||||
errorMessage: '删除部门失败,请稍后重试'
|
request.post<DepartmentResponse>(BASE_URL, data);
|
||||||
});
|
|
||||||
};
|
// 更新部门
|
||||||
|
export const updateDepartment = (id: number, data: DepartmentRequest) =>
|
||||||
|
request.put<DepartmentResponse>(`${BASE_URL}/${id}`, data);
|
||||||
|
|
||||||
|
// 删除部门
|
||||||
|
export const deleteDepartment = (id: number) =>
|
||||||
|
request.delete(`${BASE_URL}/${id}`);
|
||||||
|
|
||||||
|
// 获取用户列表(不分页)
|
||||||
|
export const getUsers = () =>
|
||||||
|
request.get<UserResponse[]>('/api/v1/user/list');
|
||||||
|
|
||||||
export const getDepartmentTree = async () => {
|
|
||||||
return request.get('/api/v1/department/tree', {
|
|
||||||
errorMessage: '获取部门树失败,请刷新重试'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@ -1,21 +1,33 @@
|
|||||||
export interface DepartmentDTO {
|
import type { BaseResponse } from '@/types/base/response';
|
||||||
id: number;
|
|
||||||
name: string;
|
export interface DepartmentResponse extends BaseResponse {
|
||||||
code: string;
|
code: string;
|
||||||
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
parentId?: number;
|
parentId?: number;
|
||||||
sort: number;
|
sort: number;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
leaderId?: number;
|
leaderId?: number;
|
||||||
leaderName?: string;
|
leaderName?: string;
|
||||||
version?: number;
|
children?: DepartmentResponse[];
|
||||||
children?: DepartmentDTO[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TreeSelectNode {
|
export interface DepartmentRequest {
|
||||||
title: string;
|
code: string;
|
||||||
value: number;
|
name: string;
|
||||||
key: number;
|
description?: string;
|
||||||
disabled: boolean;
|
parentId?: number;
|
||||||
children?: TreeSelectNode[];
|
sort: number;
|
||||||
|
enabled: boolean;
|
||||||
|
leaderId?: number;
|
||||||
|
leaderName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DepartmentQuery {
|
||||||
|
code?: string;
|
||||||
|
name?: string;
|
||||||
|
parentId?: number;
|
||||||
|
enabled?: boolean;
|
||||||
|
leaderId?: number;
|
||||||
|
leaderName?: string;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user