Commit e1fe720c27de33a26dcad8ec22ca2cc7225a5f8b

Authored by xp.Huang
2 parents 30a3cf57 08ab7d72

Merge branch 'main_dev'

# Conflicts:
#	src/api/external/customRequest/index.ts
#	src/api/external/dynamicRequest/index.ts
#	src/api/external/dynamicRequest/model/index.ts
#	src/api/external/sys/share.ts
#	src/hooks/external/useChartDataSocket.ts
#	src/hooks/external/useFetchTargetData.ts
#	src/packages/components/external/Composes/HeadCombinations/LeftCenterRightHead/index.vue
#	src/packages/components/external/Composes/HeadCombinations/LeftCenterRightHeadAnimat/index.vue
#	src/packages/components/external/Composes/Mores/Camera/cameraItem.vue
#	src/packages/components/external/Composes/Mores/Camera/config.ts
#	src/packages/components/external/Composes/Mores/Camera/index.vue
#	src/packages/components/external/Composes/Mores/Title1/config.ts
#	src/packages/components/external/Composes/Mores/Title1/config.vue
#	src/packages/components/external/Composes/Mores/Title1/index.vue
#	src/packages/components/external/Composes/Mores/Title2/config.ts
#	src/packages/components/external/Composes/Mores/Title2/config.vue
#	src/packages/components/external/Composes/Mores/Title2/index.vue
#	src/packages/components/external/Composes/Mores/Title3/config.ts
#	src/packages/components/external/Composes/Mores/Title3/config.vue
#	src/packages/components/external/Composes/Mores/Title3/index.vue
#	src/store/external/modules/socketStore.ts
#	src/views/chart/ContentConfigurations/components/ChartData/external/components/ChartDynamicRequest/index.vue
#	src/views/chart/ContentConfigurations/components/ChartData/external/components/DynamicForm/index.vue
#	src/views/chart/ContentConfigurations/components/ChartData/external/components/DynamicForm/useDynamicPublicForm.ts
#	src/views/chart/ContentConfigurations/components/ChartData/external/components/PublicInterfaceForm/index.vue
#	src/views/chart/ContentConfigurations/components/ChartData/external/components/RequestModal/index.vue
#	src/views/chart/ContentHeader/headerLeftBtn/external/index.vue
#	src/views/chart/hooks/external/useRemote.hook.ts
#	src/views/share/index.vue
Showing 53 changed files with 1222 additions and 238 deletions
  1 +import type { ErrorMessageMode } from '/#/external/axios';
  2 +
  3 +export function checkStatus(
  4 + status: number,
  5 + msg: string,
  6 + errorMessageMode: ErrorMessageMode = 'message'
  7 +) {
  8 + let errMessage = msg;
  9 + switch (status) {
  10 + case 400:
  11 + errMessage = `${msg}`;
  12 + break;
  13 + // 401: Not logged in
  14 + // Jump to the login page if not logged in, and carry the path of the current page
  15 + // Return to the current page after successful login. This step needs to be operated on the login page.
  16 + case 401:
  17 + errMessage = '没有权限';
  18 + break;
  19 + case 403:
  20 + errMessage = '未授权';
  21 + break;
  22 + // 404请求不存在
  23 + case 404:
  24 + errMessage = '未找到该资源!';
  25 + break;
  26 + case 405:
  27 + errMessage = '网络请求错误,请求方法未允许!';
  28 + break;
  29 + case 408:
  30 + errMessage = '网络请求超时!';
  31 + break;
  32 + case 500:
  33 + errMessage = '服务器错误,请联系管理员!';
  34 + break;
  35 + case 501:
  36 + errMessage = '网络未实现!';
  37 + break;
  38 + case 502:
  39 + errMessage = '网络错误!';
  40 + break;
  41 + case 503:
  42 + errMessage = '服务不可用,服务器暂时过载或维护!';
  43 + break;
  44 + case 504:
  45 + errMessage = '网络超时!';
  46 + break;
  47 + case 505:
  48 + errMessage = 'http版本不支持该请求!';
  49 + break;
  50 + default:
  51 + }
  52 +
  53 + if (errMessage) {
  54 + if (errorMessageMode === 'message') {
  55 + const { error } = window['$message']
  56 + error(errMessage);
  57 + }
  58 + }
  59 + return !!errMessage
  60 +}
... ...
  1 +import type { AxiosResponse } from 'axios';
  2 +import type { RequestOptions, Result } from '/#/external/axios';
  3 +import type { AxiosTransform, CreateAxiosOptions } from '@/utils/external/http/axios/axiosTransform';
  4 +import { useGlobSetting } from '@/hooks/external/setting';
  5 +import { RequestEnum, ContentTypeEnum } from '@/enums/external/httpEnum';
  6 +import { isString } from '@/utils/external/is';
  7 +import { getJwtToken, getShareJwtToken } from '@/utils/external/auth';
  8 +import { setObjToUrlParams, deepMerge } from '@/utils/external';
  9 +import { formatRequestDate, joinTimestamp } from '@/utils/external/http/axios/helper';
  10 +import { VAxios } from '@/utils/external/http/axios/Axios';
  11 +import { checkStatus } from './checkStatus';
  12 +
  13 +const globSetting = useGlobSetting();
  14 +const urlPrefix = globSetting.urlPrefix;
  15 +
  16 +/**
  17 + * @description: 数据处理,方便区分多种处理方式
  18 + */
  19 +const transform: AxiosTransform = {
  20 + /**
  21 + * @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误
  22 + */
  23 + transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
  24 + const { isReturnNativeResponse } = options;
  25 + // 是否返回原生响应头 比如:需要获取响应头时使用该属性
  26 + if (isReturnNativeResponse) {
  27 + return res;
  28 + }
  29 + return res.data;
  30 + },
  31 +
  32 + // 请求之前处理config
  33 + beforeRequestHook: (config, options) => {
  34 + const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options;
  35 +
  36 + if (joinPrefix) {
  37 + config.url = `${urlPrefix}${config.url}`;
  38 + }
  39 +
  40 + if (apiUrl && isString(apiUrl)) {
  41 + config.url = `${apiUrl}${config.url}`;
  42 + }
  43 +
  44 + const params = config.params || {};
  45 + const data = config.data || false;
  46 + formatDate && data && !isString(data) && formatRequestDate(data);
  47 + if (config.method?.toUpperCase() === RequestEnum.GET) {
  48 + if (!isString(params)) {
  49 + // 给 get 请求加上时间戳参数,避免从缓存中拿数据。
  50 + config.params = Object.assign(params || {}, joinTimestamp(joinTime, false));
  51 + } else {
  52 + // 兼容restful风格
  53 + config.url = config.url + params + `${joinTimestamp(joinTime, true)}`;
  54 + config.params = undefined;
  55 + }
  56 + } else {
  57 + if (!isString(params)) {
  58 + formatDate && formatRequestDate(params);
  59 + if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) {
  60 + config.data = data;
  61 + config.params = params;
  62 + } else {
  63 + // 非GET请求如果没有提供data,则将params视为data
  64 + config.data = params;
  65 + config.params = undefined;
  66 + }
  67 + if (joinParamsToUrl) {
  68 + config.url = setObjToUrlParams(
  69 + config.url as string,
  70 + Object.assign({}, config.params, config.data)
  71 + );
  72 + }
  73 + } else {
  74 + // 兼容restful风格
  75 + config.url = config.url + params;
  76 + config.params = undefined;
  77 + }
  78 + }
  79 + return config;
  80 + },
  81 +
  82 + /**
  83 + * @description: 请求拦截器处理
  84 + */
  85 + requestInterceptors: (config, options) => {
  86 + // 请求之前处理config
  87 + const { requestOptions } = config;
  88 + const { withShareToken } = requestOptions || {};
  89 + const { requestOptions: { withToken } = {} } = options;
  90 + if (withToken !== false) {
  91 + const shareToken = getShareJwtToken();
  92 + if (withShareToken && shareToken) {
  93 + config.headers!['X-Authorization'] = options.authenticationScheme
  94 + ? `${options.authenticationScheme} ${shareToken}`
  95 + : shareToken;
  96 + } else {
  97 + const token = getJwtToken();
  98 + if (token) {
  99 + config.headers!['X-Authorization'] = options.authenticationScheme
  100 + ? `${options.authenticationScheme} ${token}`
  101 + : token;
  102 + }
  103 + }
  104 + }
  105 + return config
  106 + },
  107 +
  108 + /**
  109 + * @description: 响应拦截器处理
  110 + */
  111 + responseInterceptors: (res: AxiosResponse<any>) => {
  112 + return res;
  113 + },
  114 +
  115 + /**
  116 + * @description: 响应错误处理
  117 + */
  118 + responseInterceptorsCatch: (error: any) => {
  119 +
  120 + const { response, config } = error || {};
  121 + const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none';
  122 + const errorMsgIsObj = typeof response?.data === 'object';
  123 + const msg: string = errorMsgIsObj
  124 + ? response?.data?.message || response?.data?.msg
  125 + : response?.data;
  126 +
  127 + const flag = checkStatus(error?.response?.status, msg, errorMessageMode);
  128 + return Promise.reject(response?.data);
  129 + },
  130 +};
  131 +
  132 +function createAxios(opt?: Partial<CreateAxiosOptions>) {
  133 + return new VAxios(
  134 + deepMerge(
  135 + {
  136 + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
  137 + // authentication schemes,e.g: Bearer
  138 + // authenticationScheme: 'Bearer',
  139 + authenticationScheme: 'Bearer',
  140 + timeout: 10 * 1000,
  141 + // 基础接口地址
  142 + // baseURL: globSetting.apiUrl,
  143 + // 接口可能会有通用的地址部分,可以统一抽取出来
  144 + urlPrefix: urlPrefix,
  145 + headers: { 'Content-Type': ContentTypeEnum.JSON },
  146 + // 如果是form-data格式
  147 + // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
  148 + // 数据处理方式
  149 + transform,
  150 + // 配置项,下面的选项都可以在独立的接口请求中覆盖
  151 + requestOptions: {
  152 + // 默认将prefix 添加到url
  153 + joinPrefix: true,
  154 + // 是否返回原生响应头 比如:需要获取响应头时使用该属性
  155 + isReturnNativeResponse: false,
  156 + // 需要对返回数据进行处理
  157 + isTransformResponse: true,
  158 + // post请求的时候添加参数到url
  159 + joinParamsToUrl: false,
  160 + // 格式化提交参数时间
  161 + formatDate: true,
  162 + // 消息提示类型
  163 + errorMessageMode: 'message',
  164 + // 接口地址
  165 + apiUrl: globSetting.apiUrl,
  166 + // 是否加入时间戳
  167 + joinTime: true,
  168 + // 忽略重复请求
  169 + ignoreCancelToken: true,
  170 + // 是否携带token
  171 + withToken: true
  172 + },
  173 + },
  174 + opt || {}
  175 + )
  176 + );
  177 +}
  178 +export const customHttp = createAxios();
  179 +
... ...
1 1 import { RequestBodyEnum, RequestParams } from "@/enums/httpEnum"
2   -import { ExternalRequestType, ExtraRequestConfigType } from "@/store/external/modules/extraComponentInfo.d"
3   -import { RequestConfigType, RequestGlobalConfigType } from "@/store/modules/chartEditStore/chartEditStore.d"
4   -import { defHttp } from "@/utils/external/http/axios"
  2 +import { ExtraRequestConfigType } from "@/store/external/modules/extraComponentInfo.d"
  3 +import { RequestConfigType } from "@/store/modules/chartEditStore/chartEditStore.d"
  4 +import { isShareMode } from "@/views/share/hook"
  5 +import { customHttp } from "./http"
  6 +import { SelectTimeAggregationFieldEnum } from "@/views/chart/ContentConfigurations/components/ChartData/external/components/SelectTImeAggregation"
