Commit 8ea717de73df008522289e9f57b2b55455b2230f

Authored by ww
1 parent 22a1a2d2

feat(request): 新增socket请求方式

Showing 26 changed files with 482 additions and 72 deletions
... ... @@ -2,6 +2,11 @@ import { RequestBodyEnum } from "@/enums/httpEnum"
2 2 import { RequestConfigType, RequestGlobalConfigType } from "@/store/modules/chartEditStore/chartEditStore.d"
3 3 import { defHttp } from "@/utils/external/http/axios"
4 4
  5 +export enum ParamsType {
  6 + REQUIRED,
  7 + OPTIONAL
  8 +}
  9 +
5 10 export const isFullUrl = (url = '') => {
6 11 try {
7 12 new URL(url)
... ... @@ -17,14 +22,67 @@ export const getUrl = (url = '') => {
17 22 return isFullUrlFlag ? new URL(url) : { pathname: url, origin }
18 23 }
19 24
  25 +const regOptionalParams = /(?={\?)/g
  26 +const regDynamicParams = /(?={).+?(?<=})/g
  27 +
  28 +export const isDynamicUrl = (url: string) => {
  29 + regDynamicParams.lastIndex = 0
  30 +
  31 + return regDynamicParams.test(url)
  32 +}
  33 +
  34 +export const decomposeDynamicParams = (url: string) => {
  35 + regDynamicParams.lastIndex = 0
  36 + regOptionalParams.lastIndex = 0
  37 +
  38 + return Array.from((url || '').matchAll(regDynamicParams), ([item]) => {
  39 + return {
  40 + type: regOptionalParams.test(item) ? ParamsType.OPTIONAL : ParamsType.REQUIRED,
  41 + originValue: item,
  42 + value: item.replaceAll(/[{}?]/g, '').split(',')
  43 + }
  44 + })
  45 +}
  46 +
20 47 export const customRequest = async (request: RequestConfigType) => {
21 48 const { requestHttpType, requestParams, requestParamsBodyType, requestUrl } = request as RequestGlobalConfigType & RequestConfigType
22   - const { Params, Header, Body } = requestParams
  49 + const { Header, Body } = requestParams
  50 + let { Params } = requestParams
  51 + Params = JSON.parse(JSON.stringify(Params))
  52 +
  53 + const isDynamicUrlFlag = isDynamicUrl(requestUrl || '')
  54 + const url = getUrl(requestUrl!)
  55 + const { origin } = url
  56 + let { pathname } = url
  57 +
  58 + if (isDynamicUrlFlag) {
  59 + pathname = decodeURI(pathname || '')
  60 +
  61 + const paramsList = decomposeDynamicParams(pathname)
  62 + pathname = paramsList.reduce((prev, next) => {
  63 + const { type, value, originValue } = next
  64 + if (type === ParamsType.REQUIRED) {
  65 + value.forEach(key => {
  66 + prev = prev.replace(key, Reflect.get(Params, key))
  67 + Reflect.deleteProperty(Params, key)
  68 + })
  69 + }
23 70
24   - const { origin, pathname } = getUrl(requestUrl!)
  71 + if (type === ParamsType.OPTIONAL) {
  72 + prev = prev.replace(originValue, '')
  73 + }
  74 +
  75 + return prev
  76 + }, pathname)
  77 +
  78 + pathname = pathname.replaceAll(/[{}?]/g, '')
  79 + }
25 80
26 81 const body = Body[requestParamsBodyType as Exclude<'NONE', keyof typeof RequestBodyEnum>]
27 82
  83 + // Object.assign(Params, { startTs: Params.date[0], endTs: Params.date[1] })
  84 + Reflect.deleteProperty(Params, 'date')
  85 +
28 86 return defHttp.request<any>({
29 87 url: pathname,
30 88 baseURL: origin,
... ...
... ... @@ -34,7 +34,7 @@ import { GoSystemInfo } from '@/components/GoSystemInfo/index'
34 34 import Person from './person.png'
35 35
36 36 import { icon } from '@/plugins'
37   -import { useUserStore } from '@/store/external/module/user'
  37 +import { useUserStore } from '@/store/external/modules/user'
38 38 const { ChatboxEllipsesIcon, PersonIcon, LogOutOutlineIcon, SettingsSharpIcon } = icon.ionicons5
39 39
40 40 const t = window['$t']
... ...
1   -import { ref, toRefs, toRaw } from 'vue'
  1 +import { ref, toRefs, toRaw, watch } from 'vue'
2 2 import type VChart from 'vue-echarts'
3 3 import { customizeHttp } from '@/api/http'
4 4 import { useChartDataPondFetch } from '@/hooks/'
... ... @@ -63,6 +63,7 @@ export const useChartDataFetch = (
63 63
64 64 try {
65 65 // 处理地址
  66 + // @ts-ignore
66 67 if (requestUrl?.value) {
67 68 // requestOriginUrl 允许为空
68 69 const completePath = requestOriginUrl && requestOriginUrl.value + requestUrl.value
... ... @@ -86,8 +87,18 @@ export const useChartDataFetch = (
86 87 }
87 88 }
88 89
89   - // 立即调用
90   - fetchFn()
  90 + // 普通初始化与组件交互处理监听
  91 + watch(
  92 + () => targetComponent.request,
  93 + () => {
  94 + fetchFn()
  95 + },
  96 + {
  97 + immediate: true,
  98 + deep: true
  99 + }
  100 + )
  101 +
91 102 // 定时时间
92 103 const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value
93 104 // 单位
... ...
  1 +import { RequestContentTypeEnum } from "@/enums/external/httpEnum";
  2 +import { CreateComponentType } from "@/packages/index.d";
  3 +import { useSocketStore } from "@/store/external/modules/socketStore";
  4 +import { SocketReceiveMessageType } from "@/store/external/modules/socketStore.d";
  5 +import { useChartEditStore } from "@/store/modules/chartEditStore/chartEditStore";
  6 +import { getJwtToken } from "@/utils/external/auth";
  7 +import { useWebSocket, WebSocketResult } from "@vueuse/core";
  8 +import { onMounted, unref } from "vue";
  9 +import { useFilterFn } from "./useFilterFn";
  10 +
  11 +
  12 +interface SocketConnectionPoolType {
  13 + ws: WebSocketResult<SocketReceiveMessageType>
  14 + url: string
  15 +}
  16 +
  17 +const socketConnectionPool: SocketConnectionPoolType[] = []
  18 +
  19 +const parse = (value: string) => {
  20 + try {
  21 + return JSON.parse(value)
  22 + } catch (error) {
  23 + return {}
  24 + }
  25 +}
  26 +
  27 +const getSocketInstance = (requestUrl: string, targetComponent: CreateComponentType) => {
  28 + const index = socketConnectionPool.findIndex(item => item.url === requestUrl)
  29 + if (~index) {
  30 + return socketConnectionPool[index].ws
  31 + }
  32 + const token = getJwtToken()
  33 + const socketUrl = `${requestUrl}?token=${token}`
  34 +
  35 + const instance = useWebSocket(socketUrl.replace('undefined', ''), {
  36 + onMessage() {
  37 + const { data } = instance
  38 + const { filter } = targetComponent
  39 + const { value, reason, flag } = useFilterFn(filter, parse(unref(data)))
  40 + targetComponent.option.dataset = flag ? value : reason
  41 + },
  42 + onDisconnected(ws, event) {
  43 + console.log('连接断开')
  44 + }
  45 + })
  46 +
  47 + socketConnectionPool.push({ url: requestUrl, ws: instance })
  48 +
  49 + return instance
  50 +}
  51 +
  52 +type ChartEditStoreType = typeof useChartEditStore
  53 +
  54 +export const useChartDataSocket = () => {
  55 +
  56 + const socketStore = useSocketStore()
  57 +
  58 + const initial = (targetComponent: CreateComponentType, useChartEditStore: ChartEditStoreType, updateCallback?: (...args: any) => any) => {
  59 + const { request } = targetComponent
  60 +
  61 + const { requestUrl, requestContentType } = request
  62 +
  63 + if ((requestContentType as RequestContentTypeEnum) !== RequestContentTypeEnum.WEB_SOCKET) return
  64 +
  65 + const { send } = getSocketInstance(requestUrl!, targetComponent)
  66 +
  67 + onMounted(() => {
  68 + const message = socketStore.subscribe(targetComponent)
  69 + send(JSON.stringify(message))
  70 + })
  71 + }
  72 +
  73 + const sendMessage = async (targetComponent: CreateComponentType) => {
  74 + const { request } = unref(targetComponent)
  75 + const { requestUrl } = request
  76 + const message = socketStore.subscribe(unref(targetComponent))
  77 + const { send, data } = getSocketInstance(requestUrl!, unref(targetComponent))
  78 + message && send(JSON.stringify(message))
  79 + return JSON.parse(unref(data))
  80 + }
  81 +
  82 +
  83 + return {
  84 + initial,
  85 + sendMessage
  86 + }
  87 +}
... ...
  1 +import { cloneDeep } from "lodash"
  2 +
  3 +export const useFilterFn = (filter = 'return res', value: any) => {
  4 + let flag = true
  5 + let reason = ''
  6 + let res
  7 +
  8 + try {
  9 + const fn = new Function('res', filter)
  10 + res = fn(cloneDeep(value))
  11 + } catch (error) {
  12 + flag = false
  13 + reason = error as string
  14 + }
  15 +
  16 + return {
  17 + flag,
  18 + reason,
  19 + value: res
  20 + }
  21 +}
... ...
... ... @@ -7,6 +7,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
7 7 import { RequestDataTypeEnum } from '@/enums/httpEnum'
8 8 import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
9 9 import { setOption } from '@/packages/public/chart'
  10 +import { useChartDataSocket } from './external/useChartDataSocket'
10 11
11 12 // 获取类型
12 13 type ChartEditStoreType = typeof useChartEditStore
... ... @@ -118,5 +119,9 @@ export const useChartDataFetch = (
118 119 ? addGlobalDataInterface(targetComponent, useChartEditStore, updateCallback || echartsUpdateHandle)
119 120 : requestIntervalFn()
120 121 }
  122 +
  123 + // THINGS_KIT 添加socket支持
  124 + const { initial } = useChartDataSocket()
  125 + initial(targetComponent, useChartEditStore, updateCallback)
121 126 return { vChartRef }
122 127 }
... ...
1 1 import { ProjectRuntimeEnvEnum } from "@/enums/external/envEnum";
2 2 import { PageEnum } from "@/enums/external/pageEnum";
3   -import { useUserStoreWithOut } from "@/store/external/module/user";
  3 +import { useUserStoreWithOut } from "@/store/external/modules/user";
4 4 import { NavigationGuardNext, NavigationGuardWithThis, RouteLocationNormalized, RouteLocationRaw, Router } from "vue-router";
5 5
6 6
... ...
1   -export enum DynamicRequestStoreEnum {
2   - // 组件id
3   - ID = 'id',
4   - // 请求源地址
5   - REQUEST_ORIGIN_URL = 'requestOriginUrl',
6   - // 请求间隔时间
7   - REQUEST_INTERVAL = 'requestInterval',
8   - // 请求单位
9   - REQUEST_INTERVAL_UNIT = 'requestIntervalUnit',
10   - // 请求头
11   - REQUEST_HEADER = 'requestHeader'
12   -}
13   -
14   -export interface DynamicRequestStoreType {
15   -
16   -}
1   - import { defineStore } from "pinia";
2   -
3   -export const useDynamicRequest = defineStore({
4   - id: 'useDynamicRequest',
5   - state: () => ({
6   -
7   - }),
8   - getters: {
9   -
10   - },
11   - actions: {
12   -
13   - }
14   -})
  1 +import { ChartEditStoreType } from '../../modules/chartEditStore/chartEditStore.d'
  2 +
  3 +export enum ExtraComponentInfoStoreEnum {
  4 + COMPONENT_LIST = 'componentList'
  5 +}
  6 +
  7 +export interface ExtraComponentInfoStoreType {
  8 + [ExtraComponentInfoStoreEnum.COMPONENT_LIST]: ChartEditStoreType['componentList']
  9 +}
... ...
  1 +import { CreateComponentType, CreateComponentGroupType } from "@/packages/index.d";
  2 +import { RequestConfigType } from "@/store/modules/chartEditStore/chartEditStore.d";
  3 +import { useChartEditStore } from "@/store/modules/chartEditStore/chartEditStore";
  4 +import { defineStore } from "pinia";
  5 +
  6 +export interface ExternalRequestType {
  7 + test: string
  8 +}
  9 +
  10 +export interface ECreateComponentType extends CreateComponentType {
  11 + request: RequestConfigType & ExternalRequestType
  12 +}
  13 +
  14 +const chartEditStore = useChartEditStore()
  15 +export const useExternalChartEditStore = defineStore({
  16 + id: 'useExtraComponentInfo',
  17 + actions: {
  18 + updateComponentList(index: number, newData: CreateComponentType) {
  19 + chartEditStore.updateComponentList(index, newData)
  20 + },
  21 + }
  22 +})
... ...
src/store/external/modules/projectInfo.d.ts renamed from src/store/external/module/projectInfo.d.ts
src/store/external/modules/projectInfo.ts renamed from src/store/external/module/projectInfo.ts
  1 +
  2 +export enum SocketStoreEnum {
  3 + CONNECTION_POOL = 'connectionPool',
  4 + SUBSCRIBE_POOL = 'subscribePool',
  5 + CACHE_MESSAGE = 'cacheMessage'
  6 +}
  7 +
  8 +export interface KeyBoundComponentList {
  9 + componentId: string
  10 +}
  11 +
  12 +export interface SocketSendMessageItemType {
  13 + cmdId: number
  14 + entityId: string
  15 + entityType: string
  16 + keys: string
  17 + scope: string
  18 +}
  19 +
  20 +export interface SocketSendMessageType {
  21 + tsSubCmds: SocketSendMessageItemType[]
  22 +}
  23 +
  24 +export interface SocketReceiveMessageType {
  25 + subscriptionId: number,
  26 + errorCode: number,
  27 + errorMsg: Nullable<string>,
  28 + data: {
  29 + [key: string]: [number, string]
  30 + },
  31 + latestValues: {
  32 + [key: string]: number
  33 + }
  34 +}
  35 +
  36 +export interface SocketConnectionPoolType {
  37 + [key: string]: {
  38 + [key: string]: KeyBoundComponentList[]
  39 + }
  40 +}
  41 +
  42 +export interface CacheMessageType {
  43 + [key: number]: SocketReceiveMessageType[]
  44 +}
  45 +
  46 +export interface SubscribePoolType {
  47 + subscribeId: number
  48 + entityId: string
  49 +}
  50 +
  51 +export interface SocketStoreType {
  52 + [SocketStoreEnum.CONNECTION_POOL]: SocketConnectionPoolType,
  53 + [SocketStoreEnum.SUBSCRIBE_POOL]: SubscribePoolType[],
  54 + [SocketStoreEnum.CACHE_MESSAGE]: CacheMessageType
  55 +}
... ...
  1 +import { defineStore } from "pinia";
  2 +import { KeyBoundComponentList, SocketReceiveMessageType, SocketSendMessageType, SocketStoreType } from '@/store/external/modules/socketStore.d'
  3 +import { CreateComponentType } from "@/packages/index.d";
  4 +import { RequestContentTypeEnum } from "@/enums/external/httpEnum";
  5 +
  6 +const KEYS_SEPARATOR = ','
  7 +
  8 +export const useSocketStore = defineStore({
  9 + id: 'useSocketStore',
  10 + state: (): SocketStoreType => ({
  11 + connectionPool: {},
  12 + subscribePool: [],
  13 + cacheMessage: {}
  14 + }),
  15 + getters: {
  16 +
  17 + },
  18 + actions: {
  19 + /**
  20 + * @description 更新连接池
  21 + */
  22 + updateConnectionPool(entityId: string, keys: string[], componentId: string) {
  23 +
  24 + const isExist = Reflect.has(this.connectionPool, entityId)
  25 + if (isExist) {
  26 + const temp = Reflect.get(this.connectionPool, entityId)
  27 + keys.forEach(key => {
  28 + const isExistKey = Reflect.has(temp, key)
  29 + if (!isExistKey) {
  30 + const keyBindEntityIdList = Reflect.get(temp, key) || []
  31 + Reflect.set(temp, key, [...keyBindEntityIdList, { componentId }] as KeyBoundComponentList[])
  32 + }
  33 + })
  34 + } else {
  35 + const keysRecord: Record<string, KeyBoundComponentList[]> = {}
  36 +
  37 + keys.forEach(key => {
  38 + Reflect.set(keysRecord, key, [{ componentId }])
  39 + })
  40 +
  41 + Reflect.set(this.connectionPool, entityId, keysRecord)
  42 +
  43 + }
  44 + return this.refreshSubscribedMessage(entityId)
  45 + },
  46 +
  47 + /**
  48 + * @description 获取重新刷新的消息
  49 + * @param entityId
  50 + * @returns
  51 + */
  52 + refreshSubscribedMessage(entityId: string) {
  53 + const isExist = this.subscribePool.findIndex(item => item.entityId === entityId)
  54 + if (!~isExist) {
  55 + const subscribeId = this.subscribePool.length ? Math.max(...this.subscribePool.map(item => item.subscribeId)) + 1 : 0
  56 + this.subscribePool.push({ subscribeId, entityId })
  57 + }
  58 + const subscribeId = this.subscribePool.find(item => item.entityId === entityId)!.subscribeId!
  59 +
  60 + return this.createMessage(subscribeId, entityId)
  61 + },
  62 +
  63 + /**
  64 + * @description 创建消息
  65 + * @param subscribeId
  66 + * @param entityId
  67 + * @returns
  68 + */
  69 + createMessage(subscribeId: number, entityId: string): SocketSendMessageType {
  70 + const keys = Object.keys(Reflect.get(this.connectionPool, entityId)).join(',')
  71 +
  72 + return {
  73 + tsSubCmds: [
  74 + {
  75 + entityType: 'DEVICE',
  76 + entityId: entityId,
  77 + scope: "LATEST_TELEMETRY",
  78 + cmdId: subscribeId,
  79 + keys
  80 + }
  81 + ]
  82 + }
  83 + },
  84 +
  85 + /**
  86 + * @description 订阅
  87 + * @param targetComponent
  88 + */
  89 + subscribe(targetComponent: CreateComponentType) {
  90 + const { id: componentId, request } = targetComponent
  91 + const { requestContentType, requestParams } = request
  92 + if ((requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET) {
  93 + const { Params } = requestParams
  94 + const { entityId = '', keys = '' } = Params
  95 + return this.updateConnectionPool(entityId, keys.split(KEYS_SEPARATOR), componentId)
  96 + }
  97 + },
  98 +
  99 + /**
  100 + * @description 缓存消息
  101 + * @param message
  102 + */
  103 + setCacheMessage(message: SocketReceiveMessageType) {
  104 + const { subscriptionId } = message
  105 + const existedIndex = this.subscribePool.findIndex(item => item.subscribeId === subscriptionId)
  106 +
  107 + if (~existedIndex) {
  108 + const isExistMessage = Reflect.get(this.cacheMessage, subscriptionId)
  109 + if (!isExistMessage) Reflect.set(this.cacheMessage, subscriptionId, [])
  110 + Reflect.set(this.cacheMessage, subscriptionId, [...Reflect.get(this.cacheMessage, subscriptionId), message])
  111 + }
  112 + }
  113 + }
  114 +})
... ...
src/store/external/modules/user.ts renamed from src/store/external/module/user.ts
... ... @@ -10,7 +10,7 @@ import { isFunction } from '@/utils/external/is'
10 10 import { ContentTypeEnum, RequestEnum } from '@/enums/external/httpEnum';
11 11 import omit from 'lodash/omit';
12 12 import cloneDeep from 'lodash/cloneDeep';
13   -import { useUserStore } from '@/store/external/module/user';
  13 +import { useUserStore } from '@/store/external/modules/user';
14 14
15 15 export * from './axiosTransform';
16 16
... ...
1 1 import type { ErrorMessageMode } from '/#/external/axios';
2   -import { useUserStoreWithOut } from '@/store/external/module/user';
  2 +import { useUserStoreWithOut } from '@/store/external/modules/user';
3 3
4 4 export function checkStatus(
5 5 status: number,
... ...
... ... @@ -56,12 +56,6 @@
56 56 <NDivider vertical style="height: 480px" />
57 57 <NScrollbar style="max-height: 480px">
58 58 <NSpace :size="15" vertical>
59   - <!-- <div class="editor-data-show"> -->
60   - <!-- <NSpace>
61   - <NText depth="3">默认过滤数据(data):</NText>
62   - <NCode :code="toString(sourceData?.data) || '暂无'" language="json" :word-wrap="true"></NCode>
63   - </NSpace> -->
64   - <!-- </div> -->
65 59 <div class="editor-data-show">
66 60 <NSpace>
67 61 <NText depth="3">接口返回数据(res):</NText>
... ... @@ -103,7 +97,7 @@
103 97 </template>
104 98
105 99 <script lang="ts" setup>
106   -import { ref, computed, watch, toRaw } from 'vue'
  100 +import { ref, computed, watch, toRaw, unref } from 'vue'
107 101 import { MonacoEditor } from '@/components/Pages/MonacoEditor'
108 102 import { icon } from '@/plugins'
109 103 import { goDialog, toString } from '@/utils'
... ... @@ -111,6 +105,9 @@ import cloneDeep from 'lodash/cloneDeep'
111 105 import { useTargetData } from '../../../../hooks/useTargetData.hook'
112 106 import { customRequest } from '@/api/external/customRequest'
113 107 import { NButton, NCard, NCode, NDivider, NIcon, NModal, NScrollbar, NSpace, NTag, NText } from 'naive-ui'
  108 +import { useChartDataSocket } from '@/hooks/external/useChartDataSocket'
  109 +import { CreateComponentType } from '@/packages/index.d'
  110 +import { RequestContentTypeEnum } from '@/enums/external/httpEnum'
114 111
115 112 const { DocumentTextIcon } = icon.ionicons5
116 113 const { FilterIcon, FilterEditIcon } = icon.carbon
... ... @@ -125,10 +122,15 @@ const errorFlag = ref(false)
125 122 // 目标静态/接口数据
126 123 const sourceData = ref<any>('')
127 124
  125 +const { sendMessage } = useChartDataSocket()
128 126 // 动态获取数据
129 127 const fetchTargetData = async () => {
130 128 try {
131   - const res = await customRequest(toRaw(targetData.value.request))
  129 +
  130 + const isSocketType = (targetData.value.request.requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET
  131 + const res = isSocketType
  132 + ? await sendMessage(unref(targetData) as CreateComponentType)
  133 + : await customRequest(toRaw(targetData.value.request))
132 134 if (res) {
133 135 sourceData.value = res
134 136 return
... ... @@ -143,9 +145,9 @@ const fetchTargetData = async () => {
143 145 // 过滤结果
144 146 const filterRes = computed(() => {
145 147 try {
146   - const fn = new Function('data', 'res', filter.value)
  148 + const fn = new Function('res', filter.value)
147 149 const response = cloneDeep(sourceData.value)
148   - const res = fn(response?.data, response)
  150 + const res = fn(response)
149 151 // eslint-disable-next-line vue/no-side-effects-in-computed-properties
150 152 errorFlag.value = false
151 153 return toString(res)
... ...
... ... @@ -3,7 +3,7 @@ import { ref, computed, onBeforeUnmount, watchEffect, toRaw, unref } from 'vue'
3 3 import { icon } from '@/plugins'
4 4 import { useDesignStore } from '@/store/modules/designStore/designStore'
5 5 import { SettingItemBox } from '@/components/Pages/ChartItemSetting'
6   -import { RequestDataTypeEnum } from '@/enums/external/httpEnum'
  6 +import { RequestContentTypeEnum, RequestDataTypeEnum } from '@/enums/external/httpEnum'
7 7 import { ChartDataMatchingAndShow } from '../../../external/components/ChartDataMatchingAndShow'
8 8 import { newFunctionHandle } from '@/utils'
9 9 import { useTargetData } from '../../../../hooks/useTargetData.hook'
... ... @@ -11,6 +11,9 @@ import { NButton, NSelect, NTooltip, NIcon, SelectOption } from 'naive-ui'
11 11 import { RequestInfoPanel } from '../RequestInfoPanel'
12 12 import { RequestModal } from '../RequestModal'
13 13 import { customRequest } from '@/api/external/customRequest'
  14 +import { useChartDataSocket } from '@/hooks/external/useChartDataSocket'
  15 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  16 +import { CreateComponentType } from '@/packages/index.d'
14 17
15 18 const { HelpOutlineIcon, FlashIcon } = icon.ionicons5
16 19 const { targetData } = useTargetData()
... ... @@ -39,14 +42,19 @@ const showMatching = ref(false)
39 42 let firstFocus = 0
40 43 let lastFilter: any = undefined
41 44
  45 +const { sendMessage } = useChartDataSocket()
  46 +
42 47 // 发送请求
43 48 const sendHandle = async () => {
44 49 if (!targetData.value?.request) return
45   -
46 50 loading.value = true
47 51 try {
48   - console.log('enter')
49   - const res = await customRequest(toRaw(targetData.value.request))
  52 +
  53 + const isSocketType = (targetData.value.request.requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET
  54 + const res = isSocketType
  55 + ? await sendMessage(targetData.value as CreateComponentType)
  56 + : await customRequest(toRaw(targetData.value.request))
  57 +
50 58 loading.value = false
51 59 if (res) {
52 60 targetData.value.option.dataset = newFunctionHandle(res, res, targetData.value.filter)
... ...
... ... @@ -6,13 +6,14 @@ import { RequestContentTypeEnum, RequestContentTypeNameEnum } from '@/enums/exte
6 6 import { RequestBodyEnum, RequestHttpEnum, RequestHttpIntervalEnum, RequestParams, RequestParamsTypeEnum } from '@/enums/httpEnum';
7 7 import { RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d';
8 8 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
9   -import { NForm, NCard, NDatePicker, NEmpty, NFormItem, NInput, NInputGroup, NInputNumber, NScrollbar, NSelect, NSpin, NTabPane, NTabs, NTreeSelect, SelectOption, FormInst, NButton, FormItemInst } from 'naive-ui';
  9 +import { NForm, NCard, NDatePicker, NEmpty, NFormItem, NInput, NInputGroup, NInputNumber, NScrollbar, NSelect, NSpin, NTabPane, NTabs, NTreeSelect, SelectOption, FormInst, NButton, FormItemInst, NText, NSpace, NTag } from 'naive-ui';
10 10 import { ref, reactive, onMounted, computed, unref } from 'vue'
11 11 import { selectTimeOptions, selectTypeOptions } from '../../../index.d';
12 12 import ParamsTable from '../RequestModal/ParamsTable.vue';
13 13 import RequestBody from '../RequestModal/RequestBody.vue';
14 14 import { ComponentType, useDynamicPublicForm } from './useDynamicPublicForm';
15 15 import { transferData } from './utils';
  16 +import { MonacoEditor } from '@/components/Pages/MonacoEditor';
16 17
17 18 const componentMap: { [key in ComponentType]?: any } = {
18 19 [ComponentType.SELECT_TREE]: NTreeSelect,
... ... @@ -154,15 +155,17 @@ onMounted(() => {
154 155 :name="RequestContentTypeEnum.WEB_SOCKET" :tab="getGetRequestTypeName(RequestContentTypeEnum.WEB_SOCKET)" />
155 156 </NTabs>
156 157 </SettingItemBox>
157   - <SettingItemBox>
  158 +
  159 + <SettingItemBox v-if="requestContentTypeRef === RequestContentTypeEnum.DEFAULT">
158 160 <NTabs v-model:value="requestParamsTypeRef" :default-value="RequestParamsTypeEnum.PARAMS">
159 161 <NTabPane v-for="item in RequestParamsTypeEnum" :name="item" :key="item"></NTabPane>
160 162 </NTabs>
161 163 </SettingItemBox>
162 164
163   - <SettingItemBox :item-right-style="{ gridTemplateColumns: '3fr 2fr' }">
  165 + <SettingItemBox v-if="requestContentTypeRef === RequestContentTypeEnum.DEFAULT"
  166 + :item-right-style="{ gridTemplateColumns: '7fr 1fr' }">
164 167 <NCard v-if="requestParamsTypeRef === RequestParamsTypeEnum.PARAMS" class="dynamic-form">
165   - <NScrollbar style="max-height: 400px; padding: 0 10px; box-sizing: border-box;;">
  168 + <NScrollbar style="max-height: 400px; box-sizing: border-box;">
166 169 <NForm>
167 170 <template v-for="item in getDynamicFormSchemas" :key="item.key">
168 171 <NFormItem ref="dynamicFormItemEl" :required="item.required" :label="item.name" :rule="item.rules">
... ... @@ -174,6 +177,23 @@ onMounted(() => {
174 177 </NScrollbar>
175 178 </NCard>
176 179
  180 + <!-- <section v-if="requestParamsTypeRef === RequestParamsTypeEnum.PARAMS">
  181 + <NCard>
  182 + <NSpace vertical>
  183 + <NTag type="info">
  184 + <span class="func-keyword">function</span>&nbsp;&nbsp;filter(res)&nbsp;&nbsp;{
  185 + </NTag>
  186 + <MonacoEditor v-model:modelValue="filter" width="380px" height="300px" language="javascript" />
  187 + <NTag type="info">}</NTag>
  188 + </NSpace>
  189 + </NCard>
  190 + <NCard style="margin-top: 20px;">
  191 + <NText>转换结果:</NText>
  192 + <section>
  193 + <NText>{{ params }}</NText>
  194 + </section>
  195 + </NCard>
  196 + </section> -->
177 197
178 198 <RequestBody v-if="requestParamsTypeRef === RequestParamsTypeEnum.BODY"
179 199 v-model:request-params-body-type="requestParamsBodyTypeRef" v-model:value="requestParams" />
... ... @@ -181,6 +201,21 @@ onMounted(() => {
181 201 <ParamsTable v-if="requestParamsTypeRef === RequestParamsTypeEnum.HEADER" v-model:value="headerRef" />
182 202
183 203 </SettingItemBox>
  204 +
  205 + <SettingItemBox v-if="requestContentTypeRef === RequestContentTypeEnum.WEB_SOCKET">
  206 + <NCard v-if="requestParamsTypeRef === RequestParamsTypeEnum.PARAMS" class="dynamic-form">
  207 + <NScrollbar style="max-height: 400px; box-sizing: border-box;">
  208 + <NForm>
  209 + <template v-for="item in getDynamicFormSchemas" :key="item.key">
  210 + <NFormItem ref="dynamicFormItemEl" :required="item.required" :label="item.name" :rule="item.rules">
  211 + <component :is="componentMap[item.component]" v-bind="item.props" clearable />
  212 + </NFormItem>
  213 + </template>
  214 + </NForm>
  215 + <NEmpty v-if="!selectedPublicInterface || !getDynamicFormSchemas.length" description="请选择公共接口" />
  216 + </NScrollbar>
  217 + </NCard>
  218 + </SettingItemBox>
184 219 </template>
185 220
186 221 <style scoped lang="scss">
... ...
... ... @@ -4,7 +4,7 @@ import { getDeviceAttrList, getDeviceList, getDeviceProfileList, getOrgList } fr
4 4 import { PublicInterfaceRecord, RequestParams } from "@/api/external/dynamicRequest/model"
5 5 import { RequestConfigType } from "@/store/modules/chartEditStore/chartEditStore.d"
6 6 import { DatePickerProps, FormItemRule, InputProps, SelectProps, TreeSelectProps } from "naive-ui"
7   -import { computed, onMounted, reactive, Ref, ref, unref } from "vue"
  7 +import { computed, onMounted, reactive, Ref, ref, unref, watch } from "vue"
8 8 import { DictEnum } from '@/enums/external/dictEnum'
9 9
10 10 const GROUP_SEPARATOR = ','
... ... @@ -24,6 +24,7 @@ export enum ComponentType {
24 24 INPUT = 'input'
25 25 }
26 26
  27 +
27 28 export interface DynamicFormSchema {
28 29 key: string
29 30 name?: string
... ... @@ -35,6 +36,7 @@ export interface DynamicFormSchema {
35 36
36 37 export type BuiltInVariableRecord = { [key in BuiltInVariable]: DictItem }
37 38
  39 +
38 40 export const useDynamicPublicForm = (publicInterfaceRef: Ref<PublicInterfaceRecord>) => {
39 41
40 42 const getParams = computed(() => {
... ... @@ -45,7 +47,7 @@ export const useDynamicPublicForm = (publicInterfaceRef: Ref<PublicInterfaceReco
45 47
46 48 const getUsedBuiltInVariable = computed(() => {
47 49 const hasUsed = unref(getParams).reduce((prev, next) => {
48   - const groupList = next.key.split(GROUP_SEPARATOR)
  50 + const groupList = (next.key || '').split(GROUP_SEPARATOR)
49 51 return [...prev, ...(groupList.length > 1 ? groupList : [next.key])]
50 52 }, [] as string[])
51 53 return hasUsed
... ... @@ -149,7 +151,7 @@ export const useDynamicPublicForm = (publicInterfaceRef: Ref<PublicInterfaceReco
149 151 value: params[BuiltInVariable.ENTITY_ID],
150 152 options: unref(optionsSet[BuiltInVariable.ENTITY_ID]),
151 153 labelField: 'name',
152   - valueField: 'id',
  154 + valueField: 'tbDeviceId',
153 155 onUpdateValue(value) {
154 156 params[BuiltInVariable.ENTITY_ID] = value
155 157 }
... ... @@ -177,7 +179,10 @@ export const useDynamicPublicForm = (publicInterfaceRef: Ref<PublicInterfaceReco
177 179 clearable: true,
178 180 defaultTime: ['00:00:00', '00:00:00'],
179 181 onUpdateValue(value) {
180   - params[BuiltInVariable.DATE] = value
  182 + // params[BuiltInVariable.DATE] = value
  183 + params.startTs = value[0]
  184 + params.endTs = value[1]
  185 + console.log(params)
181 186 }
182 187 } as DatePickerProps
183 188 })
... ... @@ -236,7 +241,7 @@ export const useDynamicPublicForm = (publicInterfaceRef: Ref<PublicInterfaceReco
236 241 }
237 242
238 243 const toFormSchemas = (builtInVariableKey: string, required: boolean, value: any) => {
239   - const groupList = builtInVariableKey.split(GROUP_SEPARATOR)
  244 + const groupList = (builtInVariableKey || '').split(GROUP_SEPARATOR)
240 245 return groupList.reduce((prev, next) => {
241 246 const result = builtInVariableConfiguration[next as BuiltInVariable]
242 247 const props = unref(result?.props)
... ... @@ -283,9 +288,13 @@ export const useDynamicPublicForm = (publicInterfaceRef: Ref<PublicInterfaceReco
283 288
284 289 const setParams = (Params: Recordable) => {
285 290 unref(getParams).forEach(({ key, value }) => {
286   - if (unref(getUsedBuiltInVariable).includes(key)) {
287   - params[key] = Params[key]
288   - }
  291 + const splitKeys = key.split(GROUP_SEPARATOR)
  292 + splitKeys.forEach(temp => {
  293 + if (unref(getUsedBuiltInVariable).includes(temp)) {
  294 + params[temp] = Params[temp]
  295 + }
  296 + })
  297 +
289 298 params[value] = Params[value]
290 299 })
291 300 }
... ...
... ... @@ -3,9 +3,10 @@ import { toRefs, computed } from 'vue'
3 3 import { icon } from '@/plugins'
4 4 import { useDesignStore } from '@/store/modules/designStore/designStore'
5 5 import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
6   -import { SelectHttpTimeNameObj, RequestContentTypeEnum } from '@/enums/httpEnum'
  6 +import { SelectHttpTimeNameObj } from '@/enums/httpEnum'
7 7 import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
8 8 import { NButton, NCard, NTag, NInput, NIcon } from 'naive-ui'
  9 +import { RequestContentTypeNameEnum, RequestContentTypeEnum } from '@/enums/external/httpEnum'
9 10
10 11 const emit = defineEmits(['clickPanel'])
11 12
... ... @@ -25,6 +26,10 @@ const requestModelHandle = () => {
25 26 emit('clickPanel')
26 27 }
27 28
  29 +const getContentName = (contentType: RequestContentTypeEnum) => {
  30 + return RequestContentTypeNameEnum[RequestContentTypeEnum[contentType] as unknown as keyof typeof RequestContentTypeEnum]
  31 +}
  32 +
28 33 // 颜色
29 34 const themeColor = computed(() => {
30 35 return designStore.getAppTheme
... ... @@ -37,7 +42,7 @@ const themeColor = computed(() => {
37 42 <SettingItemBox name="请求配置">
38 43 <SettingItem name="类型">
39 44 <NTag :bordered="false" type="primary" style="border-radius: 5px">
40   - {{ targetData.request.requestContentType === RequestContentTypeEnum.DEFAULT ? '普通请求' : 'SQL请求' }}
  45 + {{ getContentName(targetData.request.requestContentType) }}
41 46 </NTag>
42 47 </SettingItem>
43 48
... ...
... ... @@ -74,8 +74,7 @@ const getResult = () => {
74 74
75 75 const handleSaveAction = async () => {
76 76 if (!(await validate())) return
77   - const value = getResult()
78   - console.log(value)
  77 + const value = getResult()
79 78 if (unref(selectTarget)) {
80 79 chartEditStore.updateComponentList(chartEditStore.fetchTargetIndex(), {
81 80 ...unref(selectTarget)!,
... ...
1 1 import { fetchRouteParamsLocation, JSONStringify, JSONParse } from '@/utils'
2 2 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
3   -import { ProjectInfoEnum } from '@/store/external/module/projectInfo.d'
  3 +import { ProjectInfoEnum } from '@/store/external/modules/projectInfo.d'
4 4 import { onUnmounted } from 'vue'
5 5 import { saveInterval } from '@/settings/designSetting'
6 6 import throttle from 'lodash/throttle'
... ... @@ -8,7 +8,7 @@ import html2canvas from 'html2canvas'
8 8 import { saveDataViewList, contentUpdateApi, getDataView, uploadFile } from '@/api/external/contentSave/content'
9 9 // 画布枚举
10 10 import { SyncEnum } from '@/enums/external/editPageEnum'
11   -import { useProjectInfoStore } from '@/store/external/module/projectInfo'
  11 +import { useProjectInfoStore } from '@/store/external/modules/projectInfo'
12 12 import { useSync } from '../useSync.hook'
13 13 import { BaseUpdateContentParams } from '@/api/external/contentSave/model/contentModel'
14 14
... ...
1 1 import { PageEnum } from "@/enums/pageEnum"
2   -import { useUserStore } from "@/store/external/module/user"
  2 +import { useUserStore } from "@/store/external/modules/user"
3 3 import { cryptoEncode, routerTurnByName, setLocalStorage } from "@/utils"
4 4 import { to } from "@/utils/external/to"
5 5 import { StorageEnum } from '@/enums/storageEnum'
... ...