可正常启用

This commit is contained in:
戚辰先生 2024-12-01 14:44:21 +08:00
parent 9975d4508e
commit 6e79e0faac
3 changed files with 352 additions and 266 deletions

View File

@ -1,166 +1,187 @@
import React, { useEffect, useState } from 'react';
import { Table, Button, Modal, Form, Input, Space, message, Switch, TreeSelect } from 'antd';
import React, { useState, useEffect } from 'react';
import { Table, Button, Modal, Form, Input, Space, InputNumber, Switch, TreeSelect, Select } from 'antd';
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
import type { DepartmentDTO } from './types';
import { getDepartmentTree, createDepartment, updateDepartment, deleteDepartment, getNextSort } from './service.ts';
import type { DepartmentResponse } from './types';
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 [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 [editingDepartment, setEditingDepartment] = useState<DepartmentDTO | null>(null);
const [loading, setLoading] = useState(false);
const [editingDepartment, setEditingDepartment] = useState<DepartmentResponse | null>(null);
const [departmentTree, setDepartmentTree] = useState<DepartmentResponse[]>([]);
const [users, setUsers] = useState<UserResponse[]>([]);
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(() => {
fetchDepartments();
Promise.all([
getDepartmentTree().then(setDepartmentTree),
getUsers().then(setUsers)
]);
}, []);
const handleAdd = () => {
setEditingDepartment(null);
form.resetFields();
// 获取当前最大排序值
const maxSort = Math.max(0, ...departments.map(dept => dept.sort));
form.setFieldsValue({
enabled: true,
sort: 0
sort: maxSort + 1
});
setModalVisible(true);
};
const handleEdit = (record: DepartmentDTO) => {
const handleEdit = (record: DepartmentResponse) => {
setEditingDepartment(record);
form.setFieldsValue({
...record,
parentId: record.parentId || undefined
});
form.setFieldsValue(record);
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 () => {
try {
const values = await form.validateFields();
if (editingDepartment) {
await updateDepartment(editingDepartment.id, {
const success = await handleUpdate(editingDepartment.id, {
...values,
version: editingDepartment.version
});
message.success('更新成功');
} else {
await createDepartment(values);
message.success('创建成功');
}
if (success) {
setModalVisible(false);
fetchDepartments();
} catch (error) {
message.error('操作失败');
getDepartmentTree().then(setDepartmentTree);
}
} 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) {
console.error('获取排序号失败:', error);
console.error('操作失败:', error);
}
};
const columns = [
{
title: '部门名称',
dataIndex: 'name',
key: 'name',
width: '25%',
title: 'ID',
dataIndex: 'id',
key: 'id',
width: 60,
fixed: 'left' as FixedType,
sorter: true
},
{
title: '部门编码',
dataIndex: '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: '排序',
dataIndex: 'sort',
key: 'sort',
width: '15%',
width: 80,
sorter: true
},
{
title: '负责人',
dataIndex: 'leaderName',
key: 'leaderName',
width: 100
},
{
title: '状态',
dataIndex: 'enabled',
key: 'enabled',
width: '15%',
width: 80,
render: (enabled: boolean) => (
<Switch checked={enabled} disabled />
),
<Switch checked={enabled} disabled size="small"/>
)
},
{
title: '操作',
key: 'action',
width: '25%',
render: (_: any, record: DepartmentDTO) => (
<Space>
width: 160,
fixed: 'right' as FixedType,
render: (_: any, record: DepartmentResponse) => (
<Space size={0}>
<Button
type="link"
icon={<EditOutlined />}
size="small"
icon={<EditOutlined/>}
onClick={() => handleEdit(record)}
>
</Button>
<Button
type="link"
size="small"
danger
icon={<DeleteOutlined />}
icon={<DeleteOutlined/>}
onClick={() => handleDelete(record.id)}
disabled={record.parentId === null}
disabled={record.children?.length > 0}
>
</Button>
</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 (
<div style={{ padding: '24px' }}>
<div style={{ marginBottom: 16 }}>
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
<div style={{padding: '24px'}}>
<div style={{marginBottom: 16}}>
<Button type="primary" icon={<PlusOutlined/>} onClick={handleAdd}>
</Button>
</div>
@ -170,8 +191,8 @@ const DepartmentPage: React.FC = () => {
columns={columns}
dataSource={departments}
rowKey="id"
defaultExpandAllRows
pagination={false}
scroll={{x: 1500}}
pagination={pagination}
size="middle"
bordered
/>
@ -188,46 +209,102 @@ const DepartmentPage: React.FC = () => {
form={form}
layout="vertical"
>
<Form.Item
name="name"
label="部门名称"
rules={[{ required: true, message: '请输入部门名称' }]}
>
<Input placeholder="请输入部门名称" />
</Form.Item>
<Form.Item
name="code"
label="部门编码"
rules={[{ required: true, message: '请输入部门编码' }]}
rules={[
{required: true, message: '请输入部门编码'},
{pattern: /^[A-Z_]+$/, message: '部门编码只能包含大写字母和下划线'}
]}
>
<Input placeholder="请输入部门编码" />
<Input placeholder="请输入部门编码"/>
</Form.Item>
<Form.Item
name="name"
label="部门名称"
rules={[{required: true, message: '请输入部门名称'}]}
>
<Input placeholder="请输入部门名称"/>
</Form.Item>
<Form.Item
name="parentId"
label="上级部门"
>
<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="请选择上级部门"
allowClear
treeDefaultExpandAll
onChange={handleParentChange}
disabled={editingDepartment?.parentId === null}
disabled={editingDepartment?.children?.length > 0}
/>
</Form.Item>
<Form.Item
name="description"
label="部门描述"
>
<Input.TextArea placeholder="请输入部门描述"/>
</Form.Item>
<Form.Item
name="sort"
label="排序"
label="显示排序"
rules={[{required: true, message: '请输入显示排序'}]}
>
<Input type="number" placeholder="排序号将自动生成" disabled />
<InputNumber
style={{width: '100%'}}
min={0}
placeholder="请输入显示排序"
/>
</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
name="enabled"
label="状态"
valuePropName="checked"
initialValue={true}
>
<Switch />
<Switch checkedChildren="启用" unCheckedChildren="禁用"/>
</Form.Item>
</Form>
</Modal>

View File

@ -1,33 +1,30 @@
import request from '@/utils/request';
import type { Page } from '@/types/base/page';
import type { DepartmentResponse, DepartmentRequest, DepartmentQuery } from './types';
export const getDepartments = async (params?: DepartmentQuery) => {
return request.get('/api/v1/department', {
params,
errorMessage: '获取部门列表失败,请刷新重试'
});
};
const BASE_URL = '/api/v1/department';
export const createDepartment = async (data: DepartmentRequest) => {
return request.post('/api/v1/department', data, {
errorMessage: '创建部门失败,请稍后重试'
});
};
// 获取部门列表(分页)
export const getDepartments = (params?: DepartmentQuery) =>
request.get<Page<DepartmentResponse>>(`${BASE_URL}/page`, { params });
export const updateDepartment = async (id: number, data: DepartmentRequest) => {
return request.put(`/api/v1/department/${id}`, data, {
errorMessage: '更新部门失败,请稍后重试'
});
};
// 获取部门树
export const getDepartmentTree = () =>
request.get<DepartmentResponse[]>(`${BASE_URL}/tree`);
export const deleteDepartment = async (id: number) => {
return request.delete(`/api/v1/department/${id}`, {
errorMessage: '删除部门失败,请稍后重试'
});
};
// 创建部门
export const createDepartment = (data: DepartmentRequest) =>
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: '获取部门树失败,请刷新重试'
});
};

View File

@ -1,21 +1,33 @@
export interface DepartmentDTO {
id: number;
name: string;
import type { BaseResponse } from '@/types/base/response';
export interface DepartmentResponse extends BaseResponse {
code: string;
name: string;
description?: string;
parentId?: number;
sort: number;
enabled: boolean;
leaderId?: number;
leaderName?: string;
version?: number;
children?: DepartmentDTO[];
children?: DepartmentResponse[];
}
export interface TreeSelectNode {
title: string;
value: number;
key: number;
disabled: boolean;
children?: TreeSelectNode[];
export interface DepartmentRequest {
code: string;
name: string;
description?: string;
parentId?: number;
sort: number;
enabled: boolean;
leaderId?: number;
leaderName?: string;
}
export interface DepartmentQuery {
code?: string;
name?: string;
parentId?: number;
enabled?: boolean;
leaderId?: number;
leaderName?: string;
}