refactor(devices): 实现设备字段动态校验与配置同步
1. 新增动态设备校验Schema生成器,支持从数据库读取字段配置生成校验规则 2. 重构设备增改接口,使用动态校验替代硬编码Schema 3. 调整前端设备表单,适配字段配置并锁定核心系统字段 4. 修复前后端默认字段配置不一致问题 5. 新增字段管理页面防护,锁定核心字段的必填/可见配置
This commit is contained in:
@@ -269,14 +269,22 @@ const DeviceFormModal = ({
|
||||
}
|
||||
};
|
||||
|
||||
// 强制锁定必填的字段(不受字段管理配置影响)
|
||||
const FORCE_REQUIRED_FIELDS = ['name', 'serialNumber', 'position', 'height'];
|
||||
|
||||
const filteredFields = deviceFields.filter(
|
||||
field =>
|
||||
field.fieldName !== 'deviceId' &&
|
||||
field.fieldName !== 'rackId' &&
|
||||
field.fieldName !== 'position' &&
|
||||
field.fieldName !== 'height'
|
||||
field => field.fieldName !== 'deviceId'
|
||||
);
|
||||
|
||||
// 获取关键字段的配置(用于设备位置区块)
|
||||
const rackFieldConfig = deviceFields.find(f => f.fieldName === 'rackId');
|
||||
const positionFieldConfig = deviceFields.find(f => f.fieldName === 'position');
|
||||
const heightFieldConfig = deviceFields.find(f => f.fieldName === 'height');
|
||||
|
||||
// 动态判断是否必填(强制锁定字段 > 字段配置)
|
||||
const isPositionRequired = FORCE_REQUIRED_FIELDS.includes('position') || positionFieldConfig?.required;
|
||||
const isHeightRequired = FORCE_REQUIRED_FIELDS.includes('height') || heightFieldConfig?.required;
|
||||
|
||||
const formItems = [];
|
||||
filteredFields.forEach(field => {
|
||||
if (field.fieldName === 'serialNumber') {
|
||||
@@ -356,10 +364,10 @@ const DeviceFormModal = ({
|
||||
label={
|
||||
<span>
|
||||
机柜
|
||||
<span style={{ color: '#ff4d4f', marginLeft: '4px' }}>*</span>
|
||||
{rackFieldConfig?.required && <span style={{ color: '#ff4d4f', marginLeft: '4px' }}>*</span>}
|
||||
</span>
|
||||
}
|
||||
rules={[{ required: true, message: '请选择机柜' }]}
|
||||
rules={rackFieldConfig?.required ? [{ required: true, message: '请选择机柜' }] : []}
|
||||
style={{ marginBottom: '0' }}
|
||||
>
|
||||
<Select
|
||||
@@ -389,10 +397,10 @@ const DeviceFormModal = ({
|
||||
label={
|
||||
<span>
|
||||
安装位置 (U位)
|
||||
<span style={{ color: '#ff4d4f', marginLeft: '4px' }}>*</span>
|
||||
{isPositionRequired && <span style={{ color: '#ff4d4f', marginLeft: '4px' }}>*</span>}
|
||||
</span>
|
||||
}
|
||||
rules={[{ required: true, message: '请输入U位' }]}
|
||||
rules={isPositionRequired ? [{ required: true, message: '请输入U位' }] : []}
|
||||
style={{ marginBottom: '0' }}
|
||||
>
|
||||
<InputNumber
|
||||
@@ -410,10 +418,10 @@ const DeviceFormModal = ({
|
||||
label={
|
||||
<span>
|
||||
设备高度 (U)
|
||||
<span style={{ color: '#ff4d4f', marginLeft: '4px' }}>*</span>
|
||||
{isHeightRequired && <span style={{ color: '#ff4d4f', marginLeft: '4px' }}>*</span>}
|
||||
</span>
|
||||
}
|
||||
rules={[{ required: true, message: '请输入设备高度' }]}
|
||||
rules={isHeightRequired ? [{ required: true, message: '请输入设备高度' }] : []}
|
||||
initialValue={1}
|
||||
style={{ marginBottom: '0' }}
|
||||
>
|
||||
|
||||
@@ -30,7 +30,7 @@ export const DEFAULT_DEVICE_FIELDS = [
|
||||
fieldName: 'deviceId',
|
||||
displayName: '设备ID',
|
||||
fieldType: 'text',
|
||||
required: true,
|
||||
required: false,
|
||||
visible: true,
|
||||
editable: false,
|
||||
},
|
||||
@@ -101,7 +101,7 @@ export const DEFAULT_DEVICE_FIELDS = [
|
||||
fieldName: 'powerConsumption',
|
||||
displayName: '功率(W)',
|
||||
fieldType: 'number',
|
||||
required: false,
|
||||
required: true,
|
||||
visible: true,
|
||||
editable: true,
|
||||
},
|
||||
|
||||
@@ -338,6 +338,11 @@ const FIELD_TYPE_OPTIONS = [
|
||||
{ value: 'textarea', label: '多行文本' },
|
||||
];
|
||||
|
||||
// 强制锁定必填的系统核心字段(不受字段管理配置影响)
|
||||
const FORCE_LOCKED_REQUIRED_FIELDS = ['name', 'serialNumber', 'position', 'height'];
|
||||
// 强制锁定可见的系统核心字段(在其他模块强引用,不可关闭可见)
|
||||
const FORCE_LOCKED_VISIBLE_FIELDS = ['name', 'serialNumber'];
|
||||
|
||||
function DeviceFieldManagement() {
|
||||
const [fields, setFields] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -668,8 +673,17 @@ function DeviceFieldManagement() {
|
||||
label={<span style={formLabelStyle}>必填</span>}
|
||||
valuePropName="checked"
|
||||
style={formItemFlexStyle}
|
||||
tooltip={
|
||||
editingField && FORCE_LOCKED_REQUIRED_FIELDS.includes(editingField.fieldName)
|
||||
? '系统核心字段,不可关闭必填'
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Switch />
|
||||
<Switch
|
||||
disabled={
|
||||
editingField && FORCE_LOCKED_REQUIRED_FIELDS.includes(editingField.fieldName)
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
@@ -677,8 +691,18 @@ function DeviceFieldManagement() {
|
||||
label={<span style={formLabelStyle}>可见</span>}
|
||||
valuePropName="checked"
|
||||
style={formItemFlexStyle}
|
||||
tooltip={
|
||||
editingField && FORCE_LOCKED_VISIBLE_FIELDS.includes(editingField.fieldName)
|
||||
? '系统核心字段,在其他模块中被引用,不可关闭可见'
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Switch defaultChecked />
|
||||
<Switch
|
||||
defaultChecked
|
||||
disabled={
|
||||
editingField && FORCE_LOCKED_VISIBLE_FIELDS.includes(editingField.fieldName)
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user