5 7
6 8 export enum ParamsType {
7 9 REQUIRED,
... ... @@ -86,10 +88,25 @@ const transformBodyValue = (body: RequestParams['Body'], requestParamsBodyType:
86 88
87 89 const extraValue = (object: Recordable) => {
88 90 return Object.keys(object).reduce((prev, next) => {
89   - return {...prev, ...(object[next] ? {[next]: object[next]} : {} )}
  91 + return { ...prev, ...(object[next] ? { [next]: object[next] } : {}) }
90 92 }, {})
91 93 }
92 94
  95 +const handleParams = (Params: Recordable) => {
  96 + if (Params.keys && Params?.keys?.length) {
  97 + Params.keys = (Params.keys || [] as any).join(',')
  98 + }
  99 +
  100 + const timePeriod = Params[SelectTimeAggregationFieldEnum.TIME_PERIOD]
  101 + if (timePeriod) {
  102 + Params.startTs = Date.now() - timePeriod
  103 + Params.endTs = Date.now()
  104 + Reflect.deleteProperty(Params, SelectTimeAggregationFieldEnum.TIME_PERIOD)
  105 + }
  106 +
  107 + return Object.keys(Params).filter(Boolean).reduce((prev, next) => ({ ...prev, [next]: Params[next] }), {})
  108 +}
  109 +
93 110 export const customRequest = async (request: RequestConfigType) => {
94 111 const { requestHttpType, requestParams, requestParamsBodyType, requestOriginUrl } = request as ExtraRequestConfigType
95 112 let { requestUrl } = request as ExtraRequestConfigType
... ... @@ -104,7 +121,8 @@ export const customRequest = async (request: RequestConfigType) => {
104 121
105 122 const body = transformBodyValue(Body, requestParamsBodyType)
106 123
107   - return defHttp.request<any>({
  124 + Params = handleParams(Params)
  125 + return customHttp.request<any>({
108 126 url: requestUrl,
109 127 baseURL: getOriginUrl(requestOriginUrl!),
110 128 method: requestHttpType,
... ... @@ -113,6 +131,7 @@ export const customRequest = async (request: RequestConfigType) => {
113 131 headers: extraValue(Header)
114 132 }, {
115 133 joinPrefix: false,
116   - apiUrl: ''
  134 + apiUrl: '',
  135 + withShareToken: isShareMode()
117 136 })
118 137 }
... ...
... ... @@ -2,13 +2,20 @@ import { defHttp } from '@/utils/external/http/axios';
2 2 import { DeviceAttributesRecord, GetDeviceListParams, PublicInterfaceRecord, PublicInterfaceStateEnum } from './model';
3 3 import { PaginationResult } from '/#/external/axios';
4 4
5   -enum Api {
6   - PUBLIC_API = '/data_view_interface',
7   - ORG_LISt = '/organization/me/list',
8   - DEVICE_PROFILE_LIST = '/device_profile/me/list',
9   - DEVICE_LIST = '/device/list',
10   - DEVICE_ATTR_LIST = '/device/attributes',
11   - GET_PUBLIC_INTERFACE_ALL = '/data_view_interface/find_all_interface',
  5 + /**
  6 + * ft 更换接口
  7 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  8 + * 源代码 GET_PUBLIC_INTERFACE_ALL = '/data_view_interface/find_all_interface',
  9 + * 修改后代码 GET_PUBLIC_INTERFACE_ALL = '/data_view_interface/find/can_use_interfaces',
  10 + */
  11 + enum Api {
  12 + PUBLIC_API = '/data_view_interface',
  13 + ORG_LISt = '/organization/me/list',
  14 + DEVICE_PROFILE_LIST = '/device_profile/me/list',
  15 + DEVICE_LIST = '/device/list',
  16 + DEVICE_ATTR_LIST = '/device/attributes',
  17 + GET_PUBLIC_INTERFACE_ALL = '/data_view_interface/find/can_use_interfaces',
  18 + //ft
12 19 GET_PUBLIC_INTERFACE_DETAIL = '/data_view_interface/get_interface_details'
13 20 }
14 21
... ... @@ -52,9 +59,15 @@ export const getDeviceInterfaceDetail = async (interfaces: string[]) => {
52 59 params: interfaces
53 60 })
54 61 }
55   -
56   -export const getAllPublicInterface = async (params?: { state: PublicInterfaceStateEnum }) => {
  62 + /**
  63 + * ft 更换接口
  64 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  65 + * 源代码 url: `${Api.GET_PUBLIC_INTERFACE_ALL}${params?.state ? `/${params.state}` : ''}`
  66 + * 修改后代码 url: `${Api.GET_PUBLIC_INTERFACE_ALL}`
  67 + */
  68 +export const getAllPublicInterface = async () => {
57 69 return defHttp.get<PublicInterfaceRecord[]>({
58   - url: `${Api.GET_PUBLIC_INTERFACE_ALL}${params?.state ? `/${params.state}` : ''}`
  70 + url: `${Api.GET_PUBLIC_INTERFACE_ALL}`
59 71 })
60 72 }
  73 +//ft
\ No newline at end of file
... ...
... ... @@ -9,6 +9,7 @@ export interface ParamsItemType {
9 9 key: string
10 10 required: boolean
11 11 value: string
  12 + mores: boolean
12 13 }
13 14
14 15 export interface PublicInterfaceRequestParams {
... ...
1 1 import { ViewTypeEnum } from "@/enums/external/viewEnum"
2 2 import { defHttp } from "@/utils/external/http/axios"
  3 +import { isShareMode } from "@/views/share/hook"
3 4
4 5 enum Api {
5 6 TOKEN = '/auth/login/public',
... ... @@ -17,7 +18,7 @@ export const getPublicToken = (publicId: string) => {
17 18 return defHttp.post<Record<'token' | 'refreshToken', string>>({
18 19 url: Api.TOKEN,
19 20 data: { publicId }
20   - }, { joinPrefix: false })
  21 + }, { joinPrefix: false, withShareToken: isShareMode() })
21 22 }
22 23
23 24 /**
... ... @@ -27,7 +28,7 @@ export const getPublicToken = (publicId: string) => {
27 28 export const checkSharePageNeedAccessToken = (id: string) => {
28 29 return defHttp.get<{ data: boolean }>({
29 30 url: `${Api.CHECK}/${ViewTypeEnum.LARGE_SCREEN}/${id}`
30   - })
  31 + }, { withShareToken: isShareMode() })
31 32 }
32 33
33 34 /**
... ... @@ -39,5 +40,5 @@ export const getShareContentData = (options: Record<'id' | 'accessCredentials',
39 40 return defHttp.get<{ data: any }>({
40 41 url: `${Api.SHARE_CONTENT}/${ViewTypeEnum.LARGE_SCREEN}/share_data/${options.id}`,
41 42 params: accessCredentials ? { accessCredentials } : {}
42   - })
  43 + }, { withShareToken: isShareMode() })
43 44 }
... ...
... ... @@ -5,6 +5,10 @@ export const JWT_TOKEN_KEY = 'JWT_TOKEN';
5 5
6 6 export const REFRESH_TOKEN_KEY = 'REFRESH_TOKEN';
7 7
  8 +export const SHARE_JWT_TOKEN_KEY = 'SHARE_JWT_TOKEN';
  9 +
  10 +export const SHARE_REFRESH_TOKEN_KEY = 'SHARE_REFRESH_TOKEN';
  11 +
8 12 export const LOCALE_KEY = 'LOCALE__';
9 13
10 14 // user info key
... ...
... ... @@ -3,10 +3,11 @@ import { CreateComponentType } from "@/packages/index.d";
3 3 import { useSocketStore } from "@/store/external/modules/socketStore";
4 4 import { SocketReceiveMessageType } from "@/store/external/modules/socketStore.d";
5 5 import { useChartEditStore } from "@/store/modules/chartEditStore/chartEditStore";
6   -import { getJwtToken } from "@/utils/external/auth";
  6 +import { getJwtToken, getShareJwtToken } from "@/utils/external/auth";
7 7 import { useWebSocket, WebSocketResult } from "@vueuse/core";
8 8 import { onMounted, unref } from "vue";
9 9 import { ExtraRequestConfigType } from "@/store/external/modules/extraComponentInfo.d";
  10 +import { isShareMode } from "@/views/share/hook";
10 11
11 12
12 13 interface SocketConnectionPoolType {
... ... @@ -39,7 +40,7 @@ const getSocketInstance = (request: ExtraRequestConfigType) => {
39 40 if (~index) {
40 41 return socketConnectionPool[index].ws
41 42 }
42   - const token = getJwtToken()
  43 + const token = isShareMode() ? getShareJwtToken() : getJwtToken()
43 44 const socketUrl = `${getOriginUrl(requestOriginUrl || '')}${requestUrl}?token=${token}`
44 45
45 46 const instance = useWebSocket(socketUrl, {
... ...
... ... @@ -26,7 +26,7 @@ export const useFetchTargetData = () => {
26 26 } catch (error) {
27 27 loading.value = false
28 28 console.error(error);
29   - window['$message'].warning('数据异常,请检查参数!')
  29 + // window['$message'].warning('数据异常,请检查参数!')
30 30 }
31 31 }
32 32 return { fetchTargetData, loading }
... ...
... ... @@ -6,7 +6,7 @@ import cloneDeep from 'lodash/cloneDeep'
6 6
7 7 export const option = {
8 8 // 网站路径
9   - dataset: "https://www.mtruning.club/",
  9 + dataset: "https://www.thingskit.com/",
10 10 // 圆角
11 11 borderRadius: 10
12 12 }
... ...
... ... @@ -2,6 +2,7 @@ import { PublicConfigClass } from '@/packages/public'
2 2 import { CreateComponentType } from '@/packages/index.d'
3 3 import { LeftCenterRightHeadConfig } from './index'
4 4 import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
5 6
6 7 export const option = {
7 8 dataset: '物联网平台数据统计',
... ... @@ -20,6 +21,7 @@ export const option = {
20 21
21 22 export default class Config extends PublicConfigClass implements CreateComponentType {
22 23 public key = LeftCenterRightHeadConfig.key
  24 + public attr = { ...chartInitConfig, zIndex: 1, w: 1920, h: 100 }
23 25 public chartConfig = cloneDeep(LeftCenterRightHeadConfig)
24 26 public option = cloneDeep(option)
25 27 }
... ...
... ... @@ -59,6 +59,11 @@
59 59 <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.textColor"></n-color-picker>
60 60 </setting-item>
61 61 </setting-item-box>
  62 + <setting-item-box name="颜色">
  63 + <SettingItem>
  64 + <n-button size="small" @click="optionData.textColor = '#00f6ff'"> 恢复默认 </n-button>
  65 + </SettingItem>
  66 + </setting-item-box>
62 67 <setting-item-box name="位置x轴">
63 68 <setting-item name="字体位置x轴">
64 69 <n-input-number v-model:value="optionData.x" size="small" placeholder="字体位置"></n-input-number>
... ... @@ -96,6 +101,11 @@
96 101 <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.textRightSizeColor"></n-color-picker>
97 102 </setting-item>
98 103 </setting-item-box>
  104 + <setting-item-box name="颜色">
  105 + <SettingItem>
  106 + <n-button size="small" @click="optionData.textRightSizeColor = '#ffffff'"> 恢复默认 </n-button>
  107 + </SettingItem>
  108 + </setting-item-box>
99 109 </collapse-item>
100 110 </template>
101 111
... ...
... ... @@ -65,11 +65,8 @@ let nowData = ref('08:00:00')
65 65 let newData = ref('2021-2-3 08:00:00')
66 66
67 67 let timer: any = null
68   -const { w, h } = toRefs(props.chartConfig.attr)
69 68
70   -//修改默认宽高
71   -props.chartConfig.attr.w = 1920
72   -props.chartConfig.attr.h = 100
  69 +const { w, h } = toRefs(props.chartConfig.attr)
73 70
74 71 watch(
75 72 () => props.chartConfig.option,
... ...
... ... @@ -2,6 +2,7 @@ import { PublicConfigClass } from '@/packages/public'
2 2 import { CreateComponentType } from '@/packages/index.d'
3 3 import { LeftCenterRightHeadAnimatConfig } from './index'
4 4 import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
5 6
6 7 export const option = {
7 8 dataset: '我是标题',
... ... @@ -26,6 +27,7 @@ export const option = {
26 27
27 28 export default class Config extends PublicConfigClass implements CreateComponentType {
28 29 public key = LeftCenterRightHeadAnimatConfig.key
  30 + public attr = { ...chartInitConfig, zIndex: 1, w: 1920, h: 130 }
29 31 public chartConfig = cloneDeep(LeftCenterRightHeadAnimatConfig)
30 32 public option = cloneDeep(option)
31 33 }
... ...
... ... @@ -5,7 +5,7 @@
5 5 <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.animat.colors[index]"></n-color-picker>
6 6 </SettingItem>
7 7 <SettingItem>
8   - <n-button size="small" @click="optionData.animat.colors[index] = optionData.animat.colors[index]">
  8 + <n-button size="small" @click="optionData.animat.colors[index] = option.animat.colors[index]">
9 9 恢复默认
10 10 </n-button>
11 11 </SettingItem>
... ... @@ -47,6 +47,12 @@
47 47 <setting-item name="结束值">
48 48 <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.animat.gradient.to"></n-color-picker>
49 49 </setting-item>
  50 + <SettingItem>
  51 + <n-button size="small" @click="optionData.animat.gradient.from = '#0000FFFF'"> 恢复默认1 </n-button>
  52 + </SettingItem>
  53 + <SettingItem>
  54 + <n-button size="small" @click="optionData.animat.gradient.to = '#00FF00FF'"> 恢复默认2 </n-button>
  55 + </SettingItem>
50 56 <setting-item name="偏移角度">
51 57 <n-input-number
52 58 v-model:value="optionData.animat.gradient.deg"
... ...
... ... @@ -64,10 +64,6 @@ const props = defineProps({
64 64 }
65 65 })
66 66
67   -//修改默认宽高
68   -props.chartConfig.attr.w=1920
69   -props.chartConfig.attr.h=130
70   -
71 67 const { w, h } = toRefs(props.chartConfig.attr)
72 68
73 69 const { animat, dataset } = toRefs(props.chartConfig.option)
... ...
1 1 <template>
2 2 <div class="go-content-box" :style="{ width: w + 'px', height: h + 'px' }">
3   - <video :id="`my-player${index}`" ref="videoRef" class="video-js my-video vjs-theme-city vjs-big-play-centered">
  3 + <video
  4 + crossOrigin="anonymous"
  5 + :id="`my-player${index}`" ref="videoRef" class="video-js my-video vjs-theme-city vjs-big-play-centered">
4 6 <source :src="sourceSrc" />
5 7 </video>
6 8 </div>
... ... @@ -15,6 +17,12 @@ const props = defineProps({
15 17 sourceSrc: {
16 18 type: String
17 19 },
  20 + name: {
  21 + type: String
  22 + },
  23 + avatar: {
  24 + type: String
  25 + },
18 26 w: {
19 27 type: Number,
20 28 default: 300
... ... @@ -41,7 +49,8 @@ const options: VideoJsPlayerOptions = {
41 49 preload: 'auto', // 预加载
42 50 autoplay: true, // 是否自动播放
43 51 fluid: false, // 自适应宽高
44   - src: props.sourceSrc, // 要嵌入的视频源的源 URL
  52 + poster: props?.avatar || '',
  53 + src: props?.sourceSrc || '', // 要嵌入的视频源的源 URL
45 54 muted: true,
46 55 userActions: {
47 56 hotkeys: true
... ...
... ... @@ -6,29 +6,8 @@ import cloneDeep from 'lodash/cloneDeep'
6 6 export const option = {
7 7 dataset: [
8 8 {
9   - url: 'https://vcsplay.scjtonline.cn:8094/live/HD_664c01b9-4b67-11eb-bf78-3cd2e55e0a36.m3u8?auth_key=1681457689-0-0-a797d264f2889a388c52ff188fedf7dc'
  9 + url: ''
10 10 },
11   - {
12   - url: 'https://vcsplay.scjtonline.cn:8196/live/HD_c53fd3cb-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681457668-0-0-7ef56e21fddd9ffb9740cbe499a1824c'
13   - },
14   - {
15   - url: 'https://vcsplay.scjtonline.cn:8199/live/HD_53713154-1371-489a-a929-015cca5569fc.m3u8?auth_key=1681441451-0-0-4f1ebdcf28a71b7631c0028c099923c9'
16   - },
17   - {
18   - url: 'https://vcsplay.scjtonline.cn:8195/live/HD_c54034ca-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681457640-0-0-3a53b856ac19c09273986e8281f3d727'
19   - },
20   - {
21   - url: 'https://vcsplay.scjtonline.cn:8094/live/HD_664c01b9-4b67-11eb-bf78-3cd2e55e0a36.m3u8?auth_key=1681457689-0-0-a797d264f2889a388c52ff188fedf7dc'
22   - },
23   - {
24   - url: 'https://vcsplay.scjtonline.cn:8196/live/HD_c53fd3cb-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681457668-0-0-7ef56e21fddd9ffb9740cbe499a1824c'
25   - },
26   - {
27   - url: 'https://vcsplay.scjtonline.cn:8199/live/HD_53713154-1371-489a-a929-015cca5569fc.m3u8?auth_key=1681441451-0-0-4f1ebdcf28a71b7631c0028c099923c9'
28   - },
29   - {
30   - url: 'https://vcsplay.scjtonline.cn:8195/live/HD_c54034ca-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681457640-0-0-3a53b856ac19c09273986e8281f3d727'
31   - }
32 11 ] as any,
33 12 // 自动播放的间隔(ms)
34 13 interval: 5000,
... ...
... ... @@ -2,7 +2,17 @@
2 2 <div class="banner-box" ref="root">
3 3 <div class="wrapper">
4 4 <div v-for="(item, index) in option.dataset" :key="index + item" :class="item.className" :style="item.sty">
5   - <CameraItem ref="cameraRef" :key="item + index" :sourceSrc="item.url" :w="w" :h="h" :index="index" />
  5 + <CameraItem
  6 + ref="cameraRef"
  7 + :name="item.name"
  8 + :avatar="item.avatar"
  9 + :key="item + index"
  10 + :sourceSrc="item.url"
  11 + :w="w"
  12 + :h="h"
  13 + :index="index"
  14 + />
  15 + <span class="video-title">{{ item.name }}</span>
6 16 </div>
7 17 </div>
8 18 <a href="javascript:;" class="left" @click="changeSlide('left')"></a>
... ... @@ -37,53 +47,54 @@ let interval = ref(4000)
37 47
38 48 const computedFunc = (initial: number, source: any) => {
39 49 if (initial < 0) initial = 0
40   - let len = source.length,
41   - temp1 = initial - 2 < 0 ? initial - 2 + len : initial - 2,
42   - temp2 = initial - 1 < 0 ? initial - 1 + len : initial - 1,
43   - temp3 = initial,
44   - temp4 = initial + 1 >= len ? initial + 1 - len : initial + 1,
45   - temp5 = initial + 2 >= len ? initial + 2 - len : initial + 2
46   - return source.map((item: any, index: number) => {
47   - let transform = `translate(-50%, -50%) scale(0.7)`,
48   - zIndex = 0,
49   - className = 'slide'
50   - switch (index) {
51   - case temp3:
52   - transform = `translate(-50%, -50%) scale(1)`
53   - className = ['slide', 'activate'] as any
54   - zIndex = 3
55   - break
56   - case temp1:
57   - transform = `translate(-80%, -50%) scale(0.7)`
58   - zIndex = 1
59   - break
60   - case temp5:
61   - transform = `translate(100%, -50%) scale(0.7)`
62   - zIndex = 1
63   - break
64   - case temp2:
65   - transform = `translate(-100%, -50%) scale(0.85)`
66   - zIndex = 2
67   - break
68   - case temp4:
69   - transform = `translate(58%, -50%) scale(0.85)`
70   - zIndex = 2
71   - break
72   - }
73   - item.sty = {
74   - transform,
75   - zIndex
76   - }
77   - item.className = className
78   - return item
79   - })
  50 + if (Array.isArray(source)) {
  51 + let len = source.length,
  52 + temp1 = initial - 2 < 0 ? initial - 2 + len : initial - 2,
  53 + temp2 = initial - 1 < 0 ? initial - 1 + len : initial - 1,
  54 + temp3 = initial,
  55 + temp4 = initial + 1 >= len ? initial + 1 - len : initial + 1,
  56 + temp5 = initial + 2 >= len ? initial + 2 - len : initial + 2
  57 + return source?.map((item: any, index: number) => {
  58 + let transform = `translate(-50%, -50%) scale(0.7)`,
  59 + zIndex = 0,
  60 + className = 'slide'
  61 + switch (index) {
  62 + case temp3:
  63 + transform = `translate(-50%, -50%) scale(1)`
  64 + className = ['slide', 'activate'] as any
  65 + zIndex = 3
  66 + break
  67 + case temp1:
  68 + transform = `translate(-80%, -50%) scale(0.7)`
  69 + zIndex = 1
  70 + break
  71 + case temp5:
  72 + transform = `translate(100%, -50%) scale(0.7)`
  73 + zIndex = 1
  74 + break
  75 + case temp2:
  76 + transform = `translate(-100%, -50%) scale(0.85)`
  77 + zIndex = 2
  78 + break
  79 + case temp4:
  80 + transform = `translate(58%, -50%) scale(0.85)`
  81 + zIndex = 2
  82 + break
  83 + }
  84 + item.sty = {
  85 + transform,
  86 + zIndex
  87 + }
  88 + item.className = className
  89 + return item
  90 + })
  91 + }
80 92 }
81 93
82 94 watch(
83 95 () => props.chartConfig.option.dataset,
84 96 newData => {
85 97 option.dataset = newData
86   - console.log(option.dataset)
87 98 },
88 99 {
89 100 immediate: true,
... ... @@ -143,12 +154,6 @@ function changeSlide(dir: string) {
143 154
144 155 <style lang="scss" scoped>
145 156 .banner-box {
146   - width: 100%;
147   - height: 100%;
148   - // position: absolute;
149   - top: 50%;
150   - left: 50%;
151   - transform: translate(-50%, -50%);
152 157 .wrapper {
153 158 width: 100%;
154 159 height: 100%;
... ... @@ -162,6 +167,15 @@ function changeSlide(dir: string) {
162 167 transform: translate(-50%, -50%);
163 168 transition: 0.5s;
164 169 box-shadow: 0 0 4px black;
  170 + .video-title {
  171 + width: v-bind('w+"px"');
  172 + font-size: 30px;
  173 + color: white;
  174 + position: absolute;
  175 + bottom: 6%;
  176 + left: 10%;
  177 + z-index: 999;
  178 + }
165 179 }
166 180 }
167 181 .arrow {
... ...
... ... @@ -2,22 +2,25 @@ import { PublicConfigClass } from '@/packages/public'
2 2 import { CreateComponentType } from '@/packages/index.d'
3 3 import { Title1Config } from './index'
4 4 import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
5 6
6 7 export const option = {
7 8 dataset: '我是标题',
8 9 attribute: {
9   - linearColors: ['#0559A3', '#0654A3', '#2AFFFF', '#2AFFFF','#2affff',' #2affff','#16d9d9'],
  10 + linearColors: ['#0559A3', '#0654A3', '#2AFFFF', '#2AFFFF', '#2affff', ' #2affff', '#16d9d9'],
10 11 fontSize: 20,
11 12 fontPos: {
12 13 x: 0,
13 14 y: 20
14 15 },
15   - fontColor: '#2AFFFF'
  16 + fontColor: '#2AFFFF',
  17 + lineColor: '#2AFFFF'
16 18 }
17 19 }
18 20
19 21 export default class Config extends PublicConfigClass implements CreateComponentType {
20 22 public key = Title1Config.key
  23 + public attr = { ...chartInitConfig, zIndex: 1, w: 550, h: 60 }
21 24 public chartConfig = cloneDeep(Title1Config)
22 25 public option = cloneDeep(option)
23 26 }
... ...
... ... @@ -7,15 +7,18 @@
7 7 <SettingItem name="大小">
8 8 <n-input-number v-model:value="optionData.attribute.fontSize" />
9 9 </SettingItem>
10   - <SettingItem name="颜色">
11   - <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.attribute.fontColor"></n-color-picker>
12   - </SettingItem>
13 10 <SettingItem name="x轴位置">
14 11 <n-input-number v-model:value="optionData.attribute.fontPos.x" />
15 12 </SettingItem>
16 13 <SettingItem name="y轴位置">
17 14 <n-input-number v-model:value="optionData.attribute.fontPos.y" />
18 15 </SettingItem>
  16 + <SettingItem name="颜色">
  17 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.attribute.fontColor"></n-color-picker>
  18 + </SettingItem>
  19 + <SettingItem>
  20 + <n-button size="small" @click="optionData.attribute.fontColor = '#2AFFFF'"> 恢复默认 </n-button>
  21 + </SettingItem>
19 22 </SettingItemBox>
20 23 <SettingItemBox
21 24 :name="`装饰颜色-${index + 1}`"
... ... @@ -30,14 +33,19 @@
30 33 ></n-color-picker>
31 34 </SettingItem>
32 35 <SettingItem>
33   - <n-button
34   - size="small"
35   - @click="optionData.attribute.linearColors[index] = option.attribute.linearColors[index]"
36   - >
  36 + <n-button size="small" @click="optionData.attribute.linearColors[index] = option.attribute.linearColors[index]">
37 37 恢复默认
38 38 </n-button>
39 39 </SettingItem>
40 40 </SettingItemBox>
  41 + <SettingItemBox :name="`装饰颜色8`">
  42 + <SettingItem name="颜色">
  43 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.attribute.lineColor"></n-color-picker>
  44 + </SettingItem>
  45 + <SettingItem>
  46 + <n-button size="small" @click="optionData.attribute.lineColor = '#2AFFFF'"> 恢复默认 </n-button>
  47 + </SettingItem>
  48 + </SettingItemBox>
41 49 </CollapseItem>
42 50 </template>
43 51
... ... @@ -46,7 +54,6 @@ import { PropType } from 'vue'
46 54 import { option } from './config'
47 55 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
48 56
49   -
50 57 defineProps({
51 58 optionData: {
52 59 type: Object as PropType<typeof option>,
... ...
... ... @@ -26,11 +26,7 @@
26 26 opacity="1"
27 27 :d="`M0,${h} L${w},${h} L${w},0 L0,0 L0,${h} Z`"
28 28 />
29   - <g
30   - opacity="1"
31   - :transform="`translate(34 ${(h/2)-26/2
32   - }) rotate(0 46 13)`"
33   - >
  29 + <g opacity="1" :transform="`translate(34 ${h / 2 - 26 / 2}) rotate(0 46 13)`">
34 30 <text>
35 31 <tspan
36 32 :x="attribute.fontPos.x"
... ... @@ -49,15 +45,12 @@
49 45 <path
50 46 id="矩形 21"
51 47 fill-rule="evenodd"
52   - style="fill: #2affff"
  48 + :style="{ fill: attribute.lineColor }"
53 49 transform="translate(0 0) rotate(0 0.5 15)"
54 50 opacity="1"
55   - :d="`M0,${h}L1,${h }L1,0L0,0L0,${h}Z`"
  51 + :d="`M0,${h}L1,${h}L1,0L0,0L0,${h}Z`"
56 52 />
57   - <g
58   - opacity="1"
59   - :transform="`translate(14 ${(h/2)-8/2}) rotate(0 6.5 7)`"
60   - >
  53 + <g opacity="1" :transform="`translate(14 ${h / 2 - 8 / 2}) rotate(0 6.5 7)`">
61 54 <path
62 55 id="矩形 22"
63 56 fill-rule="evenodd"
... ... @@ -83,7 +76,7 @@
83 76 :d="`M6,0L0,7L5,7L11,0L6,0Z `"
84 77 />
85 78 </g>
86   - <g opacity="1" :transform="`translate(396 ${(h/2)-2/2}) rotate(0 46.5 13.5)`">
  79 + <g opacity="1" :transform="`translate(396 ${h / 2 - 2 / 2}) rotate(0 46.5 13.5)`">
87 80 <path
88 81 id="并集"
89 82 fill-rule="evenodd"
... ... @@ -108,11 +101,6 @@ const props = defineProps({
108 101 }
109 102 })
110 103
111   -//修改默认宽高
112   -props.chartConfig.attr.w=550
113   -props.chartConfig.attr.h=60
114   -
115   -
116 104 const { dataset, attribute } = toRefs(props.chartConfig.option)
117 105
118 106 const { w, h } = toRefs(props.chartConfig.attr)
... ...
... ... @@ -2,6 +2,7 @@ import { PublicConfigClass } from '@/packages/public'
2 2 import { CreateComponentType } from '@/packages/index.d'
3 3 import { Title2Config } from './index'
4 4 import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
5 6
6 7 export const option = {
7 8 dataset: '我是标题',
... ... @@ -18,6 +19,7 @@ export const option = {
18 19
19 20 export default class Config extends PublicConfigClass implements CreateComponentType {
20 21 public key = Title2Config.key
  22 + public attr = { ...chartInitConfig, zIndex: 1, w: 550, h: 60 }
21 23 public chartConfig = cloneDeep(Title2Config)
22 24 public option = cloneDeep(option)
23 25 }
... ...
... ... @@ -7,15 +7,18 @@
7 7 <SettingItem name="大小">
8 8 <n-input-number v-model:value="optionData.attribute.fontSize" />
9 9 </SettingItem>
10   - <SettingItem name="颜色">
11   - <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.attribute.fontColor"></n-color-picker>
12   - </SettingItem>
13 10 <SettingItem name="x轴位置">
14 11 <n-input-number v-model:value="optionData.attribute.fontPos.x" />
15 12 </SettingItem>
16 13 <SettingItem name="y轴位置">
17 14 <n-input-number v-model:value="optionData.attribute.fontPos.y" />
18 15 </SettingItem>
  16 + <SettingItem name="颜色">
  17 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.attribute.fontColor"></n-color-picker>
  18 + </SettingItem>
  19 + <SettingItem>
  20 + <n-button size="small" @click="optionData.attribute.fontColor = '#2AFFFF'"> 恢复默认 </n-button>
  21 + </SettingItem>
19 22 </SettingItemBox>
20 23 <SettingItemBox
21 24 :name="`装饰颜色-${index + 1}`"
... ... @@ -30,10 +33,7 @@
30 33 ></n-color-picker>
31 34 </SettingItem>
32 35 <SettingItem>
33   - <n-button
34   - size="small"
35   - @click="optionData.attribute.linearColors[index] = option.attribute.linearColors[index]"
36   - >
  36 + <n-button size="small" @click="optionData.attribute.linearColors[index] = option.attribute.linearColors[index]">
37 37 恢复默认
38 38 </n-button>
39 39 </SettingItem>
... ... @@ -46,7 +46,6 @@ import { PropType } from 'vue'
46 46 import { option } from './config'
47 47 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
48 48
49   -
50 49 defineProps({
51 50 optionData: {
52 51 type: Object as PropType<typeof option>,
... ...
... ... @@ -76,9 +76,7 @@ const props = defineProps({
76 76 })
77 77
78 78 const { dataset, attribute } = toRefs(props.chartConfig.option)
79   -//修改默认宽高
80   -props.chartConfig.attr.w=550
81   -props.chartConfig.attr.h=60
  79 +
82 80 const { w, h } = toRefs(props.chartConfig.attr)
83 81 </script>
84 82
... ...
... ... @@ -2,6 +2,7 @@ import { PublicConfigClass } from '@/packages/public'
2 2 import { CreateComponentType } from '@/packages/index.d'
3 3 import { Title3Config } from './index'
4 4 import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
5 6
6 7 export const option = {
7 8 dataset: '我是标题',
... ... @@ -31,6 +32,7 @@ export const option = {
31 32
32 33 export default class Config extends PublicConfigClass implements CreateComponentType {
33 34 public key = Title3Config.key
  35 + public attr = { ...chartInitConfig, zIndex: 1, w: 550, h: 60 }
34 36 public chartConfig = cloneDeep(Title3Config)
35 37 public option = cloneDeep(option)
36 38 }
... ...
... ... @@ -7,15 +7,18 @@
7 7 <SettingItem name="大小">
8 8 <n-input-number v-model:value="optionData.attribute.fontSize" />
9 9 </SettingItem>
10   - <SettingItem name="颜色">
11   - <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.attribute.fontColor"></n-color-picker>
12   - </SettingItem>
13 10 <SettingItem name="x轴位置">
14 11 <n-input-number v-model:value="optionData.attribute.fontPos.x" />
15 12 </SettingItem>
16 13 <SettingItem name="y轴位置">
17 14 <n-input-number v-model:value="optionData.attribute.fontPos.y" />
18 15 </SettingItem>
  16 + <SettingItem name="颜色">
  17 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.attribute.fontColor"></n-color-picker>
  18 + </SettingItem>
  19 + <SettingItem name="颜色">
  20 + <n-button size="small" @click="optionData.attribute.fontColor = '#2AFFFF'"> 恢复默认 </n-button>
  21 + </SettingItem>
19 22 </SettingItemBox>
20 23 <SettingItemBox
21 24 :name="`装饰颜色-${index + 1}`"
... ... @@ -30,10 +33,7 @@
30 33 ></n-color-picker>
31 34 </SettingItem>
32 35 <SettingItem>
33   - <n-button
34   - size="small"
35   - @click="optionData.attribute.linearColors[index] = option.attribute.linearColors[index]"
36   - >
  36 + <n-button size="small" @click="optionData.attribute.linearColors[index] = option.attribute.linearColors[index]">
37 37 恢复默认
38 38 </n-button>
39 39 </SettingItem>
... ... @@ -46,7 +46,6 @@ import { PropType } from 'vue'
46 46 import { option } from './config'
47 47 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
48 48
49   -
50 49 defineProps({
51 50 optionData: {
52 51 type: Object as PropType<typeof option>,
... ...
... ... @@ -117,9 +117,6 @@ const { dataset, attribute } = toRefs(props.chartConfig.option)
117 117
118 118 const { w, h } = toRefs(props.chartConfig.attr)
119 119
120   -//修改默认宽高
121   -props.chartConfig.attr.w=550
122   -props.chartConfig.attr.h=60
123 120 </script>
124 121
125 122 <style lang="scss" scoped>
... ...
... ... @@ -18,9 +18,17 @@ import {
18 18 import { chartInitConfig } from '@/settings/designSetting'
19 19 import cloneDeep from 'lodash/cloneDeep'
20 20
  21 +/**
  22 + * 这里更新版本有冲突
  23 + * ft 修改在公共接口下拉框里默认选择公共接口
  24 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  25 + * 源代码 requestDataType: RequestDataTypeEnum.AJAX,
  26 + * 修改后的代码 requestDataType: RequestDataTypeEnum.Pond,
  27 + * 修改后代码在//ft之间
  28 + */
21 29 // 请求基础属性
22 30 export const requestConfig: RequestConfigType = {
23   - requestDataType: RequestDataTypeEnum.STATIC,
  31 + requestDataType: RequestDataTypeEnum.Pond,
24 32 requestHttpType: RequestHttpEnum.GET,
25 33 requestUrl: '',
26 34 requestInterval: undefined,
... ... @@ -41,6 +49,7 @@ export const requestConfig: RequestConfigType = {
41 49 Params: {}
42 50 }
43 51 }
  52 +//ft之间
44 53
45 54 // 单实例类
46 55 export class PublicConfigClass implements PublicConfigType {
... ...
... ... @@ -33,7 +33,7 @@ export const useSocketStore = defineStore({
33 33 const { keys } = Params
34 34 return {
35 35 componentId: id,
36   - keys: keys.split(KEYS_SEPARATOR)
  36 + keys: keys as unknown as string[]
37 37 }
38 38 })
39 39 },
... ... @@ -149,8 +149,8 @@ export const useSocketStore = defineStore({
149 149 const { requestContentType, requestParams } = request
150 150 if ((requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET) {
151 151 const { Params } = requestParams
152   - const { entityId = '', keys = '' } = Params
153   - return this.updateConnectionPool(entityId, keys.split(KEYS_SEPARATOR), componentId)
  152 + const { entityId = '', keys = [] } = Params
  153 + return this.updateConnectionPool(entityId, keys as string[], componentId)
154 154 }
155 155 },
156 156
... ... @@ -197,8 +197,8 @@ export const useSocketStore = defineStore({
197 197 getComponentValueByKeys(targetComponent: CreateComponentType, value: SocketReceiveMessageType) {
198 198 const { request: { requestParams } } = targetComponent
199 199 const { Params } = requestParams
200   - const { keys = '' } = Params
201   - const targetComponentBindKeys = keys.split(KEYS_SEPARATOR)
  200 + const { keys = [] } = Params
  201 + const targetComponentBindKeys = keys as unknown as string[]
202 202
203 203 const _value = cloneDeep(value) || { data: {}, latestValues: {} }
204 204 _value.data = targetComponentBindKeys.reduce((prev, next) => {
... ... @@ -238,7 +238,6 @@ export const useSocketStore = defineStore({
238 238 const { subscriptionId, data } = value
239 239 const keys = Object.keys(data)
240 240 const componentIds = this.getNeedUpdateComponentsIdBySubscribeId(subscriptionId, keys)
241   - console.log(componentIds)
242 241 componentIds?.forEach((targetComponentId) => {
243 242 this.updateComponentById(targetComponentId as string, value)
244 243 })
... ...
... ... @@ -3,8 +3,8 @@ import type { ErrorMessageMode } from '/#/external/axios';
3 3 import { defineStore } from 'pinia';
4 4 import { pinia as store } from '@/store';
5 5 import { RoleEnum } from '@/enums/external/roleEnum';
6   -import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY, ROLES_KEY, USER_INFO_KEY } from '@/enums/external/cacheEnum';
7   -import { getAuthCache, getJwtToken, getRefreshToken, setAuthCache } from '@/utils/external/auth';
  6 +import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY, ROLES_KEY, SHARE_JWT_TOKEN_KEY, SHARE_REFRESH_TOKEN_KEY, USER_INFO_KEY } from '@/enums/external/cacheEnum';
  7 +import { getAuthCache, getJwtToken, getRefreshToken, getUserInfo, setAuthCache } from '@/utils/external/auth';
8 8 import {
9 9 LoginParams,
10 10 LoginResultModel,
... ... @@ -29,6 +29,8 @@ interface UserState {
29 29 lastUpdateTime: number;
30 30 jwtToken?: string;
31 31 refreshToken?: string;
  32 + shareJwtToken?: string;
  33 + shareRefreshToken?: string;
32 34 outTarget?: string;
33 35 }
34 36
... ... @@ -41,12 +43,14 @@ export const useUserStore = defineStore({
41 43 enterPriseInfo: storage.get('enterPriseInfo') || null,
42 44
43 45 // user info
44   - userInfo: null,
  46 + userInfo: getUserInfo() || null,
45 47 userUpdateInfo: null,
46 48 // token
47 49 jwtToken: getJwtToken() as string || undefined,
48 50 //refresh Token
49 51 refreshToken: getRefreshToken() as string || undefined,
  52 + shareJwtToken: undefined,
  53 + shareRefreshToken: undefined,
50 54 // roleList
51 55 roleList: [],
52 56 // Whether the login expired
... ... @@ -96,6 +100,12 @@ export const useUserStore = defineStore({
96 100 setAuthCache(JWT_TOKEN_KEY, jwtToken);
97 101 setAuthCache(REFRESH_TOKEN_KEY, refreshToken);
98 102 },
  103 + storeShareToken(jwtToken: string, refreshToken: string) {
  104 + this.shareJwtToken = jwtToken;
  105 + this.shareRefreshToken = refreshToken;
  106 + setAuthCache(SHARE_JWT_TOKEN_KEY, jwtToken);
  107 + setAuthCache(SHARE_REFRESH_TOKEN_KEY, refreshToken);
  108 + },
99 109 setToken(info: string | undefined) {
100 110 this.jwtToken = info;
101 111 setAuthCache(JWT_TOKEN_KEY, info);
... ... @@ -152,14 +162,6 @@ export const useUserStore = defineStore({
152 162 }
153 163 return userInfo;
154 164 },
155   - async smsCodelogin(
156   - params: SmsLoginParams & {
157   - goHome?: boolean;
158   - mode?: ErrorMessageMode;
159   - }
160   - ) {
161   -
162   - },
163 165 async getMyUserInfoAction() {
164 166 const userInfo = await getMyInfo();
165 167 this.setUserInfo(userInfo);
... ... @@ -193,6 +195,20 @@ export const useUserStore = defineStore({
193 195 },
194 196
195 197 /**
  198 + * @description 刷新分享页面的token
  199 + */
  200 + async doShareRefresh() {
  201 + try {
  202 + const req = { refreshToken: this.shareRefreshToken } as RefreshTokenParams
  203 + const { token, refreshToken } = await doRefreshToken(req)
  204 + this.storeShareToken(token, refreshToken)
  205 + } catch (error) {
  206 + window.location.reload()
  207 + throw error
  208 + }
  209 + },
  210 +
  211 + /**
196 212 * @description: Confirm before logging out
197 213 */
198 214 confirmLoginOut() {
... ...
1 1 import { Persistent, BasicKeys } from '@/utils/external/cache/persistent';
2   -import { CacheTypeEnum } from '@/enums/external/cacheEnum';
  2 +import { CacheTypeEnum, SHARE_JWT_TOKEN_KEY, SHARE_REFRESH_TOKEN_KEY, USER_INFO_KEY } from '@/enums/external/cacheEnum';
3 3 import projectSetting from '@/settings/external/projectSetting';
4 4 import { JWT_TOKEN_KEY, REFRESH_TOKEN_KEY } from '@/enums/external/cacheEnum';
  5 +import { UserInfo } from '/#/external/store';
5 6
6 7 const { permissionCacheType } = projectSetting;
7 8 const isLocal = permissionCacheType === CacheTypeEnum.LOCAL;
... ... @@ -20,9 +21,21 @@ export function clearAuthCache(immediate = true) {
20 21 const fn = isLocal ? Persistent.clearLocal : Persistent.clearSession;
21 22 return fn(immediate);
22 23 }
23   -export function getJwtToken() {
  24 +export function getJwtToken(): string {
24 25 return getAuthCache(JWT_TOKEN_KEY);
25 26 }
26   -export function getRefreshToken() {
  27 +export function getRefreshToken(): string {
27 28 return getAuthCache(REFRESH_TOKEN_KEY);
28 29 }
  30 +
  31 +export function getShareJwtToken(): string {
  32 + return getAuthCache(SHARE_JWT_TOKEN_KEY);
  33 +}
  34 +
  35 +export function getShareRefreshToken(): string {
  36 + return getAuthCache(SHARE_REFRESH_TOKEN_KEY);
  37 +}
  38 +
  39 +export function getUserInfo(): UserInfo {
  40 + return getAuthCache(USER_INFO_KEY)
  41 +}
... ...
... ... @@ -17,9 +17,11 @@ import {
17 17 APP_SESSION_CACHE_KEY,
18 18 MULTIPLE_TABS_KEY,
19 19 MENU_LIST,
  20 + SHARE_JWT_TOKEN_KEY,
  21 + SHARE_REFRESH_TOKEN_KEY,
20 22 } from '@/enums/external/cacheEnum';
21 23 import { DEFAULT_CACHE_TIME } from '@/settings/external/encryptionSetting';
22   -import { toRaw } from 'vue';
  24 +import { toRaw } from 'vue';
23 25 import omit from 'lodash/omit';
24 26 import pick from 'lodash/pick';
25 27
... ... @@ -34,6 +36,8 @@ interface BasicStore {
34 36 [PROJ_CFG_KEY]: ProjectConfig;
35 37 [MULTIPLE_TABS_KEY]: RouteLocationNormalized[];
36 38 [MENU_LIST]: any[];
  39 + [SHARE_JWT_TOKEN_KEY]: string
  40 + [SHARE_REFRESH_TOKEN_KEY]: string
37 41 }
38 42
39 43 type LocalStore = BasicStore;
... ...
1   -import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError } from 'axios';
2   -import type { CreateAxiosOptions } from './axiosTransform';
  1 +import type { AxiosInstance, AxiosResponse, AxiosError } from 'axios';
  2 +import type { AxiosRequestConfig, CreateAxiosOptions } from './axiosTransform';
3 3 import axios from 'axios';
4 4 import qs from 'qs';
5 5 import { AxiosCanceler } from './axiosCancel';
... ... @@ -115,13 +115,21 @@ export class VAxios {
115 115 this.axiosInstance.interceptors.request.use(async (config: AxiosRequestConfig) => {
116 116 // If cancel repeat request is turned on, then cancel repeat request is prohibited
117 117 const userStore = useUserStore();
118   - if (userStore && userStore.jwtToken) {
  118 + // if (userStore && (userStore.jwtToken || userStore.shareJwtToken)) {
  119 + if (userStore) {
119 120 try {
120   - const res = jwt_decode(userStore.jwtToken) as JwtModel;
121   - const currentTime = (new Date().getTime() + (config.timeout || 0)) / 1000;
122   - if (currentTime >= res.exp && this.isNeedTokenURL(config.url!)) {
123   - await this.refreshTokenBeforeReq(userStore.doRefresh);
  121 + const { requestOptions = {} } = config
  122 + const { withShareToken, withToken } = requestOptions
  123 + const token = withShareToken && withToken ? userStore.shareJwtToken : userStore.jwtToken
  124 + const doRefresh = withShareToken && withToken ? userStore.doShareRefresh : userStore.doRefresh
  125 + if (token) {
  126 + const res = jwt_decode(token) as JwtModel;
  127 + const currentTime = (new Date().getTime() + (config.timeout || 0)) / 1000;
  128 + if (currentTime >= res.exp && this.isNeedTokenURL(config.url!)) {
  129 + await this.refreshTokenBeforeReq(doRefresh);
  130 + }
124 131 }
  132 +
125 133 } catch (error) {
126 134 userStore.logout();
127 135 }
... ...
1 1 /**
2 2 * Data processing class, can be configured according to the project
3 3 */
4   -import type { AxiosRequestConfig, AxiosResponse } from 'axios';
  4 +import type { AxiosRequestConfig as OriginAxiosRequestConfig, AxiosResponse } from 'axios';
5 5 import type { RequestOptions, Result } from '/#/external/axios';
6 6
7 7 export interface CreateAxiosOptions extends AxiosRequestConfig {
... ... @@ -11,6 +11,8 @@ export interface CreateAxiosOptions extends AxiosRequestConfig {
11 11 requestOptions?: RequestOptions;
12 12 }
13 13
  14 +export type AxiosRequestConfig = OriginAxiosRequestConfig & {requestOptions?: RequestOptions}
  15 +
14 16 export abstract class AxiosTransform {
15 17 /**
16 18 * @description: Process configuration before request
... ...
... ... @@ -9,7 +9,7 @@ import { checkStatus } from './checkStatus';
9 9 import { useGlobSetting } from '@/hooks/external/setting';
10 10 import { RequestEnum, ContentTypeEnum } from '@/enums/external/httpEnum';
11 11 import { isString } from '@/utils/external/is';
12   -import { getJwtToken } from '@/utils/external/auth';
  12 +import { getJwtToken, getShareJwtToken } from '@/utils/external/auth';
13 13 import { setObjToUrlParams, deepMerge } from '@/utils/external';
14 14 import { joinTimestamp, formatRequestDate } from './helper';
15 15 import { PageEnum } from '@/enums/external/pageEnum';
... ... @@ -89,14 +89,25 @@ const transform: AxiosTransform = {
89 89 */
90 90 requestInterceptors: (config, options) => {
91 91 // 请求之前处理config
92   - const token = getJwtToken();
93   - if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
94   - // jwt token
95   - config.headers!['X-Authorization'] = options.authenticationScheme
96   - ? `${options.authenticationScheme} ${token}`
97   - : token as string;
  92 + const { requestOptions } = config;
  93 + const { withShareToken } = requestOptions || {};
  94 + const { requestOptions: { withToken } = {} } = options;
  95 + if (withToken !== false) {
  96 + const shareToken = getShareJwtToken();
  97 + if (withShareToken && shareToken) {
  98 + config.headers!['X-Authorization'] = options.authenticationScheme
  99 + ? `${options.authenticationScheme} ${shareToken}`
  100 + : shareToken;
  101 + } else {
  102 + const token = getJwtToken();
  103 + if (token) {
  104 + config.headers!['X-Authorization'] = options.authenticationScheme
  105 + ? `${options.authenticationScheme} ${token}`
  106 + : token;
  107 + }
  108 + }
98 109 }
99   - return config;
  110 + return config
100 111 },
101 112
102 113 /**
... ...
  1 +import { excludeParseEventKeyList, excludeParseEventValueList } from "@/enums/eventEnum"
  2 +
  3 +const tryRunFunction = (v: string) => {
  4 + try {
  5 + return eval(`(function(){return ${v}})()`)
  6 + } catch (error) {
  7 + return v
  8 + }
  9 +}
  10 +
  11 +export const JSONParse = (data: string) => {
  12 + return JSON.parse(data, (k, v) => {
  13 + // 过滤函数字符串
  14 + if (excludeParseEventKeyList.includes(k)) return v
  15 + // 过滤函数值表达式
  16 + if (typeof v === 'string') {
  17 + const someValue = excludeParseEventValueList.some(excludeValue => v.indexOf(excludeValue) > -1)
  18 + if (someValue) return v
  19 + }
  20 + // 还原函数值
  21 + if (typeof v === 'string' && v.indexOf && (v.indexOf('function') > -1 || v.indexOf('=>') > -1)) {
  22 + return tryRunFunction(v)
  23 + } else if (typeof v === 'string' && v.indexOf && v.indexOf('return ') > -1) {
  24 + const baseLeftIndex = v.indexOf('(')
  25 + if (baseLeftIndex > -1) {
  26 + const newFn = `function ${v.substring(baseLeftIndex)}`
  27 + return tryRunFunction(newFn)
  28 + }
  29 + }
  30 + return v
  31 + })
  32 +}
... ...
... ... @@ -12,6 +12,9 @@ import { RequestHttpIntervalEnum, RequestParamsObjType } from '@/enums/httpEnum'
12 12 import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
13 13 import { excludeParseEventKeyList, excludeParseEventValueList } from '@/enums/eventEnum'
14 14
  15 +/// THINGS_KIT 替换JSONParse解析
  16 +export { JSONParse } from './external/utils'
  17 +
15 18 /**
16 19 * * 判断是否是开发环境
17 20 * @return { Boolean }
... ... @@ -127,11 +130,11 @@ export const fileToUrl = (file: File): string => {
127 130 * * file转base64
128 131 */
129 132 export const fileTobase64 = (file: File, callback: Function) => {
130   - let reader = new FileReader()
  133 + const reader = new FileReader()
131 134 reader.readAsDataURL(file)
132 135 reader.onload = function (e: ProgressEvent<FileReader>) {
133 136 if (e.target) {
134   - let base64 = e.target.result
  137 + const base64 = e.target.result
135 138 callback(base64)
136 139 }
137 140 }
... ... @@ -318,7 +321,8 @@ export const JSONStringify = <T>(data: T) => {
318 321 * * JSON反序列化,支持函数和 undefined
319 322 * @param data
320 323 */
321   -export const JSONParse = (data: string) => {
  324 +/// THINGS_KIT 重命名 JSONParse 为 JSONParseOriginal
  325 +export const JSONParseOriginal = (data: string) => {
322 326 return JSON.parse(data, (k, v) => {
323 327 // 过滤函数字符串
324 328 if (excludeParseEventKeyList.includes(k)) return v
... ... @@ -347,4 +351,4 @@ export const JSONParse = (data: string) => {
347 351 */
348 352 export const setTitle = (title?: string) => {
349 353 title && (document.title = title)
350   -}
\ No newline at end of file
  354 +}
... ...
... ... @@ -22,7 +22,14 @@ const requestModal = ref<InstanceType<typeof RequestModal>>()
22 22 const designStore = useDesignStore()
23 23
24 24
25   -const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.AJAX)
  25 +/**
  26 + * ft 修改在公共接口下拉框里默认选择公共接口
  27 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  28 + * 源代码 const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.AJAX)
  29 + * 修改后的代码 const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.Pond)
  30 + * 修改后代码在//ft之间
  31 + */
  32 +const selectedRequestType = ref(targetData.value.request.requestDataType || RequestDataTypeEnum.Pond)
26 33
27 34 const getApiRequestType: SelectOption[] = [
28 35 { label: '自定义请求', value: RequestDataTypeEnum.AJAX },
... ... @@ -40,7 +47,10 @@ const { fetchTargetData, } = useFetchTargetData()
40 47
41 48 // 发送请求
42 49 const sendHandle = async () => {
43   - if (!targetData.value?.request) return
  50 + if (!targetData.value?.request || !targetData.value.request.requestUrl) {
  51 + window['$message'].warning('请先配置请求')
  52 + return
  53 + }
44 54 loading.value = true
45 55 try {
46 56 const res = await fetchTargetData()
... ...
... ... @@ -4,6 +4,7 @@ import { FormItemInst, NDatePicker, NForm, NFormItem, NInput, NSelect, NTreeSele
4 4 import { computed, nextTick, ref, unref, watch } from 'vue';
5 5 import { ComponentType, useDynamicPublicForm } from './useDynamicPublicForm';
6 6 import { Help } from '@vicons/ionicons5'
  7 +import { SelectTimeAggregation } from '../SelectTImeAggregation';
7 8
8 9 const props = defineProps<{
9 10 paramsItemList: ParamsItemType[]
... ... @@ -13,7 +14,8 @@ const componentMap: { [key in ComponentType]?: any } = {
13 14 [ComponentType.SELECT_TREE]: NTreeSelect,
14 15 [ComponentType.SELECT]: NSelect,
15 16 [ComponentType.INPUT]: NInput,
16   - [ComponentType.DATE_PICKER]: NDatePicker
  17 + [ComponentType.DATE_PICKER]: NDatePicker,
  18 + [ComponentType.SELECT_TIME_AGGREGATION]: SelectTimeAggregation
17 19 }
18 20
19 21 const getParamsItemList = computed(() => {
... ... @@ -39,12 +41,16 @@ const setConfigurationData = async (params: Recordable) => {
39 41 setDynamicFormValue(params)
40 42 }
41 43
  44 +const recreate = ref(false)
  45 +
42 46 watch(
43 47 () => props.paramsItemList,
44 48 (newValue) => {
45 49 if (newValue) {
  50 + recreate.value = true
46 51 clearParams()
47 52 createForm()
  53 + recreate.value = false
48 54 }
49 55 }
50 56 )
... ... @@ -59,8 +65,8 @@ defineExpose({
59 65
60 66 <template>
61 67 <NForm>
62   - <template v-for="item in getDynamicFormSchemas" :key="item.key">
63   - <NFormItem ref="dynamicFormItemEl" :required="item.required" :rule="item.rules">
  68 + <template v-for="item in getDynamicFormSchemas" :key="item.uuid">
  69 + <NFormItem v-if="!recreate" ref="dynamicFormItemEl" :required="item.required" :rule="item.rules">
64 70 <template #label>
65 71 <div class="label-container">
66 72 <span>{{ item.name }}</span>
... ...
  1 +enum TimeUnitEnum {
  2 + SECOND = 'SECOND',
  3 + MINUTE = 'MINUTE',
  4 + HOUR = 'HOUR',
  5 + DAY = 'DAY',
  6 +}
  7 +
  8 +const unitMapping = {
  9 + [TimeUnitEnum.SECOND]: '秒',
  10 + [TimeUnitEnum.MINUTE]: '分',
  11 + [TimeUnitEnum.HOUR]: '小时',
  12 + [TimeUnitEnum.DAY]: '天',
  13 +}
  14 +
  15 +const unitConversion = {
  16 + [TimeUnitEnum.SECOND]: 1 * 1000,
  17 + [TimeUnitEnum.MINUTE]: 1 * 60 * 1000,
  18 + [TimeUnitEnum.HOUR]: 1 * 60 * 60 * 1000,
  19 + [TimeUnitEnum.DAY]: 1 * 60 * 60 * 24 * 1000,
  20 +}
  21 +
  22 +export const defaultIntervalOptions = [
  23 + {
  24 + id: 1,
  25 + unit: TimeUnitEnum.SECOND,
  26 + linkage: [
  27 + { id: 1, unit: TimeUnitEnum.SECOND }
  28 + ]
  29 + },
  30 + {
  31 + id: 5,
  32 + unit: TimeUnitEnum.SECOND,
  33 + linkage: [
  34 + { id: 1, unit: TimeUnitEnum.SECOND }
  35 + ]
  36 + },
  37 + {
  38 + id: 10,
  39 + unit: TimeUnitEnum.SECOND,
  40 + linkage: [
  41 + { id: 1, unit: TimeUnitEnum.SECOND }
  42 + ]
  43 + },
  44 + {
  45 + id: 15,
  46 + unit: TimeUnitEnum.SECOND,
  47 + linkage: [
  48 + { id: 1, unit: TimeUnitEnum.SECOND }
  49 + ]
  50 + },
  51 + {
  52 + id: 30,
  53 + unit: TimeUnitEnum.SECOND,
  54 + linkage: [
  55 + { id: 1, unit: TimeUnitEnum.SECOND }
  56 + ]
  57 + },
  58 + {
  59 + id: 1,
  60 + unit: TimeUnitEnum.MINUTE,
  61 + linkage: [
  62 + { id: 1, unit: TimeUnitEnum.SECOND },
  63 + { id: 5, unit: TimeUnitEnum.SECOND },
  64 + ]
  65 + },
  66 + {
  67 + id: 2,
  68 + unit: TimeUnitEnum.MINUTE,
  69 + linkage: [
  70 + { id: 1, unit: TimeUnitEnum.SECOND },
  71 + { id: 5, unit: TimeUnitEnum.SECOND },
  72 + { id: 10, unit: TimeUnitEnum.SECOND },
  73 + { id: 15, unit: TimeUnitEnum.SECOND },
  74 + ]
  75 + },
  76 + {
  77 + id: 5,
  78 + unit: TimeUnitEnum.MINUTE,
  79 + linkage: [
  80 + { id: 1, unit: TimeUnitEnum.SECOND },
  81 + { id: 5, unit: TimeUnitEnum.SECOND },
  82 + { id: 10, unit: TimeUnitEnum.SECOND },
  83 + { id: 15, unit: TimeUnitEnum.SECOND },
  84 + { id: 30, unit: TimeUnitEnum.SECOND },
  85 + ]
  86 + },
  87 + {
  88 + id: 10,
  89 + unit: TimeUnitEnum.MINUTE,
  90 + linkage: [
  91 + { id: 5, unit: TimeUnitEnum.SECOND },
  92 + { id: 10, unit: TimeUnitEnum.SECOND },
  93 + { id: 15, unit: TimeUnitEnum.SECOND },
  94 + { id: 30, unit: TimeUnitEnum.SECOND },
  95 + { id: 1, unit: TimeUnitEnum.MINUTE },
  96 + ]
  97 + },
  98 + {
  99 + id: 15,
  100 + unit: TimeUnitEnum.MINUTE,
  101 + linkage: [
  102 + { id: 5, unit: TimeUnitEnum.SECOND },
  103 + { id: 10, unit: TimeUnitEnum.SECOND },
  104 + { id: 15, unit: TimeUnitEnum.SECOND },
  105 + { id: 30, unit: TimeUnitEnum.SECOND },
  106 + { id: 1, unit: TimeUnitEnum.MINUTE },
  107 + { id: 2, unit: TimeUnitEnum.MINUTE },
  108 + ]
  109 + },
  110 + {
  111 + id: 30,
  112 + unit: TimeUnitEnum.MINUTE,
  113 + linkage: [
  114 + { id: 5, unit: TimeUnitEnum.SECOND },
  115 + { id: 10, unit: TimeUnitEnum.SECOND },
  116 + { id: 15, unit: TimeUnitEnum.SECOND },
  117 + { id: 30, unit: TimeUnitEnum.SECOND },
  118 + { id: 1, unit: TimeUnitEnum.MINUTE },
  119 + { id: 2, unit: TimeUnitEnum.MINUTE },
  120 + ]
  121 + },
  122 + {
  123 + id: 1,
  124 + unit: TimeUnitEnum.HOUR,
  125 + linkage: [
  126 + { id: 10, unit: TimeUnitEnum.SECOND },
  127 + { id: 15, unit: TimeUnitEnum.SECOND },
  128 + { id: 30, unit: TimeUnitEnum.SECOND },
  129 + { id: 1, unit: TimeUnitEnum.MINUTE },
  130 + { id: 2, unit: TimeUnitEnum.MINUTE },
  131 + { id: 5, unit: TimeUnitEnum.MINUTE },
  132 + ]
  133 + },
  134 + {
  135 + id: 2,
  136 + unit: TimeUnitEnum.HOUR,
  137 + linkage: [
  138 + { id: 15, unit: TimeUnitEnum.SECOND },
  139 + { id: 30, unit: TimeUnitEnum.SECOND },
  140 + { id: 1, unit: TimeUnitEnum.MINUTE },
  141 + { id: 2, unit: TimeUnitEnum.MINUTE },
  142 + { id: 5, unit: TimeUnitEnum.MINUTE },
  143 + { id: 10, unit: TimeUnitEnum.MINUTE },
  144 + { id: 15, unit: TimeUnitEnum.MINUTE },
  145 + ]
  146 + },
  147 + {
  148 + id: 5,
  149 + unit: TimeUnitEnum.HOUR,
  150 + linkage: [
  151 + { id: 1, unit: TimeUnitEnum.MINUTE },
  152 + { id: 2, unit: TimeUnitEnum.MINUTE },
  153 + { id: 5, unit: TimeUnitEnum.MINUTE },
  154 + { id: 10, unit: TimeUnitEnum.MINUTE },
  155 + { id: 15, unit: TimeUnitEnum.MINUTE },
  156 + { id: 30, unit: TimeUnitEnum.MINUTE },
  157 + ]
  158 + },
  159 + {
  160 + id: 10,
  161 + unit: TimeUnitEnum.HOUR,
  162 + linkage: [
  163 + { id: 2, unit: TimeUnitEnum.MINUTE },
  164 + { id: 5, unit: TimeUnitEnum.MINUTE },
  165 + { id: 10, unit: TimeUnitEnum.MINUTE },
  166 + { id: 15, unit: TimeUnitEnum.MINUTE },
  167 + { id: 30, unit: TimeUnitEnum.MINUTE },
  168 + { id: 1, unit: TimeUnitEnum.HOUR },
  169 + ]
  170 + },
  171 + {
  172 + id: 12,
  173 + unit: TimeUnitEnum.HOUR,
  174 + linkage: [
  175 + { id: 2, unit: TimeUnitEnum.MINUTE },
  176 + { id: 5, unit: TimeUnitEnum.MINUTE },
  177 + { id: 10, unit: TimeUnitEnum.MINUTE },
  178 + { id: 15, unit: TimeUnitEnum.MINUTE },
  179 + { id: 30, unit: TimeUnitEnum.MINUTE },
  180 + { id: 1, unit: TimeUnitEnum.HOUR },
  181 + ]
  182 + },
  183 + {
  184 + id: 1,
  185 + unit: TimeUnitEnum.DAY,
  186 + linkage: [
  187 + { id: 5, unit: TimeUnitEnum.MINUTE },
  188 + { id: 10, unit: TimeUnitEnum.MINUTE },
  189 + { id: 15, unit: TimeUnitEnum.MINUTE },
  190 + { id: 30, unit: TimeUnitEnum.MINUTE },
  191 + { id: 1, unit: TimeUnitEnum.HOUR },
  192 + { id: 2, unit: TimeUnitEnum.HOUR },
  193 + ]
  194 + },
  195 + {
  196 + id: 7,
  197 + unit: TimeUnitEnum.DAY,
  198 + linkage: [
  199 + { id: 30, unit: TimeUnitEnum.MINUTE },
  200 + { id: 1, unit: TimeUnitEnum.HOUR },
  201 + { id: 2, unit: TimeUnitEnum.HOUR },
  202 + { id: 5, unit: TimeUnitEnum.HOUR },
  203 + { id: 10, unit: TimeUnitEnum.HOUR },
  204 + { id: 12, unit: TimeUnitEnum.HOUR },
  205 + { id: 1, unit: TimeUnitEnum.DAY },
  206 + ]
  207 + },
  208 + {
  209 + id: 30,
  210 + unit: TimeUnitEnum.DAY,
  211 + linkage: [
  212 + { id: 2, unit: TimeUnitEnum.HOUR },
  213 + { id: 5, unit: TimeUnitEnum.HOUR },
  214 + { id: 10, unit: TimeUnitEnum.HOUR },
  215 + { id: 12, unit: TimeUnitEnum.HOUR },
  216 + { id: 1, unit: TimeUnitEnum.DAY },
  217 + ]
  218 + },
  219 +].map(item => {
  220 + return {
  221 + id: item.id * unitConversion[item.unit],
  222 + name: item.id + unitMapping[item.unit],
  223 + linkage: item.linkage.map(item => {
  224 + return {
  225 + id: item.id * unitConversion[item.unit],
  226 + name: item.id + unitMapping[item.unit],
  227 + }
  228 + })
  229 + }
  230 +})
  231 +
  232 +export const aggergationOptions = [
  233 + { id: 'AVG', name: '平均值' },
  234 + { id: 'MIN', name: '最小值' },
  235 + { id: 'MAX', name: '最大值' },
  236 + { id: 'SUM', name: '求和' },
  237 + { id: 'COUNT', name: '计数' },
  238 + { id: 'NONE', name: '空' },
  239 +]
... ...
... ... @@ -6,6 +6,8 @@ import { RequestConfigType } from "@/store/modules/chartEditStore/chartEditStore
6 6 import { DatePickerProps, FormItemRule, InputProps, SelectProps, TreeSelectProps } from "naive-ui"
7 7 import { computed, onMounted, reactive, Ref, ref, unref } from "vue"
8 8 import { DictEnum } from '@/enums/external/dictEnum'
  9 +import { SelectTimeAggregationFieldEnum, SelectTimeAggregationValueTypw } from "../SelectTImeAggregation"
  10 +import { isArray } from "@/utils"
9 11
10 12 const GROUP_SEPARATOR = ','
11 13
... ... @@ -15,7 +17,8 @@ export enum BuiltInVariable {
15 17 ORGANIZATION_ID = 'organizationId',
16 18 DEVICE_PROFILE_ID = 'deviceProfileId',
17 19 DATE_FIXED = 'fixed_date',
18   - DATE_RANGE = 'date_range'
  20 + DATE_RANGE = 'date_range',
  21 + SELECT_TIME_AGGREGATION = 'selectTimeAggregation'
19 22 }
20 23
21 24 export enum ComponentType {
... ... @@ -23,10 +26,12 @@ export enum ComponentType {
23 26 SELECT_TREE = 'selectTree',
24 27 DATE_PICKER = 'datePicker',
25 28 INPUT = 'input',
  29 + SELECT_TIME_AGGREGATION = 'selectTimeAggregation'
26 30 }
27 31
28 32
29 33 export interface DynamicFormSchema {
  34 + uuid?: string
30 35 key: string
31 36 name?: string
32 37 component: ComponentType,
... ... @@ -57,7 +62,9 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
57 62
58 63 const builtInVariable = ref<BuiltInVariableRecord>()
59 64
60   - const params = reactive<Recordable & { [key in BuiltInVariable]?: any }>({})
  65 + const params = reactive<Recordable & { [key in BuiltInVariable]?: any }>({
  66 + [BuiltInVariable.SELECT_TIME_AGGREGATION]: {}
  67 + })
61 68
62 69 const optionsSet = reactive<Recordable>({})
63 70
... ... @@ -107,7 +114,8 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
107 114
108 115 const getDeviceOption = async () => {
109 116 if (!validIsExist(BuiltInVariable.DEVICE_PROFILE_ID) || !validIsExist(BuiltInVariable.ORGANIZATION_ID) || !params[BuiltInVariable.ORGANIZATION_ID]) return
110   - optionsSet[BuiltInVariable.ENTITY_ID] = await getDeviceList({ [BuiltInVariable.ORGANIZATION_ID]: params[BuiltInVariable.ORGANIZATION_ID], [BuiltInVariable.DEVICE_PROFILE_ID]: params[BuiltInVariable.DEVICE_PROFILE_ID] })
  117 + const result: Recordable[] = await getDeviceList({ [BuiltInVariable.ORGANIZATION_ID]: params[BuiltInVariable.ORGANIZATION_ID], [BuiltInVariable.DEVICE_PROFILE_ID]: params[BuiltInVariable.DEVICE_PROFILE_ID] })
  118 + optionsSet[BuiltInVariable.ENTITY_ID] = result.map(item => ({ ...item, alias: item.alias || item.name }))
111 119 }
112 120
113 121 const getDeviceAttrOption = async () => {
... ... @@ -119,6 +127,7 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
119 127
120 128 const getValue = computed(() => {
121 129 const value = { ...unref(params) }
  130 +
122 131 if (Reflect.has(value, BuiltInVariable.DATE_FIXED)) {
123 132 const fieldMapping = unref(getParams).find(item => item.key === BuiltInVariable.DATE_FIXED)
124 133 Reflect.set(value, fieldMapping?.value || '', value[BuiltInVariable.DATE_FIXED])
... ... @@ -128,13 +137,24 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
128 137 if (Reflect.has(value, BuiltInVariable.DATE_RANGE)) {
129 138 const fieldMapping = unref(getParams).find(item => item.key === BuiltInVariable.DATE_RANGE)
130 139 const [start, end] = ((fieldMapping || {}).value || '').split(GROUP_SEPARATOR)
131   - const [startValue, endValue] = value[BuiltInVariable.DATE_RANGE] || []
  140 + const dateRangeValue = value[BuiltInVariable.DATE_RANGE]
  141 + const [startValue, endValue] = isArray(dateRangeValue) ? dateRangeValue : [null, null]
132 142 value[start] = startValue
133 143 value[end] = endValue
134   -
135 144 Reflect.deleteProperty(value, BuiltInVariable.DATE_RANGE)
136 145 }
137 146
  147 + if (Reflect.has(value, BuiltInVariable.SELECT_TIME_AGGREGATION)) {
  148 + const fieldMapping = unref(getParams).find(item => item.key === BuiltInVariable.DATE_RANGE)
  149 + const [start, end] = ((fieldMapping || {}).value || '').split(GROUP_SEPARATOR)
  150 + const aggregation = Reflect.get(value, BuiltInVariable.SELECT_TIME_AGGREGATION) || {}
  151 + const result = { ...aggregation, [start]: aggregation.startTs, [end]: aggregation.endTs }
  152 + Reflect.deleteProperty(result, SelectTimeAggregationFieldEnum.START_TS)
  153 + Reflect.deleteProperty(result, SelectTimeAggregationFieldEnum.END_TS)
  154 + Object.assign(value, { ...result, [start]: aggregation.startTs, [end]: aggregation.endTs })
  155 + Reflect.deleteProperty(value, BuiltInVariable.SELECT_TIME_AGGREGATION)
  156 + }
  157 +
138 158 return value
139 159 })
140 160
... ... @@ -168,18 +188,25 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
168 188 }
169 189 })
170 190
  191 + /**
  192 + * ft 更改设备别名
  193 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  194 + * 源代码 labelField: 'name'
  195 + * 修改后代码 labelField: 'alias' || 'name'
  196 + */
171 197 const getSelectDevice = computed<SelectProps>(() => {
172 198 return {
173 199 ...basicPreset('name'),
174 200 value: params[BuiltInVariable.ENTITY_ID],
175 201 options: unref(optionsSet[BuiltInVariable.ENTITY_ID]),
176   - labelField: 'name',
  202 + labelField: 'alias',
177 203 valueField: 'tbDeviceId',
178 204 onUpdateValue(value) {
179 205 params[BuiltInVariable.ENTITY_ID] = value
180 206 }
181 207 }
182 208 })
  209 + //ft
183 210
184 211 const getSelectDeviceAttr = computed<SelectProps>(() => {
185 212 return {
... ... @@ -188,6 +215,7 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
188 215 options: unref(optionsSet[BuiltInVariable.KEYS]),
189 216 labelField: 'name',
190 217 valueField: 'identifier',
  218 + multiple: true,
191 219 onUpdateValue(value) {
192 220 params[BuiltInVariable.KEYS] = value
193 221 }
... ... @@ -230,6 +258,15 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
230 258 } as InputProps
231 259 }
232 260
  261 + const getSelectTimeAggregation = computed(() => {
  262 + return {
  263 + value: params[BuiltInVariable.SELECT_TIME_AGGREGATION],
  264 + onChange(value: SelectTimeAggregationValueTypw) {
  265 + params[BuiltInVariable.SELECT_TIME_AGGREGATION] = value
  266 + }
  267 + }
  268 + })
  269 +
233 270 const builtInVariableConfiguration: { [key in BuiltInVariable]?: DynamicFormSchema } = {
234 271 [BuiltInVariable.ORGANIZATION_ID]: {
235 272 component: ComponentType.SELECT_TREE,
... ... @@ -260,9 +297,31 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
260 297 component: ComponentType.DATE_PICKER,
261 298 key: BuiltInVariable.DATE_FIXED,
262 299 props: getSelectDate
  300 + },
  301 + }
  302 +
  303 + const moresComponentConfiguration: { [key in BuiltInVariable]?: DynamicFormSchema } = {
  304 + [BuiltInVariable.DATE_RANGE]: {
  305 + component: ComponentType.SELECT_TIME_AGGREGATION,
  306 + key: BuiltInVariable.SELECT_TIME_AGGREGATION,
  307 + props: getSelectTimeAggregation
263 308 }
264 309 }
265 310
  311 + const timePeriodRules = (required: boolean, key: string, message: string) => {
  312 + return [{
  313 + trigger: ['blur', 'change'],
  314 + validator() {
  315 + const record = params[BuiltInVariable.SELECT_TIME_AGGREGATION]
  316 + if (required && ![record[SelectTimeAggregationFieldEnum.AGG], record[SelectTimeAggregationFieldEnum.INTERVAL], record[SelectTimeAggregationFieldEnum.END_TS], record[SelectTimeAggregationFieldEnum.START_TS]].every(Boolean)) {
  317 + validFlag.value = false
  318 + return new Error(`${message}需要填写完整`)
  319 + }
  320 + validFlag.value = true
  321 + }
  322 + }] as FormItemRule
  323 + }
  324 +
266 325 const validFlag = ref(true)
267 326
268 327 const createRules = (required: boolean, key: string, message: string) => {
... ... @@ -278,23 +337,31 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
278 337 }] as FormItemRule
279 338 }
280 339
281   - const toFormSchemas = (builtInVariableKey: string, required: boolean, value: any) => {
  340 + const uuid = () => Number(Math.random().toString().substring(2)).toString(32)
  341 + const toFormSchemas = (builtInVariableKey: string, required: boolean, value: any, mores: boolean) => {
282 342 const groupList = (builtInVariableKey || '').split(GROUP_SEPARATOR)
283 343 return groupList.reduce((prev, next) => {
284   - const result = builtInVariableConfiguration[next as BuiltInVariable]
285   - const props = unref(result?.props)
  344 + let result = builtInVariableConfiguration[next as BuiltInVariable]
  345 + let props = unref(result?.props)
286 346 const name = (unref(builtInVariable) || {})[next as BuiltInVariable]?.itemText
287 347 let schema: DynamicFormSchema
288   - if (builtInVariableConfiguration[next as BuiltInVariable]) {
  348 + if (result) {
  349 + if (mores) {
  350 + result = moresComponentConfiguration[next as BuiltInVariable]
  351 + props = unref(result?.props)
  352 + }
  353 +
289 354 schema = {
290 355 ...result,
  356 + // uuid: uuid(),
291 357 props,
292 358 name,
293 359 required,
294   - rules: createRules(required, next, name || next)
  360 + rules: mores ? timePeriodRules(required, next, name || next) : createRules(required, next, name || next)
295 361 } as DynamicFormSchema
296 362 } else {
297 363 schema = {
  364 + // uuid: uuid(),
298 365 key: value,
299 366 name: value,
300 367 component: ComponentType.INPUT,
... ... @@ -303,7 +370,6 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
303 370 rules: createRules(required, value, value)
304 371 } as DynamicFormSchema
305 372 }
306   -
307 373 return [...prev, schema]
308 374
309 375 }, [] as DynamicFormSchema[])
... ... @@ -311,10 +377,11 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
311 377 }
312 378
313 379 const getDynamicFormSchemas = computed<DynamicFormSchema[]>(() => {
314   - return unref(getParams).reduce((prev: DynamicFormSchema[], { key, value, required }) => {
315   - const schemas = toFormSchemas(key, required, value)
  380 + const result = unref(getParams).reduce((prev: DynamicFormSchema[], { key, value, required, mores }) => {
  381 + const schemas = toFormSchemas(key, required, value, mores)
316 382 return [...prev, ...schemas]
317 383 }, [] as DynamicFormSchema[])
  384 + return result
318 385 })
319 386
320 387 const createForm = async () => {
... ... @@ -324,16 +391,23 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
324 391 getDeviceOption()
325 392 }
326 393
327   - const setParams = (Params: Recordable = {}) => {
328   - for (const { key, value } of unref(getParams)) {
329   - const splitKeys = value ? value.split(GROUP_SEPARATOR) : key.split(GROUP_SEPARATOR)
  394 + const setParams = (Params: Recordable = {}) => {
  395 + for (const { key, value, mores } of unref(getParams)) {
  396 + const splitKeys = value ? value.split(GROUP_SEPARATOR) : (key || '').split(GROUP_SEPARATOR)
330 397 if (isDateComponent(key as BuiltInVariable)) {
331 398 if (key as BuiltInVariable === BuiltInVariable.DATE_FIXED) {
332 399 params[key] = Params[splitKeys[0]] || null
333 400 continue
334 401 }
335   - const value = [Params[splitKeys[0]], Params[splitKeys[1]]]
336   - params[key] = value.every(Boolean) ? value : null
  402 + if (mores) {
  403 + const { agg, interval, limit } = Params
  404 + const startTs = Params[splitKeys[0]]
  405 + const endTs = Params[splitKeys[1]]
  406 + params[BuiltInVariable.SELECT_TIME_AGGREGATION] = { agg, interval, startTs, endTs, limit }
  407 + } else {
  408 + const value = [Params[splitKeys[0]], Params[splitKeys[1]]]
  409 + params[key] = value.every(Boolean) ? value : null
  410 + }
337 411 continue
338 412 }
339 413 for (const temp of splitKeys) {
... ... @@ -345,11 +419,14 @@ export const useDynamicPublicForm = (paramsItemList: Ref<ParamsItemType[]>) => {
345 419 const clearParams = () => {
346 420 Object.keys(params).forEach(key => {
347 421 Reflect.deleteProperty(params, key)
  422 + // params[key] = null
348 423 })
  424 + // params[BuiltInVariable.SELECT_TIME_AGGREGATION] = { startTs: null, endTs: null, limit: null, interval: null }
  425 + params[BuiltInVariable.SELECT_TIME_AGGREGATION] = {}
349 426 }
350 427
351 428 const setDynamicFormValue = (params: Recordable) => {
352   - setParams(params)
  429 + setParams(params)
353 430 getOrgOption()
354 431 getDeviceProfileOption()
355 432 getDeviceOption()
... ...
... ... @@ -2,10 +2,10 @@
2 2 import { getAllPublicInterface } from '@/api/external/dynamicRequest'
3 3 import { ParamsItemType, PublicInterfaceRecord, PublicInterfaceRequestParams, PublicInterfaceStateEnum } from '@/api/external/dynamicRequest/model';
4 4 import { SettingItem, SettingItemBox } from '@/components/Pages/ChartItemSetting';
5   -import { RequestContentTypeEnum, RequestContentTypeNameEnum } from '@/enums/external/httpEnum';
  5 +import { RequestContentTypeEnum, RequestContentTypeNameEnum, RequestEnum } from '@/enums/external/httpEnum';
6 6 import { RequestBodyEnum, RequestHttpEnum, RequestHttpIntervalEnum, RequestParams, RequestParamsTypeEnum } from '@/enums/httpEnum';
7   -import { NCard, NEmpty, NInputGroup, NInputNumber, NScrollbar, NSelect, NTabPane, NTabs, SelectOption } from 'naive-ui';
8   -import { ref, computed, unref, nextTick } from 'vue'
  7 +import { NCard, NEllipsis, NEmpty, NInputGroup, NInputNumber, NScrollbar, NSelect, NSpace, NTabPane, NTabs, SelectOption } from 'naive-ui';
  8 +import { ref, computed, unref, nextTick, h } from 'vue'
9 9 import { selectTimeOptions, selectTypeOptions } from '../../../index.d';
10 10 import ParamsTable from '../RequestModal/ParamsTable.vue';
11 11 import BodyContent from './BodyContent.vue'
... ... @@ -43,7 +43,14 @@ const getSelectedInterfaceParams = computed(() => {
43 43
44 44 const getPublicInterfaceList = async () => {
45 45 if (unref(publicInterfaceList).length) return
46   - const result = await getAllPublicInterface({ state: PublicInterfaceStateEnum.PUBLISH })
  46 + /**
  47 + * ft 更换接口
  48 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  49 + * 源代码 const result = await getAllPublicInterface({ state: PublicInterfaceStateEnum.PUBLISH })
  50 + * 修改后代码 const result = await getAllPublicInterface()
  51 + */
  52 + const result = await getAllPublicInterface()
  53 + //ft
47 54 publicInterfaceList.value = result
48 55 }
49 56
... ... @@ -141,6 +148,30 @@ const setConfigurationData = async (request: ExtraRequestConfigType) => {
141 148 setDynamicFormValue(request)
142 149 }
143 150
  151 + /**
  152 + * ft 修改在公共接口下拉框里加上接口类型
  153 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  154 + * 源代码 属于新增代码,源代码无
  155 + * 修改后代码在//ft之间
  156 + */
  157 +
  158 +const getHttpType = (httpType:RequestEnum, contentType:number) => {
  159 + if(contentType===0){
  160 + if (httpType === RequestEnum[httpType]) return RequestEnum[httpType]
  161 + }
  162 + else if (contentType===2) return 'WebSocket'
  163 +}
  164 +
  165 +const renderOption = (option: SelectOption) => {
  166 + const httpType = getHttpType(option?.requestHttpType as RequestEnum, option?.requestContentType as number)
  167 + const interfaceTypeName = option?.interfaceType === 'SYSTEM' ? '系统默认' :option?.interfaceType === 'CUSTOM'? '自定义':''
  168 + return h(NSpace, { justify: 'space-between', style: 'padding: 0 15px; height: 28px; line-height: 28px;' }, () => [
  169 + h(NEllipsis, null, () => `${!httpType?'':httpType+'/'}${interfaceTypeName}`),
  170 + h(NEllipsis, null, () => option.interfaceName),
  171 + ])
  172 +}
  173 +//ft
  174 +
144 175 defineExpose({
145 176 getConfigurationData,
146 177 setConfigurationData,
... ... @@ -154,10 +185,19 @@ defineExpose({
154 185 <SettingItemBox name="公共接口" :alone="true" :item-right-style="{ gridTemplateColumns: '5fr 2fr 1fr' }">
155 186 <SettingItem name="请求方式 & URL地址">
156 187 <NInputGroup>
  188 + <!--
  189 + /**
  190 + * ft 修改在公共接口下拉框里加上接口类型
  191 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  192 + * 源代码 无
  193 + * 修改后代码 新增一句 :render-label="renderOption"
  194 + */
  195 + -->
157 196 <NSelect v-model:value="selectedPublicInterface" label-field="interfaceName" value-field="id"
158 197 :options="publicInterfaceList" :filter="handleFilter" filterable :reset-menu-on-options-change="false"
159   - @update-value="handleSelectedInterfaceChange" size="small">
  198 + @update-value="handleSelectedInterfaceChange" size="small" :render-label="renderOption">
160 199 </NSelect>
  200 + <!-- ft -->
161 201 <NSelect v-if="requestContentTypeRef !== RequestContentTypeEnum.WEB_SOCKET" v-model:value="requestHttpTypeRef"
162 202 style="width: 150px;" size="small" :options="(selectTypeOptions as SelectOption[])" :disabled="true" />
163 203 <NSelect v-if="requestContentTypeRef === RequestContentTypeEnum.WEB_SOCKET" :disabled="true" style="width: 150px;"
... ... @@ -225,6 +265,7 @@ defineExpose({
225 265 </NScrollbar>
226 266 </NCard>
227 267 </SettingItemBox>
  268 + <!-- ft -->
228 269 </template>
229 270
230 271 <style scoped lang="scss">
... ...
... ... @@ -11,6 +11,9 @@ import { PublicInterfaceForm } from '../PublicInterfaceForm';
11 11 import ComponentConfiguration from './ComponentConfiguration.vue';
12 12 import GlobalPublicConfiguration from './GlobalPublicConfiguration.vue';
13 13 import { createRequestModalContext } from './useRequestModalContext';
  14 +import { useTargetData } from '../../../../hooks/useTargetData.hook';
  15 +import { useFetchTargetData } from '@/hooks/external/useFetchTargetData';
  16 +import { useFilterFn } from '@/hooks/external/useFilterFn';
14 17
15 18
16 19 const requestDataType = ref<RequestDataTypeEnum>(RequestDataTypeEnum.AJAX)
... ... @@ -67,9 +70,26 @@ const getResult = () => {
67 70 return {} as unknown as RequestConfigType
68 71 }
69 72
  73 +const { targetData } = useTargetData()
  74 +const { fetchTargetData } = useFetchTargetData()
  75 +// 发送请求
  76 +const sendHandle = async () => {
  77 + if (!targetData.value?.request || !targetData.value.request.requestUrl) {
  78 + window['$message'].warning('请先配置请求')
  79 + return
  80 + }
  81 + const res = await fetchTargetData()
  82 + if (res) {
  83 + const { value } = useFilterFn(targetData.value.filter, res)
  84 + targetData.value.option.dataset = value
  85 + return
  86 + }
  87 +
  88 +}
  89 +
70 90 const handleSaveAction = async () => {
71 91 if (!(await validate())) return
72   - const value = getResult()
  92 + const value = getResult()
73 93 if (unref(selectTarget)) {
74 94 chartEditStore.updateComponentList(chartEditStore.fetchTargetIndex(), {
75 95 ...unref(selectTarget)!,
... ... @@ -77,6 +97,7 @@ const handleSaveAction = async () => {
77 97 })
78 98 }
79 99 showModal.value = false
  100 + sendHandle()
80 101 }
81 102
82 103 createRequestModalContext({
... ...
  1 +export { default as SelectTimeAggregation } from './index.vue'
  2 +
  3 +export interface SelectTimeAggregationValueTypw {
  4 + timePeriod?: Nullable<number>
  5 + startTs?: Nullable<number>
  6 + endTs?: Nullable<number>
  7 + agg?: Nullable<string>
  8 + interval?: Nullable<number>
  9 +}
  10 +
  11 +
  12 +export enum SelectTimeAggregationFieldEnum {
  13 + TIME_PERIOD = 'timePeriod',
  14 + START_TS = 'startTs',
  15 + END_TS = 'endTs',
  16 + AGG = 'agg',
  17 + INTERVAL = 'interval'
  18 +}
  19 +
... ...
  1 +<script lang="ts" setup>
  2 +import { NFormItem, NGi, NGrid, NSelect, NDatePicker, NInputNumber } from 'naive-ui';
  3 +import { defaultIntervalOptions, aggergationOptions } from '../DynamicForm/timeInterval'
  4 +import { unref, computed, ref, watch } from 'vue';
  5 +import { isObject } from '@/utils/external/is';
  6 +
  7 +interface Value {
  8 + agg?: Nullable<string>
  9 + interval?: Nullable<number>
  10 + startTs?: Nullable<number>
  11 + endTs?: Nullable<number>
  12 + limit?: Nullable<number>
  13 +}
  14 +
  15 +const props = withDefaults(
  16 + defineProps<{
  17 + value?: Value
  18 + }>(),
  19 + {
  20 + value: () => ({})
  21 + }
  22 +)
  23 +
  24 +const emit = defineEmits<{
  25 + (e: 'update:value', value: Value): void
  26 + (e: 'change', value: Value): void
  27 +}>()
  28 +
  29 +
  30 +const timePeriod = ref<Nullable<[number, number]>>(null)
  31 +const agg = ref()
  32 +const interval = ref()
  33 +const limit = ref(7)
  34 +
  35 +const getRangeOptions = (number: number) => {
  36 + for (let i = 0; i < defaultIntervalOptions.length; i++) {
  37 + const option = defaultIntervalOptions[i]
  38 + if (option.id >= number || i === defaultIntervalOptions.length - 1) {
  39 + return option.linkage
  40 + }
  41 +
  42 + }
  43 +}
  44 +
  45 +const getShowLimit = computed(() => {
  46 + return unref(agg) === 'NONE'
  47 +})
  48 +
  49 +const getIntervalTimeOptions = computed(() => {
  50 + const [startTs, endTs] = unref(timePeriod) || []
  51 + if (!startTs || !endTs) return []
  52 + const diff = Math.abs(startTs - endTs)
  53 + return getRangeOptions(diff)
  54 +})
  55 +
  56 +const handleTimePerionChange = (value: number[]) => {
  57 + const [startTs, endTs] = value
  58 + emit('update:value', { ...props.value, startTs, endTs, interval: null })
  59 + emit('change', { ...props.value || {}, startTs, endTs, interval: null })
  60 +}
  61 +
  62 +const handleAggChange = (value: string) => {
  63 + const _value = { ...props.value, agg: value, ...(value === 'NONE' ? { limit: 7 } : {}) }
  64 + Reflect.deleteProperty(_value, value === 'NONE' ? 'interval' : 'limit')
  65 + emit('update:value', _value)
  66 + emit('change', _value)
  67 +}
  68 +
  69 +const handleIntervalChange = (value: number) => {
  70 + const _value = { ...props.value, interval: value }
  71 + emit('update:value', _value)
  72 + emit('change', _value)
  73 +}
  74 +
  75 +const handleLimitChange = (value: Nullable<number>) => {
  76 + const _value = { ...props.value, limit: value }
  77 + emit('update:value', _value)
  78 + emit('change', _value)
  79 +}
  80 +
  81 +watch(() => props.value, (target) => {
  82 + if (target && isObject(target)) {
  83 + const { agg: _agg, interval: _interval, startTs, endTs, limit: _limit } = target || {}
  84 + if (startTs && endTs) {
  85 + timePeriod.value = [startTs!, endTs!]
  86 + } else {
  87 + timePeriod.value = null
  88 + }
  89 + agg.value = _agg
  90 + limit.value = _limit!
  91 + interval.value = _interval
  92 + }
  93 +})
  94 +</script>
  95 +
  96 +<template>
  97 + <NGrid :cols="24">
  98 + <NGi :span="16">
  99 + <NFormItem :show-label="false">
  100 + <NDatePicker v-model:value="timePeriod" type="datetimerange" placeholder="请选择时间范围"
  101 + @update-value="handleTimePerionChange" clearable></NDatePicker>
  102 + </NFormItem>
  103 + </NGi>
  104 + <NGi :span="4">
  105 + <NFormItem :show-label="false">
  106 + <NSelect v-model:value="agg" @update:value="handleAggChange" :options="aggergationOptions" label-field="name"
  107 + value-field="id" placeholder="聚合方式" clearable></NSelect>
  108 + </NFormItem>
  109 + </NGi>
  110 + <NGi v-if="!getShowLimit" :span="4">
  111 + <NFormItem :show-label="false">
  112 + <NSelect v-model:value="interval" @update:value="handleIntervalChange" :options="getIntervalTimeOptions"
  113 + label-field="name" value-field="id" placeholder="间隔时间" clearable></NSelect>
  114 + </NFormItem>
  115 + </NGi>
  116 + <NGi v-if="getShowLimit" :span="4">
  117 + <NFormItem :show-label="false">
  118 + <NInputNumber v-model:value="limit" :default-value="7" @update:value="handleLimitChange"
  119 + :parse="(input: string) => parseInt(input)" :min="7" :max="50000" :step="1" placeholder="请输入最大条数" />
  120 + </NFormItem>
  121 + </NGi>
  122 + </NGrid>
  123 +</template>
... ...
... ... @@ -31,7 +31,7 @@
31 31 </n-tooltip>
32 32 <n-divider vertical />
33 33 <!-- 保存 -->
34   - <n-tooltip placement="bottom" trigger="hover">
  34 + <n-tooltip v-if="!isCustomerUser" placement="bottom" trigger="hover">
35 35 <template #trigger>
36 36 <div class="save-btn">
37 37 <n-button size="small" type="primary" ghost @click="dataSyncUpdate()">
... ... @@ -64,6 +64,7 @@ import { HistoryStackEnum } from '@/store/modules/chartHistoryStore/chartHistory
64 64 import { useSyncRemote } from '../../../hooks/external/useRemote.hook'
65 65 import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
66 66 import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
  67 +import { useRole } from '@/views/chart/hooks/external/business/useRole'
67 68
68 69 const { LayersIcon, BarChartIcon, PrismIcon, HomeIcon, ArrowBackIcon, ArrowForwardIcon } = icon.ionicons5
69 70 const { setItem } = useChartLayoutStore()
... ... @@ -71,6 +72,7 @@ const { getLayers, getCharts, getDetails } = toRefs(useChartLayoutStore())
71 72 const chartEditStore = useChartEditStore()
72 73 const chartHistoryStore = useChartHistoryStore()
73 74 const { dataSyncUpdate } = useSyncRemote()
  75 +const { isCustomerUser } = useRole()
74 76
75 77 interface ItemType<T> {
76 78 key: T
... ...
  1 +import { RoleEnum } from '@/enums/external/roleEnum';
  2 +import { useUserStore } from '@/store/external/modules/user';
  3 +import { computed, unref } from 'vue';
  4 +
  5 +export const useRole = () => {
  6 + const userStore = useUserStore();
  7 +
  8 + const getRole = computed(() => {
  9 + return userStore.userInfo?.roles![0] as RoleEnum;
  10 + });
  11 +
  12 + const isPlatformAdmin = computed(() => {
  13 + return unref(getRole) === RoleEnum.PLATFORM_ADMIN;
  14 + });
  15 +
  16 + const isCustomerUser = computed(() => {
  17 + return unref(getRole) === RoleEnum.CUSTOMER_USER;
  18 + });
  19 +
  20 + const isTenantAdmin = computed(() => {
  21 + return unref(getRole) === RoleEnum.TENANT_ADMIN;
  22 + });
  23 +
  24 + const isSysadmin = computed(() => {
  25 + return unref(getRole) === RoleEnum.SYS_ADMIN;
  26 + });
  27 +
  28 + return { getRole, isPlatformAdmin, isCustomerUser, isTenantAdmin, isSysadmin };
  29 +};
... ...
1 1 import { fetchRouteParamsLocation, JSONStringify, JSONParse } from '@/utils'
2 2 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
3 3 import { ProjectInfoEnum } from '@/store/external/modules/projectInfo.d'
4   -import { onUnmounted } from 'vue'
  4 +import { onUnmounted, unref } from 'vue'
5 5 import { saveInterval } from '@/settings/designSetting'
6 6 import throttle from 'lodash/throttle'
7 7 import html2canvas from 'html2canvas'
... ... @@ -11,6 +11,7 @@ import { SyncEnum } from '@/enums/external/editPageEnum'
11 11 import { useProjectInfoStore } from '@/store/external/modules/projectInfo'
12 12 import { useSync } from '../useSync.hook'
13 13 import { BaseUpdateContentParams, DateViewConfigurationInfoType } from '@/api/external/contentSave/model/contentModel'
  14 +import { useRole } from './business/useRole'
14 15
15 16 /**
16 17 * * base64转file
... ... @@ -37,6 +38,7 @@ export const useSyncRemote = () => {
37 38 const chartEditStore = useChartEditStore()
38 39 const projectInfoStore = useProjectInfoStore()
39 40 const { updateComponent } = useSync()
  41 + const { isCustomerUser } = useRole()
40 42
41 43 /**
42 44 * * 赋值全局数据
... ... @@ -71,6 +73,10 @@ export const useSyncRemote = () => {
71 73 // 数据保存
72 74 const dataSyncUpdate = throttle(async (updateImg = true) => {
73 75 if (!fetchRouteParamsLocation()) return
  76 +
  77 + // 客户角色只有查看权限
  78 + if (unref(isCustomerUser)) return
  79 +
74 80 const { dataViewId, state, organizationId, dataViewName, dataViewContent } = projectInfoStore.getProjectInfo
75 81
76 82 if (dataViewId === null || dataViewId === '') {
... ...
  1 +export const isShareMode = () => {
  2 + const sharePageReg = /^\/share\/[^/]+\/[^/]+\/[^/]+$/;
  3 + const { hash } = location;
  4 + return sharePageReg.test(hash.substring(1));
  5 +};
... ...
1 1 <template>
2 2 <section>
3 3 <preview v-if="!allowLoadPreviewPage" :key="key"></preview>
  4 + <NEmpty v-if="isEmpty" style="position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);" />
4 5 <NModal :show="showModal" :maskClosable="false" :closable="false" style="width: 300px;">
5 6 <NCard>
6 7 <NForm @keyup.enter="handleSubmit">
7 8 <NFormItem label="访问令牌">
8   - <NInput v-model:value="accessCredentials" type="password" />
9   - </NFormItem>
10   - <NFormItem :showLabel="false">
11   - <NButton :loading="loading" type="primary" style="width: 100%;" @click="handleSubmit">访问</NButton>
  9 + <NInputGroup>
  10 + <NInput v-model:value="accessCredentials" show-password-on="mousedown" type="password"
  11 + style="width: 70%;" />
  12 + <NButton :loading="loading" type="primary" style="width: 30%;" @click="handleSubmit">
  13 + <svg style="transform: rotate(180deg);" t="1682068997810" class="icon" viewBox="0 0 1024 1024"
  14 + version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="79416" width="24" height="24">
  15 + <path
  16 + d="M512 928H128c-19.2 0-32-12.8-32-32V128c0-19.2 12.8-32 32-32h384c19.2 0 32 12.8 32 32s-12.8 32-32 32H160v704h352c19.2 0 32 12.8 32 32s-12.8 32-32 32z"
  17 + fill="#fff" p-id="79417" />
  18 + <path
  19 + d="M534.4 736c-9.6 0-16-3.2-22.4-9.6l-192-192c-12.8-12.8-12.8-32 0-44.8l192-192c12.8-12.8 32-12.8 44.8 0 12.8 12.8 12.8 32 0 44.8L387.2 512l169.6 169.6c12.8 12.8 12.8 32 0 44.8-6.4 6.4-16 9.6-22.4 9.6z"
  20 + fill="#fff" p-id="79418" />
  21 + <path d="M896 544H342.4c-19.2 0-32-12.8-32-32s12.8-32 32-32H896c19.2 0 32 12.8 32 32s-12.8 32-32 32z"
  22 + fill="#fff" p-id="79419" />
  23 + </svg>
  24 + </NButton>
  25 + </NInputGroup>
12 26 </NFormItem>
13 27 </NForm>
14 28 </NCard>
... ... @@ -17,11 +31,11 @@
17 31 </template>
18 32
19 33 <script setup lang="ts">
20   -import { NModal, NCard, NForm, NFormItem, NInput, NButton, } from 'naive-ui'
  34 +import { NEmpty, NCard, NForm, NFormItem, NInput, NButton, NInputGroup } from 'naive-ui'
21 35 import { getSessionStorageInfo } from '../preview/utils'
22 36 import type { ChartEditStorageType } from '../preview/index.d'
23 37 import { SavePageEnum } from '@/enums/editPageEnum'
24   -import { JSONParse, setSessionStorage } from '@/utils'
  38 +import { JSONParse, setSessionStorage, setTitle } from '@/utils'
25 39 import { StorageEnum } from '@/enums/storageEnum'
26 40 import { onMounted, ref, unref } from 'vue'
27 41 import Preview from '../preview/index.vue'
... ... @@ -42,7 +56,7 @@ const getToken = async () => {
42 56 const { params } = ROUTE
43 57 const { publicId } = params as Record<'id' | 'publicId', string>
44 58 const { token, refreshToken } = await getPublicToken(publicId)
45   - userStore.storeToken(token, refreshToken)
  59 + userStore.storeShareToken(token, refreshToken)
46 60 }
47 61
48 62 const checkNeedAccessToken = async () => {
... ... @@ -63,6 +77,7 @@ const sharePageHandlerProcess = async () => {
63 77 }
64 78 }
65 79
  80 +const isEmpty = ref(false)
66 81 const getSharePageContentData = async () => {
67 82 try {
68 83 const { params } = ROUTE
... ... @@ -70,15 +85,17 @@ const getSharePageContentData = async () => {
70 85 loading.value = true
71 86 const res = await getShareContentData({ id, accessCredentials: unref(accessCredentials) })
72 87 const { dataViewContent, dataViewName, dataViewId } = res.data
73   - const content = JSONParse(dataViewContent.content) as ChartEditStorageType
  88 + if (!dataViewContent.content) isEmpty.value = true
  89 + const content = JSONParse(dataViewContent.content || '{}') as ChartEditStorageType
74 90 if (content) {
75 91 const { editCanvasConfig, requestGlobalConfig, componentList } = content
76 92 chartEditStore.editCanvasConfig = editCanvasConfig
77 93 chartEditStore.requestGlobalConfig = requestGlobalConfig
78 94 chartEditStore.componentList = componentList
79 95 }
  96 + setTitle(dataViewName || '')
80 97 showModal.value = false
81   - allowLoadPreviewPage.value = false
  98 + allowLoadPreviewPage.value = unref(isEmpty)
82 99 } catch (error) {
83 100 console.log(error)
84 101 } finally {
... ...
... ... @@ -20,7 +20,8 @@
20 20 ],
21 21 "typeRoots": [
22 22 "./node_modules/@types/",
23   - "./types"
  23 + "./types",
  24 + "./types/external"
24 25 ],
25 26 "paths": {
26 27 "@/*": [
... ...
... ... @@ -21,6 +21,8 @@ export interface RequestOptions {
21 21 ignoreCancelToken?: boolean;
22 22 // Whether to send token in header
23 23 withToken?: boolean;
  24 + // Carry and share token 携带分享的访问令牌
  25 + withShareToken?: boolean
24 26 }
25 27
26 28 export interface Result<T = any> {
... ...