Commit 1ebf27f77a77d229bd6e00835ee82d914c3ea0de
Merge branch 'dev-fix-ww' into 'main_dev'
fix: 修复teambition bug See merge request yunteng/thingskit-front!544
Showing
19 changed files
with
256 additions
and
89 deletions
... | ... | @@ -86,6 +86,12 @@ export interface DataSource { |
86 | 86 | deviceName: string; |
87 | 87 | deviceProfileId: string; |
88 | 88 | tbDeviceId: string; |
89 | + customCommand: { | |
90 | + transportType?: string; | |
91 | + commandType?: string; | |
92 | + command?: string; | |
93 | + service?: string; | |
94 | + }; | |
89 | 95 | |
90 | 96 | // front usage |
91 | 97 | uuid?: string; |
... | ... | @@ -93,6 +99,7 @@ export interface DataSource { |
93 | 99 | height?: number; |
94 | 100 | radio?: RadioRecord; |
95 | 101 | deviceType?: DeviceTypeEnum; |
102 | + [key: string]: any; | |
96 | 103 | } |
97 | 104 | |
98 | 105 | export interface DataComponentRecord { | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | - import { ref } from 'vue'; | |
2 | + import { ref, watch } from 'vue'; | |
3 | 3 | import JSONEditor, { JSONEditorOptions } from 'jsoneditor'; |
4 | 4 | import 'jsoneditor/dist/jsoneditor.min.css'; |
5 | 5 | import { unref } from 'vue'; |
... | ... | @@ -40,6 +40,8 @@ |
40 | 40 | |
41 | 41 | const editoreRef = ref<JSONEditor>(); |
42 | 42 | |
43 | + const isFocus = ref(false); | |
44 | + | |
43 | 45 | const handleChange = (value: any) => { |
44 | 46 | emit(EventEnum.UPDATE_VALUE, value, unref(editoreRef)); |
45 | 47 | emit(EventEnum.CHANGE, value, unref(editoreRef)); |
... | ... | @@ -54,8 +56,14 @@ |
54 | 56 | return { |
55 | 57 | ...options, |
56 | 58 | onChangeText: handleChange, |
57 | - onBlur: (event: Event) => handleEmit(event, EventEnum.BLUR), | |
58 | - onFocus: (event: Event) => handleEmit(event, EventEnum.FOCUS), | |
59 | + onBlur: (event: Event) => { | |
60 | + isFocus.value = false; | |
61 | + handleEmit(event, EventEnum.BLUR); | |
62 | + }, | |
63 | + onFocus: (event: Event) => { | |
64 | + isFocus.value = true; | |
65 | + handleEmit(event, EventEnum.FOCUS); | |
66 | + }, | |
59 | 67 | } as JSONEditorOptions; |
60 | 68 | }); |
61 | 69 | |
... | ... | @@ -63,15 +71,16 @@ |
63 | 71 | editoreRef.value = new JSONEditor(unref(jsonEditorElRef), unref(getOptions)); |
64 | 72 | }; |
65 | 73 | |
66 | - // watch( | |
67 | - // () => props.value, | |
68 | - // (target) => { | |
69 | - // unref(editoreRef)?.setText(target || ''); | |
70 | - // }, | |
71 | - // { | |
72 | - // immediate: true, | |
73 | - // } | |
74 | - // ); | |
74 | + watch( | |
75 | + () => props.value, | |
76 | + (target) => { | |
77 | + if (unref(isFocus)) return; | |
78 | + unref(editoreRef)?.setText(target || ''); | |
79 | + }, | |
80 | + { | |
81 | + immediate: true, | |
82 | + } | |
83 | + ); | |
75 | 84 | |
76 | 85 | const get = (): string => { |
77 | 86 | return unref(editoreRef)?.getText() || ''; | ... | ... |
... | ... | @@ -60,7 +60,7 @@ |
60 | 60 | }); |
61 | 61 | |
62 | 62 | const validateRepeat = (value: StructRecord, valueList: StructRecord[]) => { |
63 | - return valueList.filter((item) => item.identifier === value.identifier).length >= 1; | |
63 | + return valueList.filter((item) => item.identifier === value.identifier).length > 1; | |
64 | 64 | }; |
65 | 65 | |
66 | 66 | const handleSubmit = async () => { | ... | ... |
... | ... | @@ -20,7 +20,7 @@ export const validateValueRange = (_rule, value: Record<'min' | 'max', number>, |
20 | 20 | return Promise.resolve(); |
21 | 21 | }; |
22 | 22 | |
23 | -export const validateJSON = (_rule, value: ModelOfMatterParams[], _callback) => { | |
23 | +export const validateJSON = (_rule, value = [] as ModelOfMatterParams[], _callback) => { | |
24 | 24 | if (value.length) { |
25 | 25 | return Promise.resolve(); |
26 | 26 | } | ... | ... |
... | ... | @@ -10,6 +10,8 @@ |
10 | 10 | import { onMounted } from 'vue'; |
11 | 11 | import { getBoundingClientRect } from '/@/utils/domUtils'; |
12 | 12 | import { TaskRecordType } from '/@/api/task/model'; |
13 | + import { RunTaskModal } from '/@/views/task/center/components/RunTaskModal'; | |
14 | + import { useModal } from '/@/components/Modal'; | |
13 | 15 | |
14 | 16 | const props = defineProps<{ |
15 | 17 | tbDeviceId: string; |
... | ... | @@ -17,6 +19,8 @@ |
17 | 19 | |
18 | 20 | const listElRef = ref<Nullable<ComponentElRef>>(null); |
19 | 21 | |
22 | + const [registerRunTaskModal, { openModal }] = useModal(); | |
23 | + | |
20 | 24 | const [registerForm, { getFieldsValue }] = useForm({ |
21 | 25 | schemas: formSchemas, |
22 | 26 | baseColProps: { span: 8 }, |
... | ... | @@ -24,19 +28,25 @@ |
24 | 28 | showAdvancedButton: true, |
25 | 29 | labelWidth: 100, |
26 | 30 | submitFunc: async () => { |
27 | - pagination.params = getFieldsValue(); | |
28 | 31 | getDataSource(); |
29 | 32 | }, |
30 | 33 | }); |
31 | 34 | |
35 | + const paginationChange = (page: number, pageSize: number) => { | |
36 | + pagination.current = page - 1 * pageSize > pagination.total ? 1 : page; | |
37 | + pagination.pageSize = pageSize; | |
38 | + getDataSource(); | |
39 | + }; | |
40 | + | |
32 | 41 | const pagination = reactive({ |
33 | - total: 10, | |
34 | 42 | current: 1, |
35 | 43 | pageSize: 10, |
44 | + total: 0, | |
36 | 45 | showQuickJumper: true, |
37 | 46 | size: 'small', |
38 | 47 | showTotal: (total: number) => `共 ${total} 条数据`, |
39 | - params: {} as Recordable, | |
48 | + onChange: paginationChange, | |
49 | + onShowSizeChange: paginationChange, | |
40 | 50 | }); |
41 | 51 | |
42 | 52 | const dataSource = ref<TaskRecordType[]>([]); |
... | ... | @@ -45,12 +55,14 @@ |
45 | 55 | const getDataSource = async () => { |
46 | 56 | try { |
47 | 57 | loading.value = true; |
48 | - const { items } = await getTaskCenterList({ | |
58 | + const params = getFieldsValue() || {}; | |
59 | + const { items, total } = await getTaskCenterList({ | |
49 | 60 | page: pagination.current, |
50 | 61 | pageSize: pagination.pageSize, |
51 | 62 | tbDeviceId: props.tbDeviceId, |
52 | - ...pagination.params, | |
63 | + ...params, | |
53 | 64 | }); |
65 | + pagination.total = total; | |
54 | 66 | dataSource.value = items; |
55 | 67 | } catch (error) { |
56 | 68 | throw error; |
... | ... | @@ -79,6 +91,10 @@ |
79 | 91 | (listContainerEl.style.overflowX = 'hidden'); |
80 | 92 | }; |
81 | 93 | |
94 | + const handleRunTask = (record: TaskRecordType) => { | |
95 | + openModal(true, record); | |
96 | + }; | |
97 | + | |
82 | 98 | onMounted(() => { |
83 | 99 | setListHeight(); |
84 | 100 | getDataSource(); |
... | ... | @@ -119,10 +135,12 @@ |
119 | 135 | :reload="reload" |
120 | 136 | :tbDeviceId="tbDeviceId" |
121 | 137 | :deviceTaskCardMode="true" |
138 | + @runTask="handleRunTask" | |
122 | 139 | /> |
123 | 140 | </List.Item> |
124 | 141 | </template> |
125 | 142 | </List> |
143 | + <RunTaskModal :reload="reload" @register="registerRunTaskModal" /> | |
126 | 144 | </section> |
127 | 145 | </PageWrapper> |
128 | 146 | </template> | ... | ... |
... | ... | @@ -13,6 +13,8 @@ import { queryDeviceProfileBy } from '/@/api/device/deviceManager'; |
13 | 13 | import { getModelServices } from '/@/api/device/modelOfMatter'; |
14 | 14 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; |
15 | 15 | import useCommonFun from '../hooks/useCommonFun'; |
16 | +import { DeviceProfileModel } from '/@/api/device/model/deviceModel'; | |
17 | +import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; | |
16 | 18 | |
17 | 19 | const { useByProductGetAttribute } = useCommonFun(); |
18 | 20 | export type TOption = { |
... | ... | @@ -443,6 +445,12 @@ export const actionSchema: FormSchema[] = [ |
443 | 445 | ifShow: ({ values }) => isDeviceOut(values.outTarget), |
444 | 446 | }, |
445 | 447 | { |
448 | + field: 'transportType', | |
449 | + label: '', | |
450 | + component: 'Input', | |
451 | + show: false, | |
452 | + }, | |
453 | + { | |
446 | 454 | field: 'deviceProfileId', |
447 | 455 | label: '', |
448 | 456 | component: 'ApiSelect', |
... | ... | @@ -459,8 +467,28 @@ export const actionSchema: FormSchema[] = [ |
459 | 467 | labelField: 'name', |
460 | 468 | valueField: 'id', |
461 | 469 | getPopupContainer: () => document.body, |
462 | - onChange: () => { | |
463 | - setFieldsValue({ thingsModelId: '', deviceId: [] }); | |
470 | + onChange: (_value: string, options = {} as DeviceProfileModel) => { | |
471 | + const oldType = formModel['transportType']; | |
472 | + | |
473 | + const updateFlag = | |
474 | + oldType === TransportTypeEnum.TCP || options.transportType === TransportTypeEnum.TCP; | |
475 | + | |
476 | + setFieldsValue({ | |
477 | + thingsModelId: '', | |
478 | + deviceId: [], | |
479 | + transportType: options.transportType, | |
480 | + ...(updateFlag ? { doContext: null } : {}), | |
481 | + }); | |
482 | + }, | |
483 | + onOptionsChange(options: DeviceProfileModel[]) { | |
484 | + const deviceProfileId = formModel['deviceProfileId']; | |
485 | + if (deviceProfileId) { | |
486 | + const index = options.findIndex( | |
487 | + (item) => (item as Recordable).value === deviceProfileId | |
488 | + ); | |
489 | + | |
490 | + ~index && setFieldsValue({ transportType: options[index].transportType }); | |
491 | + } | |
464 | 492 | }, |
465 | 493 | }; |
466 | 494 | }, | ... | ... |
... | ... | @@ -39,8 +39,15 @@ |
39 | 39 | </template> |
40 | 40 | </a-select> |
41 | 41 | </template> |
42 | - <template #doContext> | |
43 | - <div class="flex" style="align-items: center"> | |
42 | + <template #doContext="{ model, field }"> | |
43 | + <div v-if="model['transportType'] === TransportTypeEnum.TCP"> | |
44 | + <Input v-model:value="model[field]" placeholder="请输入自定义命令" /> | |
45 | + </div> | |
46 | + <div | |
47 | + v-show="model['transportType'] !== TransportTypeEnum.TCP" | |
48 | + class="flex" | |
49 | + style="align-items: center" | |
50 | + > | |
44 | 51 | <div ref="jsoneditorRef" style="height: 100%; width: 100%"></div> |
45 | 52 | <a-button style="margin: -5px 0" type="text" @click="handlePremitter">格式化</a-button> |
46 | 53 | <Tooltip |
... | ... | @@ -88,11 +95,13 @@ |
88 | 95 | <script lang="ts"> |
89 | 96 | import { defineComponent } from 'vue'; |
90 | 97 | import { isNumber } from '/@/utils/is'; |
98 | + import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; | |
91 | 99 | export default defineComponent({ |
92 | 100 | components: { |
93 | 101 | VNodes: (_, { attrs }) => { |
94 | 102 | return attrs.vnodes; |
95 | 103 | }, |
104 | + Input, | |
96 | 105 | }, |
97 | 106 | inheritAttrs: false, |
98 | 107 | }); |
... | ... | @@ -101,7 +110,7 @@ |
101 | 110 | import { ref, onMounted, nextTick, unref, computed, provide } from 'vue'; |
102 | 111 | import { CollapseContainer } from '/@/components/Container/index'; |
103 | 112 | import { BasicForm, useForm } from '/@/components/Form/index'; |
104 | - import { Tooltip, Select, Checkbox, Card } from 'ant-design-vue'; | |
113 | + import { Tooltip, Select, Checkbox, Card, Input } from 'ant-design-vue'; | |
105 | 114 | import { Icon } from '/@/components/Icon'; |
106 | 115 | import { actionSchema, CommandTypeEnum } from '../config/config.data'; |
107 | 116 | import jsoneditor from 'jsoneditor'; |
... | ... | @@ -260,13 +269,14 @@ |
260 | 269 | //ft-add-2022-11-22 |
261 | 270 | //TODO-fengtao-设备验证 |
262 | 271 | const value = getFieldsValue(); |
272 | + const isTCPTransportType = value.transportType === TransportTypeEnum.TCP; | |
263 | 273 | const doContext = unref(jsonInstance)?.get() || {}; |
264 | 274 | const serviceInputValue = Reflect.get(value, 'serviceInputValue'); |
265 | 275 | |
266 | 276 | return { |
267 | 277 | ...value, |
268 | 278 | ...(Number(value.commandType) === CommandTypeEnum.CUSTOM |
269 | - ? { doContext } | |
279 | + ? { doContext: isTCPTransportType ? value.doContext : doContext } | |
270 | 280 | : { doContext: serviceInputValue }), |
271 | 281 | clearRule, |
272 | 282 | }; |
... | ... | @@ -280,7 +290,9 @@ |
280 | 290 | ...(isNumber(fieldsValue.commandType) |
281 | 291 | ? { commandType: String(fieldsValue.commandType) } |
282 | 292 | : {}), |
283 | - serviceInputValue: commandType === CommandTypeEnum.SERVICE ? doContext.params || {} : {}, | |
293 | + ...(commandType === CommandTypeEnum.SERVICE | |
294 | + ? { serviceInputValue: doContext.params || {} } | |
295 | + : { doContext: doContext.params }), | |
284 | 296 | }); |
285 | 297 | }; |
286 | 298 | //ft-add | ... | ... |
... | ... | @@ -21,8 +21,8 @@ export const genPollCronExpression = (value: number, type: TimeUnitEnum) => { |
21 | 21 | const placeholder = 'placeholder'; |
22 | 22 | const expression = { |
23 | 23 | [TimeUnitEnum.SECOND]: `${placeholder} * * * * ? *`, |
24 | - [TimeUnitEnum.MINUTE]: `* ${placeholder} * * * ? *`, | |
25 | - [TimeUnitEnum.HOUR]: `* * ${placeholder} * * ? *`, | |
24 | + [TimeUnitEnum.MINUTE]: `0 ${placeholder} * * * ? *`, | |
25 | + [TimeUnitEnum.HOUR]: `0 0 ${placeholder} * * ? *`, | |
26 | 26 | }; |
27 | 27 | const newExpression = expression[type]; |
28 | 28 | return newExpression.replace(placeholder, `0/${value}`); | ... | ... |
... | ... | @@ -35,12 +35,21 @@ |
35 | 35 | }, |
36 | 36 | }); |
37 | 37 | |
38 | + const paginationChange = (page: number, pageSize: number) => { | |
39 | + pagination.current = page - 1 * pageSize > pagination.total ? 1 : page; | |
40 | + pagination.pageSize = pageSize; | |
41 | + getDataSource(); | |
42 | + }; | |
43 | + | |
38 | 44 | const pagination = reactive({ |
39 | - total: 10, | |
40 | 45 | current: 1, |
46 | + pageSize: 10, | |
47 | + total: 0, | |
41 | 48 | showQuickJumper: true, |
42 | 49 | size: 'small', |
43 | 50 | showTotal: (total: number) => `共 ${total} 条数据`, |
51 | + onChange: paginationChange, | |
52 | + onShowSizeChange: paginationChange, | |
44 | 53 | }); |
45 | 54 | |
46 | 55 | const dataSource = ref<TaskRecordType[]>([]); |
... | ... | @@ -49,8 +58,13 @@ |
49 | 58 | try { |
50 | 59 | loading.value = true; |
51 | 60 | const params = getFieldsValue(); |
52 | - const { items } = await getTaskCenterList({ page: 1, pageSize: 10, ...params }); | |
61 | + const { items, total } = await getTaskCenterList({ | |
62 | + page: pagination.current, | |
63 | + pageSize: pagination.pageSize, | |
64 | + ...params, | |
65 | + }); | |
53 | 66 | dataSource.value = items; |
67 | + pagination.total = total; | |
54 | 68 | } catch (error) { |
55 | 69 | throw error; |
56 | 70 | } finally { | ... | ... |
... | ... | @@ -17,6 +17,9 @@ export interface ControlComponentValue { |
17 | 17 | deviceProfileId?: string; |
18 | 18 | deviceType?: DeviceTypeEnum; |
19 | 19 | organizationId?: string; |
20 | + | |
21 | + dataSource?: DataSource; | |
22 | + [key: string]: any; | |
20 | 23 | } |
21 | 24 | |
22 | 25 | export const ControlComponentDefaultConfig: ControlComponentValue = { |
... | ... | @@ -40,6 +43,7 @@ export const transformControlConfig = ( |
40 | 43 | deviceType: dataSourceRecord.deviceType, |
41 | 44 | slaveDeviceId: dataSourceRecord.slaveDeviceId, |
42 | 45 | organizationId: dataSourceRecord.organizationId, |
46 | + dataSource: dataSourceRecord, | |
43 | 47 | } as ControlComponentValue, |
44 | 48 | }; |
45 | 49 | }; | ... | ... |
1 | 1 | import { ControlComponentValue } from './control.config'; |
2 | -import { getDeviceProfile } from '/@/api/alarm/position'; | |
3 | -import { getDeviceRelation, sendCommandOneway } from '/@/api/dataBoard'; | |
4 | -import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | |
5 | -import { getModelServices } from '/@/api/device/modelOfMatter'; | |
2 | +import { sendCommandOneway } from '/@/api/dataBoard'; | |
6 | 3 | import { useMessage } from '/@/hooks/web/useMessage'; |
7 | -import { isString } from '/@/utils/is'; | |
8 | 4 | import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; |
9 | 5 | |
10 | 6 | const { createMessage } = useMessage(); |
... | ... | @@ -15,31 +11,20 @@ export function useSendCommand() { |
15 | 11 | }; |
16 | 12 | const sendCommand = async (record: ControlComponentValue, value: any) => { |
17 | 13 | if (!record) return error(); |
18 | - const { deviceProfileId, attribute, deviceType } = record; | |
19 | - let { deviceId } = record; | |
14 | + const { attribute } = record; | |
15 | + const { dataSource } = record; | |
16 | + const { customCommand } = dataSource || {}; | |
17 | + | |
18 | + const { deviceId } = record; | |
20 | 19 | if (!deviceId) return error(); |
21 | 20 | try { |
22 | - const list = await getDeviceProfile(); | |
23 | - const deviceProfile = list.find((item) => item.id === deviceProfileId); | |
24 | - if (!deviceProfile) return error(); | |
25 | - | |
26 | 21 | let params: string | Recordable = { |
27 | 22 | [attribute!]: Number(value), |
28 | 23 | }; |
29 | 24 | |
30 | 25 | // 如果是TCP设备从物模型中获取下发命令(TCP网关子设备无物模型服务与事件) |
31 | - if (deviceProfile!.transportType === TransportTypeEnum.TCP) { | |
32 | - const serviceList = (await getModelServices({ deviceProfileId: deviceProfileId! })) || []; | |
33 | - const record = serviceList.find((item) => item.identifier === attribute); | |
34 | - const sendCommand = record?.functionJson.inputData?.at(0)?.serviceCommand || ''; | |
35 | - params = isString(sendCommand) ? sendCommand : JSON.stringify(sendCommand); | |
36 | - } | |
37 | - | |
38 | - if (deviceType === DeviceTypeEnum.SENSOR) { | |
39 | - deviceId = await getDeviceRelation({ | |
40 | - deviceId, | |
41 | - isSlave: deviceType === DeviceTypeEnum.SENSOR, | |
42 | - }); | |
26 | + if (customCommand?.transportType === TransportTypeEnum.TCP) { | |
27 | + params = customCommand.command!; | |
43 | 28 | } |
44 | 29 | |
45 | 30 | // 控制按钮下发命令为0 或 1 |
... | ... | @@ -57,7 +42,6 @@ export function useSendCommand() { |
57 | 42 | createMessage.success('命令下发成功'); |
58 | 43 | return true; |
59 | 44 | } catch (msg) { |
60 | - console.log('enter'); | |
61 | 45 | return error(); |
62 | 46 | } |
63 | 47 | }; | ... | ... |
... | ... | @@ -61,7 +61,13 @@ |
61 | 61 | const hasExistEl = Object.keys(dataSourceEl).filter((key) => dataSourceEl[key]); |
62 | 62 | for (const id of hasExistEl) { |
63 | 63 | const oldValues = dataSourceEl[id]?.getFieldsValue(); |
64 | - dataSourceEl[id]?.setFieldsValue({ ...oldValues, [DataSourceField.ATTRIBUTE]: null }); | |
64 | + dataSourceEl[id]?.setFieldsValue({ | |
65 | + ...oldValues, | |
66 | + [DataSourceField.ATTRIBUTE]: null, | |
67 | + [DataSourceField.COMMAND_TYPE]: null, | |
68 | + [DataSourceField.SERVICE]: null, | |
69 | + }); | |
70 | + dataSourceEl[id]?.clearValidate(); | |
65 | 71 | } |
66 | 72 | }; |
67 | 73 | |
... | ... | @@ -125,6 +131,12 @@ |
125 | 131 | _dataSource[index] = { |
126 | 132 | ...value, |
127 | 133 | componentInfo: { ...(props.defaultConfig || {}), ...componentInfo }, |
134 | + customCommand: { | |
135 | + transportType: value.transportType, | |
136 | + service: value.service, | |
137 | + command: value.command, | |
138 | + commandType: value.commandType, | |
139 | + }, | |
128 | 140 | }; |
129 | 141 | } |
130 | 142 | |
... | ... | @@ -197,13 +209,26 @@ |
197 | 209 | dataSource.value = props.record.record.dataSource.map((item) => { |
198 | 210 | const id = buildUUID(); |
199 | 211 | |
212 | + const customCommand = item.customCommand || {}; | |
213 | + | |
200 | 214 | nextTick(() => { |
201 | - (dataSourceEl[id] as FormActionType).setFieldsValue(item); | |
215 | + (dataSourceEl[id] as FormActionType).setFieldsValue({ | |
216 | + ...item, | |
217 | + transportType: customCommand.transportType, | |
218 | + command: customCommand?.command, | |
219 | + commandType: customCommand.commandType, | |
220 | + service: customCommand.service, | |
221 | + }); | |
202 | 222 | (dataSourceEl[id] as FormActionType).clearValidate(); |
203 | 223 | }); |
224 | + | |
204 | 225 | return { |
205 | 226 | id, |
206 | 227 | ...item, |
228 | + transportType: customCommand.transportType, | |
229 | + command: customCommand?.command, | |
230 | + commandType: customCommand.commandType, | |
231 | + service: customCommand.service, | |
207 | 232 | }; |
208 | 233 | }); |
209 | 234 | }; | ... | ... |
... | ... | @@ -72,7 +72,6 @@ |
72 | 72 | const { getAllDataSourceFieldValue, validate } = unref(basicConfigurationEl)!; |
73 | 73 | await validate(); |
74 | 74 | const value = getAllDataSourceFieldValue(); |
75 | - | |
76 | 75 | unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value); |
77 | 76 | resetForm(); |
78 | 77 | } catch (error: unknown) { | ... | ... |
1 | 1 | import { getDeviceAttributes, getMeetTheConditionsDevice } from '/@/api/dataBoard'; |
2 | 2 | import { getOrganizationList } from '/@/api/system/system'; |
3 | -import { FormSchema } from '/@/components/Form'; | |
3 | +import { FormSchema, useComponentRegister } from '/@/components/Form'; | |
4 | 4 | import { copyTransFun } from '/@/utils/fnUtils'; |
5 | 5 | import { DeviceAttributeParams, MasterDeviceList } from '/@/api/dataBoard/model'; |
6 | 6 | import { FrontComponent } from '../../const/const'; |
... | ... | @@ -10,6 +10,11 @@ import { findDictItemByCode } from '/@/api/system/dict'; |
10 | 10 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
11 | 11 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; |
12 | 12 | import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; |
13 | +import { JSONEditor } from '/@/components/CodeEditor'; | |
14 | +import { CommandTypeEnum } from '/@/views/rule/linkedge/config/config.data'; | |
15 | +import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; | |
16 | + | |
17 | +useComponentRegister('JSONEditor', JSONEditor); | |
13 | 18 | |
14 | 19 | export enum BasicConfigField { |
15 | 20 | NAME = 'name', |
... | ... | @@ -47,6 +52,10 @@ export enum DataSourceField { |
47 | 52 | DEVICE_RENAME = 'deviceRename', |
48 | 53 | LONGITUDE_ATTRIBUTE = 'longitudeAttribute', |
49 | 54 | LATITUDE_ATTRIBUTE = 'latitudeAttribute', |
55 | + | |
56 | + COMMAND = 'command', | |
57 | + COMMAND_TYPE = 'commandType', | |
58 | + SERVICE = 'service', | |
50 | 59 | } |
51 | 60 | |
52 | 61 | export const isControlComponent = (frontId: FrontComponent) => { |
... | ... | @@ -139,6 +148,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For |
139 | 148 | [DataSourceField.TRANSPORT_TYPE]: null, |
140 | 149 | }); |
141 | 150 | }, |
151 | + getPopupContainer: () => document.body, | |
142 | 152 | }; |
143 | 153 | }, |
144 | 154 | }, |
... | ... | @@ -172,6 +182,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For |
172 | 182 | [DataSourceField.TRANSPORT_TYPE]: option[DataSourceField.TRANSPORT_TYPE], |
173 | 183 | }); |
174 | 184 | }, |
185 | + getPopupContainer: () => document.body, | |
175 | 186 | }; |
176 | 187 | }, |
177 | 188 | }, |
... | ... | @@ -252,31 +263,14 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For |
252 | 263 | component: 'ApiSelect', |
253 | 264 | label: '属性', |
254 | 265 | colProps: { span: 8 }, |
255 | - dynamicRules: ({ model }) => { | |
256 | - const transportType = model[DataSourceField.TRANSPORT_TYPE]; | |
257 | - return [ | |
258 | - { | |
259 | - required: true, | |
260 | - message: `${ | |
261 | - isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType) | |
262 | - ? '服务' | |
263 | - : '属性' | |
264 | - }为必填项`, | |
265 | - }, | |
266 | - ]; | |
267 | - }, | |
266 | + rules: [{ required: true, message: '请选择属性' }], | |
267 | + ifShow: ({ model }) => | |
268 | + !(isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]) && isControlComponent(frontId!)), | |
268 | 269 | componentProps({ formModel }) { |
269 | 270 | const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; |
270 | - const transportType = formModel[DataSourceField.TRANSPORT_TYPE]; | |
271 | - if (isEdit && ![deviceProfileId, transportType].every(Boolean)) | |
272 | - return { placeholder: '请选择属性', getPopupContainer: () => document.body }; | |
273 | 271 | return { |
274 | 272 | api: async () => { |
275 | 273 | try { |
276 | - if (isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)) { | |
277 | - return await getDeviceService(deviceProfileId); | |
278 | - } | |
279 | - | |
280 | 274 | if (deviceProfileId) { |
281 | 275 | return await getDeviceAttribute({ |
282 | 276 | deviceProfileId, |
... | ... | @@ -284,18 +278,87 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For |
284 | 278 | }); |
285 | 279 | } |
286 | 280 | } catch (error) {} |
287 | - | |
288 | 281 | return []; |
289 | 282 | }, |
290 | - placeholder: | |
291 | - isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType) | |
292 | - ? '请选择服务' | |
293 | - : '请选择属性', | |
283 | + placeholder: '请选择属性', | |
284 | + getPopupContainer: () => document.body, | |
285 | + }; | |
286 | + }, | |
287 | + }, | |
288 | + { | |
289 | + field: DataSourceField.COMMAND_TYPE, | |
290 | + component: 'ApiSelect', | |
291 | + label: '命令类型', | |
292 | + defaultValue: CommandTypeEnum.CUSTOM.toString(), | |
293 | + colProps: { span: 8 }, | |
294 | + ifShow: ({ model }) => | |
295 | + isControlComponent(frontId!) && isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), | |
296 | + componentProps: ({ formActionType }) => { | |
297 | + const { setFieldsValue } = formActionType; | |
298 | + return { | |
299 | + api: findDictItemByCode, | |
300 | + params: { | |
301 | + dictCode: 'custom_define', | |
302 | + }, | |
303 | + labelField: 'itemText', | |
304 | + valueField: 'itemValue', | |
305 | + placeholder: '请选择命令类型', | |
306 | + onChange() { | |
307 | + setFieldsValue({ [DataSourceField.COMMAND]: null, [DataSourceField.SERVICE]: null }); | |
308 | + }, | |
309 | + }; | |
310 | + }, | |
311 | + }, | |
312 | + { | |
313 | + field: DataSourceField.SERVICE, | |
314 | + component: 'ApiSelect', | |
315 | + label: '服务', | |
316 | + colProps: { span: 8 }, | |
317 | + rules: [{ required: true, message: '请选择服务' }], | |
318 | + ifShow: ({ model }) => | |
319 | + isControlComponent(frontId as FrontComponent) && | |
320 | + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.SERVICE.toString() && | |
321 | + isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), | |
322 | + componentProps({ formModel, formActionType }) { | |
323 | + const { setFieldsValue } = formActionType; | |
324 | + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; | |
325 | + const transportType = formModel[DataSourceField.TRANSPORT_TYPE]; | |
326 | + if (isEdit && ![deviceProfileId, transportType].every(Boolean)) | |
327 | + return { placeholder: '请选择服务', getPopupContainer: () => document.body }; | |
328 | + return { | |
329 | + api: async () => { | |
330 | + try { | |
331 | + if (deviceProfileId) { | |
332 | + return await getDeviceService(deviceProfileId); | |
333 | + } | |
334 | + } catch (error) {} | |
335 | + return []; | |
336 | + }, | |
337 | + placeholder: '请选择服务', | |
294 | 338 | getPopupContainer: () => document.body, |
339 | + onChange(value: string, options: ModelOfMatterParams) { | |
340 | + const command = value ? (options.functionJson.inputData || [])[0].serviceCommand : null; | |
341 | + setFieldsValue({ [DataSourceField.COMMAND]: command }); | |
342 | + }, | |
295 | 343 | }; |
296 | 344 | }, |
297 | 345 | }, |
298 | 346 | { |
347 | + field: DataSourceField.COMMAND, | |
348 | + component: 'Input', | |
349 | + label: '命令', | |
350 | + colProps: { span: 8 }, | |
351 | + // 是控制组件 && 自定义命令 && 传输协议为TCP | |
352 | + ifShow: ({ model }) => | |
353 | + isControlComponent(frontId!) && | |
354 | + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.CUSTOM.toString() && | |
355 | + model[DataSourceField.TRANSPORT_TYPE] && | |
356 | + isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), | |
357 | + componentProps: { | |
358 | + placeholder: '请输入下发命令', | |
359 | + }, | |
360 | + }, | |
361 | + { | |
299 | 362 | field: DataSourceField.DEVICE_RENAME, |
300 | 363 | component: 'Input', |
301 | 364 | label: '设备名', | ... | ... |
... | ... | @@ -127,13 +127,15 @@ export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) { |
127 | 127 | if (isNullAndUnDef(subscriptionId)) return; |
128 | 128 | const mappingRecord = cmdIdMapping.get(subscriptionId); |
129 | 129 | if (!mappingRecord || !data) return; |
130 | - mappingRecord.forEach((item) => { | |
130 | + | |
131 | + for (const item of mappingRecord) { | |
131 | 132 | const { attribute, recordIndex, dataSourceIndex } = item; |
133 | + if (!attribute) continue; | |
132 | 134 | const [[timespan, value]] = data[attribute]; |
133 | 135 | const record = getNeedUpdateValueByIndex(recordIndex, dataSourceIndex); |
134 | 136 | record.componentInfo.value = value; |
135 | 137 | record.componentInfo.updateTime = timespan; |
136 | - }); | |
138 | + } | |
137 | 139 | return; |
138 | 140 | } catch (error) { |
139 | 141 | throw Error(error as string); | ... | ... |