Showing
10 changed files
with
73 additions
and
62 deletions
... | ... | @@ -16,7 +16,7 @@ enum Api { |
16 | 16 | RPC_ONEWAY = '/rpc/oneway', |
17 | 17 | |
18 | 18 | GEN_MODBUS_COMMAND = '/js/modbus', |
19 | - GET_DEVICE = '/device/', // 获取设备详情 | |
19 | + GET_DEVICE_DETAIL = '/device/', // 获取设备详情 | |
20 | 20 | } |
21 | 21 | |
22 | 22 | export interface GenModbusCommandType { |
... | ... | @@ -125,7 +125,7 @@ export const getDeviceActiveTime = (entityId: string) => { |
125 | 125 | export const getDeviceInfo = (deviceId: string) => { |
126 | 126 | return defHttp.get( |
127 | 127 | { |
128 | - url: `${Api.GET_DEVICE}${deviceId}`, | |
128 | + url: `${Api.GET_DEVICE_DETAIL}${deviceId}`, | |
129 | 129 | }, |
130 | 130 | ) |
131 | 131 | } | ... | ... |
1 | -import type { ThingsModel } from '@/api/device/model' | |
1 | +import type { ThingsModelItemType } from '@/api/device/model' | |
2 | 2 | import type { ImageSelectorDataType } from '@/core/Library/components/ImageSelector' |
3 | 3 | import type { CommandWayEnum } from '@/enums/commandEnum' |
4 | 4 | import type { ActTypeEnum, AggregateTypeEnum, CommandDeliveryWayEnum, DeviceTypeEnum, EventActionTypeEnum, EventTypeEnum, SocketSubscriberEnum, TransportTypeEnum } from '@/enums/datasource' |
... | ... | @@ -79,11 +79,20 @@ export interface AlarmListOptionType { |
79 | 79 | |
80 | 80 | } |
81 | 81 | |
82 | +export interface DeviceInfoType { | |
83 | + code?: string | |
84 | + transportType?: string | |
85 | + deviceType?: string | |
86 | + deviceProfileId?: string | |
87 | + deviceName?: string | |
88 | + codeType?: string | |
89 | +} | |
90 | + | |
82 | 91 | export interface NodeDataDataSourceJsonType { |
83 | 92 | deviceId: string |
84 | 93 | deviceProfileId: string |
85 | 94 | attr: string |
86 | - attrInfo: ThingsModel | |
95 | + attrInfo: ThingsModelItemType | |
87 | 96 | |
88 | 97 | deviceType?: DeviceTypeEnum |
89 | 98 | transportType?: TransportTypeEnum |
... | ... | @@ -92,13 +101,7 @@ export interface NodeDataDataSourceJsonType { |
92 | 101 | chartOption?: ChartOptionType |
93 | 102 | videoOption?: VideoOptionType |
94 | 103 | alarmListOption?: AlarmListOptionType |
95 | - deviceInfo?: { | |
96 | - code?: string | |
97 | - transportType?: string | |
98 | - deviceType?: string | |
99 | - deviceProfileId?: string | |
100 | - label?: string | |
101 | - } | |
104 | + deviceInfo?: DeviceInfoType | |
102 | 105 | circularFlowMeterOption?: FlowMeterColorItemType[] // 圆形水球图数据暂定any |
103 | 106 | rectFlowMeterOption?: FlowMeterColorItemType[] // 方形水球图颜色配置数据暂定any |
104 | 107 | |
... | ... | @@ -126,7 +129,7 @@ export interface DoubleClickEventDataType { |
126 | 129 | serviceCommand?: Recordable |
127 | 130 | way?: CommandWayEnum |
128 | 131 | customCommand?: string |
129 | - deviceInfo?: any | |
132 | + deviceInfo?: DeviceInfoType | |
130 | 133 | commandWay?: CommandDeliveryWayEnum |
131 | 134 | callType?: string |
132 | 135 | operationPassword?: { |
... | ... | @@ -161,7 +164,7 @@ export interface BasicActDataType { |
161 | 164 | attr: string |
162 | 165 | enable?: boolean |
163 | 166 | deviceProfileId?: string | number |
164 | - attrInfo?: ThingsModel | |
167 | + attrInfo?: ThingsModelItemType | |
165 | 168 | } |
166 | 169 | |
167 | 170 | export interface FlashActDataType extends BasicActDataType { | ... | ... |
1 | 1 | <script lang="ts" setup> |
2 | 2 | import { computed, ref, unref, watch, watchEffect } from 'vue' |
3 | 3 | import { Select } from 'ant-design-vue' |
4 | -import { isFunction, isString } from '@wry-smile/utils-is' | |
4 | +import { isFunction } from '@wry-smile/utils-is' | |
5 | 5 | import { get } from 'lodash-es' |
6 | -import type { DefaultOptionType, SelectValue } from 'ant-design-vue/es/select' | |
6 | +import type { DefaultOptionType, SelectProps, SelectValue } from 'ant-design-vue/es/select' | |
7 | 7 | import { Icon } from '@iconify/vue' |
8 | 8 | import { useRuleFormItem } from '@/hooks/component/useFormItem' |
9 | 9 | |
... | ... | @@ -18,21 +18,20 @@ const props = withDefaults( |
18 | 18 | api?: ((arg?: any) => Promise<DefaultOptionType[]>) | null |
19 | 19 | params?: any |
20 | 20 | resultField?: string |
21 | - labelField?: string | string[] | |
22 | - valueField?: string | |
21 | + aliasField?: string | |
23 | 22 | immediate?: boolean |
24 | 23 | alwaysLoad?: boolean |
25 | 24 | options?: DefaultOptionType[] |
25 | + fieldNames?: SelectProps['fieldNames'] | |
26 | 26 | }>(), |
27 | 27 | { |
28 | 28 | api: null, |
29 | 29 | params: () => ({}), |
30 | 30 | resultFiled: '', |
31 | - labelField: 'label', | |
32 | - valueFiled: 'value', | |
33 | 31 | immediate: true, |
34 | 32 | alwaysLoad: false, |
35 | 33 | options: () => ([]), |
34 | + fieldNames: () => ({ label: 'label', value: 'value', options: 'options' }), | |
36 | 35 | }, |
37 | 36 | ) |
38 | 37 | |
... | ... | @@ -47,39 +46,29 @@ const emitData = ref<any[]>([]) |
47 | 46 | const [state] = useRuleFormItem(props, 'value', 'change', emitData) |
48 | 47 | |
49 | 48 | const getOptions = computed(() => { |
50 | - const { labelField: _labelField = 'label', valueField = 'value', numberToString } = props | |
49 | + const { numberToString, fieldNames } = props | |
50 | + const { value: valueField = 'value' } = fieldNames | |
51 | 51 | |
52 | 52 | const data = unref(optionsRef).reduce((prev, next: any) => { |
53 | 53 | if (next) { |
54 | 54 | const value = get(next, valueField) |
55 | - const { label } = getAliasLabelInfo(next, _labelField) | |
55 | + | |
56 | 56 | prev.push({ |
57 | - // ...omit(next, [labelField, valueField]), | |
58 | 57 | ...next, |
59 | - label, | |
60 | - value: numberToString ? `${value}` : value, | |
61 | - }) | |
58 | + [valueField]: numberToString ? `${value}` : value, | |
59 | + } as DefaultOptionType) | |
62 | 60 | } |
63 | 61 | return prev |
64 | 62 | }, [] as DefaultOptionType[]) |
63 | + | |
65 | 64 | return data.length > 0 ? data : props.options |
66 | 65 | }) |
67 | 66 | |
68 | -function getAliasLabelInfo(data: any, labelField: string | string[]) { | |
69 | - labelField = isString(labelField) ? [labelField] : labelField | |
70 | - | |
71 | - let value | |
72 | - let labelKey = labelField[0] | |
73 | - for (const label of labelField) { | |
74 | - value = get(data, label) | |
75 | - if (value) { | |
76 | - labelKey = label | |
77 | - break | |
78 | - } | |
79 | - } | |
80 | - | |
81 | - return { labelField: labelKey, label: value } | |
82 | -} | |
67 | +const getFieldNames = computed<SelectProps['fieldNames']>(() => { | |
68 | + const { fieldNames, aliasField } = props | |
69 | + const { label, value, options } = fieldNames | |
70 | + return { label: aliasField || label, value, options } | |
71 | +}) | |
83 | 72 | |
84 | 73 | watchEffect(() => { |
85 | 74 | props.immediate && !props.alwaysLoad && fetch() |
... | ... | @@ -149,7 +138,11 @@ function handleChange(value: SelectValue, ...args: any[]) { |
149 | 138 | |
150 | 139 | <template> |
151 | 140 | <Select |
152 | - v-bind="$attrs" v-model:value="state" :options="getOptions" @dropdown-visible-change="handleFetch" | |
141 | + v-bind="$attrs" | |
142 | + v-model:value="state" | |
143 | + :options="getOptions" | |
144 | + :field-names="getFieldNames" | |
145 | + @dropdown-visible-change="handleFetch" | |
153 | 146 | @change="handleChange" |
154 | 147 | > |
155 | 148 | <template v-for="item in (Object.keys($slots as Slots) as SlotName[])" #[item]="data"> | ... | ... |
... | ... | @@ -181,8 +181,7 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { |
181 | 181 | return { |
182 | 182 | api: getThingsModelServices, |
183 | 183 | params: deviceProfileId, |
184 | - labelField: 'functionName', | |
185 | - valueField: 'identifier', | |
184 | + fieldNames: { label: 'functionName', value: 'identifier' }, | |
186 | 185 | onSelect(value: string, options: ThingsModel) { |
187 | 186 | formModel[FormFieldsEnum.THINGS_MODEL] = value ? options : null |
188 | 187 | formModel.callType = options.callType | ... | ... |
... | ... | @@ -3,9 +3,10 @@ import { getDeviceAttributes, getListByDeviceProfileIds } from '@/api/device' |
3 | 3 | import type { DeviceItemType, ThingsModelItemType } from '@/api/device/model' |
4 | 4 | import type { FormSchema } from '@/components/Form' |
5 | 5 | import { ComponentEnum } from '@/components/Form/src/enum' |
6 | -import { ContentDataFieldsEnum, ContentDataFieldsNameEnum } from '@/enums/datasource' | |
6 | +import { ContentDataFieldsEnum, ContentDataFieldsNameEnum, DataTypeEnum } from '@/enums/datasource' | |
7 | 7 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' |
8 | 8 | import type { ProductAndDevice } from '@/api/content/model' |
9 | +import { ControlComponentEnum } from '@/core/Library/packages/Control' | |
9 | 10 | |
10 | 11 | const contentDataStore = useContentDataStoreWithOut() |
11 | 12 | export const formSchemas = (componentKey?: string): FormSchema[] => { |
... | ... | @@ -51,15 +52,15 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { |
51 | 52 | deviceProfileIds: (unref(contentDataStore.getProductAndDevice) || []).map((item: ProductAndDevice) => item?.profileId), |
52 | 53 | organizationId, |
53 | 54 | }, |
54 | - labelField: ['alias', 'name'], | |
55 | - valueField: 'tbDeviceId', | |
55 | + aliasField: 'alias', | |
56 | + fieldNames: { label: 'name', value: 'tbDeviceId' }, | |
56 | 57 | onSelect(value: string, option: DeviceItemType) { |
57 | 58 | formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value ? option.deviceProfileId : null |
58 | - formModel[ContentDataFieldsEnum.DEVICE_INFO] = value && option ? { code: option.code, transportType: option.transportType, deviceType: option.deviceType, deviceProfileId: option.deviceProfileId, label: option.alias || option.name } : null | |
59 | + formModel[ContentDataFieldsEnum.DEVICE_INFO] = value && option ? { code: option.code, transportType: option.transportType, deviceType: option.deviceType, deviceProfileId: option.deviceProfileId, deviceName: option.alias || option.name } : null | |
59 | 60 | formModel[ContentDataFieldsEnum.ATTR] = null |
60 | 61 | }, |
61 | - filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => | |
62 | - option.label.includes(inputValue), | |
62 | + filterOption: (inputValue: string, option: DeviceItemType) => | |
63 | + option.alias?.includes?.(inputValue) || option.name?.includes?.(inputValue), | |
63 | 64 | } |
64 | 65 | }, |
65 | 66 | }, |
... | ... | @@ -75,21 +76,20 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { |
75 | 76 | api: async (params: string) => { |
76 | 77 | if (!deviceProfileId) return [] |
77 | 78 | const options = await getDeviceAttributes(params) |
78 | - if (componentKey === 'Switch') { // 开关只返回bool | |
79 | + if (componentKey === ControlComponentEnum.SWITCH) { // 开关只返回bool | |
79 | 80 | return options.filter((item) => { |
80 | - return item.detail.dataType.type === 'BOOL' | |
81 | + return item.detail.dataType.type === DataTypeEnum.BOOL | |
81 | 82 | }) |
82 | 83 | } |
83 | 84 | return options |
84 | 85 | }, |
85 | 86 | params: deviceProfileId, |
86 | - labelField: 'name', | |
87 | - valueField: 'identifier', | |
87 | + fieldNames: { label: 'name', value: 'identifier' }, | |
88 | 88 | onSelect(value: string, option: ThingsModelItemType) { |
89 | 89 | formModel[ContentDataFieldsEnum.ATTR_INFO] = value && option ? toRaw(unref(option)) : null |
90 | 90 | }, |
91 | - filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => | |
92 | - option.label.includes(inputValue), | |
91 | + filterOption: (inputValue: string, option: ThingsModelItemType) => | |
92 | + option.name.includes(inputValue), | |
93 | 93 | } |
94 | 94 | }, |
95 | 95 | }, | ... | ... |
... | ... | @@ -121,14 +121,14 @@ export const formSchemas: FormSchema[] = [ |
121 | 121 | deviceProfileIds: unref(contentDataStore.getProductIds), |
122 | 122 | organizationId, |
123 | 123 | }, |
124 | - labelField: ['alias', 'name'], | |
125 | - valueField: 'id', | |
124 | + aliasField: 'alias', | |
125 | + fieldNames: { label: 'name', value: 'id' }, | |
126 | 126 | maxTagCount: 4, |
127 | 127 | onSelect(value: string, option: DeviceItemType) { |
128 | 128 | formModel[AlarmListFieldsEnum.DEVICE_PROFILE_ID] = value ? option.deviceProfileId : null |
129 | 129 | }, |
130 | - filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => | |
131 | - option.label.includes(inputValue), | |
130 | + filterOption: (inputValue: string, option: DeviceItemType) => | |
131 | + option.alias?.includes?.(inputValue) || option.name?.includes?.(inputValue), | |
132 | 132 | } |
133 | 133 | }, |
134 | 134 | }, | ... | ... |
1 | 1 | const data = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] |
2 | 2 | const seriesList = [ |
3 | - | |
4 | 3 | { value: 120, name: '123', itemStyle: { color: '#5470c6' } }, |
5 | 4 | { value: 150, name: '456', itemStyle: { color: '#5470c6' } }, |
6 | 5 | { value: 40, name: '789', itemStyle: { color: '#5470c6' } }, | ... | ... |
... | ... | @@ -10,6 +10,7 @@ import type { SubscriptionData } from '@/core/websocket/type/message' |
10 | 10 | import { SocketSubscriberEnum } from '@/enums/datasource' |
11 | 11 | import { formatToDateTime } from '@/utils/dateUtil' |
12 | 12 | import { useLatestMessageValue } from '@/core/Library/hook/useLatestMessageValue' |
13 | +import type { CommandSource } from '@/core/websocket/processor' | |
13 | 14 | |
14 | 15 | const props = defineProps<{ |
15 | 16 | config: CreateComponentType |
... | ... | @@ -49,7 +50,10 @@ function sliceData(data: any[], maxLength = 20) { |
49 | 50 | return data |
50 | 51 | } |
51 | 52 | |
52 | -const handlerTimeSeriesData = (message: SubscriptionData, attr: string) => { | |
53 | +const handlerTimeSeriesData = (commandSource: CommandSource, message: SubscriptionData, attr: string) => { | |
54 | + const { data } = commandSource | |
55 | + const { attrInfo, deviceInfo } = data as NodeDataDataSourceJsonType | |
56 | + const { deviceName } = deviceInfo || {} | |
53 | 57 | const { ts, latestValue } = useLatestMessageValue(message, attr) |
54 | 58 | const option = unref(chartInstance)?.getOption() as EChartsOption |
55 | 59 | const xAxisData = ((option.xAxis as XAXisComponentOption[])?.[0] as { data: string[] }).data |
... | ... | @@ -57,6 +61,9 @@ const handlerTimeSeriesData = (message: SubscriptionData, attr: string) => { |
57 | 61 | xAxisData.push(formatToDateTime(ts)) |
58 | 62 | seriesData.push(latestValue) |
59 | 63 | unref(chartInstance)?.setOption({ |
64 | + title: { | |
65 | + text: `${deviceName}-${attrInfo.name}`, | |
66 | + }, | |
60 | 67 | xAxis: { data: sliceData(xAxisData) }, |
61 | 68 | series: { data: sliceData(seriesData) }, |
62 | 69 | } as EChartsOption) |
... | ... | @@ -69,7 +76,7 @@ const { onMessage } = useOnMessage({ |
69 | 76 | const { queryType } = chartOption || {} |
70 | 77 | |
71 | 78 | if (queryType === SocketSubscriberEnum.TS_SUB_CMDS) |
72 | - handlerTimeSeriesData(message.data, attr) | |
79 | + handlerTimeSeriesData(commandSource, message.data, attr) | |
73 | 80 | else if (queryType === SocketSubscriberEnum.HISTORY_CMDS) |
74 | 81 | handleHistoryData(message.data, attr) |
75 | 82 | }, | ... | ... |