Showing
9 changed files
with
157 additions
and
69 deletions
1 | <script lang="ts"> | 1 | <script lang="ts"> |
2 | export default { | 2 | export default { |
3 | + components: { Spin }, | ||
3 | inheritAttrs: false, | 4 | inheritAttrs: false, |
4 | }; | 5 | }; |
5 | </script> | 6 | </script> |
6 | <script lang="ts" setup> | 7 | <script lang="ts" setup> |
8 | + import { Spin } from 'ant-design-vue'; | ||
7 | import { RadioRecord } from '../../detail/config/util'; | 9 | import { RadioRecord } from '../../detail/config/util'; |
8 | import { ControlComponentDefaultConfig, ControlComponentValue } from './control.config'; | 10 | import { ControlComponentDefaultConfig, ControlComponentValue } from './control.config'; |
9 | import { useSendCommand } from './useSendCommand'; | 11 | import { useSendCommand } from './useSendCommand'; |
12 | + import { ref } from 'vue'; | ||
10 | 13 | ||
11 | interface VisualComponentProps<Layout = Recordable, Value = ControlComponentValue> { | 14 | interface VisualComponentProps<Layout = Recordable, Value = ControlComponentValue> { |
12 | value?: Value; | 15 | value?: Value; |
@@ -23,33 +26,45 @@ | @@ -23,33 +26,45 @@ | ||
23 | const emit = defineEmits(['update:value', 'change']); | 26 | const emit = defineEmits(['update:value', 'change']); |
24 | 27 | ||
25 | const { sendCommand } = useSendCommand(); | 28 | const { sendCommand } = useSendCommand(); |
26 | - const handleChange = (event: Event) => { | 29 | + |
30 | + const loading = ref(false); | ||
31 | + const handleChange = async (event: Event) => { | ||
27 | const _value = (event.target as HTMLInputElement).checked; | 32 | const _value = (event.target as HTMLInputElement).checked; |
33 | + if (props.value) { | ||
34 | + loading.value = true; | ||
35 | + const flag = await sendCommand(props.value, _value); | ||
36 | + loading.value = false; | ||
37 | + if (!flag) { | ||
38 | + (event.target as HTMLInputElement).checked = !_value; | ||
39 | + return; | ||
40 | + } | ||
41 | + } | ||
28 | emit('update:value', _value); | 42 | emit('update:value', _value); |
29 | emit('change', _value); | 43 | emit('change', _value); |
30 | - sendCommand(props.value!, _value); | ||
31 | }; | 44 | }; |
32 | </script> | 45 | </script> |
33 | 46 | ||
34 | <template> | 47 | <template> |
35 | <div class="flex flex-col justify-center"> | 48 | <div class="flex flex-col justify-center"> |
36 | - <label class="sliding-switch"> | ||
37 | - <input | ||
38 | - :value="!!Number(props.value?.value)" | ||
39 | - type="checkbox" | ||
40 | - :checked="!!Number(props.value?.value)" | ||
41 | - @change="handleChange" | ||
42 | - /> | ||
43 | - <span class="slider"></span> | ||
44 | - <span class="on">ON</span> | ||
45 | - <span class="off">OFF</span> | ||
46 | - </label> | ||
47 | - <div | ||
48 | - class="text-center mt-2 text-gray-700" | ||
49 | - :style="{ color: props?.value?.fontColor || ControlComponentDefaultConfig.fontColor }" | ||
50 | - > | ||
51 | - {{ props.value?.attributeRename || props.value?.attribute }}</div | ||
52 | - > | 49 | + <Spin :spinning="loading"> |
50 | + <label class="sliding-switch"> | ||
51 | + <input | ||
52 | + :value="!!Number(props.value?.value)" | ||
53 | + type="checkbox" | ||
54 | + :checked="!!Number(props.value?.value)" | ||
55 | + @change="handleChange" | ||
56 | + /> | ||
57 | + <span class="slider"></span> | ||
58 | + <span class="on">ON</span> | ||
59 | + <span class="off">OFF</span> | ||
60 | + </label> | ||
61 | + <div | ||
62 | + class="text-center mt-2 text-gray-700" | ||
63 | + :style="{ color: props?.value?.fontColor || ControlComponentDefaultConfig.fontColor }" | ||
64 | + > | ||
65 | + {{ props.value?.attributeRename || props.value?.attribute }}</div | ||
66 | + > | ||
67 | + </Spin> | ||
53 | </div> | 68 | </div> |
54 | </template> | 69 | </template> |
55 | 70 |
@@ -31,8 +31,14 @@ | @@ -31,8 +31,14 @@ | ||
31 | const checked = ref(!!Number(props.value.value)); | 31 | const checked = ref(!!Number(props.value.value)); |
32 | 32 | ||
33 | const { sendCommand } = useSendCommand(); | 33 | const { sendCommand } = useSendCommand(); |
34 | - const handleChange = (value: boolean) => { | ||
35 | - sendCommand(props.value, value); | 34 | + const loading = ref(false); |
35 | + const handleChange = async (value: boolean) => { | ||
36 | + loading.value = true; | ||
37 | + const flag = await sendCommand(props.value, value); | ||
38 | + loading.value = false; | ||
39 | + if (!flag) { | ||
40 | + checked.value = !value; | ||
41 | + } | ||
36 | }; | 42 | }; |
37 | 43 | ||
38 | watchEffect(() => { | 44 | watchEffect(() => { |
@@ -59,6 +65,6 @@ | @@ -59,6 +65,6 @@ | ||
59 | {{ props.value.attributeRename || props.value.attribute }} | 65 | {{ props.value.attributeRename || props.value.attribute }} |
60 | </span> | 66 | </span> |
61 | </div> | 67 | </div> |
62 | - <Switch v-model:checked="checked" @change="handleChange" /> | 68 | + <Switch v-model:checked="checked" :loading="loading" @change="handleChange" /> |
63 | </div> | 69 | </div> |
64 | </template> | 70 | </template> |
1 | <script lang="ts"> | 1 | <script lang="ts"> |
2 | export default { | 2 | export default { |
3 | + components: { Spin }, | ||
3 | inheritAttrs: false, | 4 | inheritAttrs: false, |
4 | }; | 5 | }; |
5 | </script> | 6 | </script> |
@@ -8,6 +9,8 @@ | @@ -8,6 +9,8 @@ | ||
8 | import { DEFAULT_RADIO_RECORD, fontSize, RadioRecord } from '../../detail/config/util'; | 9 | import { DEFAULT_RADIO_RECORD, fontSize, RadioRecord } from '../../detail/config/util'; |
9 | import { ControlComponentDefaultConfig, ControlComponentValue } from './control.config'; | 10 | import { ControlComponentDefaultConfig, ControlComponentValue } from './control.config'; |
10 | import { useSendCommand } from './useSendCommand'; | 11 | import { useSendCommand } from './useSendCommand'; |
12 | + import { ref } from 'vue'; | ||
13 | + import { Spin } from 'ant-design-vue'; | ||
11 | 14 | ||
12 | const props = defineProps<{ | 15 | const props = defineProps<{ |
13 | value?: ControlComponentValue; | 16 | value?: ControlComponentValue; |
@@ -18,11 +21,20 @@ | @@ -18,11 +21,20 @@ | ||
18 | const emit = defineEmits(['update:value', 'change']); | 21 | const emit = defineEmits(['update:value', 'change']); |
19 | 22 | ||
20 | const { sendCommand } = useSendCommand(); | 23 | const { sendCommand } = useSendCommand(); |
21 | - const handleChange = (event: Event) => { | 24 | + const loading = ref(false); |
25 | + const handleChange = async (event: Event) => { | ||
22 | const _value = (event.target as HTMLInputElement).checked; | 26 | const _value = (event.target as HTMLInputElement).checked; |
27 | + if (props.value) { | ||
28 | + loading.value = true; | ||
29 | + const flag = await sendCommand(props.value, _value); | ||
30 | + loading.value = false; | ||
31 | + if (!flag) { | ||
32 | + (event.target as HTMLInputElement).checked = !_value; | ||
33 | + return; | ||
34 | + } | ||
35 | + } | ||
23 | emit('update:value', _value); | 36 | emit('update:value', _value); |
24 | emit('change', _value); | 37 | emit('change', _value); |
25 | - sendCommand(props.value!, _value); | ||
26 | }; | 38 | }; |
27 | 39 | ||
28 | const getRadio = computed(() => { | 40 | const getRadio = computed(() => { |
@@ -32,35 +44,37 @@ | @@ -32,35 +44,37 @@ | ||
32 | 44 | ||
33 | <template> | 45 | <template> |
34 | <div class="flex flex-col"> | 46 | <div class="flex flex-col"> |
35 | - <div | ||
36 | - class="toggle-switch" | ||
37 | - :style="{ | ||
38 | - width: fontSize({ radioRecord: getRadio, basic: 75, max: 75, min: 60 }), | ||
39 | - height: fontSize({ radioRecord: getRadio, basic: 97.5, max: 97.5, min: 80 }), | ||
40 | - }" | ||
41 | - > | ||
42 | - <label class="switch"> | ||
43 | - <input | ||
44 | - :value="!!Number(props.value?.value)" | ||
45 | - type="checkbox" | ||
46 | - :checked="!!Number(props.value?.value)" | ||
47 | - @change="handleChange" | ||
48 | - /> | ||
49 | - <div class="button"> | ||
50 | - <div class="light"></div> | ||
51 | - <div class="dots"></div> | ||
52 | - <div class="characters"></div> | ||
53 | - <div class="shine"></div> | ||
54 | - <div class="shadow"></div> | ||
55 | - </div> | ||
56 | - </label> | ||
57 | - </div> | ||
58 | - <div | ||
59 | - class="text-center mt-2 text-gray-700" | ||
60 | - :style="{ color: props?.value?.fontColor || ControlComponentDefaultConfig.fontColor }" | ||
61 | - > | ||
62 | - {{ props.value?.attributeRename || props.value?.attribute }}</div | ||
63 | - > | 47 | + <Spin :spinning="loading"> |
48 | + <div | ||
49 | + class="toggle-switch" | ||
50 | + :style="{ | ||
51 | + width: fontSize({ radioRecord: getRadio, basic: 75, max: 75, min: 60 }), | ||
52 | + height: fontSize({ radioRecord: getRadio, basic: 97.5, max: 97.5, min: 80 }), | ||
53 | + }" | ||
54 | + > | ||
55 | + <label class="switch"> | ||
56 | + <input | ||
57 | + :value="!!Number(props.value?.value)" | ||
58 | + type="checkbox" | ||
59 | + :checked="!!Number(props.value?.value)" | ||
60 | + @change="handleChange" | ||
61 | + /> | ||
62 | + <div class="button"> | ||
63 | + <div class="light"></div> | ||
64 | + <div class="dots"></div> | ||
65 | + <div class="characters"></div> | ||
66 | + <div class="shine"></div> | ||
67 | + <div class="shadow"></div> | ||
68 | + </div> | ||
69 | + </label> | ||
70 | + </div> | ||
71 | + <div | ||
72 | + class="text-center mt-2 text-gray-700" | ||
73 | + :style="{ color: props?.value?.fontColor || ControlComponentDefaultConfig.fontColor }" | ||
74 | + > | ||
75 | + {{ props.value?.attributeRename || props.value?.attribute }}</div | ||
76 | + > | ||
77 | + </Spin> | ||
64 | </div> | 78 | </div> |
65 | </template> | 79 | </template> |
66 | 80 |
@@ -5,33 +5,44 @@ import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | @@ -5,33 +5,44 @@ import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | ||
5 | import { getModelServices } from '/@/api/device/modelOfMatter'; | 5 | import { getModelServices } from '/@/api/device/modelOfMatter'; |
6 | import { useMessage } from '/@/hooks/web/useMessage'; | 6 | import { useMessage } from '/@/hooks/web/useMessage'; |
7 | import { isString } from '/@/utils/is'; | 7 | import { isString } from '/@/utils/is'; |
8 | +import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; | ||
8 | 9 | ||
9 | const { createMessage } = useMessage(); | 10 | const { createMessage } = useMessage(); |
10 | export function useSendCommand() { | 11 | export function useSendCommand() { |
12 | + const error = () => { | ||
13 | + createMessage.error('下发指令失败'); | ||
14 | + return false; | ||
15 | + }; | ||
11 | const sendCommand = async (record: ControlComponentValue, value: any) => { | 16 | const sendCommand = async (record: ControlComponentValue, value: any) => { |
12 | - if (!record) return; | 17 | + if (!record) return error(); |
13 | const { deviceProfileId, attribute, deviceType } = record; | 18 | const { deviceProfileId, attribute, deviceType } = record; |
14 | let { deviceId } = record; | 19 | let { deviceId } = record; |
15 | - if (!deviceId) return; | 20 | + if (!deviceId) return error(); |
16 | try { | 21 | try { |
17 | const list = await getDeviceProfile(); | 22 | const list = await getDeviceProfile(); |
18 | const deviceProfile = list.find((item) => item.id === deviceProfileId); | 23 | const deviceProfile = list.find((item) => item.id === deviceProfileId); |
19 | - if (!deviceProfile) return; | 24 | + if (!deviceProfile) return error(); |
25 | + | ||
20 | let params: string | Recordable = { | 26 | let params: string | Recordable = { |
21 | [attribute!]: Number(value), | 27 | [attribute!]: Number(value), |
22 | }; | 28 | }; |
23 | - if (deviceProfile.transportType === 'TCP') { | ||
24 | - const serviceList = await getModelServices({ deviceProfileId: deviceProfileId! }); | 29 | + |
30 | + // 如果是TCP设备从物模型中获取下发命令(TCP网关子设备无物模型服务与事件) | ||
31 | + if (deviceProfile!.transportType === TransportTypeEnum.TCP) { | ||
32 | + const serviceList = (await getModelServices({ deviceProfileId: deviceProfileId! })) || []; | ||
25 | const record = serviceList.find((item) => item.identifier === attribute); | 33 | const record = serviceList.find((item) => item.identifier === attribute); |
26 | const sendCommand = record?.functionJson.inputData?.at(0)?.serviceCommand || ''; | 34 | const sendCommand = record?.functionJson.inputData?.at(0)?.serviceCommand || ''; |
27 | params = isString(sendCommand) ? sendCommand : JSON.stringify(sendCommand); | 35 | params = isString(sendCommand) ? sendCommand : JSON.stringify(sendCommand); |
28 | } | 36 | } |
37 | + | ||
29 | if (deviceType === DeviceTypeEnum.SENSOR) { | 38 | if (deviceType === DeviceTypeEnum.SENSOR) { |
30 | deviceId = await getDeviceRelation({ | 39 | deviceId = await getDeviceRelation({ |
31 | deviceId, | 40 | deviceId, |
32 | isSlave: deviceType === DeviceTypeEnum.SENSOR, | 41 | isSlave: deviceType === DeviceTypeEnum.SENSOR, |
33 | }); | 42 | }); |
34 | } | 43 | } |
44 | + | ||
45 | + // 控制按钮下发命令为0 或 1 | ||
35 | await sendCommandOneway({ | 46 | await sendCommandOneway({ |
36 | deviceId, | 47 | deviceId, |
37 | value: { | 48 | value: { |
@@ -44,7 +55,11 @@ export function useSendCommand() { | @@ -44,7 +55,11 @@ export function useSendCommand() { | ||
44 | }, | 55 | }, |
45 | }); | 56 | }); |
46 | createMessage.success('命令下发成功'); | 57 | createMessage.success('命令下发成功'); |
47 | - } catch (error) {} | 58 | + } catch (msg) { |
59 | + return error(); | ||
60 | + } finally { | ||
61 | + return true; | ||
62 | + } | ||
48 | }; | 63 | }; |
49 | return { | 64 | return { |
50 | sendCommand, | 65 | sendCommand, |
@@ -57,6 +57,13 @@ | @@ -57,6 +57,13 @@ | ||
57 | } | 57 | } |
58 | }; | 58 | }; |
59 | 59 | ||
60 | + const resetFormFields = async () => { | ||
61 | + const hasExistEl = Object.keys(dataSourceEl).filter((key) => dataSourceEl[key]); | ||
62 | + for (const id of hasExistEl) { | ||
63 | + await dataSourceEl[id]?.resetFields(); | ||
64 | + } | ||
65 | + }; | ||
66 | + | ||
60 | const validate = async () => { | 67 | const validate = async () => { |
61 | await basicMethod.validate(); | 68 | await basicMethod.validate(); |
62 | await validateDataSourceField(); | 69 | await validateDataSourceField(); |
@@ -258,6 +265,16 @@ | @@ -258,6 +265,16 @@ | ||
258 | return isControlComponent(props.frontId as FrontComponent); | 265 | return isControlComponent(props.frontId as FrontComponent); |
259 | }); | 266 | }); |
260 | 267 | ||
268 | + watch( | ||
269 | + () => props.frontId, | ||
270 | + async (target, oldTarget) => { | ||
271 | + if (isControlComponent(oldTarget!)) return; | ||
272 | + if (isControlComponent(target!)) { | ||
273 | + await resetFormFields(); | ||
274 | + } | ||
275 | + } | ||
276 | + ); | ||
277 | + | ||
261 | onMounted(() => handleSort()); | 278 | onMounted(() => handleSort()); |
262 | 279 | ||
263 | defineExpose({ | 280 | defineExpose({ |
@@ -293,7 +310,7 @@ | @@ -293,7 +310,7 @@ | ||
293 | 310 | ||
294 | <section ref="formListEl"> | 311 | <section ref="formListEl"> |
295 | <div v-for="item in dataSource" :data-id="item.id" :key="item.id" class="flex bg-light-50"> | 312 | <div v-for="item in dataSource" :data-id="item.id" :key="item.id" class="flex bg-light-50"> |
296 | - <div class="w-24 text-right flex justify-end"> 选择设备 </div> | 313 | + <div class="w-24 text-right flex justify-end" style="flex: 0 0 96px"> 选择设备 </div> |
297 | <div class="pl-2 flex-auto"> | 314 | <div class="pl-2 flex-auto"> |
298 | <component | 315 | <component |
299 | :frontId="$props.frontId" | 316 | :frontId="$props.frontId" |
@@ -9,6 +9,8 @@ import { getModelServices } from '/@/api/device/modelOfMatter'; | @@ -9,6 +9,8 @@ import { getModelServices } from '/@/api/device/modelOfMatter'; | ||
9 | import { findDictItemByCode } from '/@/api/system/dict'; | 9 | import { findDictItemByCode } from '/@/api/system/dict'; |
10 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | 10 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
11 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; | 11 | import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; |
12 | +import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; | ||
13 | +import { nextTick } from 'vue'; | ||
12 | 14 | ||
13 | export enum BasicConfigField { | 15 | export enum BasicConfigField { |
14 | NAME = 'name', | 16 | NAME = 'name', |
@@ -66,7 +68,7 @@ export const isMapComponent = (frontId: FrontComponent) => { | @@ -66,7 +68,7 @@ export const isMapComponent = (frontId: FrontComponent) => { | ||
66 | }; | 68 | }; |
67 | 69 | ||
68 | const isTcpProfile = (transportType: string) => { | 70 | const isTcpProfile = (transportType: string) => { |
69 | - return transportType === 'TCP'; | 71 | + return transportType === TransportTypeEnum.TCP; |
70 | }; | 72 | }; |
71 | 73 | ||
72 | export const basicSchema: FormSchema[] = [ | 74 | export const basicSchema: FormSchema[] = [ |
@@ -117,6 +119,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For | @@ -117,6 +119,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For | ||
117 | component: 'ApiSelect', | 119 | component: 'ApiSelect', |
118 | label: '设备类型', | 120 | label: '设备类型', |
119 | colProps: { span: 8 }, | 121 | colProps: { span: 8 }, |
122 | + rules: [{ message: '请选择设备类型', required: true }], | ||
120 | // defaultValue: DeviceTypeEnum.SENSOR, | 123 | // defaultValue: DeviceTypeEnum.SENSOR, |
121 | componentProps: ({ formActionType }) => { | 124 | componentProps: ({ formActionType }) => { |
122 | const { setFieldsValue } = formActionType; | 125 | const { setFieldsValue } = formActionType; |
@@ -180,7 +183,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For | @@ -180,7 +183,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For | ||
180 | colProps: { span: 8 }, | 183 | colProps: { span: 8 }, |
181 | rules: [{ required: true, message: '组织为必填项' }], | 184 | rules: [{ required: true, message: '组织为必填项' }], |
182 | componentProps({ formActionType }) { | 185 | componentProps({ formActionType }) { |
183 | - const { setFieldsValue } = formActionType; | 186 | + const { setFieldsValue, getFieldsValue } = formActionType; |
184 | return { | 187 | return { |
185 | placeholder: '请选择组织', | 188 | placeholder: '请选择组织', |
186 | api: async () => { | 189 | api: async () => { |
@@ -192,6 +195,9 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For | @@ -192,6 +195,9 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For | ||
192 | setFieldsValue({ | 195 | setFieldsValue({ |
193 | [DataSourceField.DEVICE_ID]: null, | 196 | [DataSourceField.DEVICE_ID]: null, |
194 | }); | 197 | }); |
198 | + nextTick(() => { | ||
199 | + console.log('org change', getFieldsValue()); | ||
200 | + }); | ||
195 | }, | 201 | }, |
196 | getPopupContainer: () => document.body, | 202 | getPopupContainer: () => document.body, |
197 | }; | 203 | }; |
@@ -250,11 +256,24 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For | @@ -250,11 +256,24 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For | ||
250 | component: 'ApiSelect', | 256 | component: 'ApiSelect', |
251 | label: '属性', | 257 | label: '属性', |
252 | colProps: { span: 8 }, | 258 | colProps: { span: 8 }, |
253 | - rules: [{ required: true, message: '属性为必填项' }], | 259 | + dynamicRules: ({ model }) => { |
260 | + const transportType = model[DataSourceField.TRANSPORT_TYPE]; | ||
261 | + return [ | ||
262 | + { | ||
263 | + required: true, | ||
264 | + message: `${ | ||
265 | + isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType) | ||
266 | + ? '服务' | ||
267 | + : '属性' | ||
268 | + }为必填项`, | ||
269 | + }, | ||
270 | + ]; | ||
271 | + }, | ||
254 | componentProps({ formModel }) { | 272 | componentProps({ formModel }) { |
255 | const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; | 273 | const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; |
256 | const transportType = formModel[DataSourceField.TRANSPORT_TYPE]; | 274 | const transportType = formModel[DataSourceField.TRANSPORT_TYPE]; |
257 | - if (isEdit && ![deviceProfileId, transportType].every(Boolean)) return {}; | 275 | + if (isEdit && ![deviceProfileId, transportType].every(Boolean)) |
276 | + return { placeholder: '请选择属性', getPopupContainer: () => document.body }; | ||
258 | return { | 277 | return { |
259 | api: async () => { | 278 | api: async () => { |
260 | try { | 279 | try { |
@@ -47,7 +47,7 @@ | @@ -47,7 +47,7 @@ | ||
47 | import { BAI_DU_MAP_GL_LIB, BAI_DU_MAP_TRACK_ANIMATION } from '/@/utils/fnUtils'; | 47 | import { BAI_DU_MAP_GL_LIB, BAI_DU_MAP_TRACK_ANIMATION } from '/@/utils/fnUtils'; |
48 | 48 | ||
49 | const props = defineProps<{ | 49 | const props = defineProps<{ |
50 | - value: Recordable; | 50 | + value?: Recordable; |
51 | }>(); | 51 | }>(); |
52 | 52 | ||
53 | const ROUTE = useRoute(); | 53 | const ROUTE = useRoute(); |
@@ -126,7 +126,7 @@ export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) { | @@ -126,7 +126,7 @@ export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) { | ||
126 | const { subscriptionId, data = {} } = res; | 126 | const { subscriptionId, data = {} } = res; |
127 | if (isNullAndUnDef(subscriptionId)) return; | 127 | if (isNullAndUnDef(subscriptionId)) return; |
128 | const mappingRecord = cmdIdMapping.get(subscriptionId); | 128 | const mappingRecord = cmdIdMapping.get(subscriptionId); |
129 | - if (!mappingRecord) return; | 129 | + if (!mappingRecord || !data) return; |
130 | mappingRecord.forEach((item) => { | 130 | mappingRecord.forEach((item) => { |
131 | const { attribute, recordIndex, dataSourceIndex } = item; | 131 | const { attribute, recordIndex, dataSourceIndex } = item; |
132 | const [[timespan, value]] = data[attribute]; | 132 | const [[timespan, value]] = data[attribute]; |
@@ -249,17 +249,19 @@ | @@ -249,17 +249,19 @@ | ||
249 | </div> | 249 | </div> |
250 | </div> | 250 | </div> |
251 | <div class="flex justify-between mt-4 text-sm" style="color: #999"> | 251 | <div class="flex justify-between mt-4 text-sm" style="color: #999"> |
252 | - <div> | 252 | + <div class="flex min-w-20 mr-3"> |
253 | <span> | 253 | <span> |
254 | {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} | 254 | {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }} |
255 | </span> | 255 | </span> |
256 | <span v-if="item.viewType === ViewType.PUBLIC_VIEW"> | 256 | <span v-if="item.viewType === ViewType.PUBLIC_VIEW"> |
257 | <Tooltip title="点击复制分享链接"> | 257 | <Tooltip title="点击复制分享链接"> |
258 | - <ShareAltOutlined class="ml-2" @click.stop="handleCopyShareUrl(item)" /> | 258 | + <ShareAltOutlined class="ml-1" @click.stop="handleCopyShareUrl(item)" /> |
259 | </Tooltip> | 259 | </Tooltip> |
260 | </span> | 260 | </span> |
261 | </div> | 261 | </div> |
262 | - <div>{{ item.createTime }}</div> | 262 | + <Tooltip placement="topLeft" :title="item.createTime"> |
263 | + <div class="truncate">{{ item.createTime }}</div> | ||
264 | + </Tooltip> | ||
263 | </div> | 265 | </div> |
264 | </section> | 266 | </section> |
265 | </Card> | 267 | </Card> |