Compare commits

..

No commits in common. "5abb19f4676d8e7b4dc5a0ea16c64e7a6704513c" and "c6b59483de1f9efb39da7e1d9c0f4cba9dde8d3b" have entirely different histories.

4 changed files with 545 additions and 608 deletions

View File

@ -21,22 +21,20 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
// 允许使用短路表达式
'no-unused-expressions': 'off',
// 允许使用 let 声明后不重新赋值的变量
'prefer-const': 'off',
// 允许使用 any 类型 // 允许使用 any 类型
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
// 允许声明但未使用的变量 // 允许声明但未使用的变量
'@typescript-eslint/no-unused-vars': [ '@typescript-eslint/no-unused-vars': [
'warn', 'warn',
{ {
vars: 'all', vars: 'all', // 检查所有变量
args: 'none', args: 'none', // 不检查函数参数
ignoreRestSiblings: true, ignoreRestSiblings: true,
}, },
], ],
// 可选:关闭未定义变量检查
'no-undef': 'off', // 禁止使用未声明的变量
'no-undef': 'error',
}, },
}; };

View File

@ -23,16 +23,8 @@ export default tseslint.config(
"warn", "warn",
{ allowConstantExport: true }, { allowConstantExport: true },
], ],
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-explicit-any": "off",
// 允许使用 any 类型 // 允许使用 any 类型
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
// 允许使用 let 声明后不重新赋值的变量
"no-unused-expressions": "off",
// 允许使用 let 声明后不重新赋值的变量
"prefer-const": "off",
// 允许声明但未使用的变量 // 允许声明但未使用的变量
"@typescript-eslint/no-unused-vars": [ "@typescript-eslint/no-unused-vars": [

View File

@ -1,28 +1,23 @@
/* eslint-disable no-undef */ import { useState, useEffect, useMemo, useCallback } from 'react';
/* eslint-disable @typescript-eslint/no-unused-expressions */ import { AgGridReact } from 'ag-grid-react';
/* eslint-disable no-unused-expressions */
import { useState, useEffect, useMemo, useCallback } from "react";
import { AgGridReact } from "ag-grid-react";
import { api, useStaff } from "@nice/client"; import { api, useStaff } from "@nice/client";
import { Button, CascaderProps, message, Modal, Input, Upload } from "antd"; import { Button, CascaderProps, message, Modal, Input, Upload } 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"; import StaffInfoWrite from '@web/src/app/main/staffinfo_write/staffinfo_write.page';
import { utils, writeFile, read } from "xlsx"; import { utils, writeFile, read } from 'xlsx';
import { UploadOutlined } from "@ant-design/icons"; import { UploadOutlined } from '@ant-design/icons';
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;
for (const code of codes) { for (const code of codes) {
const found = currentLevel?.find((opt) => opt.value === code); const found = currentLevel?.find(opt => opt.value === code);
if (!found) break; if (!found) break;
result.push(String(found.label)); result.push(String(found.label));
currentLevel = found.children || []; currentLevel = found.children || [];
if (level && result.length >= level) break; // 添加层级控制 if (level && result.length >= level) break; // 添加层级控制
} }
return level return level ? result[level - 1] || '' : result.join(' / ') || codes.join('/');
? result[level - 1] || ""
: result.join(" / ") || codes.join("/");
} }
// 添加表头提取工具函数 // 添加表头提取工具函数
@ -30,8 +25,8 @@ function extractHeaders(columns: any[]): string[] {
const result: string[] = []; const result: string[] = [];
const extractHeadersRecursive = (cols: any[]) => { const extractHeadersRecursive = (cols: any[]) => {
cols.forEach((col) => { cols.forEach(col => {
if ("children" in col && col.children) { if ('children' in col && col.children) {
extractHeadersRecursive(col.children); extractHeadersRecursive(col.children);
} else if (col.headerName) { } else if (col.headerName) {
result.push(col.headerName); result.push(col.headerName);
@ -53,43 +48,39 @@ export default function StaffMessage() {
const [currentEditStaff, setCurrentEditStaff] = useState<any>(null); const [currentEditStaff, setCurrentEditStaff] = useState<any>(null);
const [gridApi, setGridApi] = useState<any>(null); const [gridApi, setGridApi] = useState<any>(null);
const [fileNameVisible, setFileNameVisible] = useState(false); const [fileNameVisible, setFileNameVisible] = useState(false);
const [fileName, setFileName] = useState(""); const [fileName, setFileName] = useState('');
const [defaultFileName] = useState( const [defaultFileName] = useState(`员工数据_${new Date().toISOString().slice(0, 10)}`);
`员工数据_${new Date().toISOString().slice(0, 10)}`
);
const [importVisible, setImportVisible] = useState(false); const [importVisible, setImportVisible] = useState(false);
// 获取数据 // 获取数据
const { data: staffData } = api.staff.findMany.useQuery({ const { data: staffData } = api.staff.findMany.useQuery({
where: { where: {
deletedAt: null, deletedAt: null
}, },
include: { include: {
fieldValues: { fieldValues: {
include: { include: {
// 添加这两个关联字段 // 添加这两个关联字段
staff: { select: { id: true } }, // 关联员工ID staff: { select: { id: true } }, // 关联员工ID
field: { select: { id: true } }, // 关联字段ID field: { select: { id: true } } // 关联字段ID
}, }
},
department: true,
}, },
department: true
}
} as any); } as any);
// console.log(staffData); // 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;
if (selectedRows.length > 1) { if (selectedRows.length > 1) {
message.error("只能选择一个员工进行编辑"); message.error('只能选择一个员工进行编辑');
return; return;
} }
setCurrentEditStaff(selectedRows[0]); setCurrentEditStaff(selectedRows[0]);
@ -106,51 +97,47 @@ export default function StaffMessage() {
// 新增删除处理函数 // 新增删除处理函数
const handleDelete = useCallback(async () => { const handleDelete = useCallback(async () => {
if (selectedRows.length === 0) return; if (selectedRows.length === 0) return;
console.log("待删除的选中行数据:", selectedRows); // 新增调试语句 console.log('待删除的选中行数据:', selectedRows); // 新增调试语句
try { try {
await softDeleteByIds.mutateAsync({ await softDeleteByIds.mutateAsync({
ids: selectedRows?.map((row) => { ids: selectedRows?.map(row => {
console.log("当前行ID:", row.id); // 检查每个ID console.log('当前行ID:', row.id); // 检查每个ID
return row.id; return row.id
}), })
}); });
message.success("删除成功"); message.success('删除成功');
} catch (error) { } catch (error) {
message.error("删除失败"); message.error('删除失败');
console.error("详细错误信息:", error); // 输出完整错误堆栈 console.error('详细错误信息:', error); // 输出完整错误堆栈
} }
// 重新获取数据或本地过滤已删除项 // 重新获取数据或本地过滤已删除项
}, [selectedRows]); }, [selectedRows]);
// 缓存基础列定义 // 缓存基础列定义
const baseColumns = useMemo( const baseColumns = useMemo(() => [
() => [
{ {
field: "showname", field: 'showname',
headerName: "姓名", headerName: '姓名',
filter: "agSetColumnFilter", filter: 'agSetColumnFilter',
pinned: "left", pinned: 'left'
}, },
{ {
field: "deptId", field: 'deptId',
headerName: "所属部门", headerName: '所属部门',
valueGetter: (params) => params.data.department?.name, valueGetter: params => params.data.department?.name,
filter: "agSetColumnFilter", filter: 'agSetColumnFilter'
}, }
], ], []);
[]
);
// 缓存动态列定义 // 缓存动态列定义
const dynamicColumns = useMemo( const dynamicColumns = useMemo(() =>
() => (fields.data || [] as any).map(field => ({
(fields.data || ([] as any)).map((field) => ({
field: field.name, field: field.name,
headerName: field.label || field.name, headerName: field.label || field.name,
filter: "agSetColumnFilter", filter: 'agSetColumnFilter',
cellStyle: { whiteSpace: "pre-line" }, cellStyle: { whiteSpace: 'pre-line' },
autoHeight: true, autoHeight: true,
valueGetter: (params) => { valueGetter: params => {
// 获取原始值 // 获取原始值
const rawValue = params.data.fieldValues?.find( const rawValue = params.data.fieldValues?.find(
(fv: any) => fv.fieldId === field.id (fv: any) => fv.fieldId === field.id
@ -158,22 +145,22 @@ export default function StaffMessage() {
// 根据字段类型格式化 // 根据字段类型格式化
switch (field.type) { switch (field.type) {
case "cascader": case 'cascader':
return rawValue ? getAreaName(rawValue.split("/")) : ""; return rawValue ? getAreaName(rawValue.split('/')) : '';
case "date": case 'date':
// 格式化日期假设存储的是ISO字符串 // 格式化日期假设存储的是ISO字符串
return rawValue ? new Date(rawValue).toLocaleDateString() : ""; return rawValue ? new Date(rawValue).toLocaleDateString() : '';
case "textarea": case 'textarea':
// 换行处理 // 换行处理
return rawValue?.replace(/,/g, "\n"); return rawValue?.replace(/,/g, '\n');
default: default:
return rawValue; return rawValue;
} }
}, }
})), })),
[fields.data] [fields.data]
); );
@ -192,9 +179,7 @@ export default function StaffMessage() {
const headerNames = extractHeaders(columnDefs); const headerNames = extractHeaders(columnDefs);
// 创建示例数据行 // 创建示例数据行
const exampleRow: Record<string, string> = {}; let exampleRow: Record<string, string> = {};
// 定义 fieldsList移到这里
const fieldsList = Array.isArray(fields?.data) ? fields.data : [];
// 检查是否有选中行 // 检查是否有选中行
if (selectedRows.length > 0) { if (selectedRows.length > 0) {
@ -202,10 +187,11 @@ export default function StaffMessage() {
const templateData = selectedRows[0]; const templateData = selectedRows[0];
// 基础字段 // 基础字段
exampleRow["姓名"] = templateData.showname || ""; exampleRow['姓名'] = templateData.showname || '';
exampleRow["所属部门"] = templateData.department?.name || ""; exampleRow['所属部门'] = templateData.department?.name || '';
// 处理自定义字段 // 处理自定义字段
const fieldsList = Array.isArray(fields?.data) ? fields.data : [];
fieldsList.forEach((field: any) => { fieldsList.forEach((field: any) => {
const fieldValue = templateData.fieldValues?.find( const fieldValue = templateData.fieldValues?.find(
(fv: any) => fv.fieldId === field.id (fv: any) => fv.fieldId === field.id
@ -214,35 +200,32 @@ export default function StaffMessage() {
let displayValue = fieldValue; let displayValue = fieldValue;
// 根据字段类型处理值 // 根据字段类型处理值
if (field.type === "cascader" && fieldValue) { if (field.type === 'cascader' && fieldValue) {
displayValue = getAreaName(fieldValue.split("/")); displayValue = getAreaName(fieldValue.split('/'));
} else if (field.type === "date" && fieldValue) { } else if (field.type === 'date' && fieldValue) {
displayValue = new Date(fieldValue).toLocaleDateString(); displayValue = new Date(fieldValue).toLocaleDateString();
} else if (field.type === "textarea" && fieldValue) { } else if (field.type === 'textarea' && fieldValue) {
displayValue = fieldValue.replace(/,/g, "\n"); displayValue = fieldValue.replace(/,/g, '\n');
} }
exampleRow[field.label || field.name] = displayValue || ""; exampleRow[field.label || field.name] = displayValue || '';
}); });
} else { } else {
// 如果没有选中行,使用默认示例数据 // 如果没有选中行,使用默认示例数据
exampleRow["姓名"] = "张三"; exampleRow['姓名'] = '张三';
exampleRow["所属部门"] = "技术部"; exampleRow['所属部门'] = '技术部';
// 添加所有自定义字段的空值 // 添加所有自定义字段的空值
fieldsList.forEach((field: any) => { fieldsList.forEach((field: any) => {
exampleRow[field.label || field.name] = ""; exampleRow[field.label || field.name] = '';
}); });
} }
// 创建空白行供用户填写 // 创建空白行供用户填写
const emptyRow = headerNames.reduce( const emptyRow = headerNames.reduce((obj, header) => {
(obj, header) => { obj[header] = '';
obj[header] = "";
return obj; return obj;
}, }, {} as Record<string, string>);
{} as Record<string, string>
);
// 创建工作簿和工作表 // 创建工作簿和工作表
const wb = utils.book_new(); const wb = utils.book_new();
@ -250,30 +233,26 @@ export default function StaffMessage() {
// 设置列宽 // 设置列宽
const colWidth = headerNames.map(() => ({ wch: 20 })); const colWidth = headerNames.map(() => ({ wch: 20 }));
ws["!cols"] = colWidth; ws['!cols'] = colWidth;
// 在第二行添加提示文字 // 在第二行添加提示文字
const rowIdx = 2; // 第二行索引 const rowIdx = 2; // 第二行索引
const cellRef = utils.encode_cell({ r: rowIdx, c: 0 }); // A3单元格 const cellRef = utils.encode_cell({ r: rowIdx, c: 0 }); // A3单元格
const tipText = const tipText = selectedRows.length > 0
selectedRows.length > 0 ? '以上为选中人员数据,请在下方行填写实际数据'
? "以上为选中人员数据,请在下方行填写实际数据" : '以上为示例数据,请在下方行填写实际数据';
: "以上为示例数据,请在下方行填写实际数据";
ws[cellRef] = { t: "s", v: tipText }; ws[cellRef] = { t: 's', v: tipText };
// 手动添加空白行 // 手动添加空白行
utils.sheet_add_json(ws, [emptyRow], { utils.sheet_add_json(ws, [emptyRow], { skipHeader: true, origin: rowIdx + 1 });
skipHeader: true,
origin: rowIdx + 1,
});
// 合并提示文字单元格 // 合并提示文字单元格
if (!ws["!merges"]) ws["!merges"] = []; if (!ws['!merges']) ws['!merges'] = [];
ws["!merges"].push({ ws['!merges'].push({
s: { r: rowIdx, c: 0 }, // 起始单元格 A3 s: { r: rowIdx, c: 0 }, // 起始单元格 A3
e: { r: rowIdx, c: Math.min(5, headerNames.length - 1) }, // 结束单元格,跨越多列 e: { r: rowIdx, c: Math.min(5, headerNames.length - 1) } // 结束单元格,跨越多列
}); });
utils.book_append_sheet(wb, ws, "员工模板"); utils.book_append_sheet(wb, ws, "员工模板");
@ -289,7 +268,7 @@ export default function StaffMessage() {
const handleFileNameConfirm = useCallback(() => { const handleFileNameConfirm = useCallback(() => {
setFileNameVisible(false); setFileNameVisible(false);
if (!gridApi) { if (!gridApi) {
console.error("Grid API 未正确初始化"); console.error('Grid API 未正确初始化');
return; return;
} }
@ -298,31 +277,29 @@ export default function StaffMessage() {
const allData = selectedRows.length > 0 ? selectedRows : rowData; const allData = selectedRows.length > 0 ? selectedRows : rowData;
// 格式化数据 // 格式化数据
const exportData = allData.map((row) => { const exportData = allData.map(row => {
const formattedRow: Record<string, any> = {}; const formattedRow: Record<string, any> = {};
// 基础字段 // 基础字段
formattedRow["姓名"] = row.showname || ""; formattedRow['姓名'] = row.showname || '';
formattedRow["所属部门"] = row.department?.name || ""; formattedRow['所属部门'] = row.department?.name || '';
// 动态字段 // 动态字段
const fieldsList = Array.isArray(fields?.data) ? fields.data : []; const fieldsList = Array.isArray(fields?.data) ? fields.data : [];
fieldsList.forEach((field: any) => { fieldsList.forEach((field: any) => {
const fieldValue = row.fieldValues?.find( const fieldValue = row.fieldValues?.find((fv: any) => fv.fieldId === field.id)?.value;
(fv: any) => fv.fieldId === field.id
)?.value;
let displayValue = fieldValue; let displayValue = fieldValue;
// 根据字段类型处理值 // 根据字段类型处理值
if (field.type === "cascader" && fieldValue) { if (field.type === 'cascader' && fieldValue) {
displayValue = getAreaName(fieldValue.split("/")); displayValue = getAreaName(fieldValue.split('/'));
} else if (field.type === "date" && fieldValue) { } else if (field.type === 'date' && fieldValue) {
displayValue = new Date(fieldValue).toLocaleDateString(); displayValue = new Date(fieldValue).toLocaleDateString();
} else if (field.type === "textarea" && fieldValue) { } else if (field.type === 'textarea' && fieldValue) {
displayValue = fieldValue.replace(/,/g, "\n"); displayValue = fieldValue.replace(/,/g, '\n');
} }
formattedRow[field.label || field.name] = displayValue || ""; formattedRow[field.label || field.name] = displayValue || '';
}); });
return formattedRow; return formattedRow;
@ -337,44 +314,43 @@ export default function StaffMessage() {
const finalFileName = fileName || defaultFileName; const finalFileName = fileName || defaultFileName;
writeFile(wb, `${finalFileName}.xlsx`); writeFile(wb, `${finalFileName}.xlsx`);
} catch (error) { } catch (error) {
console.error("导出失败:", error); console.error('导出失败:', error);
message.error("导出失败,请稍后重试"); message.error('导出失败,请稍后重试');
} }
}, [fileName, defaultFileName, rowData, selectedRows, fields.data, gridApi]); }, [fileName, defaultFileName, rowData, selectedRows, fields.data, gridApi]);
// 处理导入数据 // 处理导入数据
const createMany = api.staff.create.useMutation({ const createMany = api.staff.create.useMutation({
onSuccess: () => { onSuccess: () => {
message.success("员工数据导入成功"); message.success('员工数据导入成功');
// 刷新数据 // 刷新数据
api.staff.findMany.useQuery(); api.staff.findMany.useQuery();
setImportVisible(false); setImportVisible(false);
}, },
onError: (error) => { onError: (error) => {
message.error(`导入失败: ${error.message}`); message.error(`导入失败: ${error.message}`);
}, }
}); });
// 处理Excel导入数据 // 处理Excel导入数据
const handleImportData = useCallback( const handleImportData = useCallback((excelData: any[]) => {
(excelData: any[]) => {
if (excelData.length === 0) { if (excelData.length === 0) {
message.warning("没有可导入的数据"); message.warning('没有可导入的数据');
return; return;
} }
try { try {
// 将Excel数据转换为API需要的格式 // 将Excel数据转换为API需要的格式
const staffData = excelData.map((row) => { const staffData = excelData.map(row => {
const staff: any = { fieldValues: [] }; const staff: any = { fieldValues: [] };
// 处理基础字段 // 处理基础字段
if (row["姓名"]) staff.showname = row["姓名"]; if (row['姓名']) staff.showname = row['姓名'];
// 处理部门 // 处理部门
if (row["所属部门"]) { if (row['所属部门']) {
// 简单存储部门名称,后续可能需要查询匹配 // 简单存储部门名称,后续可能需要查询匹配
staff.departmentName = row["所属部门"]; staff.departmentName = row['所属部门'];
} }
// 处理自定义字段 // 处理自定义字段
@ -383,16 +359,16 @@ export default function StaffMessage() {
let value = row[field.label || field.name]; let value = row[field.label || field.name];
// 跳过空值 // 跳过空值
if (value === undefined || value === "") return; if (value === undefined || value === '') return;
// 根据字段类型处理输入值 // 根据字段类型处理输入值
switch (field.type) { switch (field.type) {
case "cascader": case 'cascader':
// 级联选择器可能需要将显示名称转回代码 // 级联选择器可能需要将显示名称转回代码
// 这里简单保留原值,实际可能需要查询转换 // 这里简单保留原值,实际可能需要查询转换
break; break;
case "date": case 'date':
// 尝试将日期字符串转换为ISO格式 // 尝试将日期字符串转换为ISO格式
try { try {
const dateObj = new Date(value); const dateObj = new Date(value);
@ -404,10 +380,10 @@ export default function StaffMessage() {
} }
break; break;
case "textarea": case 'textarea':
// 将换行符替换回逗号进行存储 // 将换行符替换回逗号进行存储
if (typeof value === "string") { if (typeof value === 'string') {
value = value.replace(/\n/g, ","); value = value.replace(/\n/g, ',');
} }
break; break;
@ -417,7 +393,7 @@ export default function StaffMessage() {
// 添加到fieldValues数组 // 添加到fieldValues数组
staff.fieldValues.push({ staff.fieldValues.push({
fieldId: field.id, fieldId: field.id,
value: String(value), value: String(value)
}); });
}); });
@ -425,63 +401,35 @@ export default function StaffMessage() {
}); });
// 提交数据 // 提交数据
createMany.mutate({ createMany.mutate({ data: staffData });
data: staffData[0], // 由于类型限制,这里只能一条一条导入
});
// 如果有多条数据,需要循环处理
for (let i = 1; i < staffData.length; i++) {
createMany.mutate({ data: staffData[i] });
}
message.info(`正在导入${staffData.length}条员工数据...`); message.info(`正在导入${staffData.length}条员工数据...`);
} catch (error) { } catch (error) {
console.error("处理导入数据失败:", error); console.error('处理导入数据失败:', error);
message.error("数据格式错误,导入失败"); message.error('数据格式错误,导入失败');
} }
}, }, [fields.data, createMany]);
[fields.data, createMany]
);
return ( return (
<> <>
<div className="flex justify-between items-center mb-4"> <div className="flex justify-between items-center mb-4">
<div className="space-x-2"> <div className="space-x-2">
<Button <Button className="bg-red-500 hover:bg-red-600 border-red-500 text-white rounded-md px-4 py-2"
className="bg-red-500 hover:bg-red-600 border-red-500 text-white rounded-md px-4 py-2" onClick={handleDelete}></Button>
onClick={handleDelete} <Button className="bg-blue-500 hover:bg-blue-600 border-blue-500 text-white rounded-md px-4 py-2"
> onClick={handleEdit}></Button>
<Button onClick={() => setImportVisible(true)} className="bg-orange-500 text-white px-4 py-2 rounded hover:bg-orange-600">
</Button>
<Button
className="bg-blue-500 hover:bg-blue-600 border-blue-500 text-white rounded-md px-4 py-2"
onClick={handleEdit}
>
</Button>
<Button
onClick={() => setImportVisible(true)}
className="bg-orange-500 text-white px-4 py-2 rounded hover:bg-orange-600"
>
Excel Excel
</Button> </Button>
<Button <Button onClick={handleExportTemplate} className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
onClick={handleExportTemplate}
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
</Button> </Button>
<Button <Button onClick={handleConfirm} className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">
onClick={handleConfirm}
className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
>
</Button> </Button>
</div> </div>
<Button <Button className="bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700 rounded-md px-4 py-2"
className="bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700 rounded-md px-4 py-2" onClick={() => {
onClick={() => {}} }}></Button>
>
</Button>
</div> </div>
<div className="bg-white rounded-lg shadow-md p-6 mb-4"> <div className="bg-white rounded-lg shadow-md p-6 mb-4">
@ -494,7 +442,7 @@ export default function StaffMessage() {
pagination={true} pagination={true}
paginationPageSize={10} paginationPageSize={10}
paginationPageSizeSelector={[10, 20, 50, 100]} 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" className="rounded border border-gray-200"
headerHeight={40} headerHeight={40}
@ -550,7 +498,7 @@ export default function StaffMessage() {
> >
<Upload <Upload
accept=".xlsx,.xls" accept=".xlsx,.xls"
beforeUpload={(file) => { beforeUpload={file => {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (e) => { reader.onload = (e) => {
try { try {
@ -558,15 +506,15 @@ export default function StaffMessage() {
const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
if (data.length === 0) { if (data.length === 0) {
message.warning("Excel文件中没有数据"); message.warning('Excel文件中没有数据');
return; return;
} }
message.info(`读取到${data.length}条数据,正在处理...`); message.info(`读取到${data.length}条数据,正在处理...`);
handleImportData(data); handleImportData(data);
} catch (error) { } catch (error) {
console.error("解析Excel文件失败:", error); console.error('解析Excel文件失败:', error);
message.error("Excel文件格式错误请确保使用正确的模板"); message.error('Excel文件格式错误请确保使用正确的模板');
} }
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);

View File

@ -466,8 +466,7 @@ model Staff {
enabled Boolean? @default(true) enabled Boolean? @default(true)
officerId String? @map("officer_id") officerId String? @map("officer_id")
phoneNumber String? @map("phone_number") phoneNumber String? @map("phone_number")
age Int?@map("age")
sex String?@map("sex")
// 部门关系 // 部门关系
domainId String? @map("domain_id") domainId String? @map("domain_id")
deptId String? @map("dept_id") deptId String? @map("dept_id")