This commit is contained in:
Li1304553726 2025-04-08 16:48:40 +08:00
parent ee320de2ca
commit 754900d0b8
4 changed files with 601 additions and 538 deletions

View File

@ -21,20 +21,22 @@ 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,8 +23,16 @@ 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,23 +1,28 @@
import { useState, useEffect, useMemo, useCallback } from 'react'; /* eslint-disable no-undef */
import { AgGridReact } from 'ag-grid-react'; /* eslint-disable @typescript-eslint/no-unused-expressions */
/* 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 ? result[level - 1] || '' : result.join(' / ') || codes.join('/'); return level
? result[level - 1] || ""
: result.join(" / ") || codes.join("/");
} }
// 添加表头提取工具函数 // 添加表头提取工具函数
@ -25,8 +30,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);
@ -48,39 +53,43 @@ 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(`员工数据_${new Date().toISOString().slice(0, 10)}`); const [defaultFileName] = useState(
`员工数据_${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]);
@ -97,47 +106,51 @@ 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
@ -145,22 +158,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]
); );
@ -179,7 +192,9 @@ export default function StaffMessage() {
const headerNames = extractHeaders(columnDefs); const headerNames = extractHeaders(columnDefs);
// 创建示例数据行 // 创建示例数据行
let exampleRow: Record<string, string> = {}; const exampleRow: Record<string, string> = {};
// 定义 fieldsList移到这里
const fieldsList = Array.isArray(fields?.data) ? fields.data : [];
// 检查是否有选中行 // 检查是否有选中行
if (selectedRows.length > 0) { if (selectedRows.length > 0) {
@ -187,11 +202,10 @@ 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
@ -200,32 +214,35 @@ 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((obj, header) => { const emptyRow = headerNames.reduce(
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();
@ -233,26 +250,30 @@ 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 = selectedRows.length > 0 const tipText =
? '以上为选中人员数据,请在下方行填写实际数据' selectedRows.length > 0
: '以上为示例数据,请在下方行填写实际数据'; ? "以上为选中人员数据,请在下方行填写实际数据"
: "以上为示例数据,请在下方行填写实际数据";
ws[cellRef] = { t: 's', v: tipText }; ws[cellRef] = { t: "s", v: tipText };
// 手动添加空白行 // 手动添加空白行
utils.sheet_add_json(ws, [emptyRow], { skipHeader: true, origin: rowIdx + 1 }); utils.sheet_add_json(ws, [emptyRow], {
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, "员工模板");
@ -268,7 +289,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;
} }
@ -277,29 +298,31 @@ 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((fv: any) => fv.fieldId === field.id)?.value; const fieldValue = row.fieldValues?.find(
(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;
@ -314,43 +337,44 @@ 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((excelData: any[]) => { const handleImportData = useCallback(
(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["所属部门"];
} }
// 处理自定义字段 // 处理自定义字段
@ -359,16 +383,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);
@ -380,10 +404,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;
@ -393,7 +417,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),
}); });
}); });
@ -401,35 +425,63 @@ export default function StaffMessage() {
}); });
// 提交数据 // 提交数据
createMany.mutate({ data: staffData }); createMany.mutate({
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 className="bg-red-500 hover:bg-red-600 border-red-500 text-white rounded-md px-4 py-2" <Button
onClick={handleDelete}></Button> className="bg-red-500 hover:bg-red-600 border-red-500 text-white rounded-md px-4 py-2"
<Button className="bg-blue-500 hover:bg-blue-600 border-blue-500 text-white rounded-md px-4 py-2" onClick={handleDelete}
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 onClick={handleExportTemplate} className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"> <Button
onClick={handleExportTemplate}
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
</Button> </Button>
<Button onClick={handleConfirm} className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"> <Button
onClick={handleConfirm}
className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
>
</Button> </Button>
</div> </div>
<Button className="bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700 rounded-md px-4 py-2" <Button
onClick={() => { className="bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700 rounded-md px-4 py-2"
}}></Button> onClick={() => {}}
>
</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">
@ -442,7 +494,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}
@ -498,7 +550,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 {
@ -506,15 +558,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,7 +466,8 @@ 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")