feat(设备管理): 实现设备ID自动生成功能
- 修改后端验证逻辑,允许设备ID为空或null - 添加自动生成设备ID功能,格式为DEV+三位数字 - 前端移除设备ID必填校验并隐藏该字段 - 更新设备导入逻辑,支持自动生成设备ID
This commit is contained in:
+69
-13
@@ -88,16 +88,50 @@ router.get('/', validateQuery(queryDeviceSchema), async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 生成设备ID的辅助函数
|
||||||
|
async function generateDeviceId() {
|
||||||
|
// 获取当前最大的设备ID序号
|
||||||
|
const devices = await Device.findAll({
|
||||||
|
where: {
|
||||||
|
deviceId: {
|
||||||
|
[require('sequelize').Op.like]: 'DEV%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let maxNumber = 0;
|
||||||
|
devices.forEach(device => {
|
||||||
|
const match = device.deviceId.match(/^DEV(\d+)$/);
|
||||||
|
if (match) {
|
||||||
|
const num = parseInt(match[1], 10);
|
||||||
|
if (num > maxNumber) {
|
||||||
|
maxNumber = num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 生成新的设备ID,序号+1,至少3位数字
|
||||||
|
const newNumber = maxNumber + 1;
|
||||||
|
return `DEV${String(newNumber).padStart(3, '0')}`;
|
||||||
|
}
|
||||||
|
|
||||||
// 创建设备
|
// 创建设备
|
||||||
router.post('/', validateBody(createDeviceSchema), async (req, res) => {
|
router.post('/', validateBody(createDeviceSchema), async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const device = await Device.create(req.body);
|
const deviceData = { ...req.body };
|
||||||
|
|
||||||
|
// 如果没有提供deviceId或为空,则自动生成
|
||||||
|
if (!deviceData.deviceId || deviceData.deviceId.trim() === '') {
|
||||||
|
deviceData.deviceId = await generateDeviceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
const device = await Device.create(deviceData);
|
||||||
|
|
||||||
// 更新机柜当前功率
|
// 更新机柜当前功率
|
||||||
const rack = await Rack.findByPk(req.body.rackId);
|
const rack = await Rack.findByPk(deviceData.rackId);
|
||||||
if (rack) {
|
if (rack) {
|
||||||
await rack.update({
|
await rack.update({
|
||||||
currentPower: rack.currentPower + req.body.powerConsumption
|
currentPower: rack.currentPower + deviceData.powerConsumption
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,16 +547,38 @@ router.post('/import', async (req, res) => {
|
|||||||
throw new Error(`设备类型无效,有效值为:${validTypes.join('、')},当前值:${deviceType}`);
|
throw new Error(`设备类型无效,有效值为:${validTypes.join('、')},当前值:${deviceType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证设备ID是否已存在
|
// 处理设备ID:如果为空则自动生成
|
||||||
const deviceId = getFieldValue('deviceId');
|
let deviceId = getFieldValue('deviceId');
|
||||||
if (!deviceId) {
|
if (!deviceId || deviceId.trim() === '') {
|
||||||
throw new Error('设备ID不能为空');
|
// 自动生成设备ID
|
||||||
}
|
const allDevices = await Device.findAll({
|
||||||
const existingDeviceById = await Device.findOne({
|
where: {
|
||||||
where: { deviceId: deviceId }
|
deviceId: {
|
||||||
});
|
[require('sequelize').Op.like]: 'DEV%'
|
||||||
if (existingDeviceById) {
|
}
|
||||||
throw new Error(`设备ID已存在:${deviceId}`);
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let maxNumber = 0;
|
||||||
|
allDevices.forEach(device => {
|
||||||
|
const match = device.deviceId.match(/^DEV(\d+)$/);
|
||||||
|
if (match) {
|
||||||
|
const num = parseInt(match[1], 10);
|
||||||
|
if (num > maxNumber) {
|
||||||
|
maxNumber = num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceId = `DEV${String(maxNumber + 1).padStart(3, '0')}`;
|
||||||
|
} else {
|
||||||
|
// 验证设备ID是否已存在
|
||||||
|
const existingDeviceById = await Device.findOne({
|
||||||
|
where: { deviceId: deviceId }
|
||||||
|
});
|
||||||
|
if (existingDeviceById) {
|
||||||
|
throw new Error(`设备ID已存在:${deviceId}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证序列号是否已存在
|
// 验证序列号是否已存在
|
||||||
|
|||||||
@@ -9,14 +9,12 @@ const DEVICE_STATUS = ['running', 'maintenance', 'offline', 'fault'];
|
|||||||
// 创建设备验证Schema
|
// 创建设备验证Schema
|
||||||
const createDeviceSchema = Joi.object({
|
const createDeviceSchema = Joi.object({
|
||||||
deviceId: Joi.string()
|
deviceId: Joi.string()
|
||||||
.required()
|
|
||||||
.max(50)
|
.max(50)
|
||||||
.pattern(/^[a-zA-Z0-9_-]+$/)
|
.pattern(/^[a-zA-Z0-9_-]+$/)
|
||||||
|
.allow('', null)
|
||||||
.messages({
|
.messages({
|
||||||
'string.empty': '设备ID不能为空',
|
|
||||||
'string.max': '设备ID不能超过50个字符',
|
'string.max': '设备ID不能超过50个字符',
|
||||||
'string.pattern.base': '设备ID只能包含字母、数字、下划线和横线',
|
'string.pattern.base': '设备ID只能包含字母、数字、下划线和横线'
|
||||||
'any.required': '设备ID是必填字段'
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
name: Joi.string()
|
name: Joi.string()
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ const formatDate = (date, fieldName) => {
|
|||||||
|
|
||||||
// 默认设备字段配置
|
// 默认设备字段配置
|
||||||
const defaultDeviceFields = [
|
const defaultDeviceFields = [
|
||||||
{ fieldName: 'deviceId', displayName: '设备ID', fieldType: 'string', required: true, order: 1, visible: true },
|
{ fieldName: 'deviceId', displayName: '设备ID', fieldType: 'string', required: false, order: 1, visible: false },
|
||||||
{ fieldName: 'name', displayName: '设备名称', fieldType: 'string', required: true, order: 2, visible: true },
|
{ fieldName: 'name', displayName: '设备名称', fieldType: 'string', required: true, order: 2, visible: true },
|
||||||
{ fieldName: 'type', displayName: '设备类型', fieldType: 'select', required: true, order: 3, visible: true,
|
{ fieldName: 'type', displayName: '设备类型', fieldType: 'select', required: true, order: 3, visible: true,
|
||||||
options: [{ value: 'server', label: '服务器' }, { value: 'switch', label: '交换机' }, { value: 'router', label: '路由器' }, { value: 'storage', label: '存储设备' }, { value: 'other', label: '其他设备' }] },
|
options: [{ value: 'server', label: '服务器' }, { value: 'switch', label: '交换机' }, { value: 'router', label: '路由器' }, { value: 'storage', label: '存储设备' }, { value: 'other', label: '其他设备' }] },
|
||||||
@@ -1770,7 +1770,7 @@ function DeviceManagement() {
|
|||||||
layout="vertical"
|
layout="vertical"
|
||||||
onFinish={handleSubmit}
|
onFinish={handleSubmit}
|
||||||
>
|
>
|
||||||
{deviceFields.map(field => {
|
{deviceFields.filter(field => field.fieldName !== 'deviceId').map(field => {
|
||||||
let control = null;
|
let control = null;
|
||||||
|
|
||||||
switch (field.fieldType) {
|
switch (field.fieldType) {
|
||||||
@@ -1822,7 +1822,7 @@ function DeviceManagement() {
|
|||||||
key={field.fieldName}
|
key={field.fieldName}
|
||||||
name={field.fieldName}
|
name={field.fieldName}
|
||||||
label={field.displayName}
|
label={field.displayName}
|
||||||
rules={field.required ? [{ required: true, message: `请输入${field.displayName}` }] : []}
|
rules={field.required && field.fieldName !== 'deviceId' ? [{ required: true, message: `请输入${field.displayName}` }] : []}
|
||||||
>
|
>
|
||||||
{control}
|
{control}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -1861,7 +1861,7 @@ function DeviceManagement() {
|
|||||||
>
|
>
|
||||||
<div style={{ maxHeight: 400, overflowY: 'auto' }}>
|
<div style={{ maxHeight: 400, overflowY: 'auto' }}>
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '12px' }}>
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '12px' }}>
|
||||||
{deviceFields.map(field => (
|
{deviceFields.filter(field => field.fieldName !== 'deviceId').map(field => (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
key={field.fieldName}
|
key={field.fieldName}
|
||||||
name={field.fieldName}
|
name={field.fieldName}
|
||||||
|
|||||||
Reference in New Issue
Block a user