Commit 3259190b99575bc23d15580eb69e0e6036e78251

Authored by loveumiko
1 parent ab77670d

perf: 优化折线图柱状图属性可以进行多选

... ... @@ -92,7 +92,8 @@ export interface NodeDataDataSourceJsonType {
92 92 deviceId: string
93 93 deviceProfileId: string
94 94 deviceProfileTemplateId?: string
95   - attr: string
  95 + attr: string | string[]
  96 + deviceName?: string
96 97
97 98 enable: boolean
98 99 chartOption?: ChartOptionType
... ...
... ... @@ -40,11 +40,10 @@ const contentDataStore = useContentDataStoreWithOut()
40 40 export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => {
41 41 const { getNodeData, getCellInfo, getDeviceInfo } = usePublicFormContext()
42 42 const { dataSourceJson } = unref(getNodeData) || {}
43   - const { deviceProfileId, deviceId } = dataSourceJson || {}
  43 + const { deviceProfileId } = dataSourceJson || {}
44 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 47 const isTemplate = contentDataStore.isTemplate // 判断是否是模板
49 48
50 49 return [
... ...
... ... @@ -63,6 +63,7 @@ export const formSchemas = (componentKey?: string): FormSchema[] => {
63 63 onSelect(value: string, option: DeviceItemType) {
64 64 formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value ? option.deviceProfileId : null
65 65 formModel[ContentDataFieldsEnum.ATTR] = null
  66 + formModel[ContentDataFieldsEnum.DEVICE_NAME] = value ? option.alias || option.name : ''
66 67 },
67 68 filterOption: (inputValue: string, option: DeviceItemType) => {
68 69 return option.alias?.includes?.(inputValue) || option.name?.includes?.(inputValue)
... ... @@ -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 81 field: ContentDataFieldsEnum.ATTR,
75 82 label: ContentDataFieldsNameEnum.ATTR,
76 83 component: ComponentEnum.API_SELECT,
... ...
... ... @@ -6,3 +6,10 @@ export function useLatestMessageValue(message: SubscriptionData, attr: string) {
6 6 const [ts, latestValue = null] = lateset || []
7 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 34 const { onMessage } = useOnMessage({
35 35 onReceiveDataSourceMessage(commandSource, message) {
36 36 const { data } = commandSource
37   - const { deviceInfo, attrInfo } = data || {}
38   - const { deviceName } = deviceInfo || {}
39 37 const { attr } = data as NodeDataDataSourceJsonType
40 38 const { latestValue } = useLatestMessageValue(message.data, attr)
41 39 unref(chartInstance)?.setOption({
42 40 title: {
43   - text: `${deviceName || ''}-${attrInfo.name || ''}`,
  41 + // text: `${deviceName || ''}-${attrInfo.name || ''}`,
44 42 },
45 43 series: [{
46 44 data: getSetValue(Number(latestValue)),
... ...
... ... @@ -3,7 +3,8 @@ import { Button, Divider } from 'ant-design-vue'
3 3 import { nextTick, onMounted, ref, unref } from 'vue'
4 4 import { formSchemas } from '../config'
5 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 9 import { BasicForm, useForm } from '@/components/Form'
9 10 import { FormLayoutEnum } from '@/components/Form/src/enum'
... ... @@ -46,7 +47,7 @@ const handleSubmit = async () => {
46 47 if (contentDataStore.getIsTemplate)
47 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 51 savePageContent()
51 52 createMessage.success('操作成功~')
52 53 }
... ... @@ -57,9 +58,9 @@ const handleSubmit = async () => {
57 58
58 59 const handleSetFormValues = async () => {
59 60 const { dataSourceJson } = unref(getNodeData) || {}
60   - const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId } = dataSourceJson || {}
  61 + const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId, deviceName } = dataSourceJson || {}
61 62 await nextTick()
62   - unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId })
  63 + unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceName, deviceProfileId, deviceProfileTemplateId })
63 64 setFieldsValue({ ...chartOption })
64 65 }
65 66
... ...
1 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 3 export const defaultOption = {
14   - color: ['#3398DB'],
15 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 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 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 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 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 3 import { init } from 'echarts'
4 4 import type { ECharts, EChartsOption } from 'echarts'
5 5 import { defaultOption } from './index.config'
... ... @@ -10,6 +10,7 @@ import { SocketSubscriberEnum } from '@/enums/datasource'
10 10 import type { SubscriptionData } from '@/core/websocket/type/message'
11 11 import { formatToDateTime } from '@/utils/dateUtil'
12 12 import type { CommandSource } from '@/core/websocket/processor'
  13 +import { useProductsStore } from '@/store/modules/products'
13 14
14 15 const props = defineProps<{
15 16 config: CreateComponentType
... ... @@ -21,40 +22,80 @@ const chartElRef = ref<Nullable<HTMLDivElement>>()
21 22
22 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 29 function initChartInstance() {
25 30 chartInstance.value = init(unref(chartElRef))
26 31 chartInstance.value.setOption(defaultOption)
27 32 }
28 33
  34 +const productsStore = useProductsStore()
  35 +
29 36 const handleHistoryData = (commandSource: CommandSource, message: SubscriptionData) => {
30 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 64 unref(chartInstance)?.setOption({
45 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 85 } as EChartsOption)
51 86 }
52 87
53 88 const { onMessage } = useOnMessage({
54 89 onReceiveDataSourceMessage(commandSource, message) {
55 90 const { data } = commandSource
56   - const { chartOption } = data as NodeDataDataSourceJsonType
  91 + const { chartOption, attr, deviceProfileId } = data as NodeDataDataSourceJsonType
57 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 100 if (queryType === SocketSubscriberEnum.HISTORY_CMDS)
60 101 handleHistoryData(commandSource, message.data)
... ...
... ... @@ -36,8 +36,6 @@ onMounted(() => {
36 36
37 37 const onReceiveDataSourceMessage = (commandSource: CommandSource, message: SubscriptionUpdateMsg) => {
38 38 const { data } = commandSource
39   - const { deviceInfo, attrInfo } = data || {}
40   - const { deviceName } = deviceInfo || {}
41 39 const { attr } = data as NodeDataDataSourceJsonType
42 40 const { latestValue } = useLatestMessageValue(message.data, attr)
43 41 unref(chartInstance)?.setOption({
... ... @@ -46,7 +44,7 @@ const onReceiveDataSourceMessage = (commandSource: CommandSource, message: Subsc
46 44
47 45 }],
48 46 title: {
49   - text: `${deviceName || ''}-${attrInfo.name || ''}`,
  47 + // text: `${deviceName || ''}-${attrInfo.name || ''}`,
50 48 },
51 49 } as EChartsOption)
52 50 }
... ...
... ... @@ -3,7 +3,9 @@ import { Button, Divider } from 'ant-design-vue'
3 3 import { nextTick, onMounted, ref, unref } from 'vue'
4 4 import { formSchemas } from '../config'
5 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 10 import { BasicForm, useForm } from '@/components/Form'
9 11 import { FormLayoutEnum } from '@/components/Form/src/enum'
... ... @@ -33,9 +35,9 @@ const dataSourceElRef = ref<Nullable<InstanceType<typeof DataSourceForm>>>()
33 35
34 36 const handleSetFormValues = async () => {
35 37 const { dataSourceJson } = unref(getNodeData) || {}
36   - const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId } = dataSourceJson || {}
  38 + const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId, deviceName } = dataSourceJson || {}
37 39 await nextTick()
38   - unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId })
  40 + unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId, deviceName })
39 41 setFieldsValue({ ...chartOption })
40 42 }
41 43
... ... @@ -54,7 +56,7 @@ const handleSubmit = async () => {
54 56 if (contentDataStore.getIsTemplate)
55 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 60 createMessage.success('操作成功~')
59 61 savePageContent()
60 62 }
... ...
... ... @@ -3,31 +3,35 @@ import { isLightboxMode } from '@/utils/env'
3 3
4 4 export const getDefaultOption = (): EChartsOption => {
5 5 return {
6   - tooltip: {
7   - trigger: 'item',
8   - confine: true,
  6 + legend: {
  7 + top: '10%',
  8 + left: 'center',
  9 + data: [''],
9 10 },
10 11 grid: {
11   - left: '3%',
12   - right: '4%',
13   - bottom: '3%',
  12 + top: '30%',
  13 + left: '6%',
  14 + right: '10%',
  15 + bottom: '8%',
14 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 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 4 import { init } from 'echarts'
5 5 import { getDefaultOption } from './index.config'
6 6 import type { CreateComponentType, RenderComponentExposeType } from '@/core/Library/types'
... ... @@ -9,8 +9,12 @@ import type { NodeDataDataSourceJsonType } from '@/api/node/model'
9 9 import type { SubscriptionData } from '@/core/websocket/type/message'
10 10 import { SocketSubscriberEnum } from '@/enums/datasource'
11 11 import { formatToDateTime } from '@/utils/dateUtil'
12   -import { useLatestMessageValue } from '@/core/Library/hook/useLatestMessageValue'
13 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 19 const props = defineProps<{
16 20 config: CreateComponentType
... ... @@ -22,67 +26,126 @@ const chartElRef = ref<Nullable<HTMLDivElement>>()
22 26
23 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 37 function initChartInstance() {
26 38 chartInstance.value = init(unref(chartElRef))
27 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 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 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 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 110 unref(chartInstance)?.setOption({
66 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 130 } as EChartsOption)
74 131 }
75 132
76 133 const { onMessage } = useOnMessage({
77 134 onReceiveDataSourceMessage(commandSource, message) {
78 135 const { data } = commandSource
79   - const { chartOption, attr } = data as NodeDataDataSourceJsonType
  136 + const { chartOption, attr, deviceProfileId } = data as NodeDataDataSourceJsonType
80 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 145 if (queryType === SocketSubscriberEnum.TS_SUB_CMDS)
83 146 handlerTimeSeriesData(commandSource, message.data, attr)
84 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 34 const { onMessage } = useOnMessage({
35 35 onReceiveDataSourceMessage(commandSource, message) {
36 36 const { data } = commandSource
37   - const { deviceInfo, attrInfo } = data || {}
38   - const { deviceName } = deviceInfo || {}
39 37 const { attr } = data as NodeDataDataSourceJsonType
40 38 const { latestValue } = useLatestMessageValue(message.data, attr)
41 39 unref(chartInstance)?.setOption({
42 40 title: {
43   - text: `${deviceName || ''}-${attrInfo.name || ''}`,
  41 + // text: `${deviceName || ''}-${attrInfo.name || ''}`,
44 42 },
45 43 series: [{
46 44 data: getSetValue(Number(latestValue)),
... ...
... ... @@ -26,13 +26,11 @@ function initChartInstance() {
26 26 const { onMessage } = useOnMessage({
27 27 onReceiveDataSourceMessage(commandSource, message) {
28 28 const { data } = commandSource
29   - const { deviceInfo, attrInfo } = (data || {}) as NodeDataDataSourceJsonType
30   - const { deviceName } = deviceInfo || {}
31 29 const { attr } = data as NodeDataDataSourceJsonType
32 30 const { latestValue } = useLatestMessageValue(message.data, attr)
33 31 unref(chartInstance)?.setOption({
34 32 title: {
35   - text: `${deviceName || ''}-${attrInfo.name || ''}`,
  33 + // text: `${deviceName || ''}-${attrInfo.name || ''}`,
36 34 },
37 35 series: [{
38 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 238 DEVICE_ID = 'deviceId',
239 239 ORG_ID = 'orgId',
240 240 ATTR = 'attr',
  241 + DEVICE_NAME = 'deviceName',
241 242 VIDEO_FILTER = 'videoFilter',
242 243 VIDEO_ID = 'id',
243 244 VIDEO_URL = 'videoUrl',
... ... @@ -253,6 +254,7 @@ export enum ContentDataFieldsNameEnum {
253 254 ORG_ID = '组织',
254 255 DEVICE_ID = '设备',
255 256 ATTR = '属性',
  257 + deviceName = '设备名称',
256 258 VIDEO_ID = '视频流',
257 259 ACCESS_MODE = 'ACCESS_MODE',
258 260 VIDEO_URL = '视频地址',
... ...
1 1 import { defineStore } from 'pinia'
2   -import { toRaw, unref } from 'vue'
  2 +import { toRaw } from 'vue'
3 3 import { store } from '..'
4 4 import type { NodeDataType } from '@/api/node/model'
5 5 import type { ProductAndDevice } from '@/api/content/model'
... ... @@ -7,12 +7,6 @@ import type { CreateComponentType } from '@/core/Library/types'
7 7 import { isShareMode } from '@/utils/env'
8 8 import { ConfigurationAuthEnum, ConfigurationTemplateAuthEnum } from '@/enums/authEnum'
9 9
10   -interface DeviceList {
11   - deviceId: string
12   - name: string
13   - codeType: string
14   -}
15   -
16 10 interface ContentDataStoreType {
17 11 contentData: NodeDataType[]
18 12 configurationId: Nullable<string>
... ... @@ -20,7 +14,6 @@ interface ContentDataStoreType {
20 14 isTemplate?: number | null | string
21 15 configurationContentList?: any
22 16 configurationContentId: Nullable<string>
23   - diveceDetailMap: Record<string, DeviceList>
24 17 hasDesignAuth?: boolean
25 18 hasPerviewAuth?: boolean
26 19 isTemplateLink?: boolean
... ... @@ -35,7 +28,6 @@ export const useContentDataStore = defineStore('app-content-data', {
35 28 productAndDevice: [],
36 29 configurationContentList: [],
37 30 configurationContentId: null,
38   - diveceDetailMap: {},
39 31 hasDesignAuth: true,
40 32 hasPerviewAuth: true,
41 33 isTemplateLink: false,
... ... @@ -70,17 +62,9 @@ export const useContentDataStore = defineStore('app-content-data', {
70 62
71 63 setProductAndDevice(list: ProductAndDevice[]) {
72 64 this.productAndDevice = list
73   - this.doBuildDeviceMap()
74 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 68 getCurrentNodeDataById(config: CreateComponentType): Nullable<NodeDataType> {
85 69 const { cellInfo } = config
86 70 const { id } = cellInfo || {}
... ...