add
This commit is contained in:
parent
ee320de2ca
commit
754900d0b8
|
@ -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',
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -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": [
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue