refactor(devices): 简化导入导出模板的CSV字段处理逻辑
移除字段类型提示和必填标记,统一使用displayName作为列名 重构导出逻辑使其与导入模板保持一致,使用动态生成的字段配置
This commit is contained in:
+55
-93
@@ -150,15 +150,6 @@ router.get('/import-template', async (req, res) => {
|
|||||||
order: [['order', 'ASC']]
|
order: [['order', 'ASC']]
|
||||||
});
|
});
|
||||||
|
|
||||||
// 字段类型提示映射
|
|
||||||
const fieldTypeHints = {
|
|
||||||
'设备类型': 'server/switch/router/storage/other',
|
|
||||||
'状态': 'running/maintenance/offline/fault'
|
|
||||||
};
|
|
||||||
|
|
||||||
// 日期字段提示
|
|
||||||
const dateFields = ['购买日期', '保修到期'];
|
|
||||||
|
|
||||||
// 根据字段配置动态生成CSV标题(排除设备ID,由系统自动生成)
|
// 根据字段配置动态生成CSV标题(排除设备ID,由系统自动生成)
|
||||||
// 将rackId字段替换为机房名称+机柜名称,以便唯一定位
|
// 将rackId字段替换为机房名称+机柜名称,以便唯一定位
|
||||||
const headers = [];
|
const headers = [];
|
||||||
@@ -169,32 +160,17 @@ router.get('/import-template', async (req, res) => {
|
|||||||
if (field.fieldName === 'rackId') {
|
if (field.fieldName === 'rackId') {
|
||||||
headers.push({
|
headers.push({
|
||||||
id: '所在机房名称',
|
id: '所在机房名称',
|
||||||
title: '所在机房名称(必填)'
|
title: '所在机房名称'
|
||||||
});
|
});
|
||||||
headers.push({
|
headers.push({
|
||||||
id: '所在机柜名称',
|
id: '所在机柜名称',
|
||||||
title: '所在机柜名称(必填)'
|
title: '所在机柜名称'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let title = field.displayName;
|
// 直接使用displayName作为列名,不添加任何后缀
|
||||||
|
headers.push({ id: field.displayName, title: field.displayName });
|
||||||
// 添加字段类型提示
|
|
||||||
if (fieldTypeHints[field.displayName]) {
|
|
||||||
title = `${field.displayName}(${fieldTypeHints[field.displayName]})`;
|
|
||||||
} else if (dateFields.includes(field.displayName)) {
|
|
||||||
title = `${field.displayName}(YYYY-MM-DD)`;
|
|
||||||
} else if (field.fieldType === 'select' && field.options && field.options.length > 0) {
|
|
||||||
// 下拉选择字段,显示可选值
|
|
||||||
const optionValues = field.options.map(opt => opt.value).join('/');
|
|
||||||
title = `${field.displayName}(${optionValues})`;
|
|
||||||
} else {
|
|
||||||
// 显示必填/可选标识
|
|
||||||
title = `${field.displayName}(${field.required ? '必填' : '可选'})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
headers.push({ id: field.displayName, title });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 准备示例数据(根据字段配置生成,排除设备ID)
|
// 准备示例数据(根据字段配置生成,排除设备ID)
|
||||||
@@ -334,45 +310,44 @@ router.get('/export', async (req, res) => {
|
|||||||
return res.status(404).json({ error: '未找到指定的设备' });
|
return res.status(404).json({ error: '未找到指定的设备' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 准备CSV数据
|
// 创建字段名到displayName的映射
|
||||||
const csvData = devices.map(device => {
|
const fieldNameToDisplayName = {};
|
||||||
// 创建基础数据对象
|
|
||||||
const deviceData = {
|
|
||||||
'设备ID': device.deviceId,
|
|
||||||
'设备名称': device.name,
|
|
||||||
'设备类型': device.type,
|
|
||||||
'型号': device.model,
|
|
||||||
'序列号': device.serialNumber,
|
|
||||||
'所在机房ID': device.Rack?.Room?.roomId || '',
|
|
||||||
'所在机房名称': device.Rack?.Room?.name || '',
|
|
||||||
'所在机柜ID': device.rackId,
|
|
||||||
'所在机柜名称': device.Rack?.name || '',
|
|
||||||
'位置(U)': device.position,
|
|
||||||
'高度(U)': device.height,
|
|
||||||
'功率(W)': device.powerConsumption,
|
|
||||||
'IP地址': device.ipAddress,
|
|
||||||
'状态': device.status,
|
|
||||||
'购买日期': device.purchaseDate ? new Date(device.purchaseDate).toLocaleDateString() : '',
|
|
||||||
'保修到期': device.warrantyExpiry ? new Date(device.warrantyExpiry).toLocaleDateString() : '',
|
|
||||||
'描述': device.description,
|
|
||||||
'创建时间': device.createdAt ? new Date(device.createdAt).toLocaleString() : ''
|
|
||||||
};
|
|
||||||
|
|
||||||
// 添加自定义字段(排除基础字段)
|
|
||||||
if (device.customFields) {
|
|
||||||
// 定义基础字段的显示名称
|
|
||||||
const baseFieldDisplayNames = [
|
|
||||||
'设备ID', '设备名称', '设备类型', '型号', '序列号',
|
|
||||||
'所在机房ID', '所在机房名称', '所在机柜ID', '所在机柜名称', '位置(U)', '高度(U)',
|
|
||||||
'功率(W)', 'IP地址', '状态', '购买日期', '保修到期', '描述', '创建时间'
|
|
||||||
];
|
|
||||||
|
|
||||||
deviceFields.forEach(field => {
|
deviceFields.forEach(field => {
|
||||||
// 只添加未在基础字段中出现的自定义字段
|
fieldNameToDisplayName[field.fieldName] = field.displayName;
|
||||||
if (field.visible &&
|
});
|
||||||
device.customFields[field.fieldName] &&
|
|
||||||
!baseFieldDisplayNames.includes(field.displayName)) {
|
// 准备CSV数据 - 根据字段配置动态生成,与导入模板保持一致
|
||||||
deviceData[field.displayName] = device.customFields[field.fieldName];
|
const csvData = devices.map(device => {
|
||||||
|
const deviceData = {};
|
||||||
|
|
||||||
|
// 根据字段配置生成数据(排除deviceId)
|
||||||
|
deviceFields
|
||||||
|
.filter(field => field.visible && field.fieldName !== 'deviceId')
|
||||||
|
.forEach(field => {
|
||||||
|
// rackId字段拆分为机房名称和机柜名称
|
||||||
|
if (field.fieldName === 'rackId') {
|
||||||
|
deviceData['所在机房名称'] = device.Rack?.Room?.name || '';
|
||||||
|
deviceData['所在机柜名称'] = device.Rack?.name || '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他字段使用displayName作为列名
|
||||||
|
const value = device[field.fieldName];
|
||||||
|
|
||||||
|
// 日期格式处理
|
||||||
|
if (field.fieldType === 'date' && value) {
|
||||||
|
deviceData[field.displayName] = new Date(value).toLocaleDateString();
|
||||||
|
} else {
|
||||||
|
deviceData[field.displayName] = value !== undefined && value !== null ? value : '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加自定义字段
|
||||||
|
if (device.customFields) {
|
||||||
|
Object.entries(device.customFields).forEach(([fieldName, value]) => {
|
||||||
|
const field = deviceFields.find(f => f.fieldName === fieldName);
|
||||||
|
if (field && field.visible) {
|
||||||
|
deviceData[field.displayName] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -380,37 +355,24 @@ router.get('/export', async (req, res) => {
|
|||||||
return deviceData;
|
return deviceData;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 设置CSV标题(包含自定义字段)
|
// 设置CSV标题 - 与导入模板保持一致
|
||||||
const baseHeaders = [
|
const headers = [];
|
||||||
{ id: '设备ID', title: '设备ID' },
|
deviceFields
|
||||||
{ id: '设备名称', title: '设备名称' },
|
.filter(field => field.visible && field.fieldName !== 'deviceId')
|
||||||
{ id: '设备类型', title: '设备类型' },
|
.forEach(field => {
|
||||||
{ id: '型号', title: '型号' },
|
// rackId拆分为两个列
|
||||||
{ id: '序列号', title: '序列号' },
|
if (field.fieldName === 'rackId') {
|
||||||
{ id: '所在机房ID', title: '所在机房ID' },
|
headers.push({ id: '所在机房名称', title: '所在机房名称' });
|
||||||
{ id: '所在机房名称', title: '所在机房名称' },
|
headers.push({ id: '所在机柜名称', title: '所在机柜名称' });
|
||||||
{ id: '所在机柜ID', title: '所在机柜ID' },
|
return;
|
||||||
{ id: '所在机柜名称', title: '所在机柜名称' },
|
}
|
||||||
{ id: '位置(U)', title: '位置(U)' },
|
|
||||||
{ id: '高度(U)', title: '高度(U)' },
|
|
||||||
{ id: '功率(W)', title: '功率(W)' },
|
|
||||||
{ id: 'IP地址', title: 'IP地址' },
|
|
||||||
{ id: '状态', title: '状态' },
|
|
||||||
{ id: '购买日期', title: '购买日期' },
|
|
||||||
{ id: '保修到期', title: '保修到期' },
|
|
||||||
{ id: '描述', title: '描述' },
|
|
||||||
{ id: '创建时间', title: '创建时间' }
|
|
||||||
];
|
|
||||||
|
|
||||||
// 添加自定义字段标题(排除与基础字段重复的字段)
|
headers.push({ id: field.displayName, title: field.displayName });
|
||||||
const baseFieldTitles = baseHeaders.map(header => header.id);
|
});
|
||||||
const customHeaders = deviceFields
|
|
||||||
.filter(field => field.visible && !baseFieldTitles.includes(field.displayName))
|
|
||||||
.map(field => ({ id: field.displayName, title: field.displayName }));
|
|
||||||
|
|
||||||
const csvWriter = createObjectCsvWriter({
|
const csvWriter = createObjectCsvWriter({
|
||||||
path: path.join(__dirname, '../temp/devices.csv'),
|
path: path.join(__dirname, '../temp/devices.csv'),
|
||||||
header: [...baseHeaders, ...customHeaders],
|
header: headers,
|
||||||
encoding: 'utf8'
|
encoding: 'utf8'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user