Commit 3e2f9d0a2f6eab12f274fb8489dcb251c3a4a8b9
Merge branch 'ww' into 'main_dev'
feat(request): 新增socket请求方式 See merge request yunteng/thingskit-view!21
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 | // 单位 | ... | ... |
src/hooks/external/useChartDataSocket.ts
0 → 100644
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 | +} | ... | ... |
src/hooks/external/useFilterFn.ts
0 → 100644
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 | ... | ... |
src/store/external/module/dynamicRequest.d.ts
deleted
100644 → 0
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 | -} |
src/store/external/module/dynamicRequest.ts
deleted
100644 → 0
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
src/store/external/modules/socketStore.d.ts
0 → 100644
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 | +} | ... | ... |
src/store/external/modules/socketStore.ts
0 → 100644
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 | ... | ... |
... | ... | @@ -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> filter(res) { | |
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' | ... | ... |