fix(设备管理): 改进设备导入的错误处理和验证逻辑

- 前端优化错误消息展示,区分500错误和其他错误情况
- 后端增加设备类型验证、设备ID唯一性检查和机柜ID非空验证
- 改进Sequelize错误处理,提供更友好的错误消息
- 统一前后端错误响应格式
This commit is contained in:
zhang1106
2025-12-30 14:01:16 +08:00
parent 4006453bd4
commit 25c1f5f905
2 changed files with 54 additions and 9 deletions
+41 -3
View File
@@ -424,6 +424,20 @@ router.post('/import', async (req, res) => {
throw new Error(`缺少必填字段:${missingFields.join('、')}`); throw new Error(`缺少必填字段:${missingFields.join('、')}`);
} }
// 验证设备类型值
const validTypes = ['server', 'switch', 'router', 'storage', 'other'];
if (!validTypes.includes(fieldValueMap['设备类型'])) {
throw new Error(`设备类型无效,有效值为:${validTypes.join('、')},当前值:${fieldValueMap['设备类型']}`);
}
// 验证设备ID是否已存在
const existingDeviceById = await Device.findOne({
where: { deviceId: fieldValueMap['设备ID'] }
});
if (existingDeviceById) {
throw new Error(`设备ID已存在:${fieldValueMap['设备ID']}`);
}
// 验证序列号是否已存在 // 验证序列号是否已存在
const existingDevice = await Device.findOne({ const existingDevice = await Device.findOne({
where: { serialNumber: fieldValueMap['序列号'] } where: { serialNumber: fieldValueMap['序列号'] }
@@ -432,6 +446,11 @@ router.post('/import', async (req, res) => {
throw new Error(`序列号已存在:${fieldValueMap['序列号']}`); throw new Error(`序列号已存在:${fieldValueMap['序列号']}`);
} }
// 验证机柜ID是否为空
if (!fieldValueMap['所在机柜ID'] || fieldValueMap['所在机柜ID'].trim() === '') {
throw new Error('所在机柜ID不能为空');
}
// 验证机柜是否存在,如果不存在则自动创建 // 验证机柜是否存在,如果不存在则自动创建
if (!rackIds.includes(fieldValueMap['所在机柜ID'])) { if (!rackIds.includes(fieldValueMap['所在机柜ID'])) {
// 自动创建机柜 // 自动创建机柜
@@ -546,17 +565,36 @@ router.post('/import', async (req, res) => {
stats.success++; stats.success++;
} catch (error) { } catch (error) {
stats.failed++; stats.failed++;
stats.errors.push({ row: rowNum, error: error.message, data: row }); let errorMessage = error.message;
if (error.name === 'SequelizeUniqueConstraintError') {
const errors = error.errors || [];
for (const err of errors) {
if (err.path === 'deviceId') {
errorMessage = `设备ID已存在`;
break;
} else if (err.path === 'serialNumber') {
errorMessage = `序列号已存在`;
break;
}
}
} else if (error.name === 'SequelizeValidationError') {
errorMessage = '数据验证失败,请检查字段格式';
}
stats.errors.push({ row: rowNum, error: errorMessage, data: row });
} }
} }
// 删除临时文件
fs.unlinkSync(filePath); fs.unlinkSync(filePath);
res.json({ statistics: stats }); res.json({ statistics: stats });
} catch (error) { } catch (error) {
console.error('导入设备数据失败:', error); console.error('导入设备数据失败:', error);
res.status(500).json({ error: '导入设备数据失败' }); const errorMessage = error.message || '导入过程中发生未知错误';
res.status(500).json({
errors: [{ row: 0, error: errorMessage }]
});
} }
}); });
+13 -6
View File
@@ -851,15 +851,22 @@ function DeviceManagement() {
let errorDetails = []; let errorDetails = [];
if (error.response) { if (error.response) {
const { data } = error.response; const { data, status } = error.response;
if (data && data.errors && Array.isArray(data.errors)) {
if (status === 500 && data && data.errors && Array.isArray(data.errors) && data.errors.length > 0) {
errorDetails = data.errors.map((err) => ({
row: err.row || 0,
error: err.error || err.message || '服务器内部错误'
}));
errorMessage = `导入失败:${errorDetails[0].error}`;
} else if (data && data.errors && Array.isArray(data.errors)) {
errorDetails = data.errors.map((err, index) => ({ errorDetails = data.errors.map((err, index) => ({
row: err.row || index + 1, row: err.row || index + 1,
error: err.error || err.message || '未知错误' error: err.error || err.message || '未知错误'
})); }));
errorMessage = `导入失败,共发现 ${errorDetails.length} 处数据错误`; errorMessage = `导入失败,共发现 ${errorDetails.length} 处数据错误`;
} else if (data && data.message) { } else if (data && (data.message || data.error)) {
errorMessage = data.message; errorMessage = data.message || data.error;
} }
} else if (error.message) { } else if (error.message) {
errorMessage = error.message; errorMessage = error.message;
@@ -870,8 +877,8 @@ function DeviceManagement() {
statistics: { statistics: {
total: 0, total: 0,
success: 0, success: 0,
failed: 0, failed: errorDetails.length > 0 ? errorDetails.length : 1,
errors: errorDetails, errors: errorDetails.length > 0 ? errorDetails : [{ row: 0, error: errorMessage }],
message: errorMessage message: errorMessage
} }
}); });