生产管理系统 部门全页面开发完毕

This commit is contained in:
2025-11-04 20:09:05 +08:00
parent 8974ea802a
commit e92be97393
5 changed files with 174 additions and 161 deletions

View File

@@ -35,57 +35,21 @@ export function DepartmentDeleteDialog({
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-md">
<DialogHeader>
<div className="flex items-center gap-3">
<div className="p-2 rounded-full bg-red-100 dark:bg-red-900">
<AlertTriangle className="w-5 h-5 text-red-600 dark:text-red-400" />
</div>
<div>
<DialogTitle></DialogTitle>
</div>
</div>
<DialogTitle></DialogTitle>
</DialogHeader>
<DialogDescription className="text-left">
{deletingDepartment && (
<div className="space-y-4">
{/* 部门信息 */}
<div className="flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-800 rounded-lg">
<span className="text-2xl">🏢</span>
<div>
<div className="font-medium">{deletingDepartment.name}</div>
<div className="text-sm text-muted-foreground">{deletingDepartment.code}</div>
{deletingDepartment.manager && (
<div className="text-sm text-muted-foreground">
{deletingDepartment.manager}
</div>
)}
</div>
</div>
{/* 删除影响说明 */}
<div className="p-4 bg-orange-50 dark:bg-orange-950 border border-orange-200 dark:border-orange-800 rounded-lg">
<div className="flex items-start gap-3">
<AlertTriangle className="w-5 h-5 mt-0.5 flex-shrink-0 text-orange-600 dark:text-orange-400" />
<div>
<div className="font-medium mb-2 text-orange-800 dark:text-orange-200">
</div>
<ul className="text-sm space-y-1 text-orange-700 dark:text-orange-300">
<li> </li>
<li> </li>
<li> </li>
</ul>
</div>
</div>
</div>
{/* 确认提示 */}
<div className="text-center">
<p className="text-muted-foreground">
<strong>{deletingDepartment.name}</strong>
</p>
</div>
{deletingDepartment ? (
<div className="space-y-3">
<p>
<strong>{deletingDepartment.name}</strong>
</p>
<p className="text-sm text-muted-foreground">
</p>
</div>
) : (
<p></p>
)}
</DialogDescription>
@@ -97,7 +61,7 @@ export function DepartmentDeleteDialog({
variant="destructive"
onClick={handleConfirm}
>
</Button>
</DialogFooter>
</DialogContent>

View File

@@ -7,7 +7,7 @@
'use client';
import { useState, useCallback } from 'react';
import { useState, useCallback, useEffect } from 'react';
import { toast } from 'sonner';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
@@ -17,9 +17,10 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
import { Department, CreateDepartmentForm } from '../types';
import {
createDepartment,
updateDepartment,
transformCreateDepartmentData,
debounce,
generateRandomOrderIndex,
getDefaultOrderIndex,
} from './departmentCreateApi';
interface DepartmentFormDialogProps {
@@ -47,43 +48,48 @@ export function DepartmentFormDialog({
email: '',
description: '',
status: 'active',
sort: generateRandomOrderIndex(),
sort: 0,
parentId: parentDepartment?.id || '',
level: parentDepartment ? (parentDepartment.level || 1) + 1 : 1,
});
const [loading, setLoading] = useState(false);
// 当编辑部门或父部门变化时,重置表单数据
useState(() => {
if (editingDepartment) {
setFormData({
name: editingDepartment.name,
code: editingDepartment.code,
manager: editingDepartment.manager || '',
phone: editingDepartment.phone || '',
email: editingDepartment.email || '',
description: editingDepartment.description || '',
status: editingDepartment.status,
sort: editingDepartment.sort,
parentId: editingDepartment.parentId || '',
level: editingDepartment.level,
});
} else {
setFormData({
name: '',
code: '',
manager: '',
phone: '',
email: '',
description: '',
status: 'active',
sort: generateRandomOrderIndex(),
parentId: parentDepartment?.id || '',
level: parentDepartment ? (parentDepartment.level || 1) + 1 : 1,
});
// 当弹窗打开状态变化时,处理表单数据
useEffect(() => {
if (open) {
// 弹窗打开时,根据编辑状态初始化表单
if (editingDepartment) {
// 编辑模式:带入所有部门数据
setFormData({
name: editingDepartment.name || '',
code: editingDepartment.code || '',
manager: editingDepartment.manager || '',
phone: editingDepartment.phone || '',
email: editingDepartment.email || '',
description: editingDepartment.description || '',
status: editingDepartment.status || 'active',
sort: editingDepartment.sort || 0,
parentId: editingDepartment.parentId || '',
level: editingDepartment.level || 1,
});
} else {
// 新增模式:清空表单,使用默认值
setFormData({
name: '',
code: '',
manager: '',
phone: '',
email: '',
description: '',
status: 'active',
sort: 0,
parentId: parentDepartment?.id || '',
level: parentDepartment ? (parentDepartment.level || 1) + 1 : 1,
});
}
}
});
}, [open, editingDepartment, parentDepartment]);
const handleInputChange = (field: keyof CreateDepartmentForm, value: string | number) => {
setFormData(prev => ({ ...prev, [field]: value }));
@@ -126,20 +132,6 @@ export function DepartmentFormDialog({
refreshDepartmentTree();
}
// 重置表单
setFormData({
name: '',
code: '',
manager: '',
phone: '',
email: '',
description: '',
status: 'active',
sort: generateRandomOrderIndex(),
parentId: parentDepartment?.id || '',
level: parentDepartment ? (parentDepartment.level || 1) + 1 : 1,
});
} catch (error) {
// 失败处理 - 不关闭页面
console.error('创建部门失败:', error);
@@ -158,19 +150,27 @@ export function DepartmentFormDialog({
return;
}
// 如果是编辑模式,使用原有的onSave逻辑
// 如果是编辑模式,使用API调用
if (editingDepartment) {
setLoading(true);
try {
await onSave(formData);
// 调用更新部门API
await updateDepartment(editingDepartment.id, formData);
// 成功处理
toast.success('部门更新成功');
onOpenChange(false);
// 刷新部门树
if (refreshDepartmentTree) {
refreshDepartmentTree();
}
} catch (error) {
console.error('Failed to update department:', error);
toast.error('部门更新失败');
// 失败处理 - 不关闭页面
console.error('更新部门失败:', error);
const errorMessage = error instanceof Error ? error.message : '部门更新失败';
toast.error(errorMessage);
} finally {
setLoading(false);
}
@@ -183,19 +183,6 @@ export function DepartmentFormDialog({
const handleClose = () => {
if (!loading) {
onOpenChange(false);
// 重置表单
setFormData({
name: '',
code: '',
manager: '',
phone: '',
email: '',
description: '',
status: 'active',
sort: generateRandomOrderIndex(),
parentId: parentDepartment?.id || '',
level: parentDepartment ? (parentDepartment.level || 1) + 1 : 1,
});
}
};

View File

@@ -149,16 +149,15 @@ export function DepartmentTree({
{/* 操作按钮 */}
<div className="flex items-center gap-1 ml-4">
{level < 1 && (
<Button
variant="ghost"
size="sm"
onClick={() => onAdd(dept)}
title="添加子部门"
>
<Plus className="w-4 h-4 text-green-600 dark:text-green-400" />
</Button>
)}
{/* 所有节点都可以添加子部门 */}
<Button
variant="ghost"
size="sm"
onClick={() => onAdd(dept)}
title="添加子部门"
>
<Plus className="w-4 h-4 text-green-600 dark:text-green-400" />
</Button>
<Button
variant="ghost"
size="sm"

View File

@@ -8,12 +8,17 @@
import { getAuthToken } from "@/utils/token";
import {
createDepartmentApiV1DepartmentsPost,
updateDepartmentApiV1DepartmentsDepartmentIdPut,
deleteDepartmentApiV1DepartmentsDepartmentIdDelete,
} from "@/lib/api/sdk.gen";
import {
Department,
CreateDepartmentForm,
} from '../types';
// 导出deleteDepartment供其他模块使用
export { deleteDepartment };
/**
* API请求创建部门的数据结构对应Python字段
*/
@@ -109,10 +114,82 @@ export async function createDepartment(formData: CreateDepartmentForm): Promise<
}
/**
* 生成随机排序索引0-10000
* 更新部门API调用
*/
export function generateRandomOrderIndex(): number {
return Math.floor(Math.random() * 10001);
export async function updateDepartment(departmentId: string, formData: CreateDepartmentForm): Promise<CreateDepartmentApiResponse> {
try {
// 获取认证token
const token = getAuthToken();
console.log('更新部门API调用参数:', departmentId, formData);
// 转换表单数据为API请求格式
const apiRequestData = transformCreateDepartmentData(formData);
// 邮箱格式验证
if (apiRequestData.manager_email && !isValidEmail(apiRequestData.manager_email)) {
throw new Error('邮箱格式不正确');
}
// 使用真正的SDK API调用
const response = await updateDepartmentApiV1DepartmentsDepartmentIdPut({
path: {
department_id: departmentId,
},
body: apiRequestData,
headers: token ? {
'Authorization': `Bearer ${token}`,
} : undefined,
});
if (response.error) {
throw new Error(`API error: ${response.error.message || 'Unknown error'}`);
}
const data = response.data as CreateDepartmentApiResponse;
console.log('更新部门API响应:', data);
return data;
} catch (error) {
console.error('Failed to update department:', error);
throw error;
}
}
/**
* 获取默认排序索引
*/
export function getDefaultOrderIndex(): number {
return 0;
}
/**
* 删除部门API调用
*/
export async function deleteDepartment(departmentId: string): Promise<void> {
try {
// 获取认证token
const token = getAuthToken();
console.log('删除部门API调用参数:', departmentId);
// 使用真正的SDK API调用
const response = await deleteDepartmentApiV1DepartmentsDepartmentIdDelete({
path: {
department_id: departmentId,
},
headers: token ? {
'Authorization': `Bearer ${token}`,
} : undefined,
});
if (response.error) {
throw new Error(`API error: ${response.error.message || 'Unknown error'}`);
}
console.log('删除部门API响应: 成功');
} catch (error) {
console.error('Failed to delete department:', error);
throw error;
}
}
/**

View File

@@ -22,6 +22,7 @@ import {
flattenDepartments,
type DepartmentTreeState
} from './components/departmentApi';
import { deleteDepartment } from './components/departmentCreateApi';
// 部门管理状态管理
interface DepartmentManagementState {
@@ -135,8 +136,8 @@ export default function DepartmentManagementPage() {
// 转换API数据为页面所需的格式
const departments = transformDepartmentList(response.data);
// 转换为与现有页面兼容的数据格式
const compatibleDepartments: Department[] = departments.map(dept => ({
// 递归转换部门数据为与现有页面兼容的数据格式
const transformDepartmentRecursive = (dept: any): Department => ({
id: dept.id,
name: dept.name,
code: dept.code,
@@ -150,22 +151,10 @@ export default function DepartmentManagementPage() {
parentId: dept.parentId || undefined,
createdAt: dept.createdAt,
updatedAt: dept.updatedAt,
children: dept.children.map(child => ({
id: child.id,
name: child.name,
code: child.code,
level: child.level + 1,
manager: child.manager, // 从API的manager_name字段获取
phone: child.phone, // 从API的manager_phone字段获取
email: child.email, // 从API的manager_email字段获取
description: child.description,
sort: child.sortOrder,
status: child.status as 'active' | 'inactive',
parentId: child.parentId || undefined,
createdAt: child.createdAt,
updatedAt: child.updatedAt,
})),
}));
children: dept.children ? dept.children.map(transformDepartmentRecursive) : [],
});
const compatibleDepartments: Department[] = departments.map(transformDepartmentRecursive);
dispatch({ type: 'SET_DEPARTMENTS', payload: compatibleDepartments });
// 默认展开所有一级部门
@@ -334,29 +323,26 @@ export default function DepartmentManagementPage() {
};
// 确认删除
const confirmDelete = () => {
const confirmDelete = async () => {
if (!state.deletingDepartment) return;
const deleteFromTree = (items: Department[]): Department[] => {
return items
.filter(item => item.id !== state.deletingDepartment!.id)
.map(item => {
if (item.children) {
return {
...item,
children: deleteFromTree(item.children),
};
}
return item;
});
};
try {
// 调用删除API
await deleteDepartment(state.deletingDepartment.id);
const updated = deleteFromTree(state.departments);
dispatch({ type: 'SET_DEPARTMENTS', payload: updated });
toast.success('部门删除成功');
// 删除成功后,刷新部门列表
await loadDepartments();
dispatch({ type: 'TOGGLE_DELETE_DIALOG', payload: false });
dispatch({ type: 'SET_DELETING_DEPARTMENT', payload: null });
toast.success('部门删除成功');
// 关闭删除对话框
dispatch({ type: 'TOGGLE_DELETE_DIALOG', payload: false });
dispatch({ type: 'SET_DELETING_DEPARTMENT', payload: null });
} catch (error) {
console.error('Failed to delete department:', error);
const errorMessage = error instanceof Error ? error.message : '删除部门失败';
toast.error(errorMessage);
}
};
// 拖拽功能