This commit is contained in:
Li1304553726 2025-03-27 12:59:35 +08:00
parent dd513444c5
commit 652883d142
2 changed files with 226 additions and 195 deletions

View File

@ -1,11 +1,10 @@
import { useState, useEffect, useMemo, useCallback } from 'react'; import { useState, useEffect, useMemo, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react'; import { AgGridReact } from 'ag-grid-react';
import { api, useStaff } from "@nice/client"; import { api, useStaff } from "@nice/client";
import 'ag-grid-community/styles/ag-grid.css'; import { Button, CascaderProps, message, Modal } from 'antd';
import 'ag-grid-community/styles/ag-theme-alpine.css';
import { SetFilterModule } from 'ag-grid-enterprise';
import { Button, CascaderProps, message } from 'antd';
import { areaOptions } from '@web/src/app/main/staffinfo_write/area-options'; import { areaOptions } from '@web/src/app/main/staffinfo_write/area-options';
import StaffInfoWrite from '@web/src/app/main/staffinfo_write/staffinfo_write.page';
function getAreaName(codes: string[], level?: number): string { function getAreaName(codes: string[], level?: number): string {
const result: string[] = []; const result: string[] = [];
let currentLevel: CascaderProps['options'] = areaOptions; let currentLevel: CascaderProps['options'] = areaOptions;
@ -25,6 +24,8 @@ export default function StaffMessage() {
const [selectedRows, setSelectedRows] = useState<any[]>([]); const [selectedRows, setSelectedRows] = useState<any[]>([]);
const { useCustomFields, softDeleteByIds } = useStaff(); const { useCustomFields, softDeleteByIds } = useStaff();
const fields = useCustomFields(); const fields = useCustomFields();
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
const [currentEditStaff, setCurrentEditStaff] = useState<any>(null);
// 获取数据 // 获取数据
const { data: staffData } = api.staff.findMany.useQuery({ const { data: staffData } = api.staff.findMany.useQuery({
@ -42,15 +43,14 @@ export default function StaffMessage() {
department: true department: true
} }
} as any); } as any);
// console.log(staffData);
const actionColumns = [{ const actionColumns = [{
field:"action", field: "action",
width: 50, width: 50,
checkboxSelection: true, checkboxSelection: true,
headerCheckboxSelection: true, headerCheckboxSelection: true,
pinned: 'left' pinned: 'left'
}] }]
// 新增编辑处理函数 // 新增编辑处理函数
const handleEdit = useCallback(async () => { const handleEdit = useCallback(async () => {
if (selectedRows.length === 0) return; if (selectedRows.length === 0) return;
@ -58,8 +58,17 @@ export default function StaffMessage() {
message.error('只能选择一个员工进行编辑'); message.error('只能选择一个员工进行编辑');
return; return;
} }
console.log(selectedRows[0]); setCurrentEditStaff(selectedRows[0]);
setIsEditModalVisible(true);
}, [selectedRows]); }, [selectedRows]);
console.log('选中行',currentEditStaff);
// 处理编辑完成
const handleEditComplete = useCallback(() => {
setIsEditModalVisible(false);
setCurrentEditStaff(null);
// 刷新表格数据
api.staff.findMany.useQuery();
}, []);
// 新增删除处理函数 // 新增删除处理函数
const handleDelete = useCallback(async () => { const handleDelete = useCallback(async () => {
@ -111,7 +120,7 @@ export default function StaffMessage() {
)?.value; )?.value;
// 根据字段类型格式化 // 根据字段类型格式化
switch(field.type) { switch (field.type) {
case 'cascader': case 'cascader':
return rawValue ? getAreaName(rawValue.split('/')) : ''; return rawValue ? getAreaName(rawValue.split('/')) : '';
@ -131,7 +140,6 @@ export default function StaffMessage() {
})), })),
[fields.data] [fields.data]
); );
// 合并列定义 // 合并列定义
useEffect(() => { useEffect(() => {
setColumnDefs([...actionColumns, ...baseColumns, ...dynamicColumns]); setColumnDefs([...actionColumns, ...baseColumns, ...dynamicColumns]);
@ -143,27 +151,58 @@ export default function StaffMessage() {
}, [staffData]); }, [staffData]);
return ( return (
<> <>
<Button className='mr-2' danger onClick={handleDelete} style={{ marginBottom: '10px' }}></Button> <div className="flex justify-between items-center mb-4">
<Button type="primary" onClick={handleEdit} style={{ marginBottom: '10px' }}></Button> <div className="space-x-2">
<div className="ag-theme-alpine" style={{ height: '100%', width: '100%', padding: '20px' }}> <Button className="bg-red-500 hover:bg-red-600 border-red-500 text-white rounded-md px-4 py-2"
<h1 className="text-2xl mb-4"></h1> onClick={handleDelete}></Button>
<Button className="bg-blue-500 hover:bg-blue-600 border-blue-500 text-white rounded-md px-4 py-2"
onClick={handleEdit}></Button>
</div>
<Button className="bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700 rounded-md px-4 py-2"
onClick={() => {
}}></Button>
</div>
<div className="bg-white rounded-lg shadow-md p-6 mb-4">
<h1 className="text-2xl font-bold text-gray-800 mb-4"></h1>
<div className="ag-theme-alpine w-full min-h-[480px] h-auto overflow-visible">
<AgGridReact <AgGridReact
modules={[SetFilterModule]}
rowData={rowData} rowData={rowData}
columnDefs={columnDefs} columnDefs={columnDefs}
pagination={true} pagination={true}
paginationPageSize={10} paginationPageSize={10}
paginationPageSizeSelector={[10, 20, 50, 100]}
onSelectionChanged={e => setSelectedRows(e.api.getSelectedRows())} onSelectionChanged={e => setSelectedRows(e.api.getSelectedRows())}
rowSelection="multiple" rowSelection="multiple"
className="rounded border border-gray-200"
headerHeight={40}
rowHeight={40}
domLayout="autoHeight"
/> />
</div> </div>
<Button onClick={() => { </div>
console.log('字段配置:', fields.data);
console.log('员工数据:', staffData); {/* 编辑弹窗 */}
}}></Button> <Modal
title="编辑员工信息"
open={isEditModalVisible}
onCancel={() => setIsEditModalVisible(false)}
footer={null}
width={1000}
destroyOnClose={true}
>
{currentEditStaff && (
<StaffInfoWrite
staffId={currentEditStaff.id}
initialData={currentEditStaff}
fieldValues={currentEditStaff.fieldValues}
onComplete={handleEditComplete}
setIsEditModalVisible={setIsEditModalVisible}
/>
)}
</Modal>
</> </>
); );
} }

View File

@ -5,11 +5,20 @@ import { areaOptions } from './area-options';
import InfoCard from './infoCard'; import InfoCard from './infoCard';
import DepartmentSelect from "@web/src/components/models/department/department-select"; import DepartmentSelect from "@web/src/components/models/department/department-select";
import { baseFields } from "@web/src/app/admin/staffinfo-manage/defaultFields"; import { baseFields } from "@web/src/app/admin/staffinfo-manage/defaultFields";
const StaffInfoWrite = () => { import dayjs from 'dayjs'; // 导入 dayjs
interface StaffInformationProps {
staffId?: string; // 可选,编辑模式时提供
onComplete?: () => void; // 可选,完成时的回调函数
initialData?: any; // 可选,编辑模式时提供的初始数据
fieldValues?: any[]; // 可选,编辑模式时提供的字段值数组
setIsEditModalVisible?: (visible: boolean) => void; // 可选,编辑模式时提供的回调函数
}
const StaffInfoWrite = ({ staffId, onComplete, initialData, fieldValues, setIsEditModalVisible }: StaffInformationProps) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
// 修改使用的hook方法 // 修改使用的hook方法
const { create, setCustomFieldValue, useCustomFields } = useStaff(); const { create, update, setCustomFieldValue, useCustomFields } = useStaff();
const { data: fields, isLoading: fieldsLoading } = useCustomFields(); const { data: fields, isLoading: fieldsLoading } = useCustomFields();
const [infoCards, setInfoCards] = useState<any[]>([]); const [infoCards, setInfoCards] = useState<any[]>([]);
@ -19,7 +28,10 @@ const StaffInfoWrite = () => {
// 添加状态来跟踪每个文本区域的高度 // 添加状态来跟踪每个文本区域的高度
const [textAreaHeights, setTextAreaHeights] = useState<Record<string, number>>({}); const [textAreaHeights, setTextAreaHeights] = useState<Record<string, number>>({});
const { data: staffData } = api.staff.findUnique.useQuery(
{ where: { id: staffId } },
{ enabled: !!staffId } // 只在 staffId 存在时执行查询
);
const handleAdd = (content: string[]) => { const handleAdd = (content: string[]) => {
// 将数组内容展开为独立对象 // 将数组内容展开为独立对象
const newItems = content.map(text => ({ content: text })); const newItems = content.map(text => ({ content: text }));
@ -29,26 +41,51 @@ const StaffInfoWrite = () => {
]); ]);
} }
// 在组件中添加监听字段变化 // 在组件挂载或依赖项变化时填充表单数据
useEffect(() => { useEffect(() => {
// 设置默认值 if (initialData && fieldValues && fields) {
form.setFieldsValue({ // 设置基础字段
hasTrain: false, const formValues: any = {
hasCert: false showname: initialData.showname,
}); department: initialData.deptId
// 使用 Form 的 onValuesChange 在外部监听
const fieldChangeHandler = () => {
const values = form.getFieldsValue(['hasTrain', 'hasCert']);
setHasTrain(!!values.hasTrain);
setHasCert(!!values.hasCert);
}; };
// 初始化时执行一次 // 设置自定义字段值
fieldChangeHandler(); if (Array.isArray(fieldValues)) {
fieldValues.forEach(fv => {
// 添加类型断言确保 fields 是数组
const field = Array.isArray(fields) ?
fields.find((f: any) => f.id === fv.fieldId) : undefined;
if (field) {
let value = fv.value;
// 不需要返回取消订阅,因为我们不再使用 subscribe // 根据字段类型转换值的格式
}, [form]); if (field.type === 'cascader' && value) {
value = value.split('/');
} else if (field.type === 'textarea' && value) {
value = value.split(',');
} else if (field.type === 'date' && value) {
// 使用 dayjs 而不是 new Date 来处理日期
value = value ? dayjs(value) : null;
}
formValues[field.name] = value;
// 设置培训和鉴定状态
if (field.name === 'hasTrain') {
setHasTrain(value === '是');
}
if (field.name === 'hasCert') {
setHasCert(value === '是');
}
}
});
}
// 设置表单的值
form.setFieldsValue(formValues);
}
}, [initialData, fieldValues, fields, form]);
// 按分组组织字段 // 按分组组织字段
const fieldGroups = useMemo(() => { const fieldGroups = useMemo(() => {
@ -169,7 +206,6 @@ const StaffInfoWrite = () => {
} }
}; };
const onFinish = async (e, values: any) => { const onFinish = async (e, values: any) => {
// values.preventDefault();
e.preventDefault() e.preventDefault()
console.log(values) console.log(values)
try { try {
@ -179,36 +215,51 @@ const StaffInfoWrite = () => {
message.error("姓名不能为空"); message.error("姓名不能为空");
return; return;
} }
// 创建基础员工记录
console.log('准备创建用户,数据:', { showname: values.showname }); let staff;
const staff = await create.mutateAsync({
if (staffId) {
// 编辑模式 - 更新现有员工
console.log('准备更新用户,数据:', { id: staffId, showname: values.showname });
try {
staff = await update.mutateAsync({
where: { id: staffId },
data: { data: {
showname: values.showname, showname: values.showname,
deptId: values.department? values.department : null, deptId: values.department || null,
} }
}); });
console.log('创建员工记录:', staff); console.log('更新员工记录:', staff);
// 创建系统日志记录 } catch (error) {
await api.systemLog.create.mutateAsync({ console.error('更新员工基本信息失败:', error);
level: "info", message.error("更新失败,请重试");
module: "人员管理", setLoading(false);
action: "创建用户", return; // 如果基本信息更新失败,提前返回不继续处理
targetId: staff.id, }
targetName: staff.username, } else {
message: `[${new Date().toLocaleString()}] 用户 ${staff.username} 的人员信息已成功添加`, // 创建模式 - 创建新员工
details: { console.log('准备创建用户,数据:', { showname: values.showname });
fields: validEntries.map(({ field, value }) => ({ try {
name: field.label, staff = await create.mutateAsync({
value data: {
})) showname: values.showname,
}, deptId: values.department ? values.department : null,
status: "success", }
departmentId: staff.deptId // 用户所属部门
}); });
} catch (error) {
console.error('创建员工记录失败:', error);
message.error("提交失败,请重试");
setLoading(false);
return; // 如果创建失败,提前返回不继续处理
}
}
// 只有在上面的操作成功后才继续处理自定义字段
try {
// 过滤有效字段并转换值 // 过滤有效字段并转换值
const validEntries = Object.entries(values) const validEntries = Object.entries(values)
.filter(([key, value]) => .filter(([key, value]) =>
key !== 'showname' && // 新增排除 showname key !== 'showname' &&
key !== 'username' && key !== 'username' &&
key !== 'department' && key !== 'department' &&
value !== undefined && value !== undefined &&
@ -221,12 +272,12 @@ const StaffInfoWrite = () => {
// 处理特殊字段类型 // 处理特殊字段类型
let processedValue = value; let processedValue = value;
if (field?.type === 'date') { //日期类型 if (field?.type === 'date') {
processedValue = (value as Date)?.toISOString(); processedValue = (value as any)?.format?.('YYYY-MM-DD') || value;
} else if (field?.type === 'cascader' && Array.isArray(value)) { //级联选择器 } else if (field?.type === 'cascader' && Array.isArray(value)) {
processedValue = value?.join('/'); processedValue = value?.join('/');
}else if(field?.type === 'textarea'){ //多行文本 } else if(field?.type === 'textarea'){
processedValue = (value as string[])?.join(','); processedValue = Array.isArray(value) ? value.join(',') : value;
} }
return { field, value: processedValue }; return { field, value: processedValue };
@ -243,87 +294,28 @@ const StaffInfoWrite = () => {
}) })
) )
); );
console.log('自定义字段提交成功', staff.username);
// 记录系统日志 - 用户创建成功
const timestamp = new Date().toLocaleString();
const logs = [];
// 记录用户创建
logs.push(`${timestamp} - 用户创建成功:${staff.username}`);
// 记录人员信息添加
logs.push(`[${timestamp}] 用户 ${staff.username} 的人员信息已成功添加`);
// 记录每个字段的详细信息
validEntries.forEach(({ field, value }) => {
if (field && field.label && value) {
logs.push(`[${timestamp}] 提交的数据: ${field.label}=${value}`);
}
});
// 根据字段分组记录
const fieldsByGroup = validEntries.reduce((groups, { field, value }) => {
if (field && field.group && value) {
if (!groups[field.group]) {
groups[field.group] = [];
}
groups[field.group].push({ field, value });
}
return groups;
}, {});
// 为每个分组记录信息 // 只有当所有操作都成功时才显示成功消息
Object.entries(fieldsByGroup).forEach(([groupName, fields]) => { message.success(staffId ? "信息更新成功" : "信息提交成功");
const groupValues = (fields as any[]).map(f => `${f.field.label}=${f.value}`).join(', ');
logs.push(`[${timestamp}] ${staff.username}${groupName}${groupValues || '无'}`);
});
// 获取现有日志 // 关闭编辑模态窗口(如果在编辑模式)
let currentLogs = []; if (staffId && setIsEditModalVisible) {
try { setIsEditModalVisible(false);
const storedLogs = localStorage.getItem('systemLogs');
currentLogs = storedLogs ? JSON.parse(storedLogs) : [];
} catch (error) {
console.error('读取系统日志失败', error);
} }
// 添加新日志(倒序添加,最新的在最前面) // 如果有回调函数,调用它
const updatedLogs = [...logs.reverse(), ...currentLogs]; if (onComplete) {
onComplete();
// 保存到 localStorage } else if (!staffId) {
localStorage.setItem('systemLogs', JSON.stringify(updatedLogs)); // 如果是新建模式,重置表单
// 如果有全局变量,也更新它
if (typeof window !== 'undefined') {
(window as any).globalLogs = updatedLogs;
}
message.success("信息提交成功");
form.resetFields(); form.resetFields();
}
} catch (error) {
console.error('设置自定义字段值失败:', error);
}
} catch (error) { } catch (error) {
console.error('提交出错:', error); console.error('提交出错:', error);
message.error(staffId ? "更新失败,请重试" : "提交失败,请重试");
// 记录错误日志
const timestamp = new Date().toLocaleString();
const logMessage = `${timestamp} - 创建用户失败:${values.username || '未知用户'}, 错误: ${error.message || '未知错误'}`;
// 获取现有日志
let currentLogs = [];
try {
const storedLogs = localStorage.getItem('systemLogs');
currentLogs = storedLogs ? JSON.parse(storedLogs) : [];
} catch (err) {
console.error('读取系统日志失败', err);
}
// 添加新日志
const updatedLogs = [logMessage, ...currentLogs];
// 保存到 localStorage
localStorage.setItem('systemLogs', JSON.stringify(updatedLogs));
// 如果有全局变量,也更新它
if (typeof window !== 'undefined') {
(window as any).globalLogs = updatedLogs;
}
message.error("提交失败,请重试");
} finally { } finally {
setLoading(false); setLoading(false);
} }