设备接入产品配置 界面
This commit is contained in:
@@ -213,12 +213,25 @@ export default function DeviceAccessPage() {
|
||||
if (type === 'product') {
|
||||
setProductProtocol(record?.protocolCode || '');
|
||||
const modelId = record.thingsModels ? Object.keys(record.thingsModels)[0] : null;
|
||||
const limitConfig = modelId ? record.thingsModels[modelId] : {};
|
||||
|
||||
// 👇 👇 👇 这里是关键:回显 limitConfig + actionConfig
|
||||
let limitConfig = {};
|
||||
let actionConfig = {};
|
||||
if (modelId && record.thingsModels[modelId]) {
|
||||
limitConfig = record.thingsModels[modelId].properties || {};
|
||||
actionConfig = record.thingsModels[modelId].actions || {}; // 👈 行为配置回显
|
||||
}
|
||||
|
||||
if (modelId) {
|
||||
const targetModel = thinsModelList.find(m => m.id == modelId);
|
||||
setSelectedModelId(Number(modelId));
|
||||
setPropertyList(targetModel?.supportProperties || []);
|
||||
form.setFieldsValue({ ...record, modelId, limitConfig });
|
||||
form.setFieldsValue({
|
||||
...record,
|
||||
modelId,
|
||||
limitConfig,
|
||||
actionConfig, // 👈 回显
|
||||
});
|
||||
} else {
|
||||
form.setFieldsValue(record);
|
||||
setSelectedModelId('');
|
||||
@@ -319,14 +332,23 @@ export default function DeviceAccessPage() {
|
||||
|
||||
if (modalType === 'product') {
|
||||
form.setFieldValue('modelId', selectedModelId);
|
||||
const { modelId, limitConfig, ...params } = values;
|
||||
const { modelId, limitConfig, actionConfig, ...params } = values;
|
||||
console.log('提交的产品数据:', { ...params, modelId, limitConfig, actionConfig }); // 👈 这里可以看到提交的数据结构
|
||||
|
||||
const finalLimitConfig = {};
|
||||
if (limitConfig) {
|
||||
Object.keys(limitConfig).forEach(key => {
|
||||
finalLimitConfig[key] = { min: limitConfig[key].min ?? 0, max: limitConfig[key].max ?? 100 };
|
||||
});
|
||||
}
|
||||
const thingsModels = modelId ? { [modelId]: finalLimitConfig } : {};
|
||||
|
||||
const thingsModels = modelId ? {
|
||||
[modelId]: {
|
||||
properties: finalLimitConfig,
|
||||
actions: actionConfig || {},
|
||||
}
|
||||
} : {};
|
||||
|
||||
const submitData = { ...params, thingsModels, id: editData?.id };
|
||||
const res = editData ? await updateProduct(submitData) : await addProduct(submitData);
|
||||
if (res.code === 200) {
|
||||
@@ -521,7 +543,7 @@ export default function DeviceAccessPage() {
|
||||
<Option value="udp">UDP</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item name="status" label="status" initialValue={1}>
|
||||
<Form.Item name="status" label="状态" initialValue={1}>
|
||||
<Select placeholder="状态" allowClear style={{ width: 100 }}>
|
||||
<Option value={1}>启用</Option>
|
||||
<Option value={0}>禁用</Option>
|
||||
@@ -763,6 +785,9 @@ export default function DeviceAccessPage() {
|
||||
<Form.Item label="厂商" name="manufacturer">
|
||||
<Input placeholder="迈步科技" />
|
||||
</Form.Item>
|
||||
<Form.Item name="actionConfig" hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="传输类型" name="transport">
|
||||
<Select placeholder="传输方式">
|
||||
@@ -780,7 +805,7 @@ export default function DeviceAccessPage() {
|
||||
</div>
|
||||
|
||||
<Divider>绑定物模型</Divider>
|
||||
<Form.Item label="绑定物模型">
|
||||
<Form.Item label="绑定物模型" name="modelId">
|
||||
<Select
|
||||
placeholder="请选择要绑定的物模型"
|
||||
style={{ width: '100%' }}
|
||||
@@ -792,11 +817,23 @@ export default function DeviceAccessPage() {
|
||||
setPropertyList(model.supportProperties || []);
|
||||
const protocol = model.connectType || '';
|
||||
form.setFieldsValue({ protocolCode: protocol });
|
||||
|
||||
// 属性默认配置
|
||||
const defaultLimit = {};
|
||||
model.supportProperties?.forEach(attr => {
|
||||
defaultLimit[attr.propertyKey] = { min: 0, max: 100 };
|
||||
});
|
||||
form.setFieldsValue({ limitConfig: defaultLimit });
|
||||
|
||||
// 行为默认配置
|
||||
const actionLimit = {};
|
||||
model.supportActions?.forEach(action => {
|
||||
actionLimit[action.actionId] = action.params || {};
|
||||
});
|
||||
|
||||
form.setFieldsValue({
|
||||
limitConfig: defaultLimit,
|
||||
actionConfig: actionLimit,
|
||||
});
|
||||
} else {
|
||||
setSelectedModelId('');
|
||||
setPropertyList([]);
|
||||
@@ -815,6 +852,9 @@ export default function DeviceAccessPage() {
|
||||
<Form.Item name="protocolCode" hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name="actionConfig" hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
{selectedModelId && (
|
||||
<>
|
||||
@@ -832,61 +872,76 @@ export default function DeviceAccessPage() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{form.getFieldValue('protocolCode')?.toLowerCase() === 'onvif' && (
|
||||
<>
|
||||
<Divider>协议自动配置项</Divider>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Form.Item label="IP地址" name="ip">
|
||||
<Input placeholder="192.168.1.65" />
|
||||
</Form.Item>
|
||||
<Form.Item label="端口" name="port">
|
||||
<InputNumber className="w-full" defaultValue={80} />
|
||||
</Form.Item>
|
||||
<Form.Item label="账号" name="username">
|
||||
<Input placeholder="admin" />
|
||||
</Form.Item>
|
||||
<Form.Item label="密码" name="password">
|
||||
<Input.Password placeholder="密码" />
|
||||
</Form.Item>
|
||||
{/* ==== 属性配置(你原来的) ==== */}
|
||||
<Divider>物模型属性配置</Divider>
|
||||
<div style={{ marginTop: 12 }}>
|
||||
{propertyList?.map((item) => (
|
||||
<div key={item.id} style={{ padding: '12px 16px', border: '1px solid #eee', borderRadius: 8, marginBottom: 8 }}>
|
||||
<div style={{ marginBottom: 8, fontWeight: 500 }}>
|
||||
{item.propertyName}({item.propertyKey})
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<Form.Item label="最小值" name={['limitConfig', item.propertyKey, 'min']} style={{ flex: 1 }}>
|
||||
<InputNumber style={{ width: '100%' }} placeholder="最小值" />
|
||||
</Form.Item>
|
||||
<Form.Item label="最大值" name={['limitConfig', item.propertyKey, 'max']} style={{ flex: 1 }}>
|
||||
<InputNumber style={{ width: '100%' }} placeholder="最大值" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
))}
|
||||
{(!propertyList || propertyList.length === 0) && (
|
||||
<div style={{ color: '#999', textAlign: 'center', padding: 10 }}>
|
||||
请选择物模型以显示属性
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{form.getFieldValue('protocolCode')?.toLowerCase() === 'rtsp' && (
|
||||
<>
|
||||
<Divider>协议自动配置项</Divider>
|
||||
<Form.Item label="RTSP地址" name="rtspUrl">
|
||||
<Input placeholder="rtsp://username:password@ip:port/stream" />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{/* ==== ✅ 行为(指令)配置 新增 ==== */}
|
||||
<Divider>物模型行为(指令)配置</Divider>
|
||||
<div style={{ marginTop: 12 }}>
|
||||
{thinsModelList.find(m => m.id === selectedModelId)?.supportActions?.map((action) => (
|
||||
<div key={action.actionId} style={{ padding: '12px 16px', border: '1px solid #eee', borderRadius: 8, marginBottom: 8 }}>
|
||||
<div style={{ marginBottom: 8, fontWeight: 500 }}>
|
||||
{action.actionName}({action.actionId})
|
||||
</div>
|
||||
|
||||
{Object.entries(action.params || {}).map(([paramKey, paramCfg]: [string, any]) => (
|
||||
<div key={paramKey} className="flex gap-3 mt-2">
|
||||
<Form.Item
|
||||
label={`${paramKey} 默认值`}
|
||||
name={['actionConfig', action.actionId, paramKey, 'default']}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<Input style={{ width: '100%' }} placeholder="默认值" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="类型"
|
||||
name={['actionConfig', action.actionId, paramKey, 'type']}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<Input disabled style={{ width: '100%' }} placeholder="类型" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="描述"
|
||||
name={['actionConfig', action.actionId, paramKey, 'description']}
|
||||
style={{ flex: 2 }}
|
||||
>
|
||||
<Input disabled style={{ width: '100%' }} placeholder="描述" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{(!thinsModelList.find(m => m.id === selectedModelId)?.supportActions?.length) && (
|
||||
<div style={{ color: '#999', textAlign: 'center', padding: 10 }}>
|
||||
该物模型暂无指令
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Divider>物模型属性配置</Divider>
|
||||
<Form.Item name="modelId" hidden><Input /></Form.Item>
|
||||
<div style={{ marginTop: 12 }}>
|
||||
{propertyList?.map((item) => (
|
||||
<div key={item.id} style={{ padding: '12px 16px', border: '1px solid #eee', borderRadius: 8, marginBottom: 8 }}>
|
||||
<div style={{ marginBottom: 8, fontWeight: 500 }}>
|
||||
{item.propertyName}({item.propertyKey})
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<Form.Item label="最小值" name={['limitConfig', item.propertyKey, 'min']} style={{ flex: 1 }}>
|
||||
<InputNumber style={{ width: '100%' }} placeholder="最小值" />
|
||||
</Form.Item>
|
||||
<Form.Item label="最大值" name={['limitConfig', item.propertyKey, 'max']} style={{ flex: 1 }}>
|
||||
<InputNumber style={{ width: '100%' }} placeholder="最大值" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{(!propertyList || propertyList.length === 0) && (
|
||||
<div style={{ color: '#999', textAlign: 'center', padding: 10 }}>
|
||||
请选择物模型以显示属性
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{modalType === 'model' && (
|
||||
|
||||
@@ -112,7 +112,7 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll,
|
||||
};
|
||||
|
||||
return (
|
||||
<Content style={{ maxWidth: 1800, margin: '0 auto', }}>
|
||||
<Content style={{ maxWidth: 1800, margin: '0 8', }}>
|
||||
<Row gutter={[8, 8]} style={{ marginBottom: 12, flexWrap: 'wrap' }}>
|
||||
{dynamicTopCards.map((card, idx) => (
|
||||
<Col key={idx} style={{ minWidth: '160px', flex: '1 0 auto' }}>
|
||||
|
||||
@@ -421,7 +421,7 @@ export default function WayLinePage({ planedevices }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="normal-spacing" style={{ background: '#f5f7fa', minHeight: '100vh', padding: '16px', paddingTop: 0 }}>
|
||||
<div className="normal-spacing" style={{ background: '#f5f7fa', minHeight: '100vh', padding: '0px', paddingTop: 0 }}>
|
||||
<Row gutter={[16, 16]} style={{ marginBottom: 16 }}>
|
||||
{topCards.map((item, index) => (
|
||||
<Col xs={12} sm={8} md={4} key={index}>
|
||||
@@ -527,8 +527,8 @@ export default function WayLinePage({ planedevices }) {
|
||||
</Tooltip>
|
||||
}
|
||||
bordered={false}
|
||||
bodyStyle={{ padding: 0, display: 'flex', flexDirection: 'column', flex: 1 }}
|
||||
style={{ ...cardStyle, flex: 1 }}
|
||||
bodyStyle={{ padding: 0, display: 'flex', flexDirection: 'column', height: "calc(100% - 40px)", overflow: "auto" }}
|
||||
style={{ ...cardStyle, height: "410px" }}
|
||||
>
|
||||
<Table
|
||||
size="small"
|
||||
@@ -536,8 +536,7 @@ export default function WayLinePage({ planedevices }) {
|
||||
columns={taskColumns}
|
||||
dataSource={taskList}
|
||||
pagination={false}
|
||||
scroll={{ y: 'auto', maxHeight: 260 }}
|
||||
style={{ height: '100%' }}
|
||||
style={{ height: "calc(100% - 40px)" }}
|
||||
rowClassName={(record) =>
|
||||
selectedTask?.uuid === record.uuid ? 'table-row-highlight' : ''
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user