fix: 修复后端12个+前端5个高优先级问题
后端: - devices.js: 修复 newRackId 重复声明、批量移动加事务、ID生成改MAX聚合 - tickets.js: 添加工单状态机校验、req.body白名单过滤 - roles.js: init-roles 添加 authMiddleware - backup.js: 备份列表只读4KB头部,压缩文件超1MB跳过 - consumables.js: SN查询改用数据库LIKE替代全表扫描 - consumableRecords.js: 出入库加 SELECT FOR UPDATE 行级锁 - inventory.js: not_found 状态判断从 abnormal if 内移到 else if - idleDevices.js: 删除重复的 batch-restore 路由定义(182行) - cables.js: 接线冲突检测增加反向端口检查 前端: - AuthContext.jsx: 初始化时调用 fetchProfile 验证token、Error提取message - api/index.js: backupAPI.download 返回Promise、checkAdmin改POST - Login.jsx: checkIsFirstUser 静默处理错误 - DeviceManagement.jsx: 导出 currentPage scope 使用 currentPageDevices
This commit is contained in:
@@ -779,188 +779,6 @@ router.put('/:deviceId/restore', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/batch-restore', async (req, res) => {
|
||||
const t = await require('../db').sequelize.transaction();
|
||||
try {
|
||||
const { devices } = req.body;
|
||||
|
||||
console.log('========== batch-restore 开始 ==========');
|
||||
console.log('原始请求 body:', JSON.stringify(req.body));
|
||||
console.log('devices 参数:', devices);
|
||||
|
||||
if (!devices || !Array.isArray(devices) || devices.length === 0) {
|
||||
await t.rollback();
|
||||
console.log('错误: devices 参数无效');
|
||||
return res.status(400).json({ error: '请提供有效的设备列表' });
|
||||
}
|
||||
|
||||
const deviceIds = devices.map(d => d.deviceId).filter(Boolean);
|
||||
console.log('提取的 deviceIds:', deviceIds);
|
||||
console.log('deviceIds 类型:', typeof deviceIds, Array.isArray(deviceIds));
|
||||
|
||||
if (deviceIds.length === 0) {
|
||||
await t.rollback();
|
||||
console.log('错误: deviceIds 为空');
|
||||
return res.status(400).json({ error: '设备ID不能为空' });
|
||||
}
|
||||
|
||||
console.log('开始查询设备,条件:', { deviceId: { [Op.in]: deviceIds }, isIdle: true });
|
||||
|
||||
const idleDevices = await Device.findAll({
|
||||
where: { deviceId: { [Op.in]: deviceIds }, isIdle: true },
|
||||
transaction: t,
|
||||
});
|
||||
|
||||
console.log('查询到的空闲设备数量:', idleDevices.length);
|
||||
if (idleDevices.length > 0) {
|
||||
console.log(
|
||||
'查询到的设备ID:',
|
||||
idleDevices.map(d => d.deviceId)
|
||||
);
|
||||
}
|
||||
|
||||
if (idleDevices.length === 0) {
|
||||
console.log('没有找到空闲设备,检查设备是否存在:');
|
||||
const allDevices = await Device.findAll({
|
||||
where: { deviceId: { [Op.in]: deviceIds } },
|
||||
transaction: t,
|
||||
});
|
||||
console.log('设备表中存在的设备数量:', allDevices.length);
|
||||
if (allDevices.length > 0) {
|
||||
console.log(
|
||||
'存在的设备及其 isIdle 状态:',
|
||||
allDevices.map(d => ({ deviceId: d.deviceId, isIdle: d.isIdle }))
|
||||
);
|
||||
}
|
||||
|
||||
await t.rollback();
|
||||
return res.status(404).json({ error: '没有找到空闲设备' });
|
||||
}
|
||||
|
||||
let restoredCount = 0;
|
||||
const results = [];
|
||||
|
||||
for (const device of idleDevices) {
|
||||
const deviceConfig = devices.find(d => d.deviceId === device.deviceId);
|
||||
if (!deviceConfig) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const targetRackId = deviceConfig.targetRackId;
|
||||
const targetPosition = deviceConfig.targetPosition;
|
||||
|
||||
if (!targetRackId) {
|
||||
results.push({
|
||||
deviceId: device.deviceId,
|
||||
name: device.name,
|
||||
status: 'skipped',
|
||||
reason: '未指定目标机柜',
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const targetRack = await Rack.findByPk(targetRackId, { transaction: t });
|
||||
if (!targetRack) {
|
||||
results.push({
|
||||
deviceId: device.deviceId,
|
||||
name: device.name,
|
||||
status: 'failed',
|
||||
reason: '目标机柜不存在',
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const height = device.height || 1;
|
||||
const position = targetPosition || 1;
|
||||
|
||||
const checkResult = await checkPositionAvailable(targetRackId, position, height, null, t);
|
||||
if (!checkResult.available) {
|
||||
results.push({
|
||||
deviceId: device.deviceId,
|
||||
name: device.name,
|
||||
status: 'failed',
|
||||
reason: `U位${position}已被占用`,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
await device.update(
|
||||
{
|
||||
isIdle: false,
|
||||
idleDate: null,
|
||||
idleReason: null,
|
||||
rackId: targetRackId,
|
||||
position: position,
|
||||
warehouseId: null,
|
||||
sourceType: 'rack',
|
||||
status: 'offline',
|
||||
},
|
||||
{ transaction: t }
|
||||
);
|
||||
|
||||
await targetRack.update(
|
||||
{
|
||||
currentPower: targetRack.currentPower + (device.powerConsumption || 0),
|
||||
},
|
||||
{ transaction: t }
|
||||
);
|
||||
|
||||
restoredCount++;
|
||||
results.push({
|
||||
deviceId: device.deviceId,
|
||||
name: device.name,
|
||||
status: 'success',
|
||||
targetRack: targetRack.name,
|
||||
targetPosition: position,
|
||||
});
|
||||
}
|
||||
|
||||
await t.commit();
|
||||
|
||||
const successCount = results.filter(r => r.status === 'success').length;
|
||||
const failedCount = results.filter(r => r.status === 'failed').length;
|
||||
const skippedCount = results.filter(r => r.status === 'skipped').length;
|
||||
|
||||
const successDevices = idleDevices.filter(d =>
|
||||
results.some(r => r.deviceId === d.deviceId && r.status === 'success')
|
||||
);
|
||||
const deviceSummary = successDevices
|
||||
.map(
|
||||
d =>
|
||||
`${d.name}(编号:${d.deviceId}${d.type ? `,类型:${d.type}` : ''}${d.ipAddress ? `,IP:${d.ipAddress}` : ''})`
|
||||
)
|
||||
.join('、');
|
||||
|
||||
await logDeviceOperation(
|
||||
'batch_restore',
|
||||
`批量上架 ${successCount} 台空闲设备:${deviceSummary}`,
|
||||
{
|
||||
targetId: deviceIds.join(','),
|
||||
targetName: `${successCount}台设备`,
|
||||
req,
|
||||
metadata: {
|
||||
results,
|
||||
type: 'batch_idle_device_restore',
|
||||
devices: successDevices.map(d => d.toJSON()),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
res.json({
|
||||
message: `成功上架 ${successCount} 台设备`,
|
||||
total: idleDevices.length,
|
||||
restored: successCount,
|
||||
failed: failedCount,
|
||||
skipped: skippedCount,
|
||||
details: results,
|
||||
});
|
||||
} catch (error) {
|
||||
await t.rollback();
|
||||
console.error('批量上架设备失败:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:deviceId', async (req, res) => {
|
||||
const t = await require('../db').sequelize.transaction();
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user