Showing
19 changed files
with
411 additions
and
143 deletions
| @@ -92,7 +92,8 @@ export interface NodeDataDataSourceJsonType { | @@ -92,7 +92,8 @@ export interface NodeDataDataSourceJsonType { | ||
| 92 | deviceId: string | 92 | deviceId: string |
| 93 | deviceProfileId: string | 93 | deviceProfileId: string |
| 94 | deviceProfileTemplateId?: string | 94 | deviceProfileTemplateId?: string |
| 95 | - attr: string | 95 | + attr: string | string[] |
| 96 | + deviceName?: string | ||
| 96 | 97 | ||
| 97 | enable: boolean | 98 | enable: boolean |
| 98 | chartOption?: ChartOptionType | 99 | chartOption?: ChartOptionType |
| @@ -40,11 +40,10 @@ const contentDataStore = useContentDataStoreWithOut() | @@ -40,11 +40,10 @@ const contentDataStore = useContentDataStoreWithOut() | ||
| 40 | export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { | 40 | export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { |
| 41 | const { getNodeData, getCellInfo, getDeviceInfo } = usePublicFormContext() | 41 | const { getNodeData, getCellInfo, getDeviceInfo } = usePublicFormContext() |
| 42 | const { dataSourceJson } = unref(getNodeData) || {} | 42 | const { dataSourceJson } = unref(getNodeData) || {} |
| 43 | - const { deviceProfileId, deviceId } = dataSourceJson || {} | 43 | + const { deviceProfileId } = dataSourceJson || {} |
| 44 | // transportType:判断是什么类型的设备 code:设备地址码 deviceType:设备类型 | 44 | // transportType:判断是什么类型的设备 code:设备地址码 deviceType:设备类型 |
| 45 | - let codeType: string | null = '' | ||
| 46 | - const { transportType, deviceType, codeType: deviceCodeType } = unref(getDeviceInfo) || {} | ||
| 47 | - codeType = deviceCodeType || (deviceId ? contentDataStore.diveceDetailMap?.[deviceId]?.codeType : null) | 45 | + const { transportType, deviceType, codeType } = unref(getDeviceInfo) || {} |
| 46 | + | ||
| 48 | const isTemplate = contentDataStore.isTemplate // 判断是否是模板 | 47 | const isTemplate = contentDataStore.isTemplate // 判断是否是模板 |
| 49 | 48 | ||
| 50 | return [ | 49 | return [ |
| @@ -63,6 +63,7 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { | @@ -63,6 +63,7 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { | ||
| 63 | onSelect(value: string, option: DeviceItemType) { | 63 | onSelect(value: string, option: DeviceItemType) { |
| 64 | formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value ? option.deviceProfileId : null | 64 | formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value ? option.deviceProfileId : null |
| 65 | formModel[ContentDataFieldsEnum.ATTR] = null | 65 | formModel[ContentDataFieldsEnum.ATTR] = null |
| 66 | + formModel[ContentDataFieldsEnum.DEVICE_NAME] = value ? option.alias || option.name : '' | ||
| 66 | }, | 67 | }, |
| 67 | filterOption: (inputValue: string, option: DeviceItemType) => { | 68 | filterOption: (inputValue: string, option: DeviceItemType) => { |
| 68 | return option.alias?.includes?.(inputValue) || option.name?.includes?.(inputValue) | 69 | return option.alias?.includes?.(inputValue) || option.name?.includes?.(inputValue) |
| @@ -71,6 +72,12 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { | @@ -71,6 +72,12 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { | ||
| 71 | }, | 72 | }, |
| 72 | }, | 73 | }, |
| 73 | { | 74 | { |
| 75 | + field: ContentDataFieldsEnum.DEVICE_NAME, | ||
| 76 | + label: ContentDataFieldsNameEnum.deviceName, | ||
| 77 | + component: ComponentEnum.INPUT, | ||
| 78 | + ifShow: false, | ||
| 79 | + }, | ||
| 80 | + { | ||
| 74 | field: ContentDataFieldsEnum.ATTR, | 81 | field: ContentDataFieldsEnum.ATTR, |
| 75 | label: ContentDataFieldsNameEnum.ATTR, | 82 | label: ContentDataFieldsNameEnum.ATTR, |
| 76 | component: ComponentEnum.API_SELECT, | 83 | component: ComponentEnum.API_SELECT, |
| @@ -6,3 +6,10 @@ export function useLatestMessageValue(message: SubscriptionData, attr: string) { | @@ -6,3 +6,10 @@ export function useLatestMessageValue(message: SubscriptionData, attr: string) { | ||
| 6 | const [ts, latestValue = null] = lateset || [] | 6 | const [ts, latestValue = null] = lateset || [] |
| 7 | return { ts, latestValue } | 7 | return { ts, latestValue } |
| 8 | } | 8 | } |
| 9 | + | ||
| 10 | +export function useLatestMultipleMessageValue(message: SubscriptionData, attr: string[], Fn: (attribute: string, value: any, timespan: number) => void) { | ||
| 11 | + attr.forEach((item) => { | ||
| 12 | + const [ts = null, latestValue = null] = message[item][0] || [] | ||
| 13 | + Fn(item, ts, latestValue) | ||
| 14 | + }) | ||
| 15 | +} |
| @@ -34,13 +34,11 @@ function initChartInstance() { | @@ -34,13 +34,11 @@ function initChartInstance() { | ||
| 34 | const { onMessage } = useOnMessage({ | 34 | const { onMessage } = useOnMessage({ |
| 35 | onReceiveDataSourceMessage(commandSource, message) { | 35 | onReceiveDataSourceMessage(commandSource, message) { |
| 36 | const { data } = commandSource | 36 | const { data } = commandSource |
| 37 | - const { deviceInfo, attrInfo } = data || {} | ||
| 38 | - const { deviceName } = deviceInfo || {} | ||
| 39 | const { attr } = data as NodeDataDataSourceJsonType | 37 | const { attr } = data as NodeDataDataSourceJsonType |
| 40 | const { latestValue } = useLatestMessageValue(message.data, attr) | 38 | const { latestValue } = useLatestMessageValue(message.data, attr) |
| 41 | unref(chartInstance)?.setOption({ | 39 | unref(chartInstance)?.setOption({ |
| 42 | title: { | 40 | title: { |
| 43 | - text: `${deviceName || ''}-${attrInfo.name || ''}`, | 41 | + // text: `${deviceName || ''}-${attrInfo.name || ''}`, |
| 44 | }, | 42 | }, |
| 45 | series: [{ | 43 | series: [{ |
| 46 | data: getSetValue(Number(latestValue)), | 44 | data: getSetValue(Number(latestValue)), |
| @@ -3,7 +3,8 @@ import { Button, Divider } from 'ant-design-vue' | @@ -3,7 +3,8 @@ import { Button, Divider } from 'ant-design-vue' | ||
| 3 | import { nextTick, onMounted, ref, unref } from 'vue' | 3 | import { nextTick, onMounted, ref, unref } from 'vue' |
| 4 | import { formSchemas } from '../config' | 4 | import { formSchemas } from '../config' |
| 5 | import { ChartComponentEnum } from '..' | 5 | import { ChartComponentEnum } from '..' |
| 6 | -import { DataSourceForm } from '@/core/Library/components/PublicForm/components/DataSourceForm' | 6 | +import { DataSourceForm } from '../component/index' |
| 7 | +// import { DataSourceForm } from '@/core/Library/components/PublicForm/components/DataSourceForm' | ||
| 7 | 8 | ||
| 8 | import { BasicForm, useForm } from '@/components/Form' | 9 | import { BasicForm, useForm } from '@/components/Form' |
| 9 | import { FormLayoutEnum } from '@/components/Form/src/enum' | 10 | import { FormLayoutEnum } from '@/components/Form/src/enum' |
| @@ -46,7 +47,7 @@ const handleSubmit = async () => { | @@ -46,7 +47,7 @@ const handleSubmit = async () => { | ||
| 46 | if (contentDataStore.getIsTemplate) | 47 | if (contentDataStore.getIsTemplate) |
| 47 | dataSourceJson = { ...value, deviceProfileId: value?.deviceProfileTemplateId, deviceId: null } | 48 | dataSourceJson = { ...value, deviceProfileId: value?.deviceProfileTemplateId, deviceId: null } |
| 48 | 49 | ||
| 49 | - await saveNodeAllData({ dataSourceJson: { ...dataSourceJson, chartOption: { ...values } } }) | 50 | + await saveNodeAllData({ dataSourceJson: { ...dataSourceJson, attr: typeof value.attr == 'string' ? [value.attr] : value.attr, chartOption: { ...values } } }) |
| 50 | savePageContent() | 51 | savePageContent() |
| 51 | createMessage.success('操作成功~') | 52 | createMessage.success('操作成功~') |
| 52 | } | 53 | } |
| @@ -57,9 +58,9 @@ const handleSubmit = async () => { | @@ -57,9 +58,9 @@ const handleSubmit = async () => { | ||
| 57 | 58 | ||
| 58 | const handleSetFormValues = async () => { | 59 | const handleSetFormValues = async () => { |
| 59 | const { dataSourceJson } = unref(getNodeData) || {} | 60 | const { dataSourceJson } = unref(getNodeData) || {} |
| 60 | - const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId } = dataSourceJson || {} | 61 | + const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId, deviceName } = dataSourceJson || {} |
| 61 | await nextTick() | 62 | await nextTick() |
| 62 | - unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId }) | 63 | + unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceName, deviceProfileId, deviceProfileTemplateId }) |
| 63 | setFieldsValue({ ...chartOption }) | 64 | setFieldsValue({ ...chartOption }) |
| 64 | } | 65 | } |
| 65 | 66 |
| 1 | import { isLightboxMode } from '@/utils/env' | 1 | import { isLightboxMode } from '@/utils/env' |
| 2 | 2 | ||
| 3 | -const data = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] | ||
| 4 | -const seriesList = [ | ||
| 5 | - { value: 120, name: '123', itemStyle: { color: '#5470c6' } }, | ||
| 6 | - { value: 150, name: '456', itemStyle: { color: '#5470c6' } }, | ||
| 7 | - { value: 40, name: '789', itemStyle: { color: '#5470c6' } }, | ||
| 8 | - { value: 139, name: '111', itemStyle: { color: '#5470c6' } }, | ||
| 9 | - { value: 130, name: '222', itemStyle: { color: '#5470c6' } }, | ||
| 10 | - { value: 125, name: '333', itemStyle: { color: '#5470c6' } }, | ||
| 11 | - { value: 110, name: '444', itemStyle: { color: '#5470c6' } }, | ||
| 12 | -] | ||
| 13 | export const defaultOption = { | 3 | export const defaultOption = { |
| 14 | - color: ['#3398DB'], | ||
| 15 | tooltip: { | 4 | tooltip: { |
| 16 | - // 提示框 | ||
| 17 | - trigger: 'item', | ||
| 18 | - confine: true, | ||
| 19 | - axisPointer: { | ||
| 20 | - type: 'shadow', | ||
| 21 | - }, | ||
| 22 | }, | 5 | }, |
| 23 | - xAxis: { | ||
| 24 | - type: 'category', | ||
| 25 | - data: isLightboxMode() ? [] : data, | ||
| 26 | - axisTick: { | ||
| 27 | - alignWithLabel: true, | 6 | + calculable: true, |
| 7 | + xAxis: [ | ||
| 8 | + { | ||
| 9 | + type: 'category', | ||
| 10 | + // prettier-ignore | ||
| 11 | + data: isLightboxMode() ? [] : ['Jan', 'Feb', 'Mar', 'Apr', 'May'], | ||
| 28 | }, | 12 | }, |
| 13 | + ], | ||
| 14 | + legend: { | ||
| 15 | + top: '8%', | ||
| 16 | + left: 'center', | ||
| 17 | + data: [''], | ||
| 29 | }, | 18 | }, |
| 19 | + | ||
| 30 | grid: { | 20 | grid: { |
| 31 | - top: '10%', | ||
| 32 | - left: '10%', | ||
| 33 | - bottom: '10%', | ||
| 34 | - }, | ||
| 35 | - yAxis: { | ||
| 36 | - type: 'value', | 21 | + top: '25%', |
| 22 | + left: '6%', | ||
| 23 | + right: '10%', | ||
| 24 | + bottom: '8%', | ||
| 25 | + containLabel: true, | ||
| 37 | }, | 26 | }, |
| 27 | + yAxis: [ | ||
| 28 | + { | ||
| 29 | + type: 'value', | ||
| 30 | + }, | ||
| 31 | + ], | ||
| 38 | series: [ | 32 | series: [ |
| 39 | { | 33 | { |
| 40 | - name: '', | 34 | + name: 'Rainfall', |
| 35 | + type: 'bar', | ||
| 36 | + data: [ | ||
| 37 | + 25.6, 76.7, 42.0, 27.0, 23.2, | ||
| 38 | + ], | ||
| 39 | + }, | ||
| 40 | + { | ||
| 41 | + name: 'Evaporation', | ||
| 41 | type: 'bar', | 42 | type: 'bar', |
| 42 | - barWidth: '60%', | ||
| 43 | - data: isLightboxMode () ? [] : seriesList, | 43 | + data: isLightboxMode() |
| 44 | + ? [] | ||
| 45 | + : [ | ||
| 46 | + 28.7, 32.6, 70.7, 29.0, 26.4, | ||
| 47 | + ], | ||
| 44 | }, | 48 | }, |
| 45 | ], | 49 | ], |
| 46 | } | 50 | } |
| 1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
| 2 | -import { computed, onMounted, onUnmounted, ref, unref } from 'vue' | 2 | +import { computed, onMounted, onUnmounted, ref, toRaw, unref } from 'vue' |
| 3 | import { init } from 'echarts' | 3 | import { init } from 'echarts' |
| 4 | import type { ECharts, EChartsOption } from 'echarts' | 4 | import type { ECharts, EChartsOption } from 'echarts' |
| 5 | import { defaultOption } from './index.config' | 5 | import { defaultOption } from './index.config' |
| @@ -10,6 +10,7 @@ import { SocketSubscriberEnum } from '@/enums/datasource' | @@ -10,6 +10,7 @@ import { SocketSubscriberEnum } from '@/enums/datasource' | ||
| 10 | import type { SubscriptionData } from '@/core/websocket/type/message' | 10 | import type { SubscriptionData } from '@/core/websocket/type/message' |
| 11 | import { formatToDateTime } from '@/utils/dateUtil' | 11 | import { formatToDateTime } from '@/utils/dateUtil' |
| 12 | import type { CommandSource } from '@/core/websocket/processor' | 12 | import type { CommandSource } from '@/core/websocket/processor' |
| 13 | +import { useProductsStore } from '@/store/modules/products' | ||
| 13 | 14 | ||
| 14 | const props = defineProps<{ | 15 | const props = defineProps<{ |
| 15 | config: CreateComponentType | 16 | config: CreateComponentType |
| @@ -21,40 +22,80 @@ const chartElRef = ref<Nullable<HTMLDivElement>>() | @@ -21,40 +22,80 @@ const chartElRef = ref<Nullable<HTMLDivElement>>() | ||
| 21 | 22 | ||
| 22 | const chartInstance = ref<Nullable<ECharts>>() | 23 | const chartInstance = ref<Nullable<ECharts>>() |
| 23 | 24 | ||
| 25 | +const seriesData = ref<any>([]) | ||
| 26 | +const XAxisData = ref<any>([]) | ||
| 27 | +const titleATTR = ref<string[] | any>([]) | ||
| 28 | + | ||
| 24 | function initChartInstance() { | 29 | function initChartInstance() { |
| 25 | chartInstance.value = init(unref(chartElRef)) | 30 | chartInstance.value = init(unref(chartElRef)) |
| 26 | chartInstance.value.setOption(defaultOption) | 31 | chartInstance.value.setOption(defaultOption) |
| 27 | } | 32 | } |
| 28 | 33 | ||
| 34 | +const productsStore = useProductsStore() | ||
| 35 | + | ||
| 29 | const handleHistoryData = (commandSource: CommandSource, message: SubscriptionData) => { | 36 | const handleHistoryData = (commandSource: CommandSource, message: SubscriptionData) => { |
| 30 | const { data } = commandSource | 37 | const { data } = commandSource |
| 31 | - const { attrInfo, deviceInfo, attr } = data as NodeDataDataSourceJsonType | ||
| 32 | - const { deviceName } = deviceInfo || {} | 38 | + const { attr, deviceName } = data as NodeDataDataSourceJsonType as any |
| 33 | 39 | ||
| 34 | - const historyData = message[attr] | ||
| 35 | - const xAxisData: string[] = [] | ||
| 36 | - const seriesData: number[] = [] | 40 | + attr.forEach((item: any) => { // 得到所有时间 |
| 41 | + XAxisData.value.push(...message[item].map((item1) => { | ||
| 42 | + const [ts] = item1 | ||
| 43 | + return ts | ||
| 44 | + })) | ||
| 45 | + }) | ||
| 46 | + XAxisData.value = Array.from(new Set(XAxisData.value)).sort((a: any, b: any) => a - b)// 去重获取到的时间 | ||
| 47 | + // 初始化有几个柱 | ||
| 48 | + seriesData.value.forEach((item: any) => { | ||
| 49 | + item.data = unref(XAxisData).map((time: any) => ({ name: time, value: '' })) | ||
| 50 | + }) | ||
| 37 | 51 | ||
| 38 | - for (const item of historyData) { | ||
| 39 | - const [ts, value] = item | ||
| 40 | - xAxisData.push(formatToDateTime(ts)) | ||
| 41 | - seriesData.push(value) | ||
| 42 | - } | 52 | + // 跟每个柱添加数据 |
| 53 | + seriesData.value.forEach((item: any) => { | ||
| 54 | + item.data.forEach((item1: any) => { | ||
| 55 | + message[item.attribute].forEach((messageItem) => { | ||
| 56 | + const [ts, value] = messageItem | ||
| 57 | + if (item1.name === ts) | ||
| 58 | + item1.value = value || '' | ||
| 59 | + // item1.name = formatToDateTime(item1.name) | ||
| 60 | + }) | ||
| 61 | + }) | ||
| 62 | + }) | ||
| 43 | 63 | ||
| 44 | unref(chartInstance)?.setOption({ | 64 | unref(chartInstance)?.setOption({ |
| 45 | title: { | 65 | title: { |
| 46 | - text: `${deviceName || ''}-${attrInfo.name || ''}`, | 66 | + text: `${deviceName || ''}`, |
| 67 | + }, | ||
| 68 | + xAxis: [ | ||
| 69 | + { | ||
| 70 | + type: 'category', | ||
| 71 | + data: toRaw(unref(XAxisData.value.map((item: string | number) => formatToDateTime(item)))), | ||
| 72 | + }, | ||
| 73 | + ], | ||
| 74 | + legend: { | ||
| 75 | + data: unref(titleATTR), | ||
| 47 | }, | 76 | }, |
| 48 | - xAxis: { data: xAxisData }, | ||
| 49 | - series: { data: seriesData }, | 77 | + series: toRaw(unref(seriesData).map((item: { type: string; name: string; data: any; attribute: string }) => { |
| 78 | + const { type, name, data } = item | ||
| 79 | + return { | ||
| 80 | + type, | ||
| 81 | + name, | ||
| 82 | + data: data.map((item: any) => item.value), | ||
| 83 | + } | ||
| 84 | + })), | ||
| 50 | } as EChartsOption) | 85 | } as EChartsOption) |
| 51 | } | 86 | } |
| 52 | 87 | ||
| 53 | const { onMessage } = useOnMessage({ | 88 | const { onMessage } = useOnMessage({ |
| 54 | onReceiveDataSourceMessage(commandSource, message) { | 89 | onReceiveDataSourceMessage(commandSource, message) { |
| 55 | const { data } = commandSource | 90 | const { data } = commandSource |
| 56 | - const { chartOption } = data as NodeDataDataSourceJsonType | 91 | + const { chartOption, attr, deviceProfileId } = data as NodeDataDataSourceJsonType |
| 57 | const { queryType } = chartOption || {} | 92 | const { queryType } = chartOption || {} |
| 93 | + if (!seriesData.value.length) { | ||
| 94 | + (attr as string[]).forEach((item: string) => { | ||
| 95 | + titleATTR.value.push(productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, item)?.functionName) | ||
| 96 | + seriesData.value.push({ attribute: item, data: [], type: 'bar', name: productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, item)?.functionName }) | ||
| 97 | + }) | ||
| 98 | + } | ||
| 58 | 99 | ||
| 59 | if (queryType === SocketSubscriberEnum.HISTORY_CMDS) | 100 | if (queryType === SocketSubscriberEnum.HISTORY_CMDS) |
| 60 | handleHistoryData(commandSource, message.data) | 101 | handleHistoryData(commandSource, message.data) |
| @@ -36,8 +36,6 @@ onMounted(() => { | @@ -36,8 +36,6 @@ onMounted(() => { | ||
| 36 | 36 | ||
| 37 | const onReceiveDataSourceMessage = (commandSource: CommandSource, message: SubscriptionUpdateMsg) => { | 37 | const onReceiveDataSourceMessage = (commandSource: CommandSource, message: SubscriptionUpdateMsg) => { |
| 38 | const { data } = commandSource | 38 | const { data } = commandSource |
| 39 | - const { deviceInfo, attrInfo } = data || {} | ||
| 40 | - const { deviceName } = deviceInfo || {} | ||
| 41 | const { attr } = data as NodeDataDataSourceJsonType | 39 | const { attr } = data as NodeDataDataSourceJsonType |
| 42 | const { latestValue } = useLatestMessageValue(message.data, attr) | 40 | const { latestValue } = useLatestMessageValue(message.data, attr) |
| 43 | unref(chartInstance)?.setOption({ | 41 | unref(chartInstance)?.setOption({ |
| @@ -46,7 +44,7 @@ const onReceiveDataSourceMessage = (commandSource: CommandSource, message: Subsc | @@ -46,7 +44,7 @@ const onReceiveDataSourceMessage = (commandSource: CommandSource, message: Subsc | ||
| 46 | 44 | ||
| 47 | }], | 45 | }], |
| 48 | title: { | 46 | title: { |
| 49 | - text: `${deviceName || ''}-${attrInfo.name || ''}`, | 47 | + // text: `${deviceName || ''}-${attrInfo.name || ''}`, |
| 50 | }, | 48 | }, |
| 51 | } as EChartsOption) | 49 | } as EChartsOption) |
| 52 | } | 50 | } |
| @@ -3,7 +3,9 @@ import { Button, Divider } from 'ant-design-vue' | @@ -3,7 +3,9 @@ import { Button, Divider } from 'ant-design-vue' | ||
| 3 | import { nextTick, onMounted, ref, unref } from 'vue' | 3 | import { nextTick, onMounted, ref, unref } from 'vue' |
| 4 | import { formSchemas } from '../config' | 4 | import { formSchemas } from '../config' |
| 5 | import { ChartComponentEnum } from '..' | 5 | import { ChartComponentEnum } from '..' |
| 6 | -import { DataSourceForm } from '@/core/Library/components/PublicForm/components/DataSourceForm' | 6 | + |
| 7 | +import { DataSourceForm } from '../component/index' | ||
| 8 | +// import { DataSourceForm } from '@/core/Library/components/PublicForm/components/DataSourceForm' | ||
| 7 | 9 | ||
| 8 | import { BasicForm, useForm } from '@/components/Form' | 10 | import { BasicForm, useForm } from '@/components/Form' |
| 9 | import { FormLayoutEnum } from '@/components/Form/src/enum' | 11 | import { FormLayoutEnum } from '@/components/Form/src/enum' |
| @@ -33,9 +35,9 @@ const dataSourceElRef = ref<Nullable<InstanceType<typeof DataSourceForm>>>() | @@ -33,9 +35,9 @@ const dataSourceElRef = ref<Nullable<InstanceType<typeof DataSourceForm>>>() | ||
| 33 | 35 | ||
| 34 | const handleSetFormValues = async () => { | 36 | const handleSetFormValues = async () => { |
| 35 | const { dataSourceJson } = unref(getNodeData) || {} | 37 | const { dataSourceJson } = unref(getNodeData) || {} |
| 36 | - const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId } = dataSourceJson || {} | 38 | + const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId, deviceName } = dataSourceJson || {} |
| 37 | await nextTick() | 39 | await nextTick() |
| 38 | - unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId }) | 40 | + unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId, deviceName }) |
| 39 | setFieldsValue({ ...chartOption }) | 41 | setFieldsValue({ ...chartOption }) |
| 40 | } | 42 | } |
| 41 | 43 | ||
| @@ -54,7 +56,7 @@ const handleSubmit = async () => { | @@ -54,7 +56,7 @@ const handleSubmit = async () => { | ||
| 54 | if (contentDataStore.getIsTemplate) | 56 | if (contentDataStore.getIsTemplate) |
| 55 | dataSourceJson = { ...value, deviceProfileId: value?.deviceProfileTemplateId, deviceId: null } | 57 | dataSourceJson = { ...value, deviceProfileId: value?.deviceProfileTemplateId, deviceId: null } |
| 56 | 58 | ||
| 57 | - saveNodeAllData({ dataSourceJson: { ...dataSourceJson, chartOption: { ...values } } }) | 59 | + saveNodeAllData({ dataSourceJson: { ...dataSourceJson, attr: typeof value.attr == 'string' ? [value.attr] : value.attr, chartOption: { ...values } } }) |
| 58 | createMessage.success('操作成功~') | 60 | createMessage.success('操作成功~') |
| 59 | savePageContent() | 61 | savePageContent() |
| 60 | } | 62 | } |
| @@ -3,31 +3,35 @@ import { isLightboxMode } from '@/utils/env' | @@ -3,31 +3,35 @@ import { isLightboxMode } from '@/utils/env' | ||
| 3 | 3 | ||
| 4 | export const getDefaultOption = (): EChartsOption => { | 4 | export const getDefaultOption = (): EChartsOption => { |
| 5 | return { | 5 | return { |
| 6 | - tooltip: { | ||
| 7 | - trigger: 'item', | ||
| 8 | - confine: true, | 6 | + legend: { |
| 7 | + top: '10%', | ||
| 8 | + left: 'center', | ||
| 9 | + data: [''], | ||
| 9 | }, | 10 | }, |
| 10 | grid: { | 11 | grid: { |
| 11 | - left: '3%', | ||
| 12 | - right: '4%', | ||
| 13 | - bottom: '3%', | 12 | + top: '30%', |
| 13 | + left: '6%', | ||
| 14 | + right: '10%', | ||
| 15 | + bottom: '8%', | ||
| 14 | containLabel: true, | 16 | containLabel: true, |
| 15 | }, | 17 | }, |
| 16 | - dataset: { | ||
| 17 | - source: isLightboxMode() | 18 | + xAxis: { |
| 19 | + type: 'category', | ||
| 20 | + }, | ||
| 21 | + yAxis: { | ||
| 22 | + type: 'value', | ||
| 23 | + boundaryGap: [0, '100%'], | ||
| 24 | + }, | ||
| 25 | + series: [{ | ||
| 26 | + type: 'line', | ||
| 27 | + name: '温度', | ||
| 28 | + data: isLightboxMode() | ||
| 18 | ? [] | 29 | ? [] |
| 19 | : [ | 30 | : [ |
| 20 | - ['product', '2015', '2016', '2017'], | ||
| 21 | - ['Matcha Latte', 43.3, 85.8, 93.7], | ||
| 22 | - ['Milk Tea', 83.1, 73.4, 55.1], | ||
| 23 | - ['Cheese Cocoa', 86.4, 65.2, 82.5], | ||
| 24 | - ['Walnut Brownie', 72.4, 53.9, 39.1], | ||
| 25 | - ], | ||
| 26 | - }, | ||
| 27 | - xAxis: { type: 'category' }, | ||
| 28 | - yAxis: {}, | ||
| 29 | - series: [ | ||
| 30 | - { type: 'line' }, | ||
| 31 | - ], | 31 | + ['Matcha Latte', 43.3], |
| 32 | + ['Milk Tea', 83.1], | ||
| 33 | + ['Cheese Cocoa', 86.4], | ||
| 34 | + ['Walnut Brownie', 72.4]], | ||
| 35 | + }], | ||
| 32 | } | 36 | } |
| 33 | } | 37 | } |
| 1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
| 2 | -import { computed, onMounted, onUnmounted, ref, unref } from 'vue' | ||
| 3 | -import type { DatasetComponentOption, ECharts, EChartsOption } from 'echarts' | 2 | +import { computed, onMounted, onUnmounted, ref, toRaw, unref } from 'vue' |
| 3 | +import type { ECharts, EChartsOption } from 'echarts' | ||
| 4 | import { init } from 'echarts' | 4 | import { init } from 'echarts' |
| 5 | import { getDefaultOption } from './index.config' | 5 | import { getDefaultOption } from './index.config' |
| 6 | import type { CreateComponentType, RenderComponentExposeType } from '@/core/Library/types' | 6 | import type { CreateComponentType, RenderComponentExposeType } from '@/core/Library/types' |
| @@ -9,8 +9,12 @@ import type { NodeDataDataSourceJsonType } from '@/api/node/model' | @@ -9,8 +9,12 @@ import type { NodeDataDataSourceJsonType } from '@/api/node/model' | ||
| 9 | import type { SubscriptionData } from '@/core/websocket/type/message' | 9 | import type { SubscriptionData } from '@/core/websocket/type/message' |
| 10 | import { SocketSubscriberEnum } from '@/enums/datasource' | 10 | import { SocketSubscriberEnum } from '@/enums/datasource' |
| 11 | import { formatToDateTime } from '@/utils/dateUtil' | 11 | import { formatToDateTime } from '@/utils/dateUtil' |
| 12 | -import { useLatestMessageValue } from '@/core/Library/hook/useLatestMessageValue' | ||
| 13 | import type { CommandSource } from '@/core/websocket/processor' | 12 | import type { CommandSource } from '@/core/websocket/processor' |
| 13 | +import { useLatestMultipleMessageValue } from '@/core/Library/hook/useLatestMessageValue' | ||
| 14 | +import { useProductsStore } from '@/store/modules/products' | ||
| 15 | +interface IList { | ||
| 16 | + time: string | number | ||
| 17 | +} | ||
| 14 | 18 | ||
| 15 | const props = defineProps<{ | 19 | const props = defineProps<{ |
| 16 | config: CreateComponentType | 20 | config: CreateComponentType |
| @@ -22,67 +26,126 @@ const chartElRef = ref<Nullable<HTMLDivElement>>() | @@ -22,67 +26,126 @@ const chartElRef = ref<Nullable<HTMLDivElement>>() | ||
| 22 | 26 | ||
| 23 | const chartInstance = ref<Nullable<ECharts>>() | 27 | const chartInstance = ref<Nullable<ECharts>>() |
| 24 | 28 | ||
| 29 | +const maxLength = ref<number>(20) | ||
| 30 | + | ||
| 31 | +const timeList = ref<number[] | string[] | any>([])// 存储XAxis的值 | ||
| 32 | +const seriesData = ref<any>([])// 存储series的值 | ||
| 33 | +const titleATTR = ref<string[] | any>([]) | ||
| 34 | + | ||
| 35 | +const productsStore = useProductsStore() | ||
| 36 | + | ||
| 25 | function initChartInstance() { | 37 | function initChartInstance() { |
| 26 | chartInstance.value = init(unref(chartElRef)) | 38 | chartInstance.value = init(unref(chartElRef)) |
| 27 | chartInstance.value.setOption(getDefaultOption()) | 39 | chartInstance.value.setOption(getDefaultOption()) |
| 28 | } | 40 | } |
| 29 | 41 | ||
| 30 | -const handleHistoryData = (message: SubscriptionData, attr: string) => { | ||
| 31 | - const data = message[attr] | ||
| 32 | - const xAxisData: string[] = [] | ||
| 33 | - const seriesData: number[] = [] | ||
| 34 | - | ||
| 35 | - for (const item of data) { | ||
| 36 | - const [ts, value] = item | ||
| 37 | - xAxisData.push(formatToDateTime(ts)) | ||
| 38 | - seriesData.push(value) | ||
| 39 | - } | 42 | +const handleHistoryData = (commandSource: CommandSource, message: SubscriptionData, attr: string[] | string) => { |
| 43 | + const { data } = commandSource || {} | ||
| 44 | + const { deviceName } = data as NodeDataDataSourceJsonType | ||
| 40 | 45 | ||
| 46 | + (attr as string[]).forEach((item) => { | ||
| 47 | + timeList.value.push(...message[item].map((item1) => { | ||
| 48 | + const [ts] = item1 | ||
| 49 | + return ts | ||
| 50 | + })) | ||
| 51 | + }) | ||
| 52 | + timeList.value = Array.from(new Set(timeList.value))?.sort((a: any, b: any) => a - b)// 去重获取到的时间 | ||
| 53 | + seriesData.value.forEach((item: any) => { | ||
| 54 | + item.data = unref(timeList).map((time: any) => ({ name: time, value: null })) | ||
| 55 | + }) | ||
| 56 | + seriesData.value.forEach((item: any) => { | ||
| 57 | + item.data.forEach((item1: any) => { | ||
| 58 | + message[item.attribute].forEach((messageItem) => { | ||
| 59 | + const [ts, value] = messageItem | ||
| 60 | + if (item1.name === ts) { | ||
| 61 | + item1.value = value || undefined | ||
| 62 | + item1.name = formatToDateTime(item1.name) | ||
| 63 | + } | ||
| 64 | + }) | ||
| 65 | + }) | ||
| 66 | + }) | ||
| 41 | unref(chartInstance)?.setOption({ | 67 | unref(chartInstance)?.setOption({ |
| 42 | - xAxis: { data: xAxisData }, | ||
| 43 | - series: { data: seriesData }, | 68 | + title: { |
| 69 | + text: `${deviceName || ''}`, | ||
| 70 | + }, | ||
| 71 | + xAxis: { | ||
| 72 | + data: toRaw(unref(timeList.value.map((item: string | number) => formatToDateTime(item)))), | ||
| 73 | + }, | ||
| 74 | + series: toRaw( | ||
| 75 | + unref(seriesData).map((item: { type: string; name: string; data: any }) => { | ||
| 76 | + const { type, name, data } = item | ||
| 77 | + return { | ||
| 78 | + type, | ||
| 79 | + name, | ||
| 80 | + data, | ||
| 81 | + } | ||
| 82 | + }), | ||
| 83 | + ), | ||
| 44 | } as EChartsOption) | 84 | } as EChartsOption) |
| 45 | } | 85 | } |
| 46 | 86 | ||
| 47 | -function sliceData(data: any[], maxLength = 20) { | ||
| 48 | - if (data.length > maxLength) | ||
| 49 | - return data.slice(1) | ||
| 50 | - return data | ||
| 51 | -} | 87 | +// const contentDataStore = useContentDataStoreWithOut() |
| 52 | 88 | ||
| 53 | -const handlerTimeSeriesData = (commandSource: CommandSource, message: SubscriptionData, attr: string) => { | 89 | +const handlerTimeSeriesData = (commandSource: CommandSource, message: SubscriptionData, attr: string[] | string) => { |
| 54 | const { data } = commandSource | 90 | const { data } = commandSource |
| 55 | - const { attrInfo, deviceInfo } = data as NodeDataDataSourceJsonType | ||
| 56 | - const { deviceName } = deviceInfo || {} | ||
| 57 | - const { ts, latestValue } = useLatestMessageValue(message, attr) | ||
| 58 | - const option = unref(chartInstance)?.getOption() as EChartsOption | ||
| 59 | - const oldDataset = (option.dataset as DatasetComponentOption[])?.[0].source as Recordable[] | ||
| 60 | - oldDataset.push({ | ||
| 61 | - ts: formatToDateTime(ts), | ||
| 62 | - [attr]: latestValue, | 91 | + const { deviceName } = data as NodeDataDataSourceJsonType |
| 92 | + const list: IList | any = {}// 记录时间 | ||
| 93 | + useLatestMultipleMessageValue(message, attr as any, (attribute, timespan, value) => { | ||
| 94 | + list.time = timespan || list.time | ||
| 95 | + seriesData.value.forEach((item: any) => { | ||
| 96 | + if (item.attribute === attribute) { | ||
| 97 | + item.data.push({ | ||
| 98 | + name: formatToDateTime(list.time), | ||
| 99 | + value: value || undefined, | ||
| 100 | + }) | ||
| 101 | + } | ||
| 102 | + if (item.data.length > unref(maxLength)) | ||
| 103 | + item.data.shift() | ||
| 104 | + }) | ||
| 63 | }) | 105 | }) |
| 106 | + list.time && timeList.value.push(formatToDateTime(list.time)) | ||
| 107 | + if (unref(timeList).length > unref(maxLength)) | ||
| 108 | + timeList.value.shift() | ||
| 64 | 109 | ||
| 65 | unref(chartInstance)?.setOption({ | 110 | unref(chartInstance)?.setOption({ |
| 66 | title: { | 111 | title: { |
| 67 | - text: `${deviceName || ''}-${attrInfo.name || ''}`, | 112 | + text: `${deviceName || ''}`, |
| 68 | }, | 113 | }, |
| 69 | - dataset: { | ||
| 70 | - dimensions: ['ts', attr], | ||
| 71 | - source: sliceData(oldDataset), | 114 | + xAxis: { |
| 115 | + data: toRaw(unref(timeList)), | ||
| 72 | }, | 116 | }, |
| 117 | + legend: { | ||
| 118 | + data: unref(titleATTR), | ||
| 119 | + } as any, | ||
| 120 | + series: toRaw( | ||
| 121 | + unref(seriesData).map((item: { type: string; name: string; data: any }) => { | ||
| 122 | + const { type, name, data } = item | ||
| 123 | + return { | ||
| 124 | + type, | ||
| 125 | + name, | ||
| 126 | + data, | ||
| 127 | + } | ||
| 128 | + }), | ||
| 129 | + ), | ||
| 73 | } as EChartsOption) | 130 | } as EChartsOption) |
| 74 | } | 131 | } |
| 75 | 132 | ||
| 76 | const { onMessage } = useOnMessage({ | 133 | const { onMessage } = useOnMessage({ |
| 77 | onReceiveDataSourceMessage(commandSource, message) { | 134 | onReceiveDataSourceMessage(commandSource, message) { |
| 78 | const { data } = commandSource | 135 | const { data } = commandSource |
| 79 | - const { chartOption, attr } = data as NodeDataDataSourceJsonType | 136 | + const { chartOption, attr, deviceProfileId } = data as NodeDataDataSourceJsonType |
| 80 | const { queryType } = chartOption || {} | 137 | const { queryType } = chartOption || {} |
| 138 | + if (!seriesData.value.length) { | ||
| 139 | + (attr as string[]).forEach((item: string) => { | ||
| 140 | + titleATTR.value.push(productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, item)?.functionName) | ||
| 141 | + seriesData.value.push({ attribute: item, data: [], type: 'line', name: productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, item)?.functionName }) | ||
| 142 | + }) | ||
| 143 | + } | ||
| 81 | 144 | ||
| 82 | if (queryType === SocketSubscriberEnum.TS_SUB_CMDS) | 145 | if (queryType === SocketSubscriberEnum.TS_SUB_CMDS) |
| 83 | handlerTimeSeriesData(commandSource, message.data, attr) | 146 | handlerTimeSeriesData(commandSource, message.data, attr) |
| 84 | else if (queryType === SocketSubscriberEnum.HISTORY_CMDS) | 147 | else if (queryType === SocketSubscriberEnum.HISTORY_CMDS) |
| 85 | - handleHistoryData(message.data, attr) | 148 | + handleHistoryData(commandSource, message.data, attr) |
| 86 | }, | 149 | }, |
| 87 | }) | 150 | }) |
| 88 | 151 |
| @@ -34,13 +34,11 @@ function initChartInstance() { | @@ -34,13 +34,11 @@ function initChartInstance() { | ||
| 34 | const { onMessage } = useOnMessage({ | 34 | const { onMessage } = useOnMessage({ |
| 35 | onReceiveDataSourceMessage(commandSource, message) { | 35 | onReceiveDataSourceMessage(commandSource, message) { |
| 36 | const { data } = commandSource | 36 | const { data } = commandSource |
| 37 | - const { deviceInfo, attrInfo } = data || {} | ||
| 38 | - const { deviceName } = deviceInfo || {} | ||
| 39 | const { attr } = data as NodeDataDataSourceJsonType | 37 | const { attr } = data as NodeDataDataSourceJsonType |
| 40 | const { latestValue } = useLatestMessageValue(message.data, attr) | 38 | const { latestValue } = useLatestMessageValue(message.data, attr) |
| 41 | unref(chartInstance)?.setOption({ | 39 | unref(chartInstance)?.setOption({ |
| 42 | title: { | 40 | title: { |
| 43 | - text: `${deviceName || ''}-${attrInfo.name || ''}`, | 41 | + // text: `${deviceName || ''}-${attrInfo.name || ''}`, |
| 44 | }, | 42 | }, |
| 45 | series: [{ | 43 | series: [{ |
| 46 | data: getSetValue(Number(latestValue)), | 44 | data: getSetValue(Number(latestValue)), |
| @@ -26,13 +26,11 @@ function initChartInstance() { | @@ -26,13 +26,11 @@ function initChartInstance() { | ||
| 26 | const { onMessage } = useOnMessage({ | 26 | const { onMessage } = useOnMessage({ |
| 27 | onReceiveDataSourceMessage(commandSource, message) { | 27 | onReceiveDataSourceMessage(commandSource, message) { |
| 28 | const { data } = commandSource | 28 | const { data } = commandSource |
| 29 | - const { deviceInfo, attrInfo } = (data || {}) as NodeDataDataSourceJsonType | ||
| 30 | - const { deviceName } = deviceInfo || {} | ||
| 31 | const { attr } = data as NodeDataDataSourceJsonType | 29 | const { attr } = data as NodeDataDataSourceJsonType |
| 32 | const { latestValue } = useLatestMessageValue(message.data, attr) | 30 | const { latestValue } = useLatestMessageValue(message.data, attr) |
| 33 | unref(chartInstance)?.setOption({ | 31 | unref(chartInstance)?.setOption({ |
| 34 | title: { | 32 | title: { |
| 35 | - text: `${deviceName || ''}-${attrInfo.name || ''}`, | 33 | + // text: `${deviceName || ''}-${attrInfo.name || ''}`, |
| 36 | }, | 34 | }, |
| 37 | series: [{ | 35 | series: [{ |
| 38 | data: [{ | 36 | data: [{ |
| 1 | +import { unref } from 'vue' | ||
| 2 | +import { getDeviceAttributes, getListByConfigurationId, getListByDeviceProfileIds } from '@/api/device' | ||
| 3 | +import type { DeviceItemType, ThingsModelItemType } from '@/api/device/model' | ||
| 4 | +import type { FormSchema } from '@/components/Form' | ||
| 5 | +import { ComponentEnum } from '@/components/Form/src/enum' | ||
| 6 | +import { ContentDataFieldsEnum, ContentDataFieldsNameEnum, DataTypeEnum } from '@/enums/datasource' | ||
| 7 | +import { useContentDataStoreWithOut } from '@/store/modules/contentData' | ||
| 8 | +import type { ProductAndDevice } from '@/api/content/model' | ||
| 9 | +import { ControlComponentEnum } from '@/core/Library/packages/Control' | ||
| 10 | +import { useParseParams } from '@/core/LoadData' | ||
| 11 | + | ||
| 12 | +const contentDataStore = useContentDataStoreWithOut() | ||
| 13 | +export const formSchemas = (componentKey?: string): FormSchema[] => { | ||
| 14 | + const isTemplate = contentDataStore.isTemplate // 判断是否是模板组态 | ||
| 15 | + const isTemplateLink = contentDataStore.getIsTemplateLink | ||
| 16 | + const params = useParseParams() | ||
| 17 | + const { configurationId } = params | ||
| 18 | + return [ | ||
| 19 | + { | ||
| 20 | + field: ContentDataFieldsEnum.DEVICE_PROFILE_ID, | ||
| 21 | + label: ContentDataFieldsNameEnum.DEVICE_PROFILE_ID, | ||
| 22 | + component: ComponentEnum.INPUT, | ||
| 23 | + ifShow: false, | ||
| 24 | + }, | ||
| 25 | + { | ||
| 26 | + field: ContentDataFieldsEnum.DEVICE_PROFILE_TEMPLATE_ID, // 模板产品id | ||
| 27 | + label: ContentDataFieldsNameEnum.DEVICE_PROFILE_ID, | ||
| 28 | + component: ComponentEnum.API_SELECT, | ||
| 29 | + ifShow: !!isTemplate, | ||
| 30 | + required: !!isTemplate, | ||
| 31 | + componentProps: ({ formModel }) => { | ||
| 32 | + return { | ||
| 33 | + options: (unref(contentDataStore.getProductAndDevice) || []).map((item: ProductAndDevice) => ({ label: item.profileName || item.name, value: item.profileId, transportType: item?.transportType, deviceType: item?.deviceType })), | ||
| 34 | + placeholder: '请选择产品', | ||
| 35 | + onSelect(value: string) { | ||
| 36 | + formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value | ||
| 37 | + formModel[ContentDataFieldsEnum.ATTR] = [] | ||
| 38 | + }, | ||
| 39 | + getPopupContainer: () => document.body, | ||
| 40 | + } | ||
| 41 | + }, | ||
| 42 | + }, | ||
| 43 | + { | ||
| 44 | + field: ContentDataFieldsEnum.DEVICE_ID, | ||
| 45 | + label: ContentDataFieldsNameEnum.DEVICE_ID, | ||
| 46 | + component: ComponentEnum.API_SELECT, | ||
| 47 | + ifShow: !isTemplate, | ||
| 48 | + required: !isTemplate, | ||
| 49 | + componentProps: ({ formModel }) => { | ||
| 50 | + const organizationId = window.useParseParams().organizationId | ||
| 51 | + if (!organizationId) return | ||
| 52 | + return { | ||
| 53 | + showSearch: true, | ||
| 54 | + api: async (params: Recordable) => { | ||
| 55 | + if (isTemplateLink) return await getListByConfigurationId(configurationId!) | ||
| 56 | + return await getListByDeviceProfileIds(params) | ||
| 57 | + }, | ||
| 58 | + params: { | ||
| 59 | + deviceProfileIds: unref(contentDataStore.getProductIds), | ||
| 60 | + organizationId, | ||
| 61 | + }, | ||
| 62 | + aliasField: 'alias', | ||
| 63 | + fieldNames: { label: 'name', value: 'tbDeviceId' }, | ||
| 64 | + onSelect(value: string, option: DeviceItemType) { | ||
| 65 | + formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value ? option.deviceProfileId : null | ||
| 66 | + formModel[ContentDataFieldsEnum.ATTR] = [] | ||
| 67 | + formModel[ContentDataFieldsEnum.DEVICE_NAME] = value ? option.alias || option.name : '' | ||
| 68 | + }, | ||
| 69 | + filterOption: (inputValue: string, option: DeviceItemType) => { | ||
| 70 | + return option.alias?.includes?.(inputValue) || option.name?.includes?.(inputValue) | ||
| 71 | + }, | ||
| 72 | + } | ||
| 73 | + }, | ||
| 74 | + }, | ||
| 75 | + { | ||
| 76 | + field: ContentDataFieldsEnum.DEVICE_NAME, | ||
| 77 | + label: ContentDataFieldsNameEnum.deviceName, | ||
| 78 | + component: ComponentEnum.INPUT, | ||
| 79 | + ifShow: false, | ||
| 80 | + }, | ||
| 81 | + { | ||
| 82 | + field: ContentDataFieldsEnum.ATTR, | ||
| 83 | + label: ContentDataFieldsNameEnum.ATTR, | ||
| 84 | + component: ComponentEnum.API_SELECT, | ||
| 85 | + required: true, | ||
| 86 | + componentProps: ({ formModel }) => { | ||
| 87 | + const deviceProfileId = isTemplate ? formModel[ContentDataFieldsEnum.DEVICE_PROFILE_TEMPLATE_ID] : formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] | ||
| 88 | + return { | ||
| 89 | + showSearch: true, | ||
| 90 | + mode: 'multiple', | ||
| 91 | + api: async (params: string) => { | ||
| 92 | + if (!deviceProfileId) return [] | ||
| 93 | + const options = await getDeviceAttributes(params) | ||
| 94 | + if (componentKey === ControlComponentEnum.SWITCH) { // 开关只返回bool | ||
| 95 | + return options.filter((item) => { | ||
| 96 | + return item.detail.dataType.type === DataTypeEnum.BOOL | ||
| 97 | + }) | ||
| 98 | + } | ||
| 99 | + return options | ||
| 100 | + }, | ||
| 101 | + params: deviceProfileId, | ||
| 102 | + fieldNames: { label: 'name', value: 'identifier' }, | ||
| 103 | + filterOption: (inputValue: string, option: ThingsModelItemType) => { | ||
| 104 | + return option.name.includes(inputValue) | ||
| 105 | + }, | ||
| 106 | + } | ||
| 107 | + }, | ||
| 108 | + }, | ||
| 109 | + ] | ||
| 110 | +} |
| 1 | +export { default as DataSourceForm } from './index.vue' |
| 1 | +<script setup lang="ts"> | ||
| 2 | +import { computed, unref } from 'vue' | ||
| 3 | +import type { RuleError } from 'ant-design-vue/lib/form/interface' | ||
| 4 | +import { formSchemas } from './config' | ||
| 5 | +import { FormLayoutEnum } from '@/components/Form/src/enum' | ||
| 6 | +import { BasicForm, useForm } from '@/components/Form' | ||
| 7 | + | ||
| 8 | +export interface ComponentExposeType { | ||
| 9 | + getFieldsValue: () => any | ||
| 10 | + setFieldsValue: (value: any) => void | ||
| 11 | + validate: () => Promise<RuleError | any> | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +const props = defineProps<{ componentKey?: string }>() | ||
| 15 | +defineEmits(['fieldValueChange']) | ||
| 16 | + | ||
| 17 | +const getComponentKey = computed(() => { | ||
| 18 | + return props.componentKey | ||
| 19 | +}) | ||
| 20 | + | ||
| 21 | +const [registerForm, formActionType] = useForm({ | ||
| 22 | + schemas: formSchemas(unref(getComponentKey)), | ||
| 23 | + showActionButtonGroup: false, | ||
| 24 | + layout: FormLayoutEnum.HORIZONTAL, | ||
| 25 | + labelWidth: 70, | ||
| 26 | +}) | ||
| 27 | + | ||
| 28 | +const getFieldsValue = () => { | ||
| 29 | + return formActionType.getFieldsValue() | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +const validate = async () => { | ||
| 33 | + return await formActionType.validate() | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +const setFieldsValue = (value: Recordable) => { | ||
| 37 | + formActionType.setFieldsValue(value) | ||
| 38 | + formActionType.clearValidate() | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +defineExpose<ComponentExposeType>({ | ||
| 42 | + getFieldsValue, | ||
| 43 | + setFieldsValue, | ||
| 44 | + validate, | ||
| 45 | +}) | ||
| 46 | +</script> | ||
| 47 | + | ||
| 48 | +<template> | ||
| 49 | + <BasicForm @register="registerForm" @field-value-change="$emit('fieldValueChange')" /> | ||
| 50 | +</template> |
| @@ -238,6 +238,7 @@ export enum ContentDataFieldsEnum { | @@ -238,6 +238,7 @@ export enum ContentDataFieldsEnum { | ||
| 238 | DEVICE_ID = 'deviceId', | 238 | DEVICE_ID = 'deviceId', |
| 239 | ORG_ID = 'orgId', | 239 | ORG_ID = 'orgId', |
| 240 | ATTR = 'attr', | 240 | ATTR = 'attr', |
| 241 | + DEVICE_NAME = 'deviceName', | ||
| 241 | VIDEO_FILTER = 'videoFilter', | 242 | VIDEO_FILTER = 'videoFilter', |
| 242 | VIDEO_ID = 'id', | 243 | VIDEO_ID = 'id', |
| 243 | VIDEO_URL = 'videoUrl', | 244 | VIDEO_URL = 'videoUrl', |
| @@ -253,6 +254,7 @@ export enum ContentDataFieldsNameEnum { | @@ -253,6 +254,7 @@ export enum ContentDataFieldsNameEnum { | ||
| 253 | ORG_ID = '组织', | 254 | ORG_ID = '组织', |
| 254 | DEVICE_ID = '设备', | 255 | DEVICE_ID = '设备', |
| 255 | ATTR = '属性', | 256 | ATTR = '属性', |
| 257 | + deviceName = '设备名称', | ||
| 256 | VIDEO_ID = '视频流', | 258 | VIDEO_ID = '视频流', |
| 257 | ACCESS_MODE = 'ACCESS_MODE', | 259 | ACCESS_MODE = 'ACCESS_MODE', |
| 258 | VIDEO_URL = '视频地址', | 260 | VIDEO_URL = '视频地址', |
| 1 | import { defineStore } from 'pinia' | 1 | import { defineStore } from 'pinia' |
| 2 | -import { toRaw, unref } from 'vue' | 2 | +import { toRaw } from 'vue' |
| 3 | import { store } from '..' | 3 | import { store } from '..' |
| 4 | import type { NodeDataType } from '@/api/node/model' | 4 | import type { NodeDataType } from '@/api/node/model' |
| 5 | import type { ProductAndDevice } from '@/api/content/model' | 5 | import type { ProductAndDevice } from '@/api/content/model' |
| @@ -7,12 +7,6 @@ import type { CreateComponentType } from '@/core/Library/types' | @@ -7,12 +7,6 @@ import type { CreateComponentType } from '@/core/Library/types' | ||
| 7 | import { isShareMode } from '@/utils/env' | 7 | import { isShareMode } from '@/utils/env' |
| 8 | import { ConfigurationAuthEnum, ConfigurationTemplateAuthEnum } from '@/enums/authEnum' | 8 | import { ConfigurationAuthEnum, ConfigurationTemplateAuthEnum } from '@/enums/authEnum' |
| 9 | 9 | ||
| 10 | -interface DeviceList { | ||
| 11 | - deviceId: string | ||
| 12 | - name: string | ||
| 13 | - codeType: string | ||
| 14 | -} | ||
| 15 | - | ||
| 16 | interface ContentDataStoreType { | 10 | interface ContentDataStoreType { |
| 17 | contentData: NodeDataType[] | 11 | contentData: NodeDataType[] |
| 18 | configurationId: Nullable<string> | 12 | configurationId: Nullable<string> |
| @@ -20,7 +14,6 @@ interface ContentDataStoreType { | @@ -20,7 +14,6 @@ interface ContentDataStoreType { | ||
| 20 | isTemplate?: number | null | string | 14 | isTemplate?: number | null | string |
| 21 | configurationContentList?: any | 15 | configurationContentList?: any |
| 22 | configurationContentId: Nullable<string> | 16 | configurationContentId: Nullable<string> |
| 23 | - diveceDetailMap: Record<string, DeviceList> | ||
| 24 | hasDesignAuth?: boolean | 17 | hasDesignAuth?: boolean |
| 25 | hasPerviewAuth?: boolean | 18 | hasPerviewAuth?: boolean |
| 26 | isTemplateLink?: boolean | 19 | isTemplateLink?: boolean |
| @@ -35,7 +28,6 @@ export const useContentDataStore = defineStore('app-content-data', { | @@ -35,7 +28,6 @@ export const useContentDataStore = defineStore('app-content-data', { | ||
| 35 | productAndDevice: [], | 28 | productAndDevice: [], |
| 36 | configurationContentList: [], | 29 | configurationContentList: [], |
| 37 | configurationContentId: null, | 30 | configurationContentId: null, |
| 38 | - diveceDetailMap: {}, | ||
| 39 | hasDesignAuth: true, | 31 | hasDesignAuth: true, |
| 40 | hasPerviewAuth: true, | 32 | hasPerviewAuth: true, |
| 41 | isTemplateLink: false, | 33 | isTemplateLink: false, |
| @@ -70,17 +62,9 @@ export const useContentDataStore = defineStore('app-content-data', { | @@ -70,17 +62,9 @@ export const useContentDataStore = defineStore('app-content-data', { | ||
| 70 | 62 | ||
| 71 | setProductAndDevice(list: ProductAndDevice[]) { | 63 | setProductAndDevice(list: ProductAndDevice[]) { |
| 72 | this.productAndDevice = list | 64 | this.productAndDevice = list |
| 73 | - this.doBuildDeviceMap() | ||
| 74 | return list | 65 | return list |
| 75 | }, | 66 | }, |
| 76 | 67 | ||
| 77 | - doBuildDeviceMap() { | ||
| 78 | - const list = this.productAndDevice.map(item => toRaw(unref(item.deviceList))).flat(1) | ||
| 79 | - this.diveceDetailMap = list.reduce((prev, next) => { | ||
| 80 | - return { ...prev, [next?.deviceId]: next } | ||
| 81 | - }, {} as Record<'string', DeviceList>) | ||
| 82 | - }, | ||
| 83 | - | ||
| 84 | getCurrentNodeDataById(config: CreateComponentType): Nullable<NodeDataType> { | 68 | getCurrentNodeDataById(config: CreateComponentType): Nullable<NodeDataType> { |
| 85 | const { cellInfo } = config | 69 | const { cellInfo } = config |
| 86 | const { id } = cellInfo || {} | 70 | const { id } = cellInfo || {} |