Commit d77a75713f261629c1e1230d088fa157b73d4a1c
Merge branch 'ww' into 'main'
fix: BUG in teambition See merge request huang/yun-teng-iot-front!413
Showing
26 changed files
with
247 additions
and
91 deletions
1 | +import { DeviceProfileModel } from '../../device/model/deviceModel'; | |
1 | 2 | import { HistoryData } from './model'; |
2 | 3 | import { defHttp } from '/@/utils/http/axios'; |
3 | 4 | |
4 | 5 | // 获取设备配置 |
5 | 6 | export const getDeviceProfile = () => { |
6 | - return defHttp.get({ | |
7 | + return defHttp.get<DeviceProfileModel[]>({ | |
7 | 8 | url: '/device_profile/me/list', |
8 | 9 | }); |
9 | 10 | }; | ... | ... |
... | ... | @@ -166,9 +166,10 @@ export const getShareBoardComponentInfo = (params: { boardId: string; tenantId: |
166 | 166 | * @param params |
167 | 167 | * @returns |
168 | 168 | */ |
169 | -export const getAllDeviceByOrg = (params: string) => { | |
169 | +export const getAllDeviceByOrg = (organizationId: string, deviceProfileId?: string) => { | |
170 | 170 | return defHttp.get<MasterDeviceList[]>({ |
171 | - url: `${DeviceUrl.GET_DEVICE}/${params}`, | |
171 | + url: `${DeviceUrl.GET_DEVICE}/${organizationId}`, | |
172 | + params: { deviceProfileId }, | |
172 | 173 | }); |
173 | 174 | }; |
174 | 175 | ... | ... |
... | ... | @@ -65,7 +65,7 @@ export const releaseModel = (deviceProfileId: string) => { |
65 | 65 | |
66 | 66 | export const getModelServices = (params: { deviceProfileId: string }) => { |
67 | 67 | const { deviceProfileId } = params; |
68 | - return defHttp.get({ | |
68 | + return defHttp.get<ModelOfMatterParams[]>({ | |
69 | 69 | url: `${ModelOfMatter.GET_MODEL_SERVICE}/${deviceProfileId}`, |
70 | 70 | }); |
71 | 71 | }; | ... | ... |
... | ... | @@ -56,7 +56,7 @@ |
56 | 56 | |
57 | 57 | const handleBeforeUpload = (file: File) => { |
58 | 58 | if (file.size > props.maxSize) { |
59 | - createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024)}mb`); | |
59 | + createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024 / 1024)}mb`); | |
60 | 60 | return false; |
61 | 61 | } |
62 | 62 | handleUpload(file); | ... | ... |
1 | -import { h } from 'vue'; | |
2 | 1 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; |
3 | 2 | import { findDictItemByCode } from '/@/api/system/dict'; |
4 | 3 | import { FormSchema } from '/@/components/Table'; |
... | ... | @@ -22,7 +21,6 @@ const validateValueRange = (_rule, value: Record<'min' | 'max', number>, _callba |
22 | 21 | }; |
23 | 22 | |
24 | 23 | const validateJSON = (_rule, value: ModelOfMatterParams[], _callback) => { |
25 | - console.log('validate json', value); | |
26 | 24 | if (value.length) { |
27 | 25 | return Promise.resolve(); |
28 | 26 | } |
... | ... | @@ -141,10 +139,15 @@ export const formSchemas: FormSchema[] = [ |
141 | 139 | const { setFieldsValue } = formActionType; |
142 | 140 | return { |
143 | 141 | placeholder: '请选择单位', |
144 | - api: findDictItemByCode, | |
142 | + api: async (params) => { | |
143 | + const list = await findDictItemByCode(params); | |
144 | + list.map((item) => (item.itemText = `${item.itemText} / ${item.itemValue}`)); | |
145 | + return list; | |
146 | + }, | |
145 | 147 | params: { |
146 | 148 | dictCode: 'attribute_unit', |
147 | 149 | }, |
150 | + labelInValue: true, | |
148 | 151 | labelField: 'itemText', |
149 | 152 | valueField: 'itemValue', |
150 | 153 | onChange(_, record: Record<'label' | 'value', string>) { |
... | ... | @@ -165,14 +168,6 @@ export const formSchemas: FormSchema[] = [ |
165 | 168 | ifShow: ({ values }) => |
166 | 169 | values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_INT || |
167 | 170 | values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_DOUBLE, |
168 | - renderComponentContent: () => { | |
169 | - return { | |
170 | - option: (params: Record<'label' | 'value', string>) => { | |
171 | - const { label, value } = params; | |
172 | - return h('span', `${label} / ${value}`); | |
173 | - }, | |
174 | - }; | |
175 | - }, | |
176 | 171 | }, |
177 | 172 | { |
178 | 173 | field: FormField.BOOL_CLOSE, | ... | ... |
... | ... | @@ -34,7 +34,6 @@ |
34 | 34 | let { width = 300, height = 150 } = unref(getOptions); |
35 | 35 | width = isNumber(width) ? (`${width}px` as unknown as number) : width; |
36 | 36 | height = isNumber(height) ? (`${height}px` as unknown as number) : height; |
37 | - console.log({ getOptions }); | |
38 | 37 | return { width, height } as CSSProperties; |
39 | 38 | }); |
40 | 39 | ... | ... |
src/hooks/web/useAsyncScript.ts
0 → 100644
1 | +import { onUnmounted, ref } from 'vue'; | |
2 | + | |
3 | +interface ScriptOptions { | |
4 | + src: string; | |
5 | +} | |
6 | + | |
7 | +export function useAsyncScript(opts: ScriptOptions) { | |
8 | + const isLoading = ref(false); | |
9 | + const error = ref(false); | |
10 | + const success = ref(false); | |
11 | + let script: HTMLScriptElement; | |
12 | + | |
13 | + const toPromise = () => { | |
14 | + return new Promise((resolve, reject) => { | |
15 | + script = document.createElement('script'); | |
16 | + script.type = 'text/javascript'; | |
17 | + script.onload = function () { | |
18 | + isLoading.value = false; | |
19 | + success.value = true; | |
20 | + error.value = false; | |
21 | + resolve(''); | |
22 | + }; | |
23 | + | |
24 | + script.onerror = function (err) { | |
25 | + isLoading.value = false; | |
26 | + success.value = false; | |
27 | + error.value = true; | |
28 | + reject(err); | |
29 | + }; | |
30 | + | |
31 | + script.src = opts.src; | |
32 | + document.head.appendChild(script); | |
33 | + }); | |
34 | + }; | |
35 | + | |
36 | + onUnmounted(() => { | |
37 | + script && script.remove(); | |
38 | + }); | |
39 | + | |
40 | + return { | |
41 | + isLoading, | |
42 | + error, | |
43 | + success, | |
44 | + toPromise, | |
45 | + }; | |
46 | +} | ... | ... |
... | ... | @@ -62,6 +62,7 @@ export function useECharts( |
62 | 62 | } |
63 | 63 | nextTick(() => { |
64 | 64 | useTimeoutFn(() => { |
65 | + console.log(chartInstance); | |
65 | 66 | if (!chartInstance) { |
66 | 67 | initCharts(getDarkMode.value as 'default'); |
67 | 68 | |
... | ... | @@ -70,6 +71,7 @@ export function useECharts( |
70 | 71 | clear && chartInstance?.clear(); |
71 | 72 | |
72 | 73 | chartInstance?.setOption(unref(getOptions)); |
74 | + chartInstance = null; | |
73 | 75 | }, 30); |
74 | 76 | }); |
75 | 77 | } | ... | ... |
... | ... | @@ -29,7 +29,7 @@ |
29 | 29 | import { cloneDeep } from 'lodash'; |
30 | 30 | import { usePermission } from '/@/hooks/web/usePermission'; |
31 | 31 | |
32 | - const listColumn = ref(4); | |
32 | + const listColumn = ref(5); | |
33 | 33 | |
34 | 34 | const { createMessage } = useMessage(); |
35 | 35 | |
... | ... | @@ -209,7 +209,7 @@ |
209 | 209 | <template #cover> |
210 | 210 | <div class="h-full w-full !flex justify-center items-center text-center"> |
211 | 211 | <img |
212 | - class="w-36 h-36" | |
212 | + class="w-full h-36" | |
213 | 213 | alt="example" |
214 | 214 | :src="item.thumbnail || configurationSrc" |
215 | 215 | @click="handlePreview(item)" | ... | ... |
... | ... | @@ -57,7 +57,7 @@ |
57 | 57 | </div> |
58 | 58 | <div v-if="deviceDetail?.deviceInfo?.address" class="mt-4"> |
59 | 59 | <p>设备位置</p> |
60 | - <div ref="wrapRef" style="height: 550px; width: 100%"></div> | |
60 | + <div ref="mapWrapRef" style="height: 550px; width: 100%"></div> | |
61 | 61 | </div> |
62 | 62 | </div> |
63 | 63 | </template> |
... | ... | @@ -65,7 +65,7 @@ |
65 | 65 | import { defineComponent, ref, unref, nextTick } from 'vue'; |
66 | 66 | import { Image, Tooltip } from 'ant-design-vue'; |
67 | 67 | import { descSchema } from '../../config/detail.config'; |
68 | - import { useScript } from '/@/hooks/web/useScript'; | |
68 | + import { useAsyncScript } from '/@/hooks/web/useAsyncScript'; | |
69 | 69 | import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; |
70 | 70 | import { useMessage } from '/@/hooks/web/useMessage'; |
71 | 71 | import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; |
... | ... | @@ -77,6 +77,7 @@ |
77 | 77 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
78 | 78 | |
79 | 79 | import wz from '/@/assets/images/wz.png'; |
80 | + import { useAsyncQueue } from '../../../localtion/useAsyncQueue'; | |
80 | 81 | export default defineComponent({ |
81 | 82 | components: { |
82 | 83 | Image, |
... | ... | @@ -101,13 +102,30 @@ |
101 | 102 | }); |
102 | 103 | |
103 | 104 | // 地图 |
104 | - const wrapRef = ref<HTMLDivElement | null>(null); | |
105 | - const { toPromise } = useScript({ src: BAI_DU_MAP_URL }); | |
105 | + const mapWrapRef = ref<HTMLDivElement>(); | |
106 | 106 | |
107 | - async function initMap(longitude, latitude, address) { | |
108 | - await toPromise(); | |
107 | + const { executeFlag, setTask } = useAsyncQueue(); | |
108 | + const { toPromise } = useAsyncScript({ src: BAI_DU_MAP_URL }); | |
109 | + | |
110 | + async function initMap(longitude: number, latitude: number, address: string) { | |
111 | + if (!(window as any).BMap) { | |
112 | + setTask(() => markerMap(longitude, latitude, address)); | |
113 | + let interval: Nullable<NodeJS.Timer> = setInterval(() => { | |
114 | + if ((window as any).BMap) { | |
115 | + executeFlag.value = true; | |
116 | + clearInterval(interval!); | |
117 | + interval = null; | |
118 | + } | |
119 | + }, 300); | |
120 | + await toPromise(); | |
121 | + return; | |
122 | + } | |
123 | + markerMap(longitude, latitude, address); | |
124 | + } | |
125 | + | |
126 | + async function markerMap(longitude: number, latitude: number, address: string) { | |
109 | 127 | await nextTick(); |
110 | - const wrapEl = unref(wrapRef); | |
128 | + const wrapEl = unref(mapWrapRef); | |
111 | 129 | const BMap = (window as any).BMap; |
112 | 130 | if (!wrapEl) return; |
113 | 131 | const map = new BMap.Map(wrapEl); |
... | ... | @@ -132,6 +150,7 @@ |
132 | 150 | map.enableScrollWheelZoom(true); |
133 | 151 | map.addOverlay(marker); |
134 | 152 | } |
153 | + | |
135 | 154 | const { createMessage } = useMessage(); |
136 | 155 | const { clipboardRef } = useCopyToClipboard(); |
137 | 156 | const copyTbDeviceId = () => { |
... | ... | @@ -166,7 +185,7 @@ |
166 | 185 | const remoteConnectiondGateway = () => {}; |
167 | 186 | |
168 | 187 | return { |
169 | - wrapRef, | |
188 | + mapWrapRef, | |
170 | 189 | copyTbDeviceId, |
171 | 190 | copyDeviceToken, |
172 | 191 | initMap, | ... | ... |
... | ... | @@ -6,6 +6,7 @@ import { HistoryData } from '/@/api/alarm/position/model'; |
6 | 6 | import { getDeviceAttributes } from '/@/api/dataBoard'; |
7 | 7 | import { DeviceAttributeRecord } from '/@/api/dataBoard/model'; |
8 | 8 | import { dateUtil } from '/@/utils/dateUtil'; |
9 | +import { isArray } from '/@/utils/is'; | |
9 | 10 | import { QueryWay } from '/@/views/report/config/config.data'; |
10 | 11 | import { SchemaFiled } from '/@/views/visual/board/detail/config/historyTrend.config'; |
11 | 12 | import { DEFAULT_DATE_FORMAT } from '/@/views/visual/board/detail/config/util'; |
... | ... | @@ -24,7 +25,8 @@ export function useHistoryData() { |
24 | 25 | const getDeviceAttribute = async (record: DeviceOption) => { |
25 | 26 | try { |
26 | 27 | const { deviceProfileId } = record; |
27 | - deviceAttrs.value = (await getDeviceAttributes({ deviceProfileId })) || []; | |
28 | + const list = (await getDeviceAttributes({ deviceProfileId })) || []; | |
29 | + deviceAttrs.value = isArray(list) ? list : []; | |
28 | 30 | } catch (error) { |
29 | 31 | throw error; |
30 | 32 | } | ... | ... |
... | ... | @@ -33,7 +33,9 @@ |
33 | 33 | </Button> |
34 | 34 | </Authority> |
35 | 35 | <Button type="primary" @click="handleOpenTsl"> 物模型TSL </Button> |
36 | - <Button v-if="isShowBtn" type="primary" @click="handleImportModel">导入物模型</Button> | |
36 | + <Button v-if="false && isShowBtn" type="primary" @click="handleImportModel" | |
37 | + >导入物模型</Button | |
38 | + > | |
37 | 39 | </div> |
38 | 40 | <div class="flex gap-2"> |
39 | 41 | <Authority :value="ModelOfMatterPermission.RELEASE"> | ... | ... |
... | ... | @@ -25,7 +25,7 @@ |
25 | 25 | > |
26 | 26 | <TabPane :key="FunctionType.PROPERTIES" tab="属性" /> |
27 | 27 | <TabPane :key="FunctionType.SERVICE" :disabled="isTCPGatewaySubDevice" tab="服务" /> |
28 | - <TabPane :key="FunctionType.EVENTS" tab="事件" :disabled="isTCPGatewaySubDevice" /> | |
28 | + <!-- <TabPane :key="FunctionType.EVENTS" tab="事件" :disabled=" isTCPGatewaySubDevice" /> --> | |
29 | 29 | </Tabs> |
30 | 30 | <Attribute v-if="activeKey === FunctionType.PROPERTIES" ref="AttrRef" /> |
31 | 31 | <Service | ... | ... |
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | <Tabs type="card" v-model:active-key="activeKey" @change="handleSwitchTsl"> |
12 | 12 | <Tabs.TabPane :key="FunctionType.PROPERTIES" tab="属性" /> |
13 | 13 | <Tabs.TabPane :key="FunctionType.SERVICE" tab="服务" /> |
14 | - <Tabs.TabPane :key="FunctionType.EVENTS" tab="事件" /> | |
14 | + <!-- <Tabs.TabPane :key="FunctionType.EVENTS" tab="事件" /> --> | |
15 | 15 | <template #tabBarExtraContent> |
16 | 16 | <Button @click="handlePremitter"> |
17 | 17 | <template #icon> | ... | ... |
... | ... | @@ -27,7 +27,7 @@ |
27 | 27 | const _value = (event.target as HTMLInputElement).checked; |
28 | 28 | emit('update:value', _value); |
29 | 29 | emit('change', _value); |
30 | - sendCommand(props.value?.slaveDeviceId || props.value?.deviceId, _value); | |
30 | + sendCommand(props.value!, _value); | |
31 | 31 | }; |
32 | 32 | </script> |
33 | 33 | ... | ... |
... | ... | @@ -32,8 +32,7 @@ |
32 | 32 | |
33 | 33 | const { sendCommand } = useSendCommand(); |
34 | 34 | const handleChange = (value: boolean) => { |
35 | - console.log(props.value); | |
36 | - sendCommand(props.value.slaveDeviceId! || props.value.deviceId!, value); | |
35 | + sendCommand(props.value, value); | |
37 | 36 | }; |
38 | 37 | |
39 | 38 | watchEffect(() => { | ... | ... |
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | const _value = (event.target as HTMLInputElement).checked; |
23 | 23 | emit('update:value', _value); |
24 | 24 | emit('change', _value); |
25 | - sendCommand(props.value?.slaveDeviceId || props.value?.deviceId, _value); | |
25 | + sendCommand(props.value!, _value); | |
26 | 26 | }; |
27 | 27 | |
28 | 28 | const getRadio = computed(() => { | ... | ... |
... | ... | @@ -13,6 +13,7 @@ export interface ControlComponentValue { |
13 | 13 | deviceId?: string; |
14 | 14 | fontColor?: string; |
15 | 15 | slaveDeviceId?: string; |
16 | + deviceProfileId?: string; | |
16 | 17 | } |
17 | 18 | |
18 | 19 | export const ControlComponentDefaultConfig: ControlComponentValue = { |
... | ... | @@ -31,6 +32,7 @@ export const transformControlConfig = ( |
31 | 32 | ...dataSourceRecord.componentInfo, |
32 | 33 | attribute: dataSourceRecord.attribute, |
33 | 34 | attributeRename: dataSourceRecord.attributeRename, |
35 | + deviceProfileId: dataSourceRecord.deviceProfileId, | |
34 | 36 | deviceId: dataSourceRecord.deviceId, |
35 | 37 | slaveDeviceId: dataSourceRecord.slaveDeviceId, |
36 | 38 | } as ControlComponentValue, | ... | ... |
1 | +import { ControlComponentValue } from './control.config'; | |
2 | +import { getDeviceProfile } from '/@/api/alarm/position'; | |
1 | 3 | import { sendCommandOneway } from '/@/api/dataBoard'; |
4 | +import { getModelServices } from '/@/api/device/modelOfMatter'; | |
2 | 5 | import { useMessage } from '/@/hooks/web/useMessage'; |
6 | +import { isString } from '/@/utils/is'; | |
3 | 7 | |
4 | 8 | const { createMessage } = useMessage(); |
5 | 9 | export function useSendCommand() { |
6 | - const sendCommand = async (deviceId: string, value: any) => { | |
10 | + const sendCommand = async (record: ControlComponentValue, value: any) => { | |
11 | + const { deviceId, deviceProfileId, attribute } = record; | |
7 | 12 | if (!deviceId) return; |
8 | 13 | try { |
14 | + const list = await getDeviceProfile(); | |
15 | + const deviceProfile = list.find((item) => item.id === deviceProfileId); | |
16 | + if (!deviceProfile) return; | |
17 | + let params: string | Recordable = { | |
18 | + [attribute!]: Number(value), | |
19 | + }; | |
20 | + if (deviceProfile.transportType === 'TCP') { | |
21 | + const serviceList = await getModelServices({ deviceProfileId: deviceProfileId! }); | |
22 | + const record = serviceList.find((item) => item.identifier === attribute); | |
23 | + const sendCommand = record?.functionJson.inputData?.at(0)?.serviceCommand || ''; | |
24 | + params = isString(sendCommand) ? sendCommand : JSON.stringify(sendCommand); | |
25 | + } | |
9 | 26 | await sendCommandOneway({ |
10 | 27 | deviceId, |
11 | 28 | value: { |
12 | - params: Number(value), | |
29 | + params: params, | |
13 | 30 | persistent: true, |
14 | 31 | additionalInfo: { |
15 | 32 | cmdType: 'API', | ... | ... |
... | ... | @@ -5,9 +5,9 @@ |
5 | 5 | SettingOutlined, |
6 | 6 | SwapOutlined, |
7 | 7 | } from '@ant-design/icons-vue'; |
8 | - import { Tooltip, Button } from 'ant-design-vue'; | |
8 | + import { Tooltip, Button, Alert } from 'ant-design-vue'; | |
9 | 9 | import { FormActionType, useForm } from '/@/components/Form'; |
10 | - import { basicSchema, DataSourceField } from '../config/basicConfiguration'; | |
10 | + import { basicSchema, DataSourceField, isMapComponent } from '../config/basicConfiguration'; | |
11 | 11 | import BasicForm from '/@/components/Form/src/BasicForm.vue'; |
12 | 12 | import { ref, shallowReactive, unref, nextTick, watch, computed, onMounted } from 'vue'; |
13 | 13 | import VisualOptionsModal from './VisualOptionsModal.vue'; |
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | import { useSortable } from '/@/hooks/web/useSortable'; |
23 | 23 | import { cloneDeep } from 'lodash-es'; |
24 | 24 | import { frontComponentMap } from '../../components/help'; |
25 | + import { isControlComponent } from '../config/basicConfiguration'; | |
25 | 26 | |
26 | 27 | type DataSourceFormEL = { [key: string]: Nullable<FormActionType> }; |
27 | 28 | |
... | ... | @@ -250,6 +251,14 @@ |
250 | 251 | inited = true; |
251 | 252 | } |
252 | 253 | |
254 | + const isControlCmp = computed(() => { | |
255 | + return isControlComponent(props.frontId as FrontComponent); | |
256 | + }); | |
257 | + | |
258 | + const isMapCmp = computed(() => { | |
259 | + return isMapComponent(props.frontId as FrontComponent); | |
260 | + }); | |
261 | + | |
253 | 262 | onMounted(() => handleSort()); |
254 | 263 | |
255 | 264 | defineExpose({ |
... | ... | @@ -264,7 +273,25 @@ |
264 | 273 | <div class="w-3/4"> |
265 | 274 | <BasicForm @register="basicRegister" class="w-full" /> |
266 | 275 | </div> |
276 | + <Alert type="info" show-icon v-if="isControlCmp"> | |
277 | + <template #description> | |
278 | + <div> | |
279 | + 控制组件数据源为TCP产品,则其控制命令下发为TCP产品 物模型=>服务,且不具备状态显示功能. | |
280 | + </div> | |
281 | + <div> | |
282 | + 控制组件数据源为非TCP产品,则其控制命令下发为产品 物模型=>属性,且具备状态显示功能. | |
283 | + </div> | |
284 | + </template> | |
285 | + </Alert> | |
286 | + <Alert type="info" show-icon v-if="isMapCmp"> | |
287 | + <template #description> | |
288 | + <div> | |
289 | + 地图组件,需绑定两个数据源,且数据源为同一设备。第一数据源为经度,第二数据源为维度,否则地图组件不能正常显示。 | |
290 | + </div> | |
291 | + </template> | |
292 | + </Alert> | |
267 | 293 | <h3 class="w-24 flex-shrink-0 text-right pr-2 my-4">选择数据源</h3> |
294 | + | |
268 | 295 | <section ref="formListEl"> |
269 | 296 | <div v-for="item in dataSource" :data-id="item.id" :key="item.id" class="flex bg-light-50"> |
270 | 297 | <div class="w-24 text-right flex right justify-end"> 选择设备 </div> | ... | ... |
... | ... | @@ -4,6 +4,8 @@ import { FormSchema } 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'; |
7 | +import { getDeviceProfile } from '/@/api/alarm/position'; | |
8 | +import { getModelServices } from '/@/api/device/modelOfMatter'; | |
7 | 9 | |
8 | 10 | export enum BasicConfigField { |
9 | 11 | NAME = 'name', |
... | ... | @@ -18,13 +20,22 @@ const getDeviceAttribute = async (params: DeviceAttributeParams) => { |
18 | 20 | return []; |
19 | 21 | }; |
20 | 22 | |
23 | +const getDeviceService = async (deviceProfileId: string) => { | |
24 | + try { | |
25 | + const data = await getModelServices({ deviceProfileId }); | |
26 | + if (data) | |
27 | + return data.map((item) => ({ ...item, label: item.functionName, value: item.identifier })); | |
28 | + } catch (error) {} | |
29 | + return []; | |
30 | +}; | |
31 | + | |
21 | 32 | export enum DataSourceField { |
22 | 33 | IS_GATEWAY_DEVICE = 'gatewayDevice', |
34 | + TRANSPORT_TYPE = 'transportType', | |
23 | 35 | ORIGINATION_ID = 'organizationId', |
24 | 36 | DEVICE_ID = 'deviceId', |
25 | 37 | SLAVE_DEVICE_ID = 'slaveDeviceId', |
26 | 38 | DEVICE_PROFILE_ID = 'deviceProfileId', |
27 | - SLAVE_DEVICE_PROFILE_ID = 'slaveDeviceProfileId', | |
28 | 39 | ATTRIBUTE = 'attribute', |
29 | 40 | ATTRIBUTE_RENAME = 'attributeRename', |
30 | 41 | DEVICE_NAME = 'deviceName', |
... | ... | @@ -33,16 +44,25 @@ export enum DataSourceField { |
33 | 44 | LATITUDE_ATTRIBUTE = 'latitudeAttribute', |
34 | 45 | } |
35 | 46 | |
36 | -const isControlComponent = (frontId: FrontComponent) => { | |
47 | +export const isControlComponent = (frontId: FrontComponent) => { | |
37 | 48 | const list = [ |
38 | 49 | FrontComponent.CONTROL_COMPONENT_SLIDING_SWITCH, |
39 | 50 | FrontComponent.CONTROL_COMPONENT_SWITCH_WITH_ICON, |
40 | 51 | FrontComponent.CONTROL_COMPONENT_TOGGLE_SWITCH, |
41 | 52 | ]; |
42 | - if (list.includes(frontId)) { | |
43 | - return true; | |
44 | - } | |
45 | - return false; | |
53 | + return list.includes(frontId); | |
54 | +}; | |
55 | + | |
56 | +export const isMapComponent = (frontId: FrontComponent) => { | |
57 | + const list = [ | |
58 | + FrontComponent.MAP_COMPONENT_TRACK_HISTORY, | |
59 | + FrontComponent.MAP_COMPONENT_TRACK_REAL, | |
60 | + ]; | |
61 | + return list.includes(frontId); | |
62 | +}; | |
63 | + | |
64 | +const isTcpProfile = (transportType: string) => { | |
65 | + return transportType === 'TCP'; | |
46 | 66 | }; |
47 | 67 | |
48 | 68 | export const basicSchema: FormSchema[] = [ |
... | ... | @@ -81,6 +101,45 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => { |
81 | 101 | show: false, |
82 | 102 | }, |
83 | 103 | { |
104 | + field: DataSourceField.TRANSPORT_TYPE, | |
105 | + component: 'Input', | |
106 | + label: '设备配置类型', | |
107 | + show: false, | |
108 | + }, | |
109 | + { | |
110 | + field: DataSourceField.DEVICE_PROFILE_ID, | |
111 | + component: 'ApiSelect', | |
112 | + label: '产品', | |
113 | + colProps: { span: 8 }, | |
114 | + rules: [{ required: true, message: '产品为必填项' }], | |
115 | + componentProps: ({ formActionType, formModel }) => { | |
116 | + const { setFieldsValue } = formActionType; | |
117 | + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; | |
118 | + return { | |
119 | + api: async () => { | |
120 | + const list = await getDeviceProfile(); | |
121 | + if (deviceProfileId) { | |
122 | + const record = list.find((item) => item.id === deviceProfileId); | |
123 | + setFieldsValue({ [DataSourceField.TRANSPORT_TYPE]: record?.transportType }); | |
124 | + } | |
125 | + return list; | |
126 | + }, | |
127 | + labelField: 'name', | |
128 | + valueField: 'id', | |
129 | + onChange: (_, option: Record<'transportType', string>) => { | |
130 | + console.log(option); | |
131 | + setFieldsValue({ | |
132 | + [DataSourceField.DEVICE_ID]: null, | |
133 | + [DataSourceField.ATTRIBUTE]: null, | |
134 | + [DataSourceField.SLAVE_DEVICE_ID]: null, | |
135 | + [DataSourceField.IS_GATEWAY_DEVICE]: false, | |
136 | + [DataSourceField.TRANSPORT_TYPE]: option.transportType, | |
137 | + }); | |
138 | + }, | |
139 | + }; | |
140 | + }, | |
141 | + }, | |
142 | + { | |
84 | 143 | field: DataSourceField.ORIGINATION_ID, |
85 | 144 | component: 'ApiTreeSelect', |
86 | 145 | label: '组织', |
... | ... | @@ -101,8 +160,6 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => { |
101 | 160 | [DataSourceField.ATTRIBUTE]: null, |
102 | 161 | [DataSourceField.SLAVE_DEVICE_ID]: null, |
103 | 162 | [DataSourceField.IS_GATEWAY_DEVICE]: false, |
104 | - [DataSourceField.DEVICE_PROFILE_ID]: null, | |
105 | - [DataSourceField.SLAVE_DEVICE_PROFILE_ID]: null, | |
106 | 163 | }); |
107 | 164 | }, |
108 | 165 | getPopupContainer: () => document.body, |
... | ... | @@ -124,16 +181,13 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => { |
124 | 181 | componentProps({ formModel, formActionType }) { |
125 | 182 | const { setFieldsValue } = formActionType; |
126 | 183 | const organizationId = formModel[DataSourceField.ORIGINATION_ID]; |
127 | - const deviceId = formModel[DataSourceField.DEVICE_ID]; | |
184 | + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; | |
185 | + | |
128 | 186 | return { |
129 | 187 | api: async () => { |
130 | 188 | if (organizationId) { |
131 | 189 | try { |
132 | - const data = await getAllDeviceByOrg(organizationId); | |
133 | - if (deviceId) { | |
134 | - const record = data.find((item) => item.id === deviceId); | |
135 | - setFieldsValue({ [DataSourceField.DEVICE_PROFILE_ID]: record?.deviceProfileId }); | |
136 | - } | |
190 | + const data = await getAllDeviceByOrg(organizationId, deviceProfileId); | |
137 | 191 | if (data) |
138 | 192 | return data.map((item) => ({ |
139 | 193 | ...item, |
... | ... | @@ -150,9 +204,7 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => { |
150 | 204 | setFieldsValue({ |
151 | 205 | [DataSourceField.ATTRIBUTE]: null, |
152 | 206 | [DataSourceField.IS_GATEWAY_DEVICE]: record?.deviceType === 'GATEWAY', |
153 | - [DataSourceField.DEVICE_PROFILE_ID]: record?.deviceProfileId, | |
154 | 207 | [DataSourceField.SLAVE_DEVICE_ID]: null, |
155 | - [DataSourceField.SLAVE_DEVICE_PROFILE_ID]: null, | |
156 | 208 | [DataSourceField.DEVICE_NAME]: record?.label, |
157 | 209 | }); |
158 | 210 | }, |
... | ... | @@ -162,19 +214,18 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => { |
162 | 214 | }, |
163 | 215 | }, |
164 | 216 | { |
165 | - field: DataSourceField.SLAVE_DEVICE_PROFILE_ID, | |
166 | - component: 'Input', | |
167 | - label: '', | |
168 | - show: false, | |
169 | - }, | |
170 | - { | |
171 | 217 | field: DataSourceField.SLAVE_DEVICE_ID, |
172 | 218 | label: '网关子设备', |
173 | 219 | component: 'ApiSelect', |
174 | 220 | colProps: { span: 8 }, |
175 | 221 | rules: [{ required: true, message: '网关子设备为必填项' }], |
222 | + show: false, | |
176 | 223 | ifShow({ model }) { |
177 | - return model[DataSourceField.IS_GATEWAY_DEVICE]; | |
224 | + const transportType = model[DataSourceField.TRANSPORT_TYPE]; | |
225 | + return ( | |
226 | + !(isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)) && | |
227 | + model[DataSourceField.IS_GATEWAY_DEVICE] | |
228 | + ); | |
178 | 229 | }, |
179 | 230 | dynamicRules({ model }) { |
180 | 231 | return [ |
... | ... | @@ -186,16 +237,12 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => { |
186 | 237 | const organizationId = formModel[DataSourceField.ORIGINATION_ID]; |
187 | 238 | const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE]; |
188 | 239 | const deviceId = formModel[DataSourceField.DEVICE_ID]; |
189 | - const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID]; | |
240 | + | |
190 | 241 | return { |
191 | 242 | api: async () => { |
192 | 243 | if (organizationId && isGatewayDevice) { |
193 | 244 | try { |
194 | 245 | const data = await getGatewaySlaveDevice({ organizationId, masterId: deviceId }); |
195 | - if (slaveDeviceId) { | |
196 | - const record = data.find((item) => item.id === slaveDeviceId); | |
197 | - setFieldsValue({ [DataSourceField.DEVICE_PROFILE_ID]: record?.deviceProfileId }); | |
198 | - } | |
199 | 246 | if (data) |
200 | 247 | return data.map((item) => ({ |
201 | 248 | ...item, |
... | ... | @@ -210,7 +257,6 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => { |
210 | 257 | onChange(_value, record: MasterDeviceList) { |
211 | 258 | setFieldsValue({ |
212 | 259 | [DataSourceField.ATTRIBUTE]: null, |
213 | - [DataSourceField.SLAVE_DEVICE_PROFILE_ID]: record.deviceProfileId, | |
214 | 260 | [DataSourceField.DEVICE_NAME]: record?.label, |
215 | 261 | }); |
216 | 262 | }, |
... | ... | @@ -226,33 +272,30 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => { |
226 | 272 | colProps: { span: 8 }, |
227 | 273 | rules: [{ required: true, message: '属性为必填项' }], |
228 | 274 | componentProps({ formModel }) { |
229 | - const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE]; | |
230 | - const deviceId = formModel[DataSourceField.DEVICE_ID]; | |
231 | 275 | const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; |
232 | - const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID]; | |
233 | - const slaveDeviceProfileId = formModel[DataSourceField.SLAVE_DEVICE_PROFILE_ID]; | |
276 | + const transportType = formModel[DataSourceField.TRANSPORT_TYPE]; | |
234 | 277 | |
235 | 278 | return { |
236 | 279 | api: async () => { |
237 | - if (deviceId) { | |
238 | - try { | |
239 | - if (isGatewayDevice && slaveDeviceId && slaveDeviceProfileId) { | |
240 | - return await getDeviceAttribute({ | |
241 | - deviceProfileId: slaveDeviceProfileId, | |
242 | - dataType: isControlComponent(frontId!) ? 'BOOL' : undefined, | |
243 | - }); | |
244 | - } | |
245 | - if (!isGatewayDevice && deviceProfileId) { | |
246 | - return await getDeviceAttribute({ | |
247 | - deviceProfileId, | |
248 | - dataType: isControlComponent(frontId!) ? 'BOOL' : undefined, | |
249 | - }); | |
250 | - } | |
251 | - } catch (error) {} | |
252 | - } | |
280 | + try { | |
281 | + if (isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)) { | |
282 | + return await getDeviceService(deviceProfileId); | |
283 | + } | |
284 | + | |
285 | + if (deviceProfileId) { | |
286 | + return await getDeviceAttribute({ | |
287 | + deviceProfileId, | |
288 | + dataType: isControlComponent(frontId!) ? 'BOOL' : undefined, | |
289 | + }); | |
290 | + } | |
291 | + } catch (error) {} | |
292 | + | |
253 | 293 | return []; |
254 | 294 | }, |
255 | - placeholder: '请选择属性', | |
295 | + placeholder: | |
296 | + isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType) | |
297 | + ? '请选择服务' | |
298 | + : '请选择属性', | |
256 | 299 | getPopupContainer: () => document.body, |
257 | 300 | }; |
258 | 301 | }, | ... | ... |