Commit 46909226921fc5fb02fbf9e9b59ed6499c8a8c77

Authored by xp.Huang
2 parents c0a4a0fb cb813ee9

Merge branch 'main_dev' into 'main'

Revert "Merge branch 'perf/view-interface' into 'main_dev'"

See merge request yunteng/thingskit-view!272
Showing 76 changed files with 3526 additions and 325 deletions

Too many changes to show.

To preserve performance only 76 of 95 files are displayed.

... ... @@ -12,3 +12,4 @@ VITE_GLOB_CONTENT_SECURITY_POLICY = false
12 12
13 13 # 公共路径
14 14 VITE_GLOB_PUBLIC_PATH = /large-designer/
  15 +
... ...
... ... @@ -4,6 +4,31 @@ import { Plugin } from "vite";
4 4 import { GLOB_CONFIG_FILE_NAME } from "./const";
5 5 import { getGlobalConfigName } from "./getGlobConfigName";
6 6
  7 +
  8 +const stringToJSONParse = (string: string) => {
  9 + try {
  10 + return JSON.parse(string);
  11 + } catch (error) {
  12 + return string;
  13 + }
  14 +};
  15 +
  16 +export function parseEnv(env: Record<string, string>) {
  17 + const res: Record<string, string> = {};
  18 +
  19 + Object.keys(env).forEach((key) => {
  20 + try {
  21 + const value = env[key];
  22 + res[key] = stringToJSONParse(value);
  23 + } catch (err) {
  24 + // eslint-disable-next-line no-console
  25 + console.log(`env variable ${key} can't serialization!`);
  26 + }
  27 + });
  28 +
  29 + return res;
  30 +}
  31 +
7 32 export function GenerateBuildConfig(viteEnv: Record<string, any>) {
8 33 return {
9 34 name: 'vite-plugin-generate-global-config',
... ... @@ -15,7 +40,7 @@ export function GenerateBuildConfig(viteEnv: Record<string, any>) {
15 40 try {
16 41 const windowConf = `window.${configName}`;
17 42 // Ensure that the variable will not be modified
18   - const configStr = `${windowConf}=${JSON.stringify(config)};
  43 + const configStr = `${windowConf}=${JSON.stringify(parseEnv(config))};
19 44 Object.freeze(${windowConf});
20 45 Object.defineProperty(window, "${configName}", {
21 46 configurable: false,
... ...
... ... @@ -159,4 +159,7 @@ export const getAlarmList = (params?: object) =>
159 159 defHttp.get({
160 160 url: Api.ALARM_LIST,
161 161 params
  162 + },
  163 + {
  164 + withShareToken: true
162 165 })
... ...
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';
  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 12
13   -const globSetting = useGlobSetting();
14   -const urlPrefix = globSetting.urlPrefix;
  13 +const globSetting = useGlobSetting()
  14 +const urlPrefix = globSetting.urlPrefix
15 15
16 16 /**
17 17 * @description: 数据处理,方便区分多种处理方式
... ... @@ -21,62 +21,59 @@ const transform: AxiosTransform = {
21 21 * @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误
22 22 */
23 23 transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
24   - const { isReturnNativeResponse } = options;
  24 + const { isReturnNativeResponse } = options
25 25 // 是否返回原生响应头 比如:需要获取响应头时使用该属性
26 26 if (isReturnNativeResponse) {
27   - return res;
  27 + return res
28 28 }
29   - return res.data;
  29 + return res.data
30 30 },
31 31
32 32 // 请求之前处理config
33 33 beforeRequestHook: (config, options) => {
34   - const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options;
  34 + const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options
35 35
36 36 if (joinPrefix) {
37   - config.url = `${urlPrefix}${config.url}`;
  37 + config.url = `${urlPrefix}${config.url}`
38 38 }
39 39
40 40 if (apiUrl && isString(apiUrl)) {
41   - config.url = `${apiUrl}${config.url}`;
  41 + config.url = `${apiUrl}${config.url}`
42 42 }
43 43
44   - const params = config.params || {};
45   - const data = config.data || false;
46   - formatDate && data && !isString(data) && formatRequestDate(data);
  44 + const params = config.params || {}
  45 + const data = config.data || false
  46 + formatDate && data && !isString(data) && formatRequestDate(data)
47 47 if (config.method?.toUpperCase() === RequestEnum.GET) {
48 48 if (!isString(params)) {
49 49 // 给 get 请求加上时间戳参数,避免从缓存中拿数据。
50   - config.params = Object.assign(params || {}, joinTimestamp(joinTime, false));
  50 + config.params = Object.assign(params || {}, joinTimestamp(joinTime, false))
51 51 } else {
52 52 // 兼容restful风格
53   - config.url = config.url + params + `${joinTimestamp(joinTime, true)}`;
54   - config.params = undefined;
  53 + config.url = config.url + params + `${joinTimestamp(joinTime, true)}`
  54 + config.params = undefined
55 55 }
56 56 } else {
57 57 if (!isString(params)) {
58   - formatDate && formatRequestDate(params);
  58 + formatDate && formatRequestDate(params)
59 59 if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) {
60   - config.data = data;
61   - config.params = params;
  60 + config.data = data
  61 + config.params = params
62 62 } else {
63 63 // 非GET请求如果没有提供data,则将params视为data
64   - config.data = params;
65   - config.params = undefined;
  64 + config.data = params
  65 + config.params = undefined
66 66 }
67 67 if (joinParamsToUrl) {
68   - config.url = setObjToUrlParams(
69   - config.url as string,
70   - Object.assign({}, config.params, config.data)
71   - );
  68 + config.url = setObjToUrlParams(config.url as string, Object.assign({}, config.params, config.data))
72 69 }
73 70 } else {
74 71 // 兼容restful风格
75   - config.url = config.url + params;
76   - config.params = undefined;
  72 + config.url = config.url + params
  73 + config.params = undefined
77 74 }
78 75 }
79   - return config;
  76 + return config
80 77 },
81 78
82 79 /**
... ... @@ -84,21 +81,32 @@ const transform: AxiosTransform = {
84 81 */
85 82 requestInterceptors: (config, options) => {
86 83 // 请求之前处理config
87   - const { requestOptions } = config;
88   - const { withShareToken } = requestOptions || {};
89   - const { requestOptions: { withToken } = {} } = options;
  84 + const { requestOptions } = config
  85 + const { withShareToken } = requestOptions || {}
  86 + const { requestOptions: { withToken } = {} } = options
  87 + const { withThirdTokenPrefix, withThirdTokenKey, withThirdTokenString } = config.requestOptions as Recordable
90 88 if (withToken !== false) {
91   - const shareToken = getShareJwtToken();
  89 + const shareToken = getShareJwtToken()
92 90 if (withShareToken && shareToken) {
93 91 config.headers!['X-Authorization'] = options.authenticationScheme
94 92 ? `${options.authenticationScheme} ${shareToken}`
95   - : shareToken;
  93 + : shareToken
96 94 } else {
97   - const token = getJwtToken();
98   - if (token) {
99   - config.headers!['X-Authorization'] = options.authenticationScheme
100   - ? `${options.authenticationScheme} ${token}`
101   - : token;
  95 + const token = getJwtToken()
  96 + if (!withThirdTokenString) {
  97 + // 则是此平台
  98 + if (token) {
  99 + config.headers!['X-Authorization'] = options.authenticationScheme
  100 + ? `${options.authenticationScheme} ${token}`
  101 + : token
  102 + }
  103 + } else {
  104 + // 第三方接口
  105 + const authenticationScheme = !withThirdTokenPrefix ? 'Bearer': withThirdTokenPrefix
  106 + const tokenKey = withThirdTokenKey ? withThirdTokenKey : 'X-Authorization'
  107 + config.headers![tokenKey!] = withThirdTokenPrefix
  108 + ? `${authenticationScheme} ${withThirdTokenString}`
  109 + : `${withThirdTokenString}`
102 110 }
103 111 }
104 112 }
... ... @@ -109,25 +117,22 @@ const transform: AxiosTransform = {
109 117 * @description: 响应拦截器处理
110 118 */
111 119 responseInterceptors: (res: AxiosResponse<any>) => {
112   - return res;
  120 + return res
113 121 },
114 122
115 123 /**
116 124 * @description: 响应错误处理
117 125 */
118 126 responseInterceptorsCatch: (error: any) => {
  127 + const { response, config } = error || {}
  128 + const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'
  129 + const errorMsgIsObj = typeof response?.data === 'object'
  130 + const msg: string = errorMsgIsObj ? response?.data?.message || response?.data?.msg : response?.data
119 131
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   -};
  132 + const flag = checkStatus(error?.response?.status, msg, errorMessageMode)
  133 + return Promise.reject(response?.data)
  134 + }
  135 +}
131 136
132 137 function createAxios(opt?: Partial<CreateAxiosOptions>) {
133 138 return new VAxios(
... ... @@ -169,11 +174,11 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
169 174 ignoreCancelToken: true,
170 175 // 是否携带token
171 176 withToken: true
172   - },
  177 + }
173 178 },
174 179 opt || {}
175 180 )
176   - );
  181 + )
177 182 }
178   -export const customHttp = createAxios();
179 183
  184 +export const customHttp = createAxios()
... ...
1   -import { RequestBodyEnum, RequestHttpEnum, RequestParams } from "@/enums/httpEnum"
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"
  1 +import { RequestBodyEnum, RequestHttpEnum, RequestParams, RequestParamsObjType } from '@/enums/httpEnum'
  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'
  7 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
7 8
8 9 export enum ParamsType {
9 10 REQUIRED,
... ... @@ -20,7 +21,7 @@ const regDynamicParams = /(?={).+?(?<=})/g
20 21
21 22 /**
22 23 * @description 判断是否是动态参数
23   - * @param url
  24 + * @param url
24 25 */
25 26 export const isDynamicUrl = (url: string) => {
26 27 regDynamicParams.lastIndex = 0
... ... @@ -29,7 +30,7 @@ export const isDynamicUrl = (url: string) => {
29 30
30 31 /**
31 32 * @description 解析动态参数
32   - * @param url
  33 + * @param url
33 34 */
34 35 export const decomposeDynamicParams = (url: string) => {
35 36 regDynamicParams.lastIndex = 0
... ... @@ -46,8 +47,8 @@ export const decomposeDynamicParams = (url: string) => {
46 47
47 48 /**
48 49 * @description 正则替换url中的动态参数
49   - * @param requestUrl
50   - * @param Params
  50 + * @param requestUrl
  51 + * @param Params
51 52 */
52 53 const getDynamicRequestUrl = (requestUrl = '', Params: Recordable) => {
53 54 requestUrl = decodeURI(requestUrl || '')
... ... @@ -101,9 +102,9 @@ const handleParams = (Params: Recordable) => {
101 102 * 源代码 Params.keys = (Params.keys || [] as any).join(',')
102 103 */
103 104 if (!Array.isArray(Params.keys)) {
104   - Params.keys = ([Params.keys] || [] as any).join(',')
  105 + Params.keys = ([Params.keys] || ([] as any)).join(',')
105 106 } else {
106   - Params.keys = (Params.keys || [] as any).join(',')
  107 + Params.keys = (Params.keys || ([] as any)).join(',')
107 108 }
108 109 //ft
109 110 }
... ... @@ -115,27 +116,43 @@ const handleParams = (Params: Recordable) => {
115 116 Reflect.deleteProperty(Params, SelectTimeAggregationFieldEnum.TIME_PERIOD)
116 117 }
117 118
118   - return Object.keys(Params).filter(Boolean).reduce((prev, next) => ({ ...prev, [next]: Params[next] }), {})
  119 + return Object.keys(Params)
  120 + .filter(Boolean)
  121 + .reduce((prev, next) => ({ ...prev, [next]: Params[next] }), {})
119 122 }
120 123
121 124 //post请求动态追加query参数
122 125 const objConvertQuery = (data: Recordable) => {
123   - const _result = [];
  126 + const _result = []
124 127 for (const key in data) {
125   - const value = data[key];
  128 + const value = data[key]
126 129 if (value.constructor == Array) {
127 130 value.forEach(function (_value) {
128   - _result.push(key + "=" + _value);
129   - });
  131 + _result.push(key + '=' + _value)
  132 + })
130 133 } else {
131   - _result.push(key + '=' + value);
  134 + _result.push(key + '=' + value)
132 135 }
133 136 }
134   - return _result.join('&');
  137 + return _result.join('&')
135 138 }
136 139
137 140 export const customRequest = async (request: RequestConfigType) => {
138   - const { requestHttpType, requestParams, requestParamsBodyType, requestOriginUrl } = request as ExtraRequestConfigType
  141 + const {
  142 + requestHttpType,
  143 + requestParams,
  144 + requestParamsBodyType,
  145 + requestOriginUrl,
  146 + requestVerificationToken,
  147 + pondRequestOriginUrl,
  148 + pondRequestGlobalTokenKey,
  149 + pondRequestGlobalTokenSuffix,
  150 + pondRequestGlobalIsToken
  151 + } = request as ExtraRequestConfigType
  152 + const chartEditStore = useChartEditStore()
  153 +
  154 + const {requestOriginUrl: globalRequestOriginUrl} = chartEditStore.getRequestGlobalConfig
  155 +
139 156 let { requestUrl } = request as ExtraRequestConfigType
140 157 const { Header, Body } = requestParams
141 158 let { Params } = requestParams
... ... @@ -155,18 +172,48 @@ export const customRequest = async (request: RequestConfigType) => {
155 172 * 修改后代码 requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl: `${requestUrl}?${objConvertQuery(Params)}
156 173 */
157 174 Params = handleParams(Params)
158   -
159   - return customHttp.request<any>({
160   - url: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl : `${requestUrl}?${objConvertQuery(Params)}`,
161   - baseURL: getOriginUrl(requestOriginUrl!),
162   - method: requestHttpType,
163   - params: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? Params : null,
164   - data: body,
165   - headers: extraValue(Header)
166   - }, {
167   - joinPrefix: false,
168   - apiUrl: '',
169   - withShareToken: isShareMode()
170   - })
  175 + return customHttp.request<any>(
  176 + {
  177 + url:
  178 + requestHttpType === RequestHttpEnum.GET.toUpperCase() ? requestUrl : `${requestUrl}?${objConvertQuery(Params)}`,
  179 + baseURL: pondRequestGlobalIsToken ? requestVerificationToken ? pondRequestOriginUrl : globalRequestOriginUrl ? globalRequestOriginUrl : getOriginUrl(requestOriginUrl!): pondRequestOriginUrl,
  180 + method: requestHttpType,
  181 + params: requestHttpType === RequestHttpEnum.GET.toUpperCase() ? Params : null,
  182 + data: body,
  183 + headers: extraValue(Header)
  184 + },
  185 + {
  186 + joinPrefix: false,
  187 + apiUrl: '',
  188 + withToken:true,
  189 + withShareToken: !requestVerificationToken ? isShareMode(): false,
  190 + withThirdTokenString: requestVerificationToken,
  191 + withThirdTokenKey: pondRequestGlobalTokenKey,
  192 + withThirdTokenPrefix: pondRequestGlobalTokenSuffix
  193 + }
  194 + )
171 195 //ft
172 196 }
  197 +
  198 +export interface thirdInterfaceRequest {
  199 + requestOriginUrl: string
  200 + body: RequestParamsObjType
  201 +}
  202 +
  203 +//特殊处理第三方接口,一般获取token是POST请求,暂定POST
  204 +export const customThirdInterfaceRequest = async (request: thirdInterfaceRequest) => {
  205 + const { body, requestOriginUrl } = request
  206 +
  207 + return customHttp.request<any>(
  208 + {
  209 + url: requestOriginUrl,
  210 + method: RequestHttpEnum.POST,
  211 + data: body
  212 + },
  213 + {
  214 + joinPrefix: false,
  215 + apiUrl: '',
  216 + withToken: false
  217 + }
  218 + )
  219 +}
... ...
... ... @@ -164,12 +164,17 @@
164 164 <template #header>
165 165 <n-switch v-model:value="yAxis.show" size="small"></n-switch>
166 166 </template>
  167 + <setting-item-box name="范围">
  168 + <setting-item name="开启" >
  169 + <n-switch v-model:value="yAxis.showRange" size="small"></n-switch>
  170 + </setting-item>
  171 + </setting-item-box>
167 172 <setting-item-box name="范围" v-if="yAxis.showRange">
168 173 <setting-item name="最小值" >
169   - <n-input-number v-model:value="yAxis.min" size="small" min="0"></n-input-number>
  174 + <n-input-number v-model:value="yAxis.minData" size="small" min="0"></n-input-number>
170 175 </setting-item>
171 176 <setting-item name="最大值">
172   - <n-input-number v-model:value="yAxis.max" size="small" min="0"></n-input-number>
  177 + <n-input-number v-model:value="yAxis.maxData" size="small" min="0"></n-input-number>
173 178 </setting-item>
174 179 </setting-item-box>
175 180 <setting-item-box name="单位">
... ... @@ -418,13 +423,6 @@ const xAxis = computed(() => {
418 423 })
419 424
420 425 const yAxis = computed(() => {
421   - if((props.optionData?.yAxis as Recordable)){
422   - if(!(props.optionData?.yAxis as Recordable).showRange) {
423   - //针对横向柱状图和热力图
424   - Reflect.deleteProperty((props.optionData.yAxis as Recordable),'min');
425   - Reflect.deleteProperty((props.optionData.yAxis as Recordable),'max');
426   - }
427   - }
428 426 return props.optionData.yAxis
429 427 })
430 428
... ...
1 1 <template>
2   - <div ref="el" class="go-editor-area" :style="{ width, height }"></div>
3   - <EditorWorker></EditorWorker>
  2 + <div :style="cacheConfigStyle">
  3 + <div ref="el" class="go-editor-area" :style="{ width, height }"></div>
  4 + <EditorWorker></EditorWorker>
  5 + <div style="margin-left:10px;">
  6 + <n-gradient-text type="danger">
  7 + {{ errorText }}
  8 + </n-gradient-text>
  9 +</div>
  10 + </div>
4 11 </template>
5 12
6 13 <script lang="ts" setup>
7   -import { onMounted, watch, PropType } from 'vue'
  14 +import { onMounted, watch, PropType, ref, computed } from 'vue'
8 15 import { useMonacoEditor } from './index.hook'
9 16 import { EditorWorker } from './index'
10 17
... ... @@ -32,7 +39,11 @@ const props = defineProps({
32 39 editorOptions: {
33 40 type: Object as PropType<object>,
34 41 default: () => ({})
35   - }
  42 + },
  43 + config: {
  44 + type: Boolean as PropType<boolean>,
  45 + default: false
  46 + },
36 47 })
37 48
38 49 const emits = defineEmits(['blur', 'update:modelValue'])
... ... @@ -56,9 +67,30 @@ onMounted(() => {
56 67 updateMonacoVal()
57 68 })
58 69
  70 +const errorText = ref('')
  71 +
  72 +const cacheConfigStyle = computed(() => {
  73 + const configStyle = {
  74 + display:'flex',
  75 + justifyContent: 'space-between',
  76 + alignItems: 'center'
  77 + }
  78 + return props.config ? configStyle : ''
  79 +})
  80 +
59 81 watch(
60 82 () => props.modelValue,
61 83 (val: string) => {
  84 + if(props.language === 'json') {
  85 + try {
  86 + const res = JSON.parse(val)
  87 + if(res) {
  88 + errorText.value = ''
  89 + }
  90 + } catch (_) {
  91 + errorText.value = 'JSON格式有误,请仔细检查!'
  92 + }
  93 + }
62 94 val !== getEditor()?.getValue() && updateMonacoVal(val)
63 95 }
64 96 )
... ...
1 1 <script setup lang="ts">
2   -import Player, { Events, IError } from 'xgplayer';
3   -import { FlvPlugin } from 'xgplayer-flv';
4   -import Mp4Plugin from 'xgplayer-mp4';
5   -import { HlsPlugin } from 'xgplayer-hls';
6   -import { onMounted, shallowRef, computed, unref, toRaw, onUnmounted, ref, watch } from 'vue';
7   -import PresetPlayer from 'xgplayer';
8   -import { IPlayerOptions } from 'xgplayer/es/player';
9   -import 'xgplayer/dist/index.min.css';
10   -import { StreamType, XGPlayerProps } from './types';
11   -import { isShareMode } from "@/views/share/hook";
12   -import { getJwtToken, getShareJwtToken } from "@/utils/external/auth";
13   -
14   -const props = withDefaults(defineProps<{
15   - streamType?: StreamType;
16   - autoPlay?: boolean;
17   - url?: string;
18   - withToken?: boolean;
19   - config?: Omit<IPlayerOptions, 'url'>;
20   -}>(), {
21   - streamType: 'auto',
22   - autoPlay: true,
23   - config: () => ({}),
24   -});
  2 +import Player, { Events, IError } from 'xgplayer'
  3 +import { FlvPlugin } from 'xgplayer-flv'
  4 +import Mp4Plugin from 'xgplayer-mp4'
  5 +import { HlsPlugin } from 'xgplayer-hls'
  6 +import { onMounted, shallowRef, computed, unref, toRaw, onUnmounted, ref, watch } from 'vue'
  7 +import PresetPlayer from 'xgplayer'
  8 +import { IPlayerOptions } from 'xgplayer/es/player'
  9 +import 'xgplayer/dist/index.min.css'
  10 +import { StreamType, UserActionEventType, XGPlayerProps } from './types'
  11 +import { isShareMode } from '@/views/share/hook'
  12 +import { getJwtToken, getShareJwtToken } from '@/utils/external/auth'
  13 +
  14 +const props = withDefaults(
  15 + defineProps<{
  16 + streamType?: StreamType
  17 + autoPlay?: boolean
  18 + url?: string
  19 + withToken?: boolean
  20 + config?: Omit<IPlayerOptions, 'url'>
  21 + }>(),
  22 + {
  23 + streamType: 'auto',
  24 + autoPlay: true,
  25 + config: () => ({})
  26 + }
  27 +)
25 28
26 29 const emits = defineEmits<{
27   - (eventName: 'ready', player: PresetPlayer): void;
28   - (eventName: 'onUnmounted', player: PresetPlayer): void;
29   -}>();
  30 + (eventName: 'ready', player: PresetPlayer): void
  31 + (eventName: 'userAction', event: UserActionEventType, player: PresetPlayer): void
  32 + (eventName: 'onUnmounted', player: PresetPlayer): void
  33 +}>()
30 34
31 35 function parsePlayUrl(url: string) {
32 36 try {
33   - return new URL(url).pathname;
  37 + return new URL(url).pathname
34 38 } catch {
35   - return url;
  39 + return url
36 40 }
37 41 }
38 42
39 43 function getStreamTypeByUrl(url = ''): StreamType | undefined {
40 44 url = parsePlayUrl(url) || ''
41   - if (url.endsWith('.m3u8')) return 'hls';
42   - else if (url.endsWith('.mp4')) return 'mp4';
  45 + if (url.endsWith('.m3u8')) return 'hls'
  46 + else if (url.endsWith('.mp4')) return 'mp4'
43 47 else if (url.endsWith('.flv')) {
44   - return 'flv';
45   - } else return;
  48 + return 'flv'
  49 + } else return
46 50 }
47 51
48 52 const getPluginByStreamType = (): IPlayerOptions => {
49   - let { url, withToken } = props;
50   - let { streamType } = props;
51   - streamType = streamType === 'auto' ? getStreamTypeByUrl(url)! : streamType;
  53 + let { url, withToken } = props
  54 + let { streamType } = props
  55 + streamType = streamType === 'auto' ? getStreamTypeByUrl(url)! : streamType
52 56
53 57 const liveConfig = {
54 58 targetLatency: 10,
... ... @@ -56,38 +60,38 @@ const getPluginByStreamType = (): IPlayerOptions => {
56 60 disconnectTime: 0,
57 61 fetchOptions: withToken
58 62 ? {
59   - headers: {
60   - 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`,
61   - },
62   - }
63   - : {},
64   - };
  63 + headers: {
  64 + 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`
  65 + }
  66 + }
  67 + : {}
  68 + }
65 69 const config: IPlayerOptions = {
66 70 flv: liveConfig,
67   - hls: liveConfig,
68   - };
  71 + hls: liveConfig
  72 + }
69 73 switch (streamType) {
70 74 case 'hls':
71   - config.plugins = [HlsPlugin];
72   - break;
  75 + config.plugins = [HlsPlugin]
  76 + break
73 77 case 'mp4':
74   - config.plugins = [Mp4Plugin];
75   - break;
  78 + config.plugins = [Mp4Plugin]
  79 + break
76 80 case 'flv':
77   - config.plugins = [FlvPlugin];
78   - break;
  81 + config.plugins = [FlvPlugin]
  82 + break
79 83 }
80   - return config;
81   -};
  84 + return config
  85 +}
82 86
83   -const videoElRef = shallowRef<Nullable<HTMLDivElement>>();
  87 +const videoElRef = shallowRef<Nullable<HTMLDivElement>>()
84 88
85   -const playerRef = shallowRef<Nullable<PresetPlayer>>();
  89 +const playerRef = shallowRef<Nullable<PresetPlayer>>()
86 90
87   -const propsRef = ref<XGPlayerProps>({});
  91 +const propsRef = ref<XGPlayerProps>({})
88 92
89 93 const getPlayerConfig = computed<IPlayerOptions>(() => {
90   - const { url, autoPlay, config } = props;
  94 + const { url, autoPlay, config } = props
91 95
92 96 const basicConfig: IPlayerOptions = {
93 97 ...config,
... ... @@ -97,79 +101,83 @@ const getPlayerConfig = computed<IPlayerOptions>(() => {
97 101 isLive: true,
98 102 autoplay: autoPlay,
99 103 autoplayMuted: autoPlay,
100   - ...getPluginByStreamType(),
101   - };
102   - return basicConfig;
103   -});
  104 + ...getPluginByStreamType()
  105 + }
  106 + return basicConfig
  107 +})
104 108
105 109 function onDecodeError() {
106   - console.warn('player happend decode error');
107   - playerRef.value?.switchURL(props.url!);
  110 + console.warn('player happend decode error')
  111 + playerRef.value?.switchURL(props.url!)
108 112 }
109 113
110 114 function initializePlayer() {
111 115 if (unref(playerRef)) {
112   - playerRef.value?.destroy?.();
113   - playerRef.value = null;
  116 + playerRef.value?.destroy?.()
  117 + playerRef.value = null
114 118 }
115 119
116   - const config = toRaw(unref(getPlayerConfig));
  120 + const config = toRaw(unref(getPlayerConfig))
117 121
118   - if (!unref(videoElRef)) return;
  122 + if (!unref(videoElRef)) return
119 123
120   - const player = (playerRef.value = new Player(Object.assign(config, { el: unref(videoElRef) })));
  124 + const player = (playerRef.value = new Player(Object.assign(config, { el: unref(videoElRef) })))
121 125
122 126 player.on(Events.READY, () => {
123   - emits('ready', player);
124   - });
  127 + emits('ready', player)
  128 + })
  129 +
  130 + player.on(Events.USER_ACTION, (event: UserActionEventType) => {
  131 + emits('userAction', event, player)
  132 + })
125 133
126 134 player.setEventsMiddleware({
127 135 error: (event, callback) => {
128 136 const code = (
129 137 event as unknown as {
130   - error: MediaError;
  138 + error: MediaError
131 139 }
132   - ).error.code;
  140 + ).error.code
133 141 if (code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED) {
134 142 if (!props.url) {
135   - return;
  143 + return
136 144 }
137   - callback();
138   - return;
  145 + callback()
  146 + return
139 147 }
140 148
141 149 if (code === MediaError.MEDIA_ERR_DECODE) {
142 150 // 视频流可以播放 中途解码失败重载
143 151 if (playerRef.value?.isPlaying) {
144   - onDecodeError();
  152 + onDecodeError()
145 153 }
146   - return;
  154 + return
147 155 }
148 156
149   - callback();
150   - },
151   - });
  157 + callback()
  158 + }
  159 + })
152 160 }
153 161
154 162 onMounted(() => {
155   - initializePlayer();
156   -});
  163 + initializePlayer()
  164 +})
157 165
158 166 onUnmounted(() => {
159   - emits('onUnmounted', unref(playerRef)!);
160   - playerRef.value?.destroy?.();
161   -});
  167 + emits('onUnmounted', unref(playerRef)!)
  168 + playerRef.value?.destroy?.()
  169 +})
162 170
163 171 watch(
164 172 () => props.url,
165 173 () => {
166   - initializePlayer();
  174 + initializePlayer()
167 175 }
168   -);
  176 +)
169 177
170 178 defineExpose({
171   - getPlayerInstance: () => unref(playerRef),
172   -});
  179 + getPlayerInstance: () => unref(playerRef)
  180 +})
173 181 </script>
174 182
175 183 <template>
... ...
1   -import { IPlayerOptions } from 'xgplayer/es/player';
  1 +import { IPlayerOptions } from 'xgplayer/es/player'
2 2
3   -export type StreamType = 'flv' | 'mp4' | 'hls' | 'auto';
  3 +export type StreamType = 'flv' | 'mp4' | 'hls' | 'auto'
4 4 export interface XGPlayerProps {
5   - streamType?: StreamType;
6   - autoPlay?: boolean;
7   - url?: string;
8   - withToken?: boolean;
9   - config?: Omit<IPlayerOptions, 'url'>;
  5 + streamType?: StreamType
  6 + autoPlay?: boolean
  7 + url?: string
  8 + withToken?: boolean
  9 + config?: Omit<IPlayerOptions, 'url'>
  10 +}
  11 +
  12 +export interface UserActionEventType {
  13 + action: string // 用户行为
  14 + pluginName: string // 从哪个插件触发
  15 + props: [
  16 + {
  17 + // 发生变化的属性列表
  18 + props: string // 发生变化的属性
  19 + from: any // 变化前的值
  20 + to: any // 变化后的值
  21 + }
  22 + ]
  23 + event: Event // 事件
  24 + currentTime: number // 当前播放时间
  25 + duration: number // 当前播放器时长
  26 + ended: boolean // 是否播放结束
  27 + paused: boolean // 是否暂停
  28 + from?: boolean
  29 + to?: boolean
10 30 }
... ...
  1 +export enum DataTypeEnum {
  2 + DATA_RANGE = 'dataRange',
  3 + DATA_INPUT = 'dataInput'
  4 +}
  5 +
  6 +export enum DataTypeNameEnum {
  7 + DATA_RANGE = '日期区间',
  8 + DATA_INPUT = '文本输入'
  9 +}
... ...
  1 +export enum TokenEnum {
  2 + DEFAULT_TOKEN = 'Token',
  3 + TOKEN_STRING = 'TokenString',
  4 + NO_VERIFICATION = 'NoVerification'
  5 +}
  6 +
  7 +export enum TokenNameEnum {
  8 + DEFAULT_TOKEN = 'Token',
  9 + TOKEN_STRING = '令牌',
  10 + NO_VERIFICATION = '无验证'
  11 +}
... ...
... ... @@ -25,7 +25,8 @@ export enum RequestContentTypeEnum {
25 25 // 普通请求
26 26 DEFAULT = 0,
27 27 // SQL请求
28   - SQL = 1
  28 + SQL = 1,
  29 + WEB_SOCKET
29 30 }
30 31
31 32 /**
... ...
... ... @@ -10,7 +10,7 @@ export const useGlobSetting = (): Readonly<GlobConfig> => {
10 10 VITE_GLOB_UPLOAD_URL,
11 11 VITE_GLOB_WEB_SOCKET,
12 12 VITE_GLOB_CONTENT_SECURITY_POLICY,
13   - VITE_GLOB_PUBLIC_PATH
  13 + VITE_GLOB_PUBLIC_PATH,
14 14 } = getAppEnvConfig();
15 15
16 16 if (!/[a-zA-Z_]*/.test(VITE_GLOB_APP_SHORT_NAME)) {
... ... @@ -28,7 +28,7 @@ export const useGlobSetting = (): Readonly<GlobConfig> => {
28 28 uploadUrl: VITE_GLOB_UPLOAD_URL,
29 29 socketUrl: VITE_GLOB_WEB_SOCKET,
30 30 securityPolicy: VITE_GLOB_CONTENT_SECURITY_POLICY,
31   - publicPath: VITE_GLOB_PUBLIC_PATH
  31 + publicPath: VITE_GLOB_PUBLIC_PATH,
32 32 };
33 33
34 34 return glob as Readonly<GlobConfig>;
... ...
1 1 import {ref, toRefs, toRaw, watch} from 'vue'
2 2 import type VChart from 'vue-echarts'
3   -import {useChartDataPondFetch} from '@/hooks/'
4 3 import {CreateComponentType, ChartFrameEnum, CreateComponentGroupType} from '@/packages/index.d'
5 4 import {useChartEditStore} from '@/store/modules/chartEditStore/chartEditStore'
6 5 import {isPreview, intervalUnitHandle} from '@/utils'
7 6 import {setOption} from '@/packages/public/chart'
8 7 import {useChartDataSocket} from './useChartDataSocket'
9   -import {customRequest} from '@/api/external/customRequest'
  8 +import {customRequest, customThirdInterfaceRequest, thirdInterfaceRequest} from '@/api/external/customRequest'
10 9 import {useFilterFn} from './useFilterFn'
11 10 import {RequestContentTypeEnum} from '@/enums/external/httpEnum'
12 11 import dayjs from 'dayjs'
  12 +import { RequestDataPondItemType } from '@/store/modules/chartEditStore/chartEditStore.d'
  13 +import { JSONParse, convertToCascadingData, findItemByLabel } from '@/utils/external/utils'
  14 +import { CascaderOption } from 'naive-ui'
  15 +import { useUserStore } from '@/store/external/modules/user'
13 16
14 17
15 18 // 获取类型
... ... @@ -40,7 +43,8 @@ export const useChartDataFetch = (
40 43 }
41 44 }
42 45 }
43   -
  46 +
  47 + // 单个组件请求
44 48 const requestIntervalFn = () => {
45 49 const chartEditStore = useChartEditStore()
46 50 if ((targetComponent.request.requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET) return
... ... @@ -52,6 +56,12 @@ export const useChartDataFetch = (
52 56 requestInterval: globalRequestInterval
53 57 } = toRefs(chartEditStore.getRequestGlobalConfig)
54 58
  59 + // 公共配置
  60 + const {
  61 + pondRequestGlobalInterval,
  62 + pondRequestGlobalIntervalUnit
  63 + } = toRefs(targetComponent.request)
  64 +
55 65 // 目标组件
56 66 const {
57 67 requestUrl,
... ... @@ -92,11 +102,55 @@ export const useChartDataFetch = (
92 102 (toRaw(targetComponent.request).requestParams.Params.startTs as unknown as number) = startTs as unknown as number
93 103 (toRaw(targetComponent.request).requestParams.Params.endTs as unknown as number) = endTs as unknown as number
94 104 }
  105 + //处理过期
  106 + const userStore = useUserStore();
  107 + const findCurrentPond = () => {
  108 + return chartEditStore.getRequestGlobalConfig.requestDataPond.find((pondItem: RequestDataPondItemType) =>
  109 + pondItem.dataPondId === targetComponent?.request?.requestDataPondId && userStore.getThirdTokenIsExp)
  110 + }
  111 + const handleExecuteRequest = async () => {
  112 + try {
  113 + if(findCurrentPond()?.dataPondRequestConfig?.pondRequestOriginUrl){
  114 + const originUrlString = findCurrentPond()?.dataPondRequestConfig?.pondRequestOriginUrl
  115 + const requestUrlString = findCurrentPond()?.dataPondRequestConfig?.pondRequestUrl
  116 + const body = findCurrentPond()?.dataPondRequestConfig?.pondRequestParams!['Body']['json']
  117 + const request = {
  118 + requestOriginUrl: `${originUrlString}${requestUrlString}`,
  119 + body
  120 + }
  121 + const res = await customThirdInterfaceRequest(request as unknown as thirdInterfaceRequest)
  122 + const resOptions = convertToCascadingData(res) as unknown as CascaderOption[]
  123 + const findLabel = findItemByLabel(resOptions, targetComponent.request.thirdSelectCascaderLabel as string)
  124 + if(findLabel) {
  125 + targetComponent.request.requestVerificationToken = findLabel?.value
  126 + }
  127 + }
  128 + } catch (e) {
  129 + console.error(e)
  130 + }
  131 + }
  132 + // 定时时间
  133 + const time = targetInterval && targetInterval.value ? targetInterval.value : pondRequestGlobalInterval?.value?pondRequestGlobalInterval?.value: globalRequestInterval.value
  134 + // 单位
  135 + const unit = targetInterval && targetInterval.value ? targetUnit.value :pondRequestGlobalIntervalUnit?.value?pondRequestGlobalIntervalUnit?.value: globalUnit.value
  136 + setInterval(handleExecuteRequest, intervalUnitHandle(time, (unit as unknown as any)))
  137 + //
95 138 const res = await customRequest(toRaw(targetComponent.request))
96 139 if (res) {
97 140 try {
98 141 const filter = targetComponent.filter
99 142 const {value} = useFilterFn(filter, res)
  143 + //分组更新下面子组件
  144 + if(targetComponent.isGroup) {
  145 + const parseHistoryInput = JSONParse(targetComponent.saveHistoryInput!)
  146 + parseHistoryInput?.forEach((historyItem:Recordable) => {
  147 + const findCurrentItem = targetComponent.groupList?.find((groupItem:CreateComponentType | CreateComponentGroupType) => groupItem.id === historyItem.id)
  148 + if(findCurrentItem) {
  149 + findCurrentItem.option.dataset = value[historyItem.inputValue]
  150 + }
  151 + })
  152 + }
  153 + //
100 154 echartsUpdateHandle(value)
101 155 // 更新回调函数
102 156 if (updateCallback) {
... ... @@ -119,13 +173,14 @@ export const useChartDataFetch = (
119 173 deep: true
120 174 }
121 175 )
122   -
123 176 // 定时时间
124   - const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value
  177 + const time = targetInterval && targetInterval.value ? targetInterval.value : pondRequestGlobalInterval?.value?pondRequestGlobalInterval?.value: globalRequestInterval.value
125 178 // 单位
126   - const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
  179 + const unit = targetInterval && targetInterval.value ? targetUnit.value :pondRequestGlobalIntervalUnit?.value?pondRequestGlobalIntervalUnit?.value: globalUnit.value
127 180 // 开启轮询
128   - if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
  181 + if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, (unit as unknown as any)))
  182 +
  183 +
129 184 }
130 185 // eslint-disable-next-line no-empty
131 186 } catch (error) {
... ... @@ -140,11 +195,12 @@ export const useChartDataFetch = (
140 195 /**
141 196 * 支持分组也可以接受ws
142 197 * 如果是分组并且绑定了ws
  198 + * 也支持http轮询
143 199 */
144 200 chartEditStore.getComponentList?.forEach((item: CreateComponentType | CreateComponentGroupType) => {
145 201 if (item.isGroup) {
146 202 if (item.request.requestUrl?.includes('ws')) {
147   - initial(item, useChartEditStore, updateCallback)
  203 + initial(item, useChartEditStore, updateCallback) // ws
148 204 }
149 205 }
150 206 })
... ...
... ... @@ -2,8 +2,9 @@
2 2 * 重写select下拉框联动
3 3 */
4 4 import { toRefs } from 'vue'
5   -import { CreateComponentType } from '@/packages/index.d'
  5 +import { CreateComponentType } from '@/packages/index.d'
6 6 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  7 +import { JSONParse } from '@/utils/external/utils'
7 8
8 9 // 获取类型
9 10 type ChartEditStoreType = typeof useChartEditStore
... ... @@ -32,9 +33,19 @@ export const useChartInteract = (
32 33 chartEditStore.getComponentList.forEach(targetItem => {
33 34 if (targetItem.isGroup) {
34 35 targetItem.groupList?.forEach(groupItem => {
  36 + let jsonBody: any = null
35 37 if (groupItem.id === item.interactComponentId) {
36   - const { Params, Header } = toRefs(groupItem.request.requestParams)
  38 + const { Params, Header, Body } = toRefs(groupItem.request.requestParams)
37 39 Object.keys(item.interactFn).forEach(key => {
  40 + if (Body.value['json']) {
  41 + jsonBody = JSONParse(Body.value['json'])
  42 + const splitDaterange = param['daterange'].split('-')
  43 + jsonBody[item.interactFn[key][0]] = decodeURIComponent(splitDaterange[0])
  44 + jsonBody[item.interactFn[key][1]] = decodeURIComponent(splitDaterange[1])
  45 + }
  46 + if (jsonBody) {
  47 + Body.value['json'] = JSON.stringify(jsonBody)
  48 + }
38 49 if (Params.value[key]) {
39 50 Params.value[key] = param[item.interactFn[key]]
40 51 }
... ... @@ -45,9 +56,19 @@ export const useChartInteract = (
45 56 }
46 57 })
47 58 } else {
  59 + let jsonBody: any = null
48 60 if (targetItem.id === item.interactComponentId) {
49   - const { Params, Header } = toRefs(targetItem.request.requestParams)
  61 + const { Params, Header, Body } = toRefs(targetItem.request.requestParams)
50 62 Object.keys(item.interactFn).forEach(key => {
  63 + if (Body.value['json']) {
  64 + jsonBody = JSONParse(Body.value['json'])
  65 + const splitDaterange = param['daterange'].split('-')
  66 + jsonBody[item.interactFn[key][0]] = decodeURIComponent(splitDaterange[0])
  67 + jsonBody[item.interactFn[key][1]] = decodeURIComponent(splitDaterange[1])
  68 + }
  69 + if (jsonBody) {
  70 + Body.value['json'] = JSON.stringify(jsonBody)
  71 + }
51 72 if (Params.value[key]) {
52 73 Params.value[key] = param[item.interactFn[key]]
53 74 }
... ...
... ... @@ -4,6 +4,7 @@
4 4 import { toRefs } from 'vue'
5 5 import { CreateComponentType } from '@/packages/index.d'
6 6 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  7 +import { JSONParse } from '@/utils'
7 8
8 9 // 获取类型
9 10 type ChartEditStoreType = typeof useChartEditStore
... ... @@ -33,21 +34,38 @@ export const useChartInteract = (
33 34 if (targetItem.isGroup) {
34 35 targetItem.groupList?.forEach(groupItem => {
35 36 if (groupItem.id === item.interactComponentId) {
36   - const { Params, Header } = toRefs(groupItem.request.requestParams)
37   - Object.keys(item.interactFn).forEach(key => {
38   - Params.value[key] = decodeURIComponent(param[item.interactFn[key]])
39   - if(Reflect.has(Params.value, 'attrName')) {
40   - Params.value['attrName'] = attrNames as unknown as string // 修改联动选择,lengend未实时更新
41   - }
42   - if (key in Header.value) {
43   - Header.value[key] = param[item.interactFn[key]]
  37 + const { Params, Header, Body } = toRefs(groupItem.request.requestParams)
  38 + //特殊处理 只针对两个下拉选择器,一个是产品下拉,一个是设备下拉,选择了产品,设备列表选择值清空
  39 + if (targetItem.chartConfig.title.includes('设备列表下拉选择器')) {
  40 + if (window.location.href.includes('preview')) {
  41 + if (window.sessionStorage.getItem('deviceProfileSelectStatus') === 'selected') {
  42 + targetItem.option.selectValue = "'"
44 43 }
  44 + }
  45 + }
  46 + //
  47 + let jsonBody: any = null
  48 + Object.keys(item.interactFn).forEach(key => {
  49 + Params.value[key] = decodeURIComponent(param[item.interactFn[key]])
  50 + if (Body.value['json']) {
  51 + jsonBody = JSONParse(Body.value['json'])
  52 + jsonBody[item.interactFn[key]] = decodeURIComponent(param['data'])
  53 + }
  54 + if (jsonBody) {
  55 + Body.value['json'] = JSON.stringify(jsonBody)
  56 + }
  57 + if (Reflect.has(Params.value, 'attrName')) {
  58 + Params.value['attrName'] = attrNames as unknown as string // 修改联动选择,lengend未实时更新
  59 + }
  60 + if (key in Header.value) {
  61 + Header.value[key] = param[item.interactFn[key]]
  62 + }
45 63 })
46 64 }
47 65 })
48 66 } else {
49 67 if (targetItem.id === item.interactComponentId) {
50   - const { Params, Header } = toRefs(targetItem.request.requestParams)
  68 + const { Params, Header, Body } = toRefs(targetItem.request.requestParams)
51 69 //特殊处理 只针对两个下拉选择器,一个是产品下拉,一个是设备下拉,选择了产品,设备列表选择值清空
52 70 if (targetItem.chartConfig.title.includes('设备列表下拉选择器')) {
53 71 if (window.location.href.includes('preview')) {
... ... @@ -57,14 +75,22 @@ export const useChartInteract = (
57 75 }
58 76 }
59 77 //
  78 + let jsonBody: any = null
60 79 Object.keys(item.interactFn).forEach(key => {
61   - Params.value[key] = decodeURIComponent(param[item.interactFn[key]])
62   - if(Reflect.has(Params.value, 'attrName')) {
63   - Params.value['attrName'] = attrNames as unknown as string // 修改联动选择,lengend未实时更新
64   - }
65   - if (key in Header.value) {
66   - Header.value[key] = param[item.interactFn[key]]
67   - }
  80 + Params.value[key] = decodeURIComponent(param[item.interactFn[key]])
  81 + if (Body.value['json']) {
  82 + jsonBody = JSONParse(Body.value['json'])
  83 + jsonBody[item.interactFn[key]] = decodeURIComponent(param['data'])
  84 + }
  85 + if (jsonBody) {
  86 + Body.value['json'] = JSON.stringify(jsonBody)
  87 + }
  88 + if (Reflect.has(Params.value, 'attrName')) {
  89 + Params.value['attrName'] = attrNames as unknown as string // 修改联动选择,lengend未实时更新
  90 + }
  91 + if (key in Header.value) {
  92 + Header.value[key] = param[item.interactFn[key]]
  93 + }
68 94 })
69 95 }
70 96 }
... ...
... ... @@ -12,17 +12,18 @@ export const useFetchTargetData = () => {
12 12 const fetchTargetData = async () => {
13 13 const { targetData } = useTargetData()
14 14 if (unref(targetData).request.requestDataType === RequestDataTypeEnum.STATIC) return
  15 + if (!unref(targetData).request.requestUrl) return
15 16 loading.value = true
16 17 try {
17   - const isSocketType = (targetData.value.request.requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET
18   - const res = isSocketType
19   - ? await sendMessage(unref(targetData) as CreateComponentType)
20   - : await customRequest(toRaw(targetData.value.request))
21   -
22   - if (res) {
23   - return res
24   - }
25   - window['$message'].warning('没有拿到返回值,请检查接口!')
  18 + const isSocketType = (targetData.value.request.requestContentType as RequestContentTypeEnum) === RequestContentTypeEnum.WEB_SOCKET
  19 + const res = isSocketType
  20 + ? await sendMessage(unref(targetData) as CreateComponentType)
  21 + : await customRequest(toRaw(targetData.value.request))
  22 +
  23 + if (res) {
  24 + return res
  25 + }
  26 + window['$message'].warning('没有拿到返回值,请检查接口!')
26 27 } catch (error) {
27 28 loading.value = false
28 29 console.error(error);
... ...
  1 +/**
  2 + * 此hook用于获取物模型
  3 + * @param entityId 设备id
  4 + * @returns
  5 + */
  6 +
  7 +import { getAttribute, getDeviceDetail } from '@/api/external/common'
  8 +
  9 +export function useTsl() {
  10 + const handleDeviceProfileAttributes = async (entityId: string) => {
  11 + const deviceDetailRes = await getDeviceDetail(entityId)
  12 + const { deviceProfileId } = deviceDetailRes
  13 + if (!deviceProfileId) return
  14 + const attributeRes = await getAttribute(deviceProfileId)
  15 + const dataFormat = handleDataFormat(deviceDetailRes, attributeRes)
  16 + return dataFormat
  17 + }
  18 +
  19 + const handleDataFormat = (deviceDetail: Recordable, attributes: Recordable[]) => {
  20 + const { name, tbDeviceId } = deviceDetail
  21 + const attribute = attributes.map((item: Recordable) => ({
  22 + identifier: item.identifier,
  23 + name: item.name,
  24 + detail: item.detail
  25 + }))
  26 + return {
  27 + name,
  28 + tbDeviceId,
  29 + attribute
  30 + }
  31 + }
  32 +
  33 + return {
  34 + handleDeviceProfileAttributes
  35 + }
  36 +}
... ...
... ... @@ -6,8 +6,7 @@ let initialFlag = false;
6 6 export function useWebSecurityPolicy() {
7 7 if (window && window.document && window.document.documentElement) {
8 8 const { securityPolicy } = useGlobSetting();
9   - const flag = isBoolean(securityPolicy) ? securityPolicy : securityPolicy === 'true'
10   - if (flag && !initialFlag) {
  9 + if (securityPolicy && !initialFlag) {
11 10 const meta = document.createElement('meta');
12 11 meta.setAttribute('http-equiv', 'Content-Security-Policy');
13 12 meta.setAttribute('content', 'upgrade-insecure-requests');
... ...
... ... @@ -129,7 +129,7 @@ const props = defineProps({
129 129
130 130 const header = ref()
131 131 const median = ref<string[]>([])
132   -props.optionData.dataset.dimensions.forEach(item => {
  132 +props.optionData.dataset?.dimensions?.forEach(item => {
133 133 median.value.push(item.title)
134 134 })
135 135
... ... @@ -138,7 +138,7 @@ watch(
138 138 () => props.optionData,
139 139 () => {
140 140 median.value = []
141   - props.optionData.dataset.dimensions.forEach(item => {
  141 + props.optionData.dataset.dimensions?.forEach(item => {
142 142 median.value.push(item.title)
143 143 })
144 144 header.value = median.value.toString()
... ... @@ -153,8 +153,10 @@ watch(
153 153 watch([header], ([headerNew], [headerOld]) => {
154 154 if (headerNew !== headerOld) {
155 155 headerNew.split(',').forEach((item: string, index: number) => {
156   - if (index + 1 <= props.optionData.dataset.dimensions.length) {
157   - props.optionData.dataset.dimensions[index].title = headerNew.split(',')[index]
  156 + if(props.optionData.dataset?.dimensions) {
  157 + if (index + 1 <= props.optionData.dataset.dimensions.length) {
  158 + props.optionData.dataset.dimensions[index].title = headerNew.split(',')[index]
  159 + }
158 160 }
159 161 })
160 162 }
... ...
... ... @@ -62,6 +62,8 @@ const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSe
62 62
63 63 const { queryCondition } = toRefs(props.chartConfig.option)
64 64
  65 +const { limit, startTs, endTs, interval, agg } = toRefs(props.chartConfig.request.requestParams.Params)
  66 +
65 67 use([DatasetComponent, CanvasRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent])
66 68
67 69 const chartEditStore = useChartEditStore()
... ... @@ -286,6 +288,23 @@ const handleAggChange = (value: string) => {
286 288 }
287 289
288 290 onMounted(() => {
  291 + if (Reflect.get(props.chartConfig.request.requestParams.Params, 'startTs')) {
  292 + queryCondition.value.timeRange[0] = startTs.value
  293 + getPacketIntervalByRange(queryCondition.value.timeRange)
  294 + }
  295 + if (Reflect.get(props.chartConfig.request.requestParams.Params, 'endTs')) {
  296 + queryCondition.value.timeRange[1] = endTs.value
  297 + getPacketIntervalByRange(queryCondition.value.timeRange)
  298 + }
  299 + if (Reflect.get(props.chartConfig.request.requestParams.Params, 'agg')) {
  300 + queryCondition.value.agg = agg.value
  301 + }
  302 + if (Reflect.get(props.chartConfig.request.requestParams.Params, 'interval')) {
  303 + queryCondition.value.interval = interval.value
  304 + }
  305 + if (Reflect.get(props.chartConfig.request.requestParams.Params, 'limit')) {
  306 + queryCondition.value.limit = limit.value
  307 + }
289 308 seriesDataMaxLength = dataJson.source.length
290 309 if (props.chartConfig.option.isCarousel) {
291 310 addPieInterval(undefined, true)
... ...
... ... @@ -6,6 +6,7 @@ import { chartInitConfig } from '@/settings/designSetting'
6 6
7 7 export const option = {
8 8 dataset: 80,
  9 + valueRange: [0, 100],
9 10 unitStr: '个',
10 11 openAnim: true,
11 12 duration: 3,
... ...
... ... @@ -12,6 +12,12 @@
12 12 <n-input-number :min="0.1" step="0.5" v-model:value="optionData.duration"></n-input-number>
13 13 </SettingItem>
14 14 </SettingItemBox>
  15 + <setting-item-box name="范围">
  16 + <setting-item name="范围">
  17 + <n-input-number :min="0" :max="99" v-model:value="optionData.valueRange[0]" />
  18 + <n-input-number :min="1" :max="100" v-model:value="optionData.valueRange[1]" />
  19 + </setting-item>
  20 + </setting-item-box>
15 21 <setting-item-box name="数据源">
16 22 <setting-item name="数据">
17 23 <n-input-number :min="0" :max="100" v-model:value="optionData.dataset" />
... ...
... ... @@ -260,7 +260,7 @@
260 260 d="M202.38 399.21C205.97 399.21 208.88 402.12 208.88 405.71C208.88 409.3 205.97 412.21 202.38 412.21C198.79 412.21 195.88 409.3 195.88 405.71C195.88 402.12 198.79 399.21 202.38 399.21L202.38 399.21Z"
261 261 />
262 262 <animateMotion
263   - path="M0,0 L0 -5 L0 -13 L0 -15 L0 -17 L0 -19 L0 -22 L0 -26 L0 -36
  263 + path="M0,0 L0 -5 L0 -13 L0 -15 L0 -17 L0 -19 L0 -22 L0 -26 L0 -36
264 264 L0 -46 L0 -50 L0 -59 L0 -60 L0 -69 L0 -71 L0 -79 L0 -89 L0 -91 L0 -122 L0 -132 L0 -142 L0 -162 L0 -172 L0 -182 L0 -192
265 265 "
266 266 begin="1.5s"
... ... @@ -278,7 +278,7 @@
278 278 d="M231.69 443.18C235.28 443.18 238.19 446.09 238.19 449.68C238.19 453.27 235.28 456.18 231.69 456.18C228.1 456.18 225.19 453.27 225.19 449.68C225.19 446.09 228.1 443.18 231.69 443.18L231.69 443.18Z"
279 279 />
280 280 <animateMotion
281   - path="M0,0 L0 -5 L0 -13 L0 -15 L0 -17 L0 -19 L0 -22 L0 -26 L0 -36
  281 + path="M0,0 L0 -5 L0 -13 L0 -15 L0 -17 L0 -19 L0 -22 L0 -26 L0 -36
282 282 L0 -46 L0 -50 L0 -59 L0 -60 L0 -69 L0 -71 L0 -79 L0 -89 L0 -91 L0 -122 L0 -132 L0 -142 L0 -162 L0 -172 L0 -182 L0 -192
283 283 "
284 284 begin="1.5s"
... ... @@ -296,7 +296,7 @@
296 296 d="M231.69 443.18C235.28 443.18 238.19 446.09 238.19 449.68C238.19 453.27 235.28 456.18 231.69 456.18C228.1 456.18 225.19 453.27 225.19 449.68C225.19 446.09 228.1 443.18 231.69 443.18L231.69 443.18Z"
297 297 />
298 298 <animateMotion
299   - path="M0,0 L0 -5 L0 -13 L0 -15 L0 -17 L0 -19 L0 -22 L0 -26 L0 -36
  299 + path="M0,0 L0 -5 L0 -13 L0 -15 L0 -17 L0 -19 L0 -22 L0 -26 L0 -36
300 300 L0 -46 L0 -50 L0 -59 L0 -60 L0 -69 L0 -71 L0 -79 L0 -89 L0 -91 L0 -122 L0 -132 L0 -142 L0 -162 L0 -172 L0 -182 L0 -192
301 301 "
302 302 begin="1.5s"
... ... @@ -656,7 +656,7 @@
656 656 </div>
657 657 </template>
658 658 <script setup lang="ts">
659   -import { PropType, toRefs } from 'vue'
  659 +import { PropType, toRefs, watch } from 'vue'
660 660 import { CreateComponentType } from '@/packages/index.d'
661 661 import { option } from './config'
662 662 import { useChartDataFetch } from '@/hooks'
... ... @@ -671,13 +671,29 @@ const props = defineProps({
671 671
672 672 const { w, h } = toRefs(props.chartConfig.attr)
673 673
674   -const { dataset, unitStr, colorConfig, openAnim, duration, fontConfig } = toRefs(
  674 +const { dataset, unitStr, colorConfig, openAnim, duration, fontConfig, valueRange } = toRefs(
675 675 props.chartConfig.option as typeof option
676 676 )
677 677
  678 +watch(()=>dataset.value,(newData)=>{
  679 + if((Number(newData)) >= valueRange.value[1]){
  680 + newData = valueRange.value[1]
  681 + }
  682 + if((Number(newData)) <= valueRange.value[0]){
  683 + newData = valueRange.value[0]
  684 + }
  685 + dataset.value = newData as number
  686 +})
  687 +
678 688 // 预览更新
679   -useChartDataFetch(props.chartConfig, useChartEditStore, (newData: number) => {
680   - dataset.value = newData
  689 +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: number | string) => {
  690 + if((Number(newData)) >= valueRange.value[1]){
  691 + newData = valueRange.value[1]
  692 + }
  693 + if((Number(newData)) <= valueRange.value[0]){
  694 + newData = valueRange.value[0]
  695 + }
  696 + dataset.value = newData as number
681 697 })
682 698 </script>
683 699
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { Decorates27Config } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
  6 +
  7 +export const option = {
  8 + dataset: '模块标题',
  9 + fontConfig: {
  10 + x1: '132',
  11 + y1: '129.8828125',
  12 + x2: '103',
  13 + y2: '64.96000000000001',
  14 + datasetTspanFill: '#00F0A2',
  15 + titleTspanFill: '#FFFFFF',
  16 + datasetTspanFontSize: 30,
  17 + }
  18 +}
  19 +
  20 +export default class Config extends PublicConfigClass implements CreateComponentType {
  21 + public key = Decorates27Config.key
  22 + public attr = { ...chartInitConfig, w: 305, h: 110, zIndex: -1 }
  23 + public chartConfig = cloneDeep(Decorates27Config)
  24 + public option = cloneDeep(option)
  25 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem name="配置" :expanded="true">
  5 + <setting-item-box name="数据源">
  6 + <setting-item name="数据">
  7 + <n-input v-model:value="optionData.dataset" />
  8 + </setting-item>
  9 + </setting-item-box>
  10 + <SettingItemBox :name="`数据源字体配置`">
  11 + <SettingItem name="x">
  12 + <n-input-number :min="0" v-model:value="optionData.fontConfig.x1"></n-input-number>
  13 + </SettingItem>
  14 + <SettingItem name="y">
  15 + <n-input-number :min="0" v-model:value="optionData.fontConfig.y1"></n-input-number>
  16 + </SettingItem>
  17 + <SettingItem name="大小">
  18 + <n-input-number :min="0" v-model:value="optionData.fontConfig.datasetTspanFontSize"></n-input-number>
  19 + </SettingItem>
  20 + <SettingItem name="颜色">
  21 + <n-color-picker
  22 + size="small"
  23 + :modes="['hex']"
  24 + v-model:value="optionData.fontConfig.datasetTspanFill"
  25 + ></n-color-picker>
  26 + </SettingItem>
  27 + </SettingItemBox>
  28 + </CollapseItem>
  29 +</template>
  30 +
  31 +<script setup lang="ts">
  32 +import { PropType } from 'vue'
  33 +import { option } from './config'
  34 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  35 +
  36 +defineProps({
  37 + optionData: {
  38 + type: Object as PropType<typeof option>,
  39 + required: true
  40 + }
  41 +})
  42 +</script>
... ...
  1 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  2 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, chartKey, conKey } = useWidgetKey('Decorates27', true)
  6 +
  7 +export const Decorates27Config: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '模块标题27',
  12 + category: ChatCategoryEnum.DECORATE,
  13 + categoryName: ChatCategoryEnumName.DECORATE,
  14 + package: PackagesCategoryEnum.DECORATES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'decorates27.png'
  17 +}
... ...
  1 +<template>
  2 + <div class="go-content-box">
  3 + <svg
  4 + xmlns="http://www.w3.org/2000/svg"
  5 + xmlns:xlink="http://www.w3.org/1999/xlink"
  6 + :width="w"
  7 + :height="h"
  8 + viewBox="0 0 420 147"
  9 + fill="none"
  10 + >
  11 + <g opacity="0.3">
  12 + <g filter="url(#filter_f159ebae-322a-4973-83f9-9355681bcf9d)">
  13 + <rect
  14 + x="9"
  15 + y="10"
  16 + width="402"
  17 + height="134"
  18 + stroke="rgba(11, 97, 184, 1)"
  19 + stroke-width="2"
  20 + fill="#011231"
  21 + fill-opacity="0.6"
  22 + ></rect>
  23 + </g>
  24 + </g>
  25 + <rect x="9" y="1" width="402" height="134" fill="#022C5B"></rect>
  26 + <g filter="url(#filter_d39fec7c-b2c4-483b-a0f9-e184380ce12e)">
  27 + <rect x="9" y="1" width="402" height="134" stroke="rgba(11, 97, 184, 1)" stroke-width="2"></rect>
  28 + </g>
  29 + <rect x="1" y="0" width="2" height="136" fill="#00ABFF"></rect>
  30 + <rect x="417" y="0" width="2" height="136" fill="#00ABFF"></rect>
  31 + <rect x="416" y="0" width="4" height="30" fill="#00F6FF"></rect>
  32 + <rect x="416" y="106" width="4" height="30" fill="#00F6FF"></rect>
  33 + <rect x="0" y="0" width="4" height="30" fill="#00F6FF"></rect>
  34 + <rect x="0" y="106" width="4" height="30" fill="#00F6FF"></rect>
  35 + <rect x="15" y="6" width="8" height="4" fill="#00F6FF"></rect>
  36 + <rect x="395" y="6" width="8" height="4" fill="#00F6FF"></rect>
  37 + <g opacity="0.6">
  38 + <rect x="382" y="6" width="8" height="4" fill="#00F6FF"></rect>
  39 + </g>
  40 + <g opacity="0.2">
  41 + <rect x="369" y="6" width="8" height="4" fill="#00F6FF"></rect>
  42 + </g>
  43 + <g opacity="0.6">
  44 + <rect x="28" y="6" width="8" height="4" fill="#00F6FF"></rect>
  45 + </g>
  46 + <g opacity="0.2">
  47 + <rect x="41" y="6" width="8" height="4" fill="#00F6FF"></rect>
  48 + </g>
  49 + <g opacity="0.5">
  50 + <path stroke="rgba(11, 97, 184, 1)" stroke-width="2" d="M134 1.5L149.5 16.5L269 16.5L284 1.5"></path>
  51 + </g>
  52 + <g opacity="0.5">
  53 + <path stroke="rgba(11, 97, 184, 1)" stroke-width="2" d="M134 135L149.5 120L269 120L284 135"></path>
  54 + </g>
  55 + <g opacity="1" transform="translate(11 -50)">
  56 + <text>
  57 + <tspan
  58 + :x="fontConfig.x1"
  59 + :y="fontConfig.y1"
  60 + :font-size="fontConfig.datasetTspanFontSize"
  61 + line-height="0"
  62 + :fill="fontConfig.datasetTspanFill"
  63 + opacity="1"
  64 + font-family="Roboto-Regular"
  65 + font-weight="Regular"
  66 + letter-spacing="0"
  67 + >
  68 + {{ dataset }}
  69 + </tspan>
  70 + </text>
  71 + </g>
  72 + <path
  73 + d="M85.5 33C102.9 33 117 47.1 117 64.5C117 81.9 89.87 103 85.5 103C81.13 103 54 81.9 54 64.5C54 47.1 68.1 33 85.5 33ZM85.495 54.875C90.815 54.875 95.125 59.185 95.125 64.495C95.125 69.815 90.815 74.125 85.495 74.125C80.185 74.125 75.875 69.815 75.875 64.495C75.875 59.185 80.185 54.875 85.495 54.875Z"
  74 + fill-rule="evenodd"
  75 + fill="url(#linear_fill_24aadc2d-dd75-4fb1-b98a-92d6c45d95db)"
  76 + ></path>
  77 + <path
  78 + fill-rule="evenodd"
  79 + fill="url(#linear_fill_5b832155-7920-462b-94fb-fb2e3ed3f1d4_0)"
  80 + d="M85.5 38C102.9 38 117 52.1 117 69.5C117 86.9 89.87 108 85.5 108C81.13 108 54 86.9 54 69.5C54 52.1 68.1 38 85.5 38ZM85.495 59.875C90.815 59.875 95.125 64.185 95.125 69.495C95.125 74.815 90.815 79.125 85.495 79.125C80.185 79.125 75.875 74.815 75.875 69.495C75.875 64.185 80.185 59.875 85.495 59.875Z"
  81 + ></path>
  82 + <path
  83 + fill-rule="evenodd"
  84 + fill="rgba(4, 220, 237, 0.26)"
  85 + d="M117 69.5C117 52.1 102.9 38 85.5 38C68.1 38 54 52.1 54 69.5C54 86.9 81.13 108 85.5 108C89.87 108 117 86.9 117 69.5ZM55 69.5C55 52.6553 68.6553 39 85.5 39C102.345 39 116 52.6553 116 69.5Q116 80.5209 102.176 94.5737Q97.0168 99.8181 91.6852 103.617Q86.9368 107 85.5 107Q84.0632 107 79.3148 103.617Q73.9832 99.8181 68.8241 94.5737Q55 80.5209 55 69.5ZM96.125 69.495C96.125 63.6297 91.3603 58.875 85.495 58.875C79.6297 58.875 74.875 63.6297 74.875 69.495C74.875 75.3658 79.6242 80.125 85.495 80.125C91.3658 80.125 96.125 75.3658 96.125 69.495ZM95.125 69.495C95.125 64.185 90.815 59.875 85.495 59.875C80.185 59.875 75.875 64.185 75.875 69.495C75.875 74.815 80.185 79.125 85.495 79.125C90.815 79.125 95.125 74.815 95.125 69.495Z"
  86 + ></path>
  87 + <defs>
  88 + <filter
  89 + id="filter_f159ebae-322a-4973-83f9-9355681bcf9d"
  90 + x="6"
  91 + y="7"
  92 + width="408"
  93 + height="140"
  94 + filterUnits="userSpaceOnUse"
  95 + color-interpolation-filters="sRGB"
  96 + >
  97 + <feFlood flood-opacity="0" result="feFloodId_f159ebae-322a-4973-83f9-9355681bcf9d" />
  98 + <feBlend
  99 + mode="normal"
  100 + in="SourceGraphic"
  101 + in2="feFloodId_f159ebae-322a-4973-83f9-9355681bcf9d"
  102 + result="shape"
  103 + />
  104 + <feGaussianBlur result="gaussian_blur_f159ebae-322a-4973-83f9-9355681bcf9d" stdDeviation="1" />
  105 + </filter>
  106 + <filter
  107 + id="filter_d39fec7c-b2c4-483b-a0f9-e184380ce12e"
  108 + x="8"
  109 + y="0"
  110 + width="404"
  111 + height="136"
  112 + filterUnits="userSpaceOnUse"
  113 + color-interpolation-filters="sRGB"
  114 + >
  115 + <feFlood flood-opacity="0" result="feFloodId_d39fec7c-b2c4-483b-a0f9-e184380ce12e" />
  116 + <feBlend
  117 + mode="normal"
  118 + in="SourceGraphic"
  119 + in2="feFloodId_d39fec7c-b2c4-483b-a0f9-e184380ce12e"
  120 + result="shape_d39fec7c-b2c4-483b-a0f9-e184380ce12e"
  121 + />
  122 + <feColorMatrix
  123 + in="SourceAlpha"
  124 + type="matrix"
  125 + values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
  126 + result="hardAlpha_d39fec7c-b2c4-483b-a0f9-e184380ce12e"
  127 + />
  128 + <feOffset dx="0" dy="0" />
  129 + <feGaussianBlur stdDeviation="10" />
  130 + <feComposite in2="hardAlpha_d39fec7c-b2c4-483b-a0f9-e184380ce12e" operator="arithmetic" k2="-1" k3="1" />
  131 + <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.6509803921568628 0 0 0 0 1 0 0 0 0.8 0" />
  132 + <feBlend
  133 + mode="normal"
  134 + in2="shape_d39fec7c-b2c4-483b-a0f9-e184380ce12e"
  135 + result="innerShadow_0_d39fec7c-b2c4-483b-a0f9-e184380ce12e"
  136 + />
  137 + </filter>
  138 + <linearGradient
  139 + id="linear_fill_24aadc2d-dd75-4fb1-b98a-92d6c45d95db"
  140 + x1="85.5"
  141 + y1="103"
  142 + x2="85.5"
  143 + y2="33"
  144 + gradientUnits="userSpaceOnUse"
  145 + >
  146 + <stop offset="0" stop-color="#18698C" />
  147 + <stop offset="1" stop-color="#11A6A6" />
  148 + </linearGradient>
  149 + <linearGradient
  150 + id="linear_fill_5b832155-7920-462b-94fb-fb2e3ed3f1d4_0"
  151 + x1="85.5"
  152 + y1="108"
  153 + x2="85.5"
  154 + y2="38"
  155 + gradientUnits="userSpaceOnUse"
  156 + >
  157 + <stop offset="0" stop-color="#0E668C" />
  158 + <stop offset="1" stop-color="#00F2EE" />
  159 + </linearGradient>
  160 + </defs>
  161 + </svg>
  162 + </div>
  163 +</template>
  164 +<script setup lang="ts">
  165 +import { PropType, toRefs } from 'vue'
  166 +import { CreateComponentType } from '@/packages/index.d'
  167 +import { option } from './config'
  168 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  169 +import { useChartDataFetch } from '@/hooks'
  170 +import { isObject } from '@/utils/external/is'
  171 +
  172 +const props = defineProps({
  173 + chartConfig: {
  174 + type: Object as PropType<CreateComponentType & typeof option>,
  175 + required: true
  176 + }
  177 +})
  178 +
  179 +const { w, h } = toRefs(props.chartConfig.attr)
  180 +
  181 +const { dataset, fontConfig } = toRefs(props.chartConfig.option as typeof option)
  182 +
  183 +// 预览更新
  184 +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: string) => {
  185 + if (isObject(newData)) return
  186 + dataset.value = newData as string
  187 +})
  188 +</script>
  189 +
  190 +<style lang="scss" scoped>
  191 +.go-content-box {
  192 + width: v-bind('w+"px"');
  193 + height: v-bind('h+"px"');
  194 + display: flex;
  195 + align-items: center;
  196 + justify-content: center;
  197 +}
  198 +</style>
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { Decorates28Config } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
  6 +
  7 +export const option = {
  8 + dataset: '模块标题',
  9 + fontConfig: {
  10 + x1: '132',
  11 + y1: '129.8828125',
  12 + x2: '103',
  13 + y2: '64.96000000000001',
  14 + datasetTspanFill: '#00F0A2',
  15 + titleTspanFill: '#FFFFFF',
  16 + datasetTspanFontSize: 30,
  17 + }
  18 +}
  19 +
  20 +export default class Config extends PublicConfigClass implements CreateComponentType {
  21 + public key = Decorates28Config.key
  22 + public attr = { ...chartInitConfig, w: 305, h: 110, zIndex: -1 }
  23 + public chartConfig = cloneDeep(Decorates28Config)
  24 + public option = cloneDeep(option)
  25 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem name="配置" :expanded="true">
  5 + <setting-item-box name="数据源">
  6 + <setting-item name="数据">
  7 + <n-input v-model:value="optionData.dataset" />
  8 + </setting-item>
  9 + </setting-item-box>
  10 + <SettingItemBox :name="`数据源字体配置`">
  11 + <SettingItem name="x">
  12 + <n-input-number :min="0" v-model:value="optionData.fontConfig.x1"></n-input-number>
  13 + </SettingItem>
  14 + <SettingItem name="y">
  15 + <n-input-number :min="0" v-model:value="optionData.fontConfig.y1"></n-input-number>
  16 + </SettingItem>
  17 + <SettingItem name="大小">
  18 + <n-input-number :min="0" v-model:value="optionData.fontConfig.datasetTspanFontSize"></n-input-number>
  19 + </SettingItem>
  20 + <SettingItem name="颜色">
  21 + <n-color-picker
  22 + size="small"
  23 + :modes="['hex']"
  24 + v-model:value="optionData.fontConfig.datasetTspanFill"
  25 + ></n-color-picker>
  26 + </SettingItem>
  27 + </SettingItemBox>
  28 + </CollapseItem>
  29 +</template>
  30 +
  31 +<script setup lang="ts">
  32 +import { PropType } from 'vue'
  33 +import { option } from './config'
  34 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  35 +
  36 +defineProps({
  37 + optionData: {
  38 + type: Object as PropType<typeof option>,
  39 + required: true
  40 + }
  41 +})
  42 +</script>
... ...
  1 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  2 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, chartKey, conKey } = useWidgetKey('Decorates28', true)
  6 +
  7 +export const Decorates28Config: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '模块标题28',
  12 + category: ChatCategoryEnum.DECORATE,
  13 + categoryName: ChatCategoryEnumName.DECORATE,
  14 + package: PackagesCategoryEnum.DECORATES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'decorates28.png'
  17 +}
... ...
  1 +<template>
  2 + <div class="go-content-box">
  3 + <svg
  4 + xmlns="http://www.w3.org/2000/svg"
  5 + xmlns:xlink="http://www.w3.org/1999/xlink"
  6 + :width="w"
  7 + :height="h"
  8 + viewBox="0 0 428.1663818359375 121.5"
  9 + fill="none"
  10 + >
  11 + <g>
  12 + <g filter="url(#filter_98d03be6-b8cb-4e27-b332-bc2820d07903)">
  13 + <path
  14 + d="M409.722 14.36C409.342 13.82 408.732 13.5 408.072 13.5L44.8918 13.5C44.1218 13.5 43.4118 13.94 43.0818 14.64L12.9417 78.35C12.6517 78.95 12.6917 79.66 13.0317 80.23L35.8918 118.53C36.2518 119.13 36.9118 119.5 37.6118 119.5L385.422 119.5C386.182 119.5 386.882 119.06 387.212 118.38L425.962 39.67C426.282 39.02 426.222 38.25 425.812 37.65L409.722 14.36Z"
  15 + fill="#011231"
  16 + fill-opacity="0.6"
  17 + ></path>
  18 + </g>
  19 + <g filter="url(#filter_c8b60da4-9052-4ab3-a895-6acbad140e0b)">
  20 + <path
  21 + d="M409.722 14.36C409.342 13.82 408.732 13.5 408.072 13.5L44.8918 13.5C44.1218 13.5 43.4118 13.94 43.0818 14.64L12.9417 78.35C12.6517 78.95 12.6917 79.66 13.0317 80.23L35.8918 118.53C36.2518 119.13 36.9118 119.5 37.6118 119.5L385.422 119.5C386.182 119.5 386.882 119.06 387.212 118.38L425.962 39.67C426.282 39.02 426.222 38.25 425.812 37.65L409.722 14.36Z"
  22 + stroke="rgba(11, 97, 184, 1)"
  23 + stroke-width="2"
  24 + ></path>
  25 + </g>
  26 + </g>
  27 + <path
  28 + d="M417.481 27.54C417.791 26.89 417.731 26.13 417.331 25.54L401.581 2.38C401.211 1.83 400.591 1.5 399.921 1.5L44.2517 1.5C43.4717 1.5 42.7717 1.95 42.4417 2.66L12.9218 66.05C12.6418 66.65 12.6818 67.34 13.0118 67.91L35.4017 106.01C35.7617 106.62 36.4117 107 37.1217 107L377.731 107C378.501 107 379.201 106.56 379.531 105.87L417.481 27.54Z"
  29 + fill="#011231"
  30 + fill-opacity="0.6"
  31 + ></path>
  32 + <g filter="url(#filter_19131d1d-3e49-4887-91be-ebc5057ba529)">
  33 + <path
  34 + d="M417.481 27.54C417.791 26.89 417.731 26.13 417.331 25.54L401.581 2.38C401.211 1.83 400.591 1.5 399.921 1.5L44.2517 1.5C43.4717 1.5 42.7717 1.95 42.4417 2.66L12.9218 66.05C12.6418 66.65 12.6818 67.34 13.0118 67.91L35.4017 106.01C35.7617 106.62 36.4117 107 37.1217 107L377.731 107C378.501 107 379.201 106.56 379.531 105.87L417.481 27.54Z"
  35 + stroke="rgba(11, 97, 184, 1)"
  36 + stroke-width="2"
  37 + ></path>
  38 + </g>
  39 + <g opacity="0.6">
  40 + <path
  41 + d="M58.098 7.86505C57.338 7.86505 56.648 8.28505 56.308 8.96505L28.3379 64.7651C28.0279 65.3851 28.0579 66.1351 28.4279 66.7251L49.608 100.205C49.978 100.785 50.608 101.135 51.298 101.135L375.488 101.135C376.238 101.135 376.918 100.725 377.268 100.065L413.248 31.0751C413.608 30.4051 413.548 29.5851 413.098 28.9651L398.248 8.68505C397.868 8.16505 397.268 7.86505 396.628 7.86505L58.098 7.86505Z"
  42 + fill="#081837"
  43 + fill-opacity="0.6"
  44 + ></path>
  45 + <g filter="url(#filter_ecbd7b82-4d30-47dd-822d-74022aba9497)">
  46 + <path
  47 + d="M58.098 7.86505C57.338 7.86505 56.648 8.28505 56.308 8.96505L28.3379 64.7651C28.0279 65.3851 28.0579 66.1351 28.4279 66.7251L49.608 100.205C49.978 100.785 50.608 101.135 51.298 101.135L375.488 101.135C376.238 101.135 376.918 100.725 377.268 100.065L413.248 31.0751C413.608 30.4051 413.548 29.5851 413.098 28.9651L398.248 8.68505C397.868 8.16505 397.268 7.86505 396.628 7.86505L58.098 7.86505Z"
  48 + fill="#081837"
  49 + fill-opacity="0.6"
  50 + ></path>
  51 + </g>
  52 + </g>
  53 + <path
  54 + d="M50.4818 7.5L44.4818 20L51.9818 20L54.9818 12.5L65.9818 12.5L62.4818 7.5L50.4818 7.5Z"
  55 + fill="#0BD9FC"
  56 + ></path>
  57 + <path
  58 + d="M371.482 101L377.482 88.5L369.982 88.5L366.982 96L355.982 96L359.482 101L371.482 101Z"
  59 + fill="#0BD9FC"
  60 + ></path>
  61 + <g opacity="0.8">
  62 + <path d="M348.982 96L343.482 96L348.982 101L354.482 101L348.982 96Z" fill="#0BD9FC"></path>
  63 + </g>
  64 + <g opacity="0.6">
  65 + <path d="M336.982 96L331.482 96L336.982 101L342.482 101L336.982 96Z" fill="#0BD9FC"></path>
  66 + </g>
  67 + <g opacity="0.3">
  68 + <path d="M325.982 96L320.482 96L325.982 101L331.482 101L325.982 96Z" fill="#0BD9FC"></path>
  69 + </g>
  70 + <g opacity="0.8">
  71 + <path d="M72.9818 12.5L78.4818 12.5L72.9818 7.5L67.4818 7.5L72.9818 12.5Z" fill="#0BD9FC"></path>
  72 + </g>
  73 + <g opacity="0.6">
  74 + <path d="M84.9818 12.5L90.4818 12.5L84.9818 7.5L79.4818 7.5L84.9818 12.5Z" fill="#0BD9FC"></path>
  75 + </g>
  76 + <g opacity="0.3">
  77 + <path d="M95.9818 12.5L101.482 12.5L95.9818 7.5L90.4818 7.5L95.9818 12.5Z" fill="#0BD9FC"></path>
  78 + </g>
  79 + <g opacity="0.6">
  80 + <path
  81 + d="M22.1417 106C22.5117 106 22.8417 105.8 23.0217 105.47C23.1917 105.15 23.1717 104.76 22.9717 104.45L10.9917 86.05C10.7917 85.74 10.4417 85.56 10.0717 85.59C9.70171 85.62 9.38171 85.85 9.23171 86.19L1.1017 104.6C0.961703 104.91 1.0017 105.27 1.1817 105.55C1.3717 105.83 1.6817 106 2.02171 106L22.1417 106Z"
  82 + stroke="rgba(0, 185, 255, 1)"
  83 + stroke-width="2"
  84 + fill="#0E3F80"
  85 + ></path>
  86 + </g>
  87 + <g opacity="1" transform="translate(22 -65)">
  88 + <text>
  89 + <tspan
  90 + :x="fontConfig.x1"
  91 + :y="fontConfig.y1"
  92 + :font-size="fontConfig.datasetTspanFontSize"
  93 + line-height="0"
  94 + :fill="fontConfig.datasetTspanFill"
  95 + opacity="1"
  96 + font-family="Roboto-Regular"
  97 + font-weight="Regular"
  98 + letter-spacing="0"
  99 + >
  100 + {{ dataset }}
  101 + </tspan>
  102 + </text>
  103 + </g>
  104 + <path
  105 + d="M82.8819 108.069L37.6304 108.069C35.7021 108.069 34.4931 106.6 34.4426 106.537L34.395 106.478L34.3569 106.413C33.4674 104.889 12.5669 69.0836 12.0755 68.1901C11.4897 67.1249 11.7768 66.1139 12.0729 65.6206L25.08 37.9282L26.8903 38.7785L13.8059 66.6353L13.784 66.6593C13.7442 66.7397 13.6747 66.9476 13.828 67.2263C14.2959 68.0771 34.8648 103.316 36.034 105.319C36.1941 105.487 36.8063 106.069 37.6304 106.069L82.8819 106.069L82.8819 108.069Z"
  106 + fill="url(#linear_fill_a36ae718-b1ea-4e08-8516-037b53322938)"
  107 + ></path>
  108 + <path
  109 + d="M397.024 71.9896L395.227 71.1121C395.43 70.6963 415.542 29.5053 416.397 27.6251C416.809 26.7185 416.707 26.1818 416.589 26.0099L416.545 25.9688L416.483 25.8788C415.903 25.0347 402.256 5.18647 401.226 3.53913C400.579 2.50379 399.663 2.49152 399.518 2.4972L399.465 2.50367L399.439 2.50007L361.457 2.50007L361.457 0.500061L399.403 0.500061C400.241 0.446289 401.874 0.802368 402.922 2.47906C403.903 4.04908 417.289 23.5203 418.094 24.6921C418.413 25.0638 419.203 26.2852 418.217 28.4527C417.351 30.3579 397.854 70.2907 397.024 71.9896Z"
  110 + fill="url(#linear_fill_e679ec05-c54c-45fa-afbc-1f4cc272d7de)"
  111 + ></path>
  112 + <rect
  113 + x="136.48175048828125"
  114 + y="0.5"
  115 + width="174"
  116 + height="2"
  117 + stroke="rgba(0, 0, 0, 0)"
  118 + stroke-width="1"
  119 + fill="url(#linear_fill_67dd1fd1-a96a-4a67-a858-60eb1cc7970d)"
  120 + ></rect>
  121 + <rect
  122 + x="96.48175048828125"
  123 + y="106.5"
  124 + width="174"
  125 + height="2"
  126 + stroke="rgba(0, 0, 0, 0)"
  127 + stroke-width="1"
  128 + fill="url(#linear_fill_2d07459b-3ef9-4b88-a694-f39f3a4fb8db)"
  129 + ></rect>
  130 + <path
  131 + d="M84.9818 34.142C84.9827 32.629 86.2087 31.403 87.7217 31.402L110.112 31.402C111.432 31.402 112.67 32.337 113.032 33.605L115.145 40.999L137.985 40.999C139.957 40.999 141.574 42.566 141.635 44.538L141.636 44.652L141.636 73.445C141.636 75.462 139.998 77.098 137.985 77.098L88.6338 77.098C86.6168 77.098 84.9818 75.462 84.9818 73.445L84.9818 34.142ZM109.646 35.058L88.6367 35.058L88.6367 40.999L111.343 40.999L109.646 35.058Z"
  132 + fill-rule="evenodd"
  133 + fill="#00A8FF"
  134 + ></path>
  135 + <path
  136 + d="M84.9818 34.142C84.9827 32.629 86.2087 31.403 87.7217 31.402L110.112 31.402C111.432 31.402 112.67 32.337 113.032 33.605L115.145 40.999L137.985 40.999C139.957 40.999 141.574 42.566 141.635 44.538L141.636 44.652L141.636 73.445C141.636 75.462 139.998 77.098 137.985 77.098L88.6338 77.098C86.6168 77.098 84.9818 75.462 84.9818 73.445L84.9818 34.142ZM109.646 35.058L88.6367 35.058L88.6367 40.999L111.343 40.999L109.646 35.058Z"
  137 + fill="url(#linear_fill_5a73a61e-dfec-44ae-ab41-e59e92779ecb)"
  138 + ></path>
  139 + <defs>
  140 + <filter
  141 + id="filter_98d03be6-b8cb-4e27-b332-bc2820d07903"
  142 + x="10.74798583984375"
  143 + y="11.5"
  144 + width="417.41839599609375"
  145 + height="110"
  146 + filterUnits="userSpaceOnUse"
  147 + color-interpolation-filters="sRGB"
  148 + >
  149 + <feFlood flood-opacity="0" result="feFloodId_98d03be6-b8cb-4e27-b332-bc2820d07903" />
  150 + <feBlend
  151 + mode="normal"
  152 + in="SourceGraphic"
  153 + in2="feFloodId_98d03be6-b8cb-4e27-b332-bc2820d07903"
  154 + result="shape"
  155 + />
  156 + <feGaussianBlur result="gaussian_blur_98d03be6-b8cb-4e27-b332-bc2820d07903" stdDeviation="1" />
  157 + </filter>
  158 + <filter
  159 + id="filter_c8b60da4-9052-4ab3-a895-6acbad140e0b"
  160 + x="11.722366333007812"
  161 + y="12.5"
  162 + width="415.47483825683594"
  163 + height="108"
  164 + filterUnits="userSpaceOnUse"
  165 + color-interpolation-filters="sRGB"
  166 + >
  167 + <feFlood flood-opacity="0" result="feFloodId_c8b60da4-9052-4ab3-a895-6acbad140e0b" />
  168 + <feBlend
  169 + mode="normal"
  170 + in="SourceGraphic"
  171 + in2="feFloodId_c8b60da4-9052-4ab3-a895-6acbad140e0b"
  172 + result="shape_c8b60da4-9052-4ab3-a895-6acbad140e0b"
  173 + />
  174 + <feColorMatrix
  175 + in="SourceAlpha"
  176 + type="matrix"
  177 + values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
  178 + result="hardAlpha_c8b60da4-9052-4ab3-a895-6acbad140e0b"
  179 + />
  180 + <feOffset dx="0" dy="0" />
  181 + <feGaussianBlur stdDeviation="10" />
  182 + <feComposite in2="hardAlpha_c8b60da4-9052-4ab3-a895-6acbad140e0b" operator="arithmetic" k2="-1" k3="1" />
  183 + <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.6509803921568628 0 0 0 0 1 0 0 0 0.8 0" />
  184 + <feBlend
  185 + mode="normal"
  186 + in2="shape_c8b60da4-9052-4ab3-a895-6acbad140e0b"
  187 + result="innerShadow_0_c8b60da4-9052-4ab3-a895-6acbad140e0b"
  188 + />
  189 + </filter>
  190 + <filter
  191 + id="filter_19131d1d-3e49-4887-91be-ebc5057ba529"
  192 + x="11.714736938476562"
  193 + y="0.5"
  194 + width="406.99278259277344"
  195 + height="107.5"
  196 + filterUnits="userSpaceOnUse"
  197 + color-interpolation-filters="sRGB"
  198 + >
  199 + <feFlood flood-opacity="0" result="feFloodId_19131d1d-3e49-4887-91be-ebc5057ba529" />
  200 + <feBlend
  201 + mode="normal"
  202 + in="SourceGraphic"
  203 + in2="feFloodId_19131d1d-3e49-4887-91be-ebc5057ba529"
  204 + result="shape_19131d1d-3e49-4887-91be-ebc5057ba529"
  205 + />
  206 + <feColorMatrix
  207 + in="SourceAlpha"
  208 + type="matrix"
  209 + values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
  210 + result="hardAlpha_19131d1d-3e49-4887-91be-ebc5057ba529"
  211 + />
  212 + <feOffset dx="0" dy="0" />
  213 + <feGaussianBlur stdDeviation="10" />
  214 + <feComposite in2="hardAlpha_19131d1d-3e49-4887-91be-ebc5057ba529" operator="arithmetic" k2="-1" k3="1" />
  215 + <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.6509803921568628 0 0 0 0 1 0 0 0 0.8 0" />
  216 + <feBlend
  217 + mode="normal"
  218 + in2="shape_19131d1d-3e49-4887-91be-ebc5057ba529"
  219 + result="innerShadow_0_19131d1d-3e49-4887-91be-ebc5057ba529"
  220 + />
  221 + </filter>
  222 + <filter
  223 + id="filter_ecbd7b82-4d30-47dd-822d-74022aba9497"
  224 + x="28.125961303710938"
  225 + y="7.86505126953125"
  226 + width="385.35585021972656"
  227 + height="93.26998901367188"
  228 + filterUnits="userSpaceOnUse"
  229 + color-interpolation-filters="sRGB"
  230 + >
  231 + <feFlood flood-opacity="0" result="feFloodId_ecbd7b82-4d30-47dd-822d-74022aba9497" />
  232 + <feBlend
  233 + mode="normal"
  234 + in="SourceGraphic"
  235 + in2="feFloodId_ecbd7b82-4d30-47dd-822d-74022aba9497"
  236 + result="shape_ecbd7b82-4d30-47dd-822d-74022aba9497"
  237 + />
  238 + <feColorMatrix
  239 + in="SourceAlpha"
  240 + type="matrix"
  241 + values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
  242 + result="hardAlpha_ecbd7b82-4d30-47dd-822d-74022aba9497"
  243 + />
  244 + <feOffset dx="0" dy="0" />
  245 + <feGaussianBlur stdDeviation="10" />
  246 + <feComposite in2="hardAlpha_ecbd7b82-4d30-47dd-822d-74022aba9497" operator="arithmetic" k2="-1" k3="1" />
  247 + <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.6509803921568628 0 0 0 0 1 0 0 0 0.8 0" />
  248 + <feBlend
  249 + mode="normal"
  250 + in2="shape_ecbd7b82-4d30-47dd-822d-74022aba9497"
  251 + result="innerShadow_0_ecbd7b82-4d30-47dd-822d-74022aba9497"
  252 + />
  253 + </filter>
  254 + <linearGradient
  255 + id="linear_fill_a36ae718-b1ea-4e08-8516-037b53322938"
  256 + x1="20.389801025390625"
  257 + y1="80.09097290039062"
  258 + x2="47.30860900878906"
  259 + y2="63.687042236328125"
  260 + gradientUnits="userSpaceOnUse"
  261 + >
  262 + <stop offset="0" stop-color="#00F6FF" />
  263 + <stop offset="1" stop-color="#0055D5" stop-opacity="0" />
  264 + </linearGradient>
  265 + <linearGradient
  266 + id="linear_fill_e679ec05-c54c-45fa-afbc-1f4cc272d7de"
  267 + x1="410.9110107421875"
  268 + y1="15.723907470703125"
  269 + x2="380.83074951171875"
  270 + y2="39.813629150390625"
  271 + gradientUnits="userSpaceOnUse"
  272 + >
  273 + <stop offset="0" stop-color="#00F6FF" />
  274 + <stop offset="1" stop-color="#0055D5" stop-opacity="0" />
  275 + </linearGradient>
  276 + <linearGradient
  277 + id="linear_fill_67dd1fd1-a96a-4a67-a858-60eb1cc7970d"
  278 + x1="311.72615027427673"
  279 + y1="2.5"
  280 + x2="141.3970258012414"
  281 + y2="4.917073726654053"
  282 + gradientUnits="userSpaceOnUse"
  283 + >
  284 + <stop offset="0" stop-color="#05EEFF" stop-opacity="0" />
  285 + <stop offset="0.519694983959198" stop-color="#00D2FF" />
  286 + <stop offset="1" stop-color="#04679A" stop-opacity="0" />
  287 + </linearGradient>
  288 + <linearGradient
  289 + id="linear_fill_2d07459b-3ef9-4b88-a694-f39f3a4fb8db"
  290 + x1="271.72615027427673"
  291 + y1="108.5"
  292 + x2="101.3970258012414"
  293 + y2="110.91707372665405"
  294 + gradientUnits="userSpaceOnUse"
  295 + >
  296 + <stop offset="0" stop-color="#05EEFF" stop-opacity="0" />
  297 + <stop offset="0.519694983959198" stop-color="#00D2FF" />
  298 + <stop offset="1" stop-color="#04679A" stop-opacity="0" />
  299 + </linearGradient>
  300 + <linearGradient
  301 + id="linear_fill_5a73a61e-dfec-44ae-ab41-e59e92779ecb"
  302 + x1="84.98175048828125"
  303 + y1="77.0980224609375"
  304 + x2="84.98175048828125"
  305 + y2="31.402008056640625"
  306 + gradientUnits="userSpaceOnUse"
  307 + >
  308 + <stop offset="0" stop-color="#2787FF" />
  309 + <stop offset="1" stop-color="#46FBFD" />
  310 + </linearGradient>
  311 + </defs>
  312 + </svg>
  313 + </div>
  314 +</template>
  315 +<script setup lang="ts">
  316 +import { PropType, toRefs } from 'vue'
  317 +import { CreateComponentType } from '@/packages/index.d'
  318 +import { option } from './config'
  319 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  320 +import { useChartDataFetch } from '@/hooks'
  321 +import { isObject } from '@/utils/external/is'
  322 +
  323 +const props = defineProps({
  324 + chartConfig: {
  325 + type: Object as PropType<CreateComponentType & typeof option>,
  326 + required: true
  327 + }
  328 +})
  329 +
  330 +const { w, h } = toRefs(props.chartConfig.attr)
  331 +
  332 +const { dataset, fontConfig } = toRefs(props.chartConfig.option as typeof option)
  333 +
  334 +// 预览更新
  335 +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: string) => {
  336 + if (isObject(newData)) return
  337 + dataset.value = newData as string
  338 +})
  339 +</script>
  340 +
  341 +<style lang="scss" scoped>
  342 +.go-content-box {
  343 + width: v-bind('w+"px"');
  344 + height: v-bind('h+"px"');
  345 + display: flex;
  346 + align-items: center;
  347 + justify-content: center;
  348 +}
  349 +</style>
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { Decorates29Config } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
  6 +
  7 +export const option = {
  8 + dataset: '模块标题',
  9 + fontConfig: {
  10 + x1: '132',
  11 + y1: '129.8828125',
  12 + x2: '103',
  13 + y2: '64.96000000000001',
  14 + datasetTspanFill: '#00F0A2',
  15 + titleTspanFill: '#FFFFFF',
  16 + datasetTspanFontSize: 30,
  17 + }
  18 +}
  19 +
  20 +export default class Config extends PublicConfigClass implements CreateComponentType {
  21 + public key = Decorates29Config.key
  22 + public attr = { ...chartInitConfig, w: 305, h: 110, zIndex: -1 }
  23 + public chartConfig = cloneDeep(Decorates29Config)
  24 + public option = cloneDeep(option)
  25 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem name="配置" :expanded="true">
  5 + <setting-item-box name="数据源">
  6 + <setting-item name="数据">
  7 + <n-input v-model:value="optionData.dataset" />
  8 + </setting-item>
  9 + </setting-item-box>
  10 + <SettingItemBox :name="`数据源字体配置`">
  11 + <SettingItem name="x">
  12 + <n-input-number :min="0" v-model:value="optionData.fontConfig.x1"></n-input-number>
  13 + </SettingItem>
  14 + <SettingItem name="y">
  15 + <n-input-number :min="0" v-model:value="optionData.fontConfig.y1"></n-input-number>
  16 + </SettingItem>
  17 + <SettingItem name="大小">
  18 + <n-input-number :min="0" v-model:value="optionData.fontConfig.datasetTspanFontSize"></n-input-number>
  19 + </SettingItem>
  20 + <SettingItem name="颜色">
  21 + <n-color-picker
  22 + size="small"
  23 + :modes="['hex']"
  24 + v-model:value="optionData.fontConfig.datasetTspanFill"
  25 + ></n-color-picker>
  26 + </SettingItem>
  27 + </SettingItemBox>
  28 + </CollapseItem>
  29 +</template>
  30 +
  31 +<script setup lang="ts">
  32 +import { PropType } from 'vue'
  33 +import { option } from './config'
  34 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  35 +
  36 +defineProps({
  37 + optionData: {
  38 + type: Object as PropType<typeof option>,
  39 + required: true
  40 + }
  41 +})
  42 +</script>
... ...
  1 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  2 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, chartKey, conKey } = useWidgetKey('Decorates29', true)
  6 +
  7 +export const Decorates29Config: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '模块标题29',
  12 + category: ChatCategoryEnum.DECORATE,
  13 + categoryName: ChatCategoryEnumName.DECORATE,
  14 + package: PackagesCategoryEnum.DECORATES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'decorates29.png'
  17 +}
... ...
  1 +<template>
  2 + <div class="go-content-box">
  3 + <svg
  4 + xmlns="http://www.w3.org/2000/svg"
  5 + xmlns:xlink="http://www.w3.org/1999/xlink"
  6 + :width="w"
  7 + :height="h"
  8 + viewBox="0 0 625 188"
  9 + fill="none"
  10 + >
  11 + <path
  12 + d="M625 23L103 23L103 23.04C138.72 23.54 168.05 50.35 172.45 84.98C168.59 88.55 162.6 93.75 162.64 94C162.64 94.29 168.77 98.65 173.03 101.79C169.13 137 139.12 164.46 103 164.96L103 165L625 165L625 23Z"
  13 + fill="url(#linear_fill_8429581d-818b-40fa-b8e2-65e2f7ce17f2)"
  14 + ></path>
  15 + <path
  16 + d="M173 85.5C169.44 87.88 161.71 94 163 94C161.71 94 169.03 99.42 173 101.5C170.24 126.95 157.91 141 154.61 141L595 141L595 47L153 47C155.18 47 171.69 62.91 173 85.5Z"
  17 + fill="url(#linear_fill_552846d5-6f9c-4dc7-9f6f-1867df41fd74)"
  18 + ></path>
  19 + <rect x="109" y="163" width="516" height="2" fill="url(#linear_fill_5bbe4e01-073b-4a63-b060-4cb8ef016116)"></rect>
  20 + <rect x="109" y="23" width="516" height="2" fill="url(#linear_fill_009e1028-4c17-4ca5-9439-a3ea85c86a5e)"></rect>
  21 + <g>
  22 + <path
  23 + fill="#063475"
  24 + fill-opacity="0.6"
  25 + d="M103 0C51.09 0 9 42.09 9 94C9 145.91 51.09 188 103 188C154.91 188 197 145.91 197 94C197 42.09 154.91 0 103 0Z"
  26 + ></path>
  27 + <path
  28 + fill-rule="evenodd"
  29 + fill="rgba(3, 169, 255, 0.43)"
  30 + d="M9 94C9 42.09 51.09 0 103 0C154.91 0 197 42.09 197 94C197 145.91 154.91 188 103 188C51.09 188 9 145.91 9 94ZM11 94C11 43.1898 52.1898 2 103 2C153.81 2 195 43.1898 195 94C195 144.81 153.81 186 103 186C52.1898 186 11 144.81 11 94Z"
  31 + ></path>
  32 + </g>
  33 + <path
  34 + d="M173.42 84.98C169.02 50.02 139.15 23 103 23C66.85 23 36.98 50.02 32.58 84.98C36.4 88.59 42.43 93.75 42.39 94C42.39 94.29 36.26 98.65 32 101.79C35.9 137.33 66.42 165 103 165C139.58 165 170.1 137.33 174 101.79C169.74 98.65 163.61 94.29 163.61 94C163.57 93.75 169.6 88.59 173.42 84.98Z"
  35 + fill="#0B305F"
  36 + fill-opacity="0.6"
  37 + ></path>
  38 + <g filter="url(#filter_4913fbad-67bd-4cb2-8b05-e187c1858401)">
  39 + <path
  40 + fill-rule="evenodd"
  41 + fill="rgba(27, 140, 199, 1)"
  42 + d="M103 23C139.15 23 169.02 50.02 173.42 84.98C171.698 86.6074 169.527 88.5497 167.665 90.2153C165.397 92.2444 163.588 93.8627 163.61 94C163.61 94.29 169.74 98.65 174 101.79C170.1 137.33 139.58 165 103 165C66.42 165 35.9 137.33 32 101.79C36.26 98.65 42.39 94.29 42.39 94C42.412 93.8627 40.603 92.2444 38.3349 90.2152C36.4731 88.5497 34.302 86.6074 32.58 84.98C36.98 50.02 66.85 23 103 23ZM34.6979 84.2221Q36.4313 85.8287 39.6684 88.7247Q44.0053 92.6046 44.3437 94L44.39 94Q44.39 94.0655 44.3685 94.1431Q44.3776 94.2363 44.3649 94.316L44.306 94.3066Q43.5918 95.8122 36.8034 100.756Q35.1678 101.947 34.1219 102.713Q37.2751 127.952 56.579 145.232Q76.4268 163 103 163Q129.573 163 149.421 145.232Q168.725 127.952 171.878 102.713Q170.832 101.947 169.196 100.756Q162.408 95.8121 161.694 94.3065L161.635 94.3159Q161.622 94.2363 161.631 94.1431Q161.61 94.0655 161.61 94L161.656 94Q161.995 92.6047 166.332 88.7247Q169.569 85.8287 171.302 84.2221Q167.828 59.2722 148.789 42.3759Q129.209 25 103 25Q76.7914 25 57.2113 42.3759Q38.1718 59.2721 34.6979 84.2221Z"
  43 + ></path>
  44 + </g>
  45 + <g opacity="0.2">
  46 + <g filter="url(#filter_72875209-e966-4c55-8b84-785fbe6126cc)">
  47 + <path
  48 + fill="#0B305F"
  49 + fill-opacity="0.6"
  50 + d="M163.5 86.25C159.72 56.22 134.06 33 103 33C71.94 33 46.28 56.22 42.5 86.25C45.78 89.35 50.96 93.78 50.93 94C50.93 94.25 45.66 98 42 100.7C45.35 131.23 71.57 155 103 155C134.43 155 160.65 131.23 164 100.7C160.34 98 155.07 94.25 155.07 94C155.04 93.78 160.22 89.35 163.5 86.25Z"
  51 + ></path>
  52 + <path
  53 + fill-rule="evenodd"
  54 + fill="rgba(26, 148, 214, 1)"
  55 + d="M103 33C134.06 33 159.72 56.22 163.5 86.25C162.021 87.648 160.155 89.3165 158.555 90.7473C156.608 92.4894 155.054 93.8792 155.07 94C155.07 94.25 160.34 98 164 100.7C160.65 131.23 134.43 155 103 155C71.57 155 45.35 131.23 42 100.7C45.66 98 50.93 94.25 50.93 94C50.9465 93.8792 49.3924 92.4894 47.4446 90.7473C45.8447 89.3165 43.9792 87.648 42.5 86.25C46.28 56.22 71.94 33 103 33ZM43.5575 85.8711Q45.0601 87.2732 48.1112 90.0019Q51.6678 93.1827 51.9057 94L51.93 94Q51.93 94.0283 51.9196 94.0629Q51.9253 94.1026 51.9208 94.1351L51.8923 94.1312Q51.4459 95.045 45.7197 99.2179Q44.0219 100.455 43.0592 101.162Q45.6913 123.386 62.6369 138.554Q79.8937 154 103 154Q126.106 154 143.363 138.554Q160.309 123.386 162.941 101.162Q161.977 100.455 160.28 99.218Q154.554 95.045 154.108 94.1312L154.079 94.1351Q154.075 94.1026 154.08 94.0629Q154.07 94.0283 154.07 94L154.094 94Q154.332 93.1827 157.889 90.0019Q160.94 87.2733 162.442 85.8711Q159.513 63.9305 142.816 49.1117Q125.79 34 103 34Q80.2103 34 63.1838 49.1117Q46.4873 63.9304 43.5575 85.8711Z"
  56 + ></path>
  57 + </g>
  58 + </g>
  59 + <g opacity="0.2">
  60 + <rect
  61 + x="10.606597900390625"
  62 + y="89"
  63 + width="15"
  64 + height="15"
  65 + transform="rotate(45 10.606597900390625 89)"
  66 + fill="#03A9FF"
  67 + ></rect>
  68 + </g>
  69 + <g opacity="0.2">
  70 + <rect
  71 + x="195.6099853515625"
  72 + y="89.0033950805664"
  73 + width="15"
  74 + height="15"
  75 + transform="rotate(45 195.6099853515625 89.0033950805664)"
  76 + fill="#03A9FF"
  77 + ></rect>
  78 + </g>
  79 + <g opacity="0.2">
  80 + <rect
  81 + x="10.606597900390625"
  82 + y="79"
  83 + width="15"
  84 + height="15"
  85 + transform="rotate(45 10.606597900390625 79)"
  86 + fill="#03A9FF"
  87 + ></rect>
  88 + </g>
  89 + <g opacity="0.2">
  90 + <rect
  91 + x="195.6099853515625"
  92 + y="79.0033950805664"
  93 + width="15"
  94 + height="15"
  95 + transform="rotate(45 195.6099853515625 79.0033950805664)"
  96 + fill="#03A9FF"
  97 + ></rect>
  98 + </g>
  99 + <path
  100 + fill-rule="evenodd"
  101 + fill="rgba(3, 169, 255, 1)"
  102 + d="M10.6066 105.213L-3.8147e-06 94.6066L10.6066 84L21.2132 94.6066L10.6066 105.213ZM15.5563 94.6066L10.6066 89.6569L5.65685 94.6066L10.6066 99.5564L15.5563 94.6066Z"
  103 + ></path>
  104 + <path
  105 + fill-rule="evenodd"
  106 + fill="rgba(3, 169, 255, 1)"
  107 + d="M195.61 105.217L185.003 94.61L195.61 84.0034L206.217 94.61L195.61 105.217ZM200.56 94.61L195.61 89.6602L190.66 94.61L195.61 99.5597L200.56 94.61Z"
  108 + ></path>
  109 + <g opacity="1" transform="translate(88 -26)">
  110 + <text>
  111 + <tspan
  112 + :x="fontConfig.x1"
  113 + :y="fontConfig.y1"
  114 + :font-size="fontConfig.datasetTspanFontSize"
  115 + line-height="0"
  116 + :fill="fontConfig.datasetTspanFill"
  117 + opacity="1"
  118 + font-family="Roboto-Regular"
  119 + font-weight="Regular"
  120 + letter-spacing="0"
  121 + >
  122 + {{ dataset }}
  123 + </tspan>
  124 + </text>
  125 + </g>
  126 + <g filter="url(#filter_375ad2c7-128f-4997-9ac6-7bbb64a0f289)">
  127 + <path
  128 + d="M84.9911 72.02L84.9911 63L99.9911 63L99.9911 72.16C96.1911 72.55 92.4711 73.65 89.1011 75.42L84.9911 72.02ZM116.898 75.42C113.498 73.65 109.808 72.55 105.978 72.16L105.978 63L120.978 63L120.978 72.02L116.898 75.42ZM103 126.004C89.74 126.034 79 115.284 79 102.004C79 88.7635 89.74 78.0135 103 78.0135C116.26 78.0135 127 88.7635 127 102.004C127 115.284 116.26 126.004 103 126.004ZM99.0269 96.5394L102.997 88.5194L106.967 96.5394L115.837 97.8194L109.417 104.069L110.937 112.899L102.997 108.719L95.0569 112.899L96.5869 104.069L90.1669 97.8194L99.0269 96.5394Z"
  129 + fill-rule="evenodd"
  130 + fill="url(#linear_fill_375ad2c7-128f-4997-9ac6-7bbb64a0f289)"
  131 + ></path>
  132 + </g>
  133 + <path
  134 + fill-rule="evenodd"
  135 + fill="url(#linear_fill_5d114998-6e33-4cae-9064-4cf557eef946_0)"
  136 + d="M84.9911 69.02L84.9911 60L99.9911 60L99.9911 69.16C96.1911 69.55 92.4711 70.65 89.1011 72.42L84.9911 69.02ZM116.898 72.42C113.498 70.65 109.808 69.55 105.978 69.16L105.978 60L120.978 60L120.978 69.02L116.898 72.42ZM103 123.004C89.74 123.034 79 112.284 79 99.0035C79 85.7635 89.74 75.0135 103 75.0135C116.26 75.0135 127 85.7635 127 99.0035C127 112.284 116.26 123.004 103 123.004ZM109.417 101.069L110.937 109.899L102.997 105.719L95.0569 109.899L96.5869 101.069L90.1669 94.8194L99.0269 93.5394L102.997 85.5194L106.967 93.5394L115.837 94.8194L109.417 101.069Z"
  137 + ></path>
  138 + <path
  139 + fill-rule="evenodd"
  140 + fill="rgba(159, 223, 255, 1)"
  141 + d="M84.9911 69.02L84.9911 60L99.9911 60L99.9911 69.16C96.1911 69.55 92.4711 70.65 89.1011 72.42L84.9911 69.02ZM89.2315 71.2301Q93.8202 68.9448 98.9911 68.2698L98.9911 61L85.9911 61L85.9911 68.5494L89.2315 71.2301ZM116.898 72.42C113.498 70.65 109.808 69.55 105.978 69.16L105.978 60L120.978 60L120.978 69.02L116.898 72.42ZM119.978 68.5516L119.978 61L106.978 61L106.978 68.2693Q112.128 68.9391 116.763 71.2304L119.978 68.5516ZM79 99.0035C79 112.284 89.74 123.034 103 123.004C116.26 123.004 127 112.284 127 99.0035C127 85.7635 116.26 75.0135 103 75.0135C89.74 75.0135 79 85.7635 79 99.0035ZM126 99.0035C126 111.706 115.703 122.004 103 122.004L102.998 122.004C90.2749 122.032 80 111.726 80 99.0035C80 86.301 90.2975 76.0135 103 76.0135C115.697 76.0135 126 86.3065 126 99.0035ZM109.417 101.069L110.723 108.657L110.937 109.899L109.821 109.312L102.997 105.719L96.1737 109.311L95.0569 109.899L95.2724 108.656L96.5869 101.069L91.0706 95.6992L90.1669 94.8194L91.4152 94.6391L99.0269 93.5394L102.439 86.6465L102.997 85.5194L103.555 86.6465L106.967 93.5394L114.588 94.6392L115.837 94.8194L114.933 95.6993L109.417 101.069ZM107.63 92.6247L102.997 83.2653L98.3638 92.6248L88.0148 94.1199L95.5116 101.418L93.7247 111.731L102.997 106.85L112.267 111.73L110.492 101.419L117.989 94.1196L107.63 92.6247Z"
  142 + ></path>
  143 + <defs>
  144 + <linearGradient
  145 + id="linear_fill_8429581d-818b-40fa-b8e2-65e2f7ce17f2"
  146 + x1="103"
  147 + y1="94"
  148 + x2="625"
  149 + y2="94"
  150 + gradientUnits="userSpaceOnUse"
  151 + >
  152 + <stop offset="0" stop-color="#0C3162" />
  153 + <stop offset="1" stop-color="#010E24" stop-opacity="0" />
  154 + </linearGradient>
  155 + <linearGradient
  156 + id="linear_fill_552846d5-6f9c-4dc7-9f6f-1867df41fd74"
  157 + x1="153"
  158 + y1="94"
  159 + x2="595"
  160 + y2="94"
  161 + gradientUnits="userSpaceOnUse"
  162 + >
  163 + <stop offset="0" stop-color="#0C3162" />
  164 + <stop offset="1" stop-color="#0B2F6E" stop-opacity="0" />
  165 + </linearGradient>
  166 + <linearGradient
  167 + id="linear_fill_5bbe4e01-073b-4a63-b060-4cb8ef016116"
  168 + x1="109"
  169 + y1="164"
  170 + x2="625"
  171 + y2="164"
  172 + gradientUnits="userSpaceOnUse"
  173 + >
  174 + <stop offset="0" stop-color="#1B8CC7" />
  175 + <stop offset="1" stop-color="#1B8CC7" stop-opacity="0" />
  176 + </linearGradient>
  177 + <linearGradient
  178 + id="linear_fill_009e1028-4c17-4ca5-9439-a3ea85c86a5e"
  179 + x1="109"
  180 + y1="24"
  181 + x2="625"
  182 + y2="24"
  183 + gradientUnits="userSpaceOnUse"
  184 + >
  185 + <stop offset="0" stop-color="#1B8CC7" />
  186 + <stop offset="1" stop-color="#1B8CC7" stop-opacity="0" />
  187 + </linearGradient>
  188 + <filter
  189 + id="filter_4913fbad-67bd-4cb2-8b05-e187c1858401"
  190 + x="32"
  191 + y="23"
  192 + width="142"
  193 + height="142"
  194 + filterUnits="userSpaceOnUse"
  195 + color-interpolation-filters="sRGB"
  196 + >
  197 + <feFlood flood-opacity="0" result="feFloodId_4913fbad-67bd-4cb2-8b05-e187c1858401" />
  198 + <feBlend
  199 + mode="normal"
  200 + in="SourceGraphic"
  201 + in2="feFloodId_4913fbad-67bd-4cb2-8b05-e187c1858401"
  202 + result="shape_4913fbad-67bd-4cb2-8b05-e187c1858401"
  203 + />
  204 + <feColorMatrix
  205 + in="SourceAlpha"
  206 + type="matrix"
  207 + values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
  208 + result="hardAlpha_4913fbad-67bd-4cb2-8b05-e187c1858401"
  209 + />
  210 + <feOffset dx="0" dy="0" />
  211 + <feGaussianBlur stdDeviation="5" />
  212 + <feComposite in2="hardAlpha_4913fbad-67bd-4cb2-8b05-e187c1858401" operator="arithmetic" k2="-1" k3="1" />
  213 + <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.7843137254901961 0 0 0 0 1 0 0 0 0.6 0" />
  214 + <feBlend
  215 + mode="normal"
  216 + in2="shape_4913fbad-67bd-4cb2-8b05-e187c1858401"
  217 + result="innerShadow_0_4913fbad-67bd-4cb2-8b05-e187c1858401"
  218 + />
  219 + </filter>
  220 + <filter
  221 + id="filter_72875209-e966-4c55-8b84-785fbe6126cc"
  222 + x="40"
  223 + y="31"
  224 + width="126"
  225 + height="126"
  226 + filterUnits="userSpaceOnUse"
  227 + color-interpolation-filters="sRGB"
  228 + >
  229 + <feFlood flood-opacity="0" result="feFloodId_72875209-e966-4c55-8b84-785fbe6126cc" />
  230 + <feBlend
  231 + mode="normal"
  232 + in="SourceGraphic"
  233 + in2="feFloodId_72875209-e966-4c55-8b84-785fbe6126cc"
  234 + result="shape"
  235 + />
  236 + <feGaussianBlur result="gaussian_blur_72875209-e966-4c55-8b84-785fbe6126cc" stdDeviation="1" />
  237 + </filter>
  238 + <linearGradient
  239 + id="linear_fill_375ad2c7-128f-4997-9ac6-7bbb64a0f289"
  240 + x1="103"
  241 + y1="126"
  242 + x2="103"
  243 + y2="63"
  244 + gradientUnits="userSpaceOnUse"
  245 + >
  246 + <stop offset="0" stop-color="#1B7BB3" />
  247 + <stop offset="1" stop-color="#2BACBA" />
  248 + </linearGradient>
  249 + <filter
  250 + id="filter_375ad2c7-128f-4997-9ac6-7bbb64a0f289"
  251 + x="69"
  252 + y="53"
  253 + width="68"
  254 + height="83.03350067138672"
  255 + filterUnits="userSpaceOnUse"
  256 + color-interpolation-filters="sRGB"
  257 + >
  258 + <feFlood flood-opacity="0" result="feFloodId_375ad2c7-128f-4997-9ac6-7bbb64a0f289" />
  259 + <feColorMatrix
  260 + in="SourceAlpha"
  261 + type="matrix"
  262 + values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
  263 + result="hardAlpha_375ad2c7-128f-4997-9ac6-7bbb64a0f289"
  264 + />
  265 + <feOffset dx="0" dy="0" />
  266 + <feGaussianBlur stdDeviation="5" />
  267 + <feComposite in2="hardAlpha_375ad2c7-128f-4997-9ac6-7bbb64a0f289" operator="out" />
  268 + <feColorMatrix
  269 + type="matrix"
  270 + values="0 0 0 0 0.27058823529411763 0 0 0 0 0.7803921568627451 0 0 0 0 1 0 0 0 0.5 0"
  271 + />
  272 + <feBlend
  273 + mode="normal"
  274 + in2="feFloodId_375ad2c7-128f-4997-9ac6-7bbb64a0f289"
  275 + result="dropShadow_1_375ad2c7-128f-4997-9ac6-7bbb64a0f289"
  276 + />
  277 + <feBlend
  278 + mode="normal"
  279 + in="SourceGraphic"
  280 + in2="dropShadow_1_375ad2c7-128f-4997-9ac6-7bbb64a0f289"
  281 + result="shape_375ad2c7-128f-4997-9ac6-7bbb64a0f289"
  282 + />
  283 + </filter>
  284 + <linearGradient
  285 + id="linear_fill_5d114998-6e33-4cae-9064-4cf557eef946_0"
  286 + x1="103"
  287 + y1="123"
  288 + x2="103"
  289 + y2="60"
  290 + gradientUnits="userSpaceOnUse"
  291 + >
  292 + <stop offset="0" stop-color="#3AB4F9" />
  293 + <stop offset="1" stop-color="#6DD0DA" />
  294 + </linearGradient>
  295 + </defs>
  296 + </svg>
  297 + </div>
  298 +</template>
  299 +<script setup lang="ts">
  300 +import { PropType, toRefs } from 'vue'
  301 +import { CreateComponentType } from '@/packages/index.d'
  302 +import { option } from './config'
  303 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  304 +import { useChartDataFetch } from '@/hooks'
  305 +import { isObject } from '@/utils/external/is'
  306 +
  307 +const props = defineProps({
  308 + chartConfig: {
  309 + type: Object as PropType<CreateComponentType & typeof option>,
  310 + required: true
  311 + }
  312 +})
  313 +
  314 +const { w, h } = toRefs(props.chartConfig.attr)
  315 +
  316 +const { dataset, fontConfig } = toRefs(props.chartConfig.option as typeof option)
  317 +
  318 +// 预览更新
  319 +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: string) => {
  320 + if (isObject(newData)) return
  321 + dataset.value = newData as string
  322 +})
  323 +</script>
  324 +
  325 +<style lang="scss" scoped>
  326 +.go-content-box {
  327 + width: v-bind('w+"px"');
  328 + height: v-bind('h+"px"');
  329 + display: flex;
  330 + align-items: center;
  331 + justify-content: center;
  332 +}
  333 +</style>
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { Decorates30Config } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
  6 +
  7 +export const option = {
  8 + dataset: '32',
  9 + unitStr: '个',
  10 + titleStr: '设备总数',
  11 + fontConfig: {
  12 + x1: '320', //数据源
  13 + y1: '80',
  14 + x2: '366', //单位
  15 + y2: '79',
  16 + x3: '11', //标题
  17 + y3: '79',
  18 + datasetTspanFill: '#00F0A2',
  19 + titleTspanFill: '#FFFFFF',
  20 + unitTspanFill: '#FFFFFF',
  21 + datasetTspanFontSize: 30,
  22 + titleTspanFontSize: 30,
  23 + unitTspanFontSize: 30
  24 + }
  25 +}
  26 +
  27 +export default class Config extends PublicConfigClass implements CreateComponentType {
  28 + public key = Decorates30Config.key
  29 + public attr = { ...chartInitConfig, w: 305, h: 110, zIndex: -1 }
  30 + public chartConfig = cloneDeep(Decorates30Config)
  31 + public option = cloneDeep(option)
  32 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem name="配置" :expanded="true">
  5 + <setting-item-box name="数据源">
  6 + <setting-item name="数据">
  7 + <n-input v-model:value="optionData.dataset" />
  8 + </setting-item>
  9 + <setting-item name="单位">
  10 + <n-input v-model:value="optionData.unitStr" />
  11 + </setting-item>
  12 + <setting-item name="标题">
  13 + <n-input v-model:value="optionData.titleStr" />
  14 + </setting-item>
  15 + </setting-item-box>
  16 + <SettingItemBox :name="`单位字体配置`">
  17 + <SettingItem name="x">
  18 + <n-input-number :min="0" v-model:value="optionData.fontConfig.x2"></n-input-number>
  19 + </SettingItem>
  20 + <SettingItem name="y">
  21 + <n-input-number :min="0" v-model:value="optionData.fontConfig.y2"></n-input-number>
  22 + </SettingItem>
  23 + <SettingItem name="大小">
  24 + <n-input-number :min="0" v-model:value="optionData.fontConfig.unitTspanFontSize"></n-input-number>
  25 + </SettingItem>
  26 + <SettingItem name="颜色">
  27 + <n-color-picker
  28 + size="small"
  29 + :modes="['hex']"
  30 + v-model:value="optionData.fontConfig.unitTspanFill"
  31 + ></n-color-picker>
  32 + </SettingItem>
  33 + </SettingItemBox>
  34 + <SettingItemBox :name="`数据源字体配置`">
  35 + <SettingItem name="x">
  36 + <n-input-number :min="0" v-model:value="optionData.fontConfig.x1"></n-input-number>
  37 + </SettingItem>
  38 + <SettingItem name="y">
  39 + <n-input-number :min="0" v-model:value="optionData.fontConfig.y1"></n-input-number>
  40 + </SettingItem>
  41 + <SettingItem name="大小">
  42 + <n-input-number :min="0" v-model:value="optionData.fontConfig.datasetTspanFontSize"></n-input-number>
  43 + </SettingItem>
  44 + <SettingItem name="颜色">
  45 + <n-color-picker
  46 + size="small"
  47 + :modes="['hex']"
  48 + v-model:value="optionData.fontConfig.datasetTspanFill"
  49 + ></n-color-picker>
  50 + </SettingItem>
  51 + </SettingItemBox>
  52 + <SettingItemBox :name="`标题字体配置`">
  53 + <SettingItem name="x">
  54 + <n-input-number :min="0" v-model:value="optionData.fontConfig.x3"></n-input-number>
  55 + </SettingItem>
  56 + <SettingItem name="y">
  57 + <n-input-number :min="0" v-model:value="optionData.fontConfig.y3"></n-input-number>
  58 + </SettingItem>
  59 + <SettingItem name="大小">
  60 + <n-input-number :min="0" v-model:value="optionData.fontConfig.titleTspanFontSize"></n-input-number>
  61 + </SettingItem>
  62 + <SettingItem name="颜色">
  63 + <n-color-picker
  64 + size="small"
  65 + :modes="['hex']"
  66 + v-model:value="optionData.fontConfig.titleTspanFill"
  67 + ></n-color-picker>
  68 + </SettingItem>
  69 + </SettingItemBox>
  70 + </CollapseItem>
  71 +</template>
  72 +
  73 +<script setup lang="ts">
  74 +import { PropType } from 'vue'
  75 +import { option } from './config'
  76 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  77 +
  78 +defineProps({
  79 + optionData: {
  80 + type: Object as PropType<typeof option>,
  81 + required: true
  82 + }
  83 +})
  84 +</script>
... ...
  1 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  2 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, chartKey, conKey } = useWidgetKey('Decorates30', true)
  6 +
  7 +export const Decorates30Config: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '数据标题30',
  12 + category: ChatCategoryEnum.DECORATE,
  13 + categoryName: ChatCategoryEnumName.DECORATE,
  14 + package: PackagesCategoryEnum.DECORATES,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'decorates30.png'
  17 +}
... ...
  1 +<template>
  2 + <div class="go-content-box">
  3 + <svg
  4 + xmlns="http://www.w3.org/2000/svg"
  5 + xmlns:xlink="http://www.w3.org/1999/xlink"
  6 + :width="w"
  7 + :height="h"
  8 + viewBox="0 0 442 141"
  9 + fill="none"
  10 + >
  11 + <g>
  12 + <g filter="url(#filter_95b2f60e-40ab-42fb-81a1-c50e11e63c01)">
  13 + <rect x="11" y="19" width="429" height="120" fill="#012651" fill-opacity="0.5"></rect>
  14 + <path
  15 + fill-rule="evenodd"
  16 + fill="rgba(1, 80, 152, 1)"
  17 + d="M440 139L11 139L11 19L440 19L440 139ZM438 21L13 21L13 137L438 137L438 21Z"
  18 + ></path>
  19 + </g>
  20 + </g>
  21 + <rect x="0" y="11" width="429" height="120" fill="#012651" fill-opacity="0.5"></rect>
  22 + <g filter="url(#filter_edebad1d-8cf8-4ddf-87ba-cceec465951b)">
  23 + <path
  24 + fill-rule="evenodd"
  25 + fill="rgba(1, 80, 152, 1)"
  26 + d="M429 131L0 131L0 11L429 11L429 131ZM427 13L2 13L2 129L427 129L427 13Z"
  27 + ></path>
  28 + </g>
  29 + <path d="M0 7.2L370 7.2L366.29 3.76L127.79 3.76L122.29 0L3.79 0.59L0 7.2Z" fill="#008AFF"></path>
  30 + <rect x="417" y="1.199951171875" width="11" height="6" fill="#00FDC7"></rect>
  31 + <rect x="12" y="20" width="6" height="6" fill="#00EEFD"></rect>
  32 + <g opacity="0.5">
  33 + <rect x="24" y="20" width="6" height="6" fill="#00EEFD"></rect>
  34 + </g>
  35 + <g opacity="0.2">
  36 + <rect x="36" y="20" width="6" height="6" fill="#00EEFD"></rect>
  37 + </g>
  38 + <rect x="399" y="1.199951171875" width="11" height="6" fill="#00FDC7" fill-opacity="0.6"></rect>
  39 + <rect x="381" y="1.199951171875" width="11" height="6" fill="#00FDC7" fill-opacity="0.2"></rect>
  40 + <path d="M403 131L429 131L429 102L403 131Z" fill="#00B5C6"></path>
  41 + <path
  42 + d="M3 129L31.5 129L87.5 13L59 13L3 129Z"
  43 + fill="url(#linear_fill_d377d882-63b6-4b2f-b075-f04757ddaaf2)"
  44 + ></path>
  45 + <path
  46 + d="M51.8571 129L80.3571 129L136.357 13L107.857 13L51.8571 129Z"
  47 + fill="url(#linear_fill_bffa1776-bd2b-433f-8c5d-b7a711801df9)"
  48 + ></path>
  49 + <path
  50 + d="M100.714 129L129.214 129L185.214 13L156.714 13L100.714 129Z"
  51 + fill="url(#linear_fill_c9bca278-5d80-4ff7-ba93-f353162e7011)"
  52 + ></path>
  53 + <path
  54 + d="M149.571 129L178.071 129L234.071 13L205.571 13L149.571 129Z"
  55 + fill="url(#linear_fill_8c82d359-5e14-4e92-a053-701212e20ddb)"
  56 + ></path>
  57 + <path
  58 + d="M198.429 129L226.929 129L282.929 13L254.429 13L198.429 129Z"
  59 + fill="url(#linear_fill_c1497f7e-7db6-469b-916e-03fb85481d4e)"
  60 + ></path>
  61 + <path
  62 + d="M247.286 129L275.786 129L331.786 13L303.286 13L247.286 129Z"
  63 + fill="url(#linear_fill_52ee754d-41b8-4575-9561-981422976caa)"
  64 + ></path>
  65 + <path
  66 + d="M296.143 129L324.643 129L380.643 13L352.143 13L296.143 129Z"
  67 + fill="url(#linear_fill_3febdb91-9c5c-4985-97d3-16ec34fa4b5c)"
  68 + ></path>
  69 + <path
  70 + d="M345 129L373.5 129L429.5 13L401 13L345 129Z"
  71 + fill="url(#linear_fill_bd8f0060-6382-48ce-9408-29c6216ec4cc)"
  72 + ></path>
  73 + <g>
  74 + <text>
  75 + <tspan
  76 + :x="fontConfig.x3"
  77 + :y="fontConfig.y3"
  78 + :font-size="fontConfig.titleTspanFontSize"
  79 + line-height="0"
  80 + :fill="fontConfig.titleTspanFill"
  81 + opacity="1"
  82 + font-family="Roboto-Regular"
  83 + font-weight="Regular"
  84 + letter-spacing="0"
  85 + >
  86 + {{ titleStr }}
  87 + </tspan>
  88 + </text>
  89 + </g>
  90 + <g opacity="0.8">
  91 + <text>
  92 + <tspan
  93 + :x="fontConfig.x2"
  94 + :y="fontConfig.y2"
  95 + :font-size="fontConfig.unitTspanFontSize"
  96 + line-height="0"
  97 + :fill="fontConfig.unitTspanFill"
  98 + opacity="1"
  99 + font-family="Roboto-Regular"
  100 + font-weight="Regular"
  101 + letter-spacing="0"
  102 + >
  103 + {{ unitStr }}
  104 + </tspan>
  105 + </text>
  106 + </g>
  107 + <g>
  108 + <text>
  109 + <tspan
  110 + :x="fontConfig.x1"
  111 + :y="fontConfig.y1"
  112 + :font-size="fontConfig.datasetTspanFontSize"
  113 + line-height="0"
  114 + :fill="fontConfig.datasetTspanFill"
  115 + opacity="1"
  116 + font-family="Roboto-Regular"
  117 + font-weight="Regular"
  118 + letter-spacing="0"
  119 + >
  120 + {{ dataset }}
  121 + </tspan>
  122 + </text>
  123 + </g>
  124 + <defs>
  125 + <filter
  126 + id="filter_95b2f60e-40ab-42fb-81a1-c50e11e63c01"
  127 + x="9"
  128 + y="17"
  129 + width="433"
  130 + height="124"
  131 + filterUnits="userSpaceOnUse"
  132 + color-interpolation-filters="sRGB"
  133 + >
  134 + <feFlood flood-opacity="0" result="feFloodId_95b2f60e-40ab-42fb-81a1-c50e11e63c01" />
  135 + <feBlend
  136 + mode="normal"
  137 + in="SourceGraphic"
  138 + in2="feFloodId_95b2f60e-40ab-42fb-81a1-c50e11e63c01"
  139 + result="shape"
  140 + />
  141 + <feGaussianBlur result="gaussian_blur_95b2f60e-40ab-42fb-81a1-c50e11e63c01" stdDeviation="1" />
  142 + </filter>
  143 + <filter
  144 + id="filter_edebad1d-8cf8-4ddf-87ba-cceec465951b"
  145 + x="0"
  146 + y="11"
  147 + width="429"
  148 + height="120"
  149 + filterUnits="userSpaceOnUse"
  150 + color-interpolation-filters="sRGB"
  151 + >
  152 + <feFlood flood-opacity="0" result="feFloodId_edebad1d-8cf8-4ddf-87ba-cceec465951b" />
  153 + <feBlend
  154 + mode="normal"
  155 + in="SourceGraphic"
  156 + in2="feFloodId_edebad1d-8cf8-4ddf-87ba-cceec465951b"
  157 + result="shape_edebad1d-8cf8-4ddf-87ba-cceec465951b"
  158 + />
  159 + <feColorMatrix
  160 + in="SourceAlpha"
  161 + type="matrix"
  162 + values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
  163 + result="hardAlpha_edebad1d-8cf8-4ddf-87ba-cceec465951b"
  164 + />
  165 + <feOffset dx="0" dy="0" />
  166 + <feGaussianBlur stdDeviation="5" />
  167 + <feComposite in2="hardAlpha_edebad1d-8cf8-4ddf-87ba-cceec465951b" operator="arithmetic" k2="-1" k3="1" />
  168 + <feColorMatrix
  169 + type="matrix"
  170 + values="0 0 0 0 0 0 0 0 0 0.9333333333333333 0 0 0 0 0.9921568627450981 0 0 0 0.5 0"
  171 + />
  172 + <feBlend
  173 + mode="normal"
  174 + in2="shape_edebad1d-8cf8-4ddf-87ba-cceec465951b"
  175 + result="innerShadow_0_edebad1d-8cf8-4ddf-87ba-cceec465951b"
  176 + />
  177 + </filter>
  178 + <linearGradient
  179 + id="linear_fill_d377d882-63b6-4b2f-b075-f04757ddaaf2"
  180 + x1="25.0595703125"
  181 + y1="129"
  182 + x2="74.54360961914062"
  183 + y2="32.833740234375"
  184 + gradientUnits="userSpaceOnUse"
  185 + >
  186 + <stop offset="0" stop-color="#2466BD" stop-opacity="0.2" />
  187 + <stop offset="1" stop-color="#2466BD" stop-opacity="0" />
  188 + </linearGradient>
  189 + <linearGradient
  190 + id="linear_fill_bffa1776-bd2b-433f-8c5d-b7a711801df9"
  191 + x1="73.91671752929688"
  192 + y1="129"
  193 + x2="123.4007568359375"
  194 + y2="32.833740234375"
  195 + gradientUnits="userSpaceOnUse"
  196 + >
  197 + <stop offset="0" stop-color="#2466BD" stop-opacity="0.2" />
  198 + <stop offset="1" stop-color="#2466BD" stop-opacity="0" />
  199 + </linearGradient>
  200 + <linearGradient
  201 + id="linear_fill_c9bca278-5d80-4ff7-ba93-f353162e7011"
  202 + x1="122.77386474609375"
  203 + y1="129"
  204 + x2="172.25790405273438"
  205 + y2="32.833740234375"
  206 + gradientUnits="userSpaceOnUse"
  207 + >
  208 + <stop offset="0" stop-color="#2466BD" stop-opacity="0.2" />
  209 + <stop offset="1" stop-color="#2466BD" stop-opacity="0" />
  210 + </linearGradient>
  211 + <linearGradient
  212 + id="linear_fill_8c82d359-5e14-4e92-a053-701212e20ddb"
  213 + x1="171.6309814453125"
  214 + y1="129"
  215 + x2="221.11502075195312"
  216 + y2="32.833740234375"
  217 + gradientUnits="userSpaceOnUse"
  218 + >
  219 + <stop offset="0" stop-color="#2466BD" stop-opacity="0.2" />
  220 + <stop offset="1" stop-color="#2466BD" stop-opacity="0" />
  221 + </linearGradient>
  222 + <linearGradient
  223 + id="linear_fill_c1497f7e-7db6-469b-916e-03fb85481d4e"
  224 + x1="220.4881591796875"
  225 + y1="129"
  226 + x2="269.9721984863281"
  227 + y2="32.833740234375"
  228 + gradientUnits="userSpaceOnUse"
  229 + >
  230 + <stop offset="0" stop-color="#2466BD" stop-opacity="0.2" />
  231 + <stop offset="1" stop-color="#2466BD" stop-opacity="0" />
  232 + </linearGradient>
  233 + <linearGradient
  234 + id="linear_fill_52ee754d-41b8-4575-9561-981422976caa"
  235 + x1="269.34527587890625"
  236 + y1="129"
  237 + x2="318.8293151855469"
  238 + y2="32.833740234375"
  239 + gradientUnits="userSpaceOnUse"
  240 + >
  241 + <stop offset="0" stop-color="#2466BD" stop-opacity="0.2" />
  242 + <stop offset="1" stop-color="#2466BD" stop-opacity="0" />
  243 + </linearGradient>
  244 + <linearGradient
  245 + id="linear_fill_3febdb91-9c5c-4985-97d3-16ec34fa4b5c"
  246 + x1="318.2024230957031"
  247 + y1="129"
  248 + x2="367.68646240234375"
  249 + y2="32.833740234375"
  250 + gradientUnits="userSpaceOnUse"
  251 + >
  252 + <stop offset="0" stop-color="#2466BD" stop-opacity="0.2" />
  253 + <stop offset="1" stop-color="#2466BD" stop-opacity="0" />
  254 + </linearGradient>
  255 + <linearGradient
  256 + id="linear_fill_bd8f0060-6382-48ce-9408-29c6216ec4cc"
  257 + x1="367.0595703125"
  258 + y1="129"
  259 + x2="416.5435791015625"
  260 + y2="32.833740234375"
  261 + gradientUnits="userSpaceOnUse"
  262 + >
  263 + <stop offset="0" stop-color="#2466BD" stop-opacity="0.2" />
  264 + <stop offset="1" stop-color="#2466BD" stop-opacity="0" />
  265 + </linearGradient>
  266 + </defs>
  267 + </svg>
  268 + </div>
  269 +</template>
  270 +<script setup lang="ts">
  271 +import { PropType, toRefs } from 'vue'
  272 +import { CreateComponentType } from '@/packages/index.d'
  273 +import { option } from './config'
  274 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  275 +import { useChartDataFetch } from '@/hooks'
  276 +import { isObject } from '@/utils/external/is'
  277 +
  278 +const props = defineProps({
  279 + chartConfig: {
  280 + type: Object as PropType<CreateComponentType & typeof option>,
  281 + required: true
  282 + }
  283 +})
  284 +
  285 +const { w, h } = toRefs(props.chartConfig.attr)
  286 +
  287 +const { dataset, fontConfig, unitStr, titleStr } = toRefs(props.chartConfig.option as typeof option)
  288 +
  289 +// 预览更新
  290 +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: string) => {
  291 + if (isObject(newData)) return
  292 + dataset.value = newData as string
  293 +})
  294 +</script>
  295 +
  296 +<style lang="scss" scoped>
  297 +.go-content-box {
  298 + width: v-bind('w+"px"');
  299 + height: v-bind('h+"px"');
  300 + display: flex;
  301 + align-items: center;
  302 + justify-content: center;
  303 +}
  304 +</style>
... ...
... ... @@ -71,7 +71,6 @@ const onChange = (v: number | number[] | null) => {
71 71 dateEnd = dayjs(lastTs).set('hour', 23).set('minute', 59).set('second', 59).valueOf()
72 72 }
73 73 }
74   - console.log(daterange)
75 74 // 存储到联动数据
76 75 useChartInteract(
77 76 props.chartConfig,
... ...
... ... @@ -2,11 +2,12 @@ import { PublicConfigClass } from '@/packages/public'
2 2 import { CreateComponentType } from '@/packages/index.d'
3 3 import { SingleCameraConfig } from './index'
4 4 import cloneDeep from 'lodash/cloneDeep'
5   -import {StreamType} from "@/components/Video/src/types";
6   -import {useFingerprint} from "@/utils/external/useFingerprint";
7   -import {getOpenFlvPlayUrl, getVideoControlStart} from "@/api/external/flvPlay";
8   -import {getVideoUrl} from "@/api/external/common";
9   -import {CameraRecord} from "@/api/external/common/model";
  5 +import { StreamType } from "@/components/Video/src/types";
  6 +import { useFingerprint } from "@/utils/external/useFingerprint";
  7 +import { getOpenFlvPlayUrl, getVideoControlStart } from "@/api/external/flvPlay";
  8 +import { getVideoUrl } from "@/api/external/common";
  9 +import { CameraRecord } from "@/api/external/common/model";
  10 +import { useGlobSetting } from '@/hooks/external/setting';
10 11
11 12 export enum sourceTypeEnum {
12 13 CUSTOM = 'custom',
... ... @@ -89,7 +90,7 @@ export const isRtspProtocol = (url: string) => {
89 90 };
90 91
91 92 export async function getPlayUrl(
92   - params: CameraRecord
  93 + params: CameraRecord
93 94 ): Promise<{ url: string; type: StreamType } | undefined> {
94 95 const { accessMode } = params;
95 96 if (accessMode === AccessMode.ManuallyEnter) {
... ... @@ -106,18 +107,20 @@ export async function getPlayUrl(
106 107 }
107 108 }
108 109 } else if (accessMode === AccessMode.GBT28181) {
  110 + const { securityPolicy } = useGlobSetting()
  111 + console.log(useGlobSetting())
109 112 const { deviceId, channelNo } = params?.params || {};
110 113 const result = await getVideoControlStart({ channelId: channelNo!, deviceId: deviceId! });
111   - return { url: result.data.flv, type: 'flv' };
  114 + return { url: securityPolicy ? result.data.https_flv : result.data.flv, type: 'flv' };
112 115 } else {
113 116 const { id, playProtocol } = params;
114 117 const result = await getVideoUrl(id);
115 118 const type: StreamType =
116   - playProtocol === FluoriteMideaProtocolEnum.FLV
117   - ? 'flv'
118   - : playProtocol === FluoriteMideaProtocolEnum.HLS
119   - ? 'hls'
120   - : 'auto';
  119 + playProtocol === FluoriteMideaProtocolEnum.FLV
  120 + ? 'flv'
  121 + : playProtocol === FluoriteMideaProtocolEnum.HLS
  122 + ? 'hls'
  123 + : 'auto';
121 124 return { url: result.data.url, type };
122 125 }
123 126 }
... ...
1 1 <template>
2 2 <div>
3 3 <n-spin size="medium" :show="showLoading" class="player-spin">
4   - <XGPlayer :url="sourceUrl" :stream-type="playType"
5   - :config="{width: '100%', height: '100%', poster: option.poster}"
6   - :auto-play="option.autoplay"/>
  4 + <XGPlayer
  5 + ref="XGPlayerRef"
  6 + @userAction="handleOnUserAction"
  7 + :url="sourceUrl"
  8 + :stream-type="playType"
  9 + :config="{ width: '100%', height: '100%', poster: poster }"
  10 + :auto-play="autoplay"
  11 + />
7 12 </n-spin>
8 13 </div>
9 14 </template>
10 15 <script setup lang="ts">
11   -import {PropType, toRefs, shallowReactive, watch, ref} from 'vue'
12   -import {CreateComponentType} from '@/packages/index.d'
13   -import {Dataset, getPlayUrl, option as configOption} from './config'
14   -import {XGPlayer} from '@/components/Video'
15   -import {StreamType} from "@/components/Video/src/types";
16   -import {CameraRecord} from "@/api/external/common/model";
17   -import { isNullOrUnDef } from '@/utils/external/is';
  16 +import { PropType, toRefs, shallowReactive, watch, ref, nextTick } from 'vue'
  17 +import { CreateComponentType } from '@/packages/index.d'
  18 +import { Dataset, getPlayUrl, option as configOption } from './config'
  19 +import { XGPlayer } from '@/components/Video'
  20 +import { StreamType, UserActionEventType } from '@/components/Video/src/types'
  21 +import { CameraRecord } from '@/api/external/common/model'
  22 +import { isNullOrUnDef } from '@/utils/external/is'
18 23
19 24 const props = defineProps({
20 25 chartConfig: {
... ... @@ -25,9 +30,11 @@ const props = defineProps({
25 30
26 31 const showLoading = ref(false)
27 32
28   -const {w, h} = toRefs(props.chartConfig.attr)
  33 +const XGPlayerRef = ref<InstanceType<typeof XGPlayer>>()
29 34
30   -const {autoplay, dataset, poster, customVideoUrl} = toRefs(props.chartConfig.option as typeof configOption)
  35 +const { w, h } = toRefs(props.chartConfig.attr)
  36 +
  37 +const { autoplay, dataset, poster, customVideoUrl } = toRefs(props.chartConfig.option as typeof configOption)
31 38
32 39 const option = shallowReactive({
33 40 dataset: configOption.dataset,
... ... @@ -36,36 +43,55 @@ const option = shallowReactive({
36 43 })
37 44
38 45 const sourceUrl = ref('')
39   -const playType = ref<StreamType>()
40 46
  47 +const playType = ref<StreamType>()
41 48
42 49 async function getPlaySource(params: Dataset) {
43   - const {id, channelId, deviceId, accessMode, customUrl, playProtocol} = params
44   - if (isNullOrUnDef(accessMode)) return
45   - const {type, url} = await getPlayUrl({
  50 + if (!autoplay.value) return
  51 + doPlaySource(params)
  52 +}
  53 +
  54 +async function doPlaySource(params?: Dataset) {
  55 + const { id, channelId, deviceId, accessMode, customUrl, playProtocol } = params as unknown as Dataset
  56 + if (isNullOrUnDef(accessMode)) return
  57 + const { type, url } =
  58 + (await getPlayUrl({
46 59 id: id,
47 60 accessMode: accessMode,
48 61 playProtocol: playProtocol,
49 62 videoUrl: customUrl,
50 63 params: {
51 64 deviceId: deviceId,
52   - channelNo: channelId,
53   - },
54   - } as unknown as CameraRecord) || {}
55   - sourceUrl.value = url!
56   - playType.value = type
  65 + channelNo: channelId
  66 + }
  67 + } as unknown as CameraRecord)) || {}
  68 + sourceUrl.value = url!
  69 + playType.value = type
  70 +}
  71 +
  72 +function handleOnUserAction(event: UserActionEventType) {
  73 + const { from, to } = event
  74 + if (from && !to) {
  75 + doPlaySource(dataset?.value)
  76 + nextTick(() => {
  77 + XGPlayerRef.value?.getPlayerInstance()?.play()
  78 + })
  79 + } else if (!from && to) {
  80 + nextTick(() => {
  81 + XGPlayerRef.value?.getPlayerInstance()?.pause()
  82 + })
  83 + }
57 84 }
58 85
59 86 watch(
60   - () => dataset?.value,
61   - async (newData) => {
62   - getPlaySource(newData)
63   - },
64   - {
65   - immediate: true
66   - }
  87 + () => dataset?.value,
  88 + async newData => {
  89 + getPlaySource(newData)
  90 + },
  91 + {
  92 + immediate: true
  93 + }
67 94 )
68   -
69 95 </script>
70 96
71 97 <style lang="scss" scoped>
... ...
... ... @@ -36,8 +36,8 @@ export const option = {
36 36 fontWeight: 'normal',
37 37
38 38 // 边框
39   - borderWidth: 0,
40   - borderColor: '#ffffff',
  39 + borderWidth: 1,
  40 + borderColor: '#3c7eff',
41 41 borderRadius: 5,
42 42
43 43 // 字间距
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { CreateComponentType } from '@/packages/index.d'
  3 +import { OverrideTextEnumCommonConfig } from './index'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import { chartInitConfig } from '@/settings/designSetting'
  6 +
  7 +export enum WritingModeEnum {
  8 + HORIZONTAL = '水平',
  9 + VERTICAL = '垂直'
  10 +}
  11 +
  12 +export const WritingModeObject = {
  13 + [WritingModeEnum.HORIZONTAL]: 'horizontal-tb',
  14 + [WritingModeEnum.VERTICAL]: 'vertical-rl'
  15 +}
  16 +
  17 +export enum FontWeightEnum {
  18 + NORMAL = '常规',
  19 + BOLD = '加粗'
  20 +}
  21 +
  22 +export const FontWeightObject = {
  23 + [FontWeightEnum.NORMAL]: 'normal',
  24 + [FontWeightEnum.BOLD]: 'bold'
  25 +}
  26 +
  27 +export const option = {
  28 + link: '',
  29 + linkHead: 'http://',
  30 + dataset: '我是文本',
  31 + fontSize: 20,
  32 + fontColor: '#ffffff',
  33 + paddingX: 10,
  34 + paddingY: 10,
  35 + textAlign: 'center', // 水平对齐方式
  36 + fontWeight: 'normal',
  37 +
  38 + // 边框
  39 + borderWidth: 1,
  40 + borderColor: '#3c7eff',
  41 + borderRadius: 5,
  42 +
  43 + // 字间距
  44 + letterSpacing: 5,
  45 + writingMode: 'horizontal-tb',
  46 + backgroundColor: '#00000000',
  47 +
  48 + //跳转方式
  49 + linkMethod: 'default'
  50 +}
  51 +
  52 +export default class Config extends PublicConfigClass implements CreateComponentType {
  53 + public key = OverrideTextEnumCommonConfig.key
  54 + public attr = { ...chartInitConfig, w: 150, h: 40, zIndex: -1 }
  55 + public chartConfig = cloneDeep(OverrideTextEnumCommonConfig)
  56 + public option = cloneDeep(option)
  57 +}
... ...
  1 +<template>
  2 + <collapse-item name="信息" :expanded="true">
  3 + <setting-item-box name="文字" :alone="true">
  4 + <setting-item>
  5 + <n-input v-model:value="optionData.dataset" type="textarea" size="small"></n-input>
  6 + </setting-item>
  7 + </setting-item-box>
  8 + <setting-item-box name="链接" :alone="true">
  9 + <setting-item>
  10 + <n-input-group>
  11 + <n-select
  12 + v-model:value="optionData.linkHead"
  13 + size="small"
  14 + :style="{ width: '80%' }"
  15 + :options="linkHeadOptions"
  16 + />
  17 + <n-input v-model:value="optionData.link" size="small"></n-input>
  18 + </n-input-group>
  19 + </setting-item>
  20 + </setting-item-box>
  21 + <setting-item-box name="跳转方式" :alone="true">
  22 + <setting-item>
  23 + <n-input-group>
  24 + <n-select
  25 + v-model:value="optionData.linkMethod"
  26 + size="small"
  27 + :style="{ width: '80%' }"
  28 + :options="linkMethodOptions"
  29 + />
  30 + <n-button
  31 + :disabled="!optionData.linkMethod"
  32 + secondary
  33 + size="small"
  34 + @click="handleLinkClick(optionData.linkMethod)"
  35 + >跳转</n-button
  36 + >
  37 + </n-input-group>
  38 + </setting-item>
  39 + </setting-item-box>
  40 + </collapse-item>
  41 +
  42 + <collapse-item name="样式" :expanded="true">
  43 + <setting-item-box name="文字">
  44 + <setting-item name="颜色">
  45 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.fontColor"></n-color-picker>
  46 + </setting-item>
  47 + <setting-item name="字体大小">
  48 + <n-input-number v-model:value="optionData.fontSize" size="small" placeholder="字体大小"></n-input-number>
  49 + </setting-item>
  50 + <setting-item name="字体粗细">
  51 + <n-select v-model:value="optionData.fontWeight" size="small" :options="fontWeightOptions" />
  52 + </setting-item>
  53 + <setting-item name="X轴内边距">
  54 + <n-input-number v-model:value="optionData.paddingX" size="small" placeholder="输入内边距"></n-input-number>
  55 + </setting-item>
  56 + <setting-item name="Y轴内边距">
  57 + <n-input-number v-model:value="optionData.paddingY" size="small" placeholder="输入内边距"></n-input-number>
  58 + </setting-item>
  59 +
  60 + <setting-item name="水平对齐">
  61 + <n-select v-model:value="optionData.textAlign" size="small" :options="textAlignOptions" />
  62 + </setting-item>
  63 + <setting-item name="文本方向">
  64 + <n-select v-model:value="optionData.writingMode" size="small" :options="verticalOptions" />
  65 + </setting-item>
  66 +
  67 + <setting-item name="字间距">
  68 + <n-input-number v-model:value="optionData.letterSpacing" size="small" placeholder="输入字间距"></n-input-number>
  69 + </setting-item>
  70 + </setting-item-box>
  71 +
  72 + <setting-item-box name="边框">
  73 + <setting-item name="宽度">
  74 + <n-input-number
  75 + v-model:value="optionData.borderWidth"
  76 + size="small"
  77 + :min="0"
  78 + placeholder="宽度"
  79 + ></n-input-number>
  80 + </setting-item>
  81 + <setting-item name="颜色">
  82 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.borderColor"></n-color-picker>
  83 + </setting-item>
  84 + <setting-item name="圆角">
  85 + <n-input-number
  86 + v-model:value="optionData.borderRadius"
  87 + size="small"
  88 + :min="0"
  89 + placeholder="圆角"
  90 + ></n-input-number>
  91 + </setting-item>
  92 + </setting-item-box>
  93 +
  94 + <setting-item-box name="背景" :alone="true">
  95 + <setting-item name="背景颜色">
  96 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.backgroundColor"></n-color-picker>
  97 + </setting-item>
  98 + </setting-item-box>
  99 + </collapse-item>
  100 +</template>
  101 +
  102 +<script setup lang="ts">
  103 +import { PropType } from 'vue'
  104 +import { option, WritingModeEnum, WritingModeObject, FontWeightEnum, FontWeightObject } from './config'
  105 +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  106 +const props = defineProps({
  107 + optionData: {
  108 + type: Object as PropType<typeof option>,
  109 + required: true
  110 + }
  111 +})
  112 +
  113 +const textAlignOptions = [
  114 + { label: '左对齐', value: 'start' },
  115 + { label: '居中', value: 'center' },
  116 + { label: '右对齐', value: 'end' }
  117 +]
  118 +
  119 +const linkMethodOptions = [
  120 + { label: '默认', value: 'default' },
  121 + { label: '新开窗口', value: 'open' }
  122 +]
  123 +
  124 +const verticalOptions = [
  125 + {
  126 + label: WritingModeEnum.HORIZONTAL,
  127 + value: WritingModeObject[WritingModeEnum.HORIZONTAL]
  128 + },
  129 + {
  130 + label: WritingModeEnum.VERTICAL,
  131 + value: WritingModeObject[WritingModeEnum.VERTICAL]
  132 + }
  133 +]
  134 +const fontWeightOptions = [
  135 + {
  136 + label: FontWeightEnum.NORMAL,
  137 + value: FontWeightObject[FontWeightEnum.NORMAL]
  138 + },
  139 + {
  140 + label: FontWeightEnum.BOLD,
  141 + value: FontWeightObject[FontWeightEnum.BOLD]
  142 + }
  143 +]
  144 +const handleLinkClick = (target: string) => {
  145 + const hrefStr = props.optionData.linkHead + props.optionData.link
  146 + if (target === 'open') window.open(hrefStr)
  147 + else window.location.href = hrefStr
  148 +}
  149 +const linkHeadOptions = [
  150 + { label: 'http://', value: 'http://' },
  151 + { label: 'https://', value: 'https://' }
  152 +]
  153 +</script>
... ...
  1 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  2 +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Informations/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, conKey, chartKey } = useWidgetKey('OverrideTextEnumCommon', true)
  6 +
  7 +export const OverrideTextEnumCommonConfig: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '自定义文字(支持枚举)',
  12 + category: ChatCategoryEnum.TEXT,
  13 + categoryName: ChatCategoryEnumName.TEXT,
  14 + package: PackagesCategoryEnum.INFORMATIONS,
  15 + chartFrame: ChartFrameEnum.COMMON,
  16 + image: 'text_static.png'
  17 +}
... ...
  1 +<template>
  2 + <div class="go-text-box">
  3 + <div class="content">
  4 + <span style="cursor: pointer; white-space: pre-wrap" v-if="link" @click="click">{{ option.dataset }}</span>
  5 + <span style="white-space: pre-wrap" v-else>{{ option.dataset }}</span>
  6 + </div>
  7 + </div>
  8 +</template>
  9 +
  10 +<script setup lang="ts">
  11 +import { PropType, toRefs, shallowReactive } from 'vue'
  12 +import { CreateComponentType } from '@/packages/index.d'
  13 +import { useChartDataFetch } from '@/hooks'
  14 +import { useTsl } from '@/hooks/external/useTsl'
  15 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  16 +import { option as configOption } from './config'
  17 +
  18 +const props = defineProps({
  19 + chartConfig: {
  20 + type: Object as PropType<CreateComponentType & typeof option>,
  21 + required: true
  22 + }
  23 +})
  24 +
  25 +const { handleDeviceProfileAttributes } = useTsl()
  26 +
  27 +const {
  28 + linkHead,
  29 + link,
  30 + fontColor,
  31 + fontSize,
  32 + letterSpacing,
  33 + paddingY,
  34 + paddingX,
  35 + textAlign,
  36 + borderWidth,
  37 + borderColor,
  38 + borderRadius,
  39 + writingMode,
  40 + backgroundColor,
  41 + fontWeight,
  42 + linkMethod
  43 +} = toRefs(props.chartConfig.option)
  44 +
  45 +const option = shallowReactive({
  46 + dataset: configOption.dataset
  47 +})
  48 +
  49 +//动态请求物模型
  50 +const fetchTsl = (entityId: string) => {
  51 + return handleDeviceProfileAttributes(entityId)
  52 +}
  53 +
  54 +//解构设备和属性参数
  55 +const deconstructionParams = (chartConfig: CreateComponentType) => {
  56 + const { request } = chartConfig
  57 + const { requestParams } = request
  58 + const { Params } = requestParams
  59 + const { entityId, keys } = Params
  60 + return { entityId, keys }
  61 +}
  62 +
  63 +//找到枚举值name,属性暂时只选择一个
  64 +const findEnumName = (attribute: Recordable[], keys: string[], newData: Recordable) => {
  65 + const findCurrentAttr = attribute.find(findAttrItem => findAttrItem.identifier === keys.at(0))?.detail?.dataType
  66 + ?.specsList
  67 + return findCurrentAttr.find(
  68 + (findCurrentItem: Recordable) => findCurrentItem.value === Number(newData.data[keys.at(0)!][0][1])
  69 + )?.name
  70 +}
  71 +
  72 +// 预览更新
  73 +useChartDataFetch(props.chartConfig, useChartEditStore, async (newData: string) => {
  74 + const { entityId, keys } = deconstructionParams(props.chartConfig) as Recordable
  75 + const { attribute } = (await fetchTsl(entityId)) as unknown as Recordable
  76 + if (Object.prototype.toString.call(newData) !== '[object Object]') {
  77 + option.dataset = newData
  78 + } else if ('subscriptionId' in (newData as unknown as Recordable)) {
  79 + // ws
  80 + option.dataset = findEnumName(attribute, keys, newData as unknown as Recordable) || '暂无数据'
  81 + }
  82 +})
  83 +
  84 +//打开链接
  85 +const click = () => {
  86 + const hrefStr = linkHead.value + link.value
  87 + if (linkMethod.value === 'open') window.open(hrefStr)
  88 + else window.location.href = hrefStr
  89 +}
  90 +</script>
  91 +
  92 +<style lang="scss" scoped>
  93 +@include go('text-box') {
  94 + display: flex;
  95 + align-items: center;
  96 + justify-content: v-bind('textAlign');
  97 +
  98 + .content {
  99 + color: v-bind('fontColor');
  100 + padding: v-bind('`${paddingY}px ${paddingX}px`');
  101 + font-size: v-bind('fontSize + "px"');
  102 + letter-spacing: v-bind('letterSpacing + "px"');
  103 + writing-mode: v-bind('writingMode');
  104 + font-weight: v-bind('fontWeight');
  105 + border-style: solid;
  106 + border-width: v-bind('borderWidth + "px"');
  107 + border-radius: v-bind('borderRadius + "px"');
  108 + border-color: v-bind('borderColor');
  109 +
  110 + background-color: v-bind('backgroundColor');
  111 + }
  112 +}
  113 +</style>
... ...
... ... @@ -351,8 +351,9 @@ useChartDataFetch(props.chartConfig, useChartEditStore, async (resData: any[], r
351 351 const { requestParams } = res
352 352 if (!requestParams) return
353 353 const { Params } = requestParams
354   - if (!Params) return
  354 + if (!Params) return
355 355 const { entityId } = Params
  356 + if(!entityId) return window['$message'].warning('您选择的公共接口不适合此组件,请选择匹配此组件的公共接口')
356 357 const thingsModel = await handleDeviceProfileAttributes(entityId)
357 358 const { attribute } = thingsModel as any
358 359 const resDataFormat = resData.reduce((acc, curr) => {
... ... @@ -373,6 +374,7 @@ onUnmounted(() => {
373 374 })
374 375
375 376 const handleDeviceProfileAttributes = async (entityId: string) => {
  377 + if(!entityId) return window['$message'].warning('您选择的公共接口不适合此组件,请选择匹配此组件的公共接口')
376 378 const deviceDetailRes = await getDeviceDetail(entityId)
377 379 const { deviceProfileId } = deviceDetailRes
378 380 if (!deviceProfileId) return
... ...
... ... @@ -9,6 +9,7 @@ import { OverrideInputsDateConfig } from '@/packages/components/external/Informa
9 9 import { OverrideInputsTabConfig } from '@/packages/components/external/Informations/Inputs/OverrideInputsTab'
10 10 import { OverrideIframeConfig } from '@/packages/components/external/Informations/Mores/OverrideIframe'
11 11 import { OverrideTextCommonConfig } from '@/packages/components/external/Informations/Texts/OverrideTextCommon'
  12 +import { OverrideTextEnumCommonConfig } from '@/packages/components/external/Informations/Texts/OverrideTextEnumCommon'
12 13 import { OverrideTextBarrageConfig } from '@/packages/components/external/Informations/Texts/OverrideTextBarrage'
13 14 import { OverrideTextGradientConfig } from '@/packages/components/external/Informations/Texts/OverrideTextGradient'
14 15 import { OverrideVideoConfig } from '@/packages/components/external/Informations/Mores/OverrideVideo'
... ... @@ -68,6 +69,10 @@ import { Decorates23Config } from '@/packages/components/external/Decorates/Deco
68 69 import { Decorates24Config } from '@/packages/components/external/Decorates/Decorates/Decorates24'
69 70 import { Decorates25Config } from '@/packages/components/external/Decorates/Decorates/Decorates25'
70 71 import { Decorates26Config } from '@/packages/components/external/Decorates/Decorates/Decorates26'
  72 +import { Decorates27Config } from '@/packages/components/external/Decorates/Decorates/Decorates27'
  73 +import { Decorates28Config } from '@/packages/components/external/Decorates/Decorates/Decorates28'
  74 +import { Decorates29Config } from '@/packages/components/external/Decorates/Decorates/Decorates29'
  75 +import { Decorates30Config } from '@/packages/components/external/Decorates/Decorates/Decorates30'
71 76 import { OverrideTableScrollBoardConfig } from '@/packages/components/external/Tables/Tables/OverrideTableScrollBoard'
72 77 import { OverrideTablesBasicConfig } from '@/packages/components/external/Tables/Tables/OverrideTablesBasic'
73 78
... ... @@ -114,6 +119,10 @@ export function useInjectLib(packagesList: EPackagesType) {
114 119 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, Decorates24Config)//新增动画装饰装饰24
115 120 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, Decorates25Config)//新增动画装饰装饰25
116 121 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, Decorates26Config)//新增动画装饰装饰26
  122 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, Decorates27Config)//新增动画装饰装饰27
  123 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, Decorates28Config)//新增动画装饰装饰28
  124 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, Decorates29Config)//新增动画装饰装饰29
  125 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.DECORATES, Decorates30Config)//新增动画装饰装饰30
117 126 //
118 127
119 128 //信息
... ... @@ -128,6 +137,7 @@ export function useInjectLib(packagesList: EPackagesType) {
128 137 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideInputsDateConfig)//重写信息下的日期
129 138 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideInputsTabConfig)//重写信息下的tab
130 139 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideTextCommonConfig)//重写信息下的文字
  140 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideTextEnumCommonConfig)//重写信息下的文字(支持枚举)
131 141 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideTextBarrageConfig)//重写信息下的弹幕文字
132 142 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideTextGradientConfig)//重写信息下的渐变文字
133 143 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideVideoConfig)//重写信息下的视频
... ...
... ... @@ -9,6 +9,7 @@ const getAllConfigFile = async () => {
9 9
10 10 const getChartConfigFile = async (path: string) => {
11 11 const fileList = await getAllConfigFile()
  12 + if (path.includes('group')) return // 分组则终止
12 13 return fileList[path]() as any
13 14 }
14 15
... ... @@ -41,6 +42,7 @@ export const createComponent = async (configType: ConfigType) => {
41 42 //
42 43 const hasExternalPrefix = matchExternalPrefixReg.test(chartKey)
43 44 const filePath = `../components${hasExternalPrefix ? '/external' : ''}/${packageName}/${category}/${key}/config.ts`
  45 + if (filePath.includes('group')) return // 分组则终止
44 46 const chart = await getChartConfigFile(filePath)
45 47 return new chart.default()
46 48 }
... ...
... ... @@ -41,7 +41,30 @@ export const requestConfig: RequestConfigType = {
41 41 },
42 42 Header: {},
43 43 Params: {}
44   - }
  44 + },
  45 + pondRequestOriginUrl: '',
  46 + pondRequestInterval: 0,
  47 + pondRequestIntervalUnit: '',
  48 + pondRequestGlobalTokenSuffix: '',
  49 + pondRequestGlobalTokenKey: '',
  50 + pondRequestHttpType: RequestHttpEnum.GET,
  51 + pondRequestContentType: RequestContentTypeEnum.DEFAULT,
  52 + pondRequestUrl:'',
  53 + pondRequestSQLContent: {
  54 + sql: ''
  55 + },
  56 + pondRequestParamsBodyType: RequestBodyEnum.NONE,
  57 + pondRequestParams: {
  58 + "Body": {
  59 + "form-data": {},
  60 + "x-www-form-urlencoded": {},
  61 + "json": "",
  62 + "xml": ""
  63 + },
  64 + "Header": {},
  65 + "Params": {}
  66 + },
  67 + pondRequestGlobalIsToken: true
45 68 }
46 69
47 70 // 单实例类
... ...
... ... @@ -48,9 +48,9 @@
48 48 }
49 49 },
50 50 "yAxis": {
51   - "showRange":true,
52   - "min": 0,
53   - "max": 200,
  51 + "showRange": false,
  52 + "minData": 0,
  53 + "maxData": 350,
54 54 "show": true,
55 55 "name": "",
56 56 "nameGap": 15,
... ...
... ... @@ -32,6 +32,7 @@ interface UserState {
32 32 shareJwtToken?: string;
33 33 shareRefreshToken?: string;
34 34 outTarget?: string;
  35 + thirdTokenIsExp?: boolean;
35 36 }
36 37
37 38 const storage = createLocalStorage();
... ... @@ -57,9 +58,14 @@ export const useUserStore = defineStore({
57 58 sessionTimeout: false,
58 59 // Last fetch time
59 60 lastUpdateTime: 0,
  61 + // 用于三方接口Token是否过期
  62 + thirdTokenIsExp: false
60 63 }),
61 64
62 65 getters: {
  66 + getThirdTokenIsExp(): boolean {
  67 + return this.thirdTokenIsExp!;
  68 + },
63 69 getPlatInfo(): any {
64 70 return this.platInfo;
65 71 },
... ... @@ -87,6 +93,9 @@ export const useUserStore = defineStore({
87 93 },
88 94 },
89 95 actions: {
  96 + setThirdTokenIsExp(expStatus:boolean) {
  97 + this.thirdTokenIsExp = expStatus
  98 + },
90 99 setPlatInfo(platInfo: any) {
91 100 this.platInfo = platInfo;
92 101 },
... ...
... ... @@ -23,7 +23,7 @@ export enum EditCanvasTypeEnum {
23 23 IS_CREATE = 'isCreate',
24 24 IS_DRAG = 'isDrag',
25 25 IS_SELECT = 'isSelect',
26   - IS_CODE_EDIT = "isCodeEdit"
  26 + IS_CODE_EDIT = 'isCodeEdit'
27 27 }
28 28
29 29 // 编辑区域
... ... @@ -61,10 +61,9 @@ export enum EditCanvasConfigEnum {
61 61 BACKGROUND_IMAGE = 'backgroundImage',
62 62 SELECT_COLOR = 'selectColor',
63 63 PREVIEW_SCALE_TYPE = 'previewScaleType',
64   - ANIMATION_STYLE_CONFIG = 'animationsStyleConfig',
  64 + ANIMATION_STYLE_CONFIG = 'animationsStyleConfig'
65 65 }
66 66
67   -
68 67 export interface EditCanvasConfigType {
69 68 // 滤镜-启用
70 69 [FilterEnum.FILTERS_SHOW]: boolean
... ... @@ -176,8 +175,8 @@ type RequestPublicConfigType = {
176 175
177 176 // 数据池项类型
178 177 export type RequestDataPondItemType = {
179   - dataPondId: string,
180   - dataPondName: string,
  178 + dataPondId: string
  179 + dataPondName: string
181 180 dataPondRequestConfig: RequestConfigType
182 181 }
183 182
... ... @@ -189,6 +188,18 @@ export interface RequestGlobalConfigType extends RequestPublicConfigType {
189 188 requestOriginUrl?: string
190 189 // 公共数据池
191 190 requestDataPond: RequestDataPondItemType[]
  191 + // 验证方式
  192 + requestVerificationMethods?: TokenEnum
  193 + // 全局Token
  194 + requestVerificationToken?: string
  195 + // 请求头里的Token键
  196 + requestTokenKey?: string
  197 + // 请求头里的Token前缀
  198 + requestTokenSuffix?: string,
  199 + // 全局配置Token前缀
  200 + requestGlobalTokenSuffix?: string,
  201 + // 全局配置Token键
  202 + requestGlobalTokenKey?: string,
192 203 }
193 204
194 205 // 单个图表请求配置
... ... @@ -211,6 +222,36 @@ export interface RequestConfigType extends RequestPublicConfigType {
211 222 requestSQLContent: {
212 223 sql: string
213 224 }
  225 +
  226 + // 三方Token相关
  227 + requestVerificationToken?: string
  228 + // 请求头里的Token键
  229 + requestTokenKey?: string
  230 + // 请求头里的Token前缀
  231 + requestTokenSuffix?: string
  232 + pondRequestOriginUrl?: string
  233 + pondRequestGlobalInterval?: number
  234 + pondRequestGlobalIntervalUnit?: string
  235 + pondRequestGlobalTokenSuffix?: string
  236 + pondRequestGlobalTokenKey?: string
  237 + pondRequestGlobalCascaderOption?: Recordable
  238 + pondRequestGlobalCascaderKey?: string
  239 + pondRequestHttpType?: RequestHttpEnum
  240 + pondRequestInterval?: number
  241 + pondRequestIntervalUnit?: string
  242 + pondRequestContentType?: number
  243 + pondRequestParams?: RequestParams
  244 + pondRequestParamsBodyType?: RequestBodyEnum
  245 + pondRequestUrl?: string
  246 + pondRequestSQLContent?: {
  247 + sql: string
  248 + }
  249 + thirdTokenIsExp?: boolean
  250 + thirdSelectCascaderLabel?: string
  251 + publicInterfaceSelectId?: string
  252 + thirdRequestDataPondId?: string
  253 + pondRequestGlobalIsToken?: boolean
  254 + //
214 255 }
215 256
216 257 // Store 类型
... ...
... ... @@ -135,7 +135,9 @@ function createNewPageItem(id: string = getUUID(), title = '页面'): PageChartE
135 135 },
136 136 Header: {},
137 137 Params: {}
138   - }
  138 + },
  139 + requestVerificationMethods: 'Token',
  140 + requestVerificationToken: '',
139 141 },
140 142 // 图表数组(需存储给后端)
141 143 componentList: []
... ...
... ... @@ -4,6 +4,30 @@ import type { GlobEnvConfig } from '/#/external/config';
4 4 import { getGlobalConfigName } from '../../../../build/external/vite/plugins/globConfig/getGlobConfigName';
5 5 import { ProjectRuntimeEnvEnum } from '@/enums/external/envEnum';
6 6
  7 +const stringToJSONParse = (string: string) => {
  8 + try {
  9 + return JSON.parse(string);
  10 + } catch (error) {
  11 + return string;
  12 + }
  13 +};
  14 +
  15 +export function parseEnv(env: Record<string, string>) {
  16 + const res: Record<string, string> = {};
  17 +
  18 + Object.keys(env).forEach((key) => {
  19 + try {
  20 + const value = env[key];
  21 + res[key] = stringToJSONParse(value);
  22 + } catch (err) {
  23 + // eslint-disable-next-line no-console
  24 + console.log(`env variable ${key} can't serialization!`);
  25 + }
  26 + });
  27 +
  28 + return res;
  29 +}
  30 +
7 31
8 32 export function getCommonStoragePrefix() {
9 33 // const { VITE_GLOB_APP_SHORT_NAME } = getAppEnvConfig();
... ... @@ -23,7 +47,7 @@ export function getAppEnvConfig() {
23 47
24 48 const ENV = (import.meta.env.DEV
25 49 ? // Get the global configuration (the configuration will be extracted independently when packaging)
26   - (import.meta.env as unknown as GlobEnvConfig)
  50 + (parseEnv(import.meta.env) as unknown as GlobEnvConfig)
27 51 : window[ENV_NAME as any]) as unknown as GlobEnvConfig;
28 52
29 53 const {
... ... @@ -35,7 +59,7 @@ export function getAppEnvConfig() {
35 59 VITE_GLOB_WEB_SOCKET,
36 60 VITE_GLOB_ALARM_NOTIFY_DURATION,
37 61 VITE_GLOB_CONTENT_SECURITY_POLICY,
38   - VITE_GLOB_PUBLIC_PATH
  62 + VITE_GLOB_PUBLIC_PATH,
39 63 } = ENV;
40 64
41 65 if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) {
... ... @@ -53,7 +77,7 @@ export function getAppEnvConfig() {
53 77 VITE_GLOB_WEB_SOCKET,
54 78 VITE_GLOB_ALARM_NOTIFY_DURATION,
55 79 VITE_GLOB_CONTENT_SECURITY_POLICY,
56   - VITE_GLOB_PUBLIC_PATH
  80 + VITE_GLOB_PUBLIC_PATH,
57 81 };
58 82 }
59 83
... ...
... ... @@ -11,6 +11,7 @@ import { ContentTypeEnum, RequestEnum } from '@/enums/external/httpEnum';
11 11 import omit from 'lodash/omit';
12 12 import cloneDeep from 'lodash/cloneDeep';
13 13 import { useUserStore } from '@/store/external/modules/user';
  14 +import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook';
14 15
15 16 export * from './axiosTransform';
16 17
... ... @@ -115,11 +116,25 @@ export class VAxios {
115 116 this.axiosInstance.interceptors.request.use(async (config: AxiosRequestConfig) => {
116 117 // If cancel repeat request is turned on, then cancel repeat request is prohibited
117 118 const userStore = useUserStore();
  119 + const { targetData } = useTargetData()
  120 +
118 121 // if (userStore && (userStore.jwtToken || userStore.shareJwtToken)) {
119 122 if (userStore) {
120 123 try {
121 124 const { requestOptions = {} } = config
122   - const { withShareToken, withToken } = requestOptions
  125 + const { withShareToken, withToken, withThirdTokenString } = requestOptions
  126 + if (withThirdTokenString) {
  127 + //三方平台逻辑
  128 + const res = jwt_decode(withThirdTokenString) as Recordable;
  129 + const currentTime = (new Date().getTime() + (config.timeout || 0)) / 1000;
  130 + if (currentTime >= res?.exp) {
  131 + targetData.value.request.thirdTokenIsExp = true
  132 + userStore.setThirdTokenIsExp(true)
  133 + }else{
  134 + userStore.setThirdTokenIsExp(false)
  135 + }
  136 + } else {
  137 + //此平台逻辑
123 138 const token = withShareToken && withToken ? userStore.shareJwtToken : userStore.jwtToken
124 139 const doRefresh = withShareToken && withToken ? userStore.doShareRefresh : userStore.doRefresh
125 140 if (token) {
... ... @@ -129,7 +144,8 @@ export class VAxios {
129 144 await this.refreshTokenBeforeReq(doRefresh);
130 145 }
131 146 }
132   -
  147 + //
  148 + }
133 149 } catch (error) {
134 150 userStore.logout();
135 151 }
... ...
... ... @@ -38,3 +38,46 @@ export const parseWebUrl = (str = window.location.search) => {
38 38 str.replace(reg, (_, k, v) => (params[k] = v))
39 39 return params
40 40 }
  41 +
  42 +//嵌套对象转换为级联选择器数据格式
  43 +interface cascadingData {
  44 + label: string
  45 + value: string | cascadingData[] | number
  46 + children: cascadingData[] | null
  47 +}
  48 +export const convertToCascadingData = (obj: Recordable): cascadingData[] => {
  49 + const result: cascadingData[] = []
  50 + for (const key in obj) {
  51 + // eslint-disable-next-line no-prototype-builtins
  52 + if (obj.hasOwnProperty(key)) {
  53 + let value: cascadingData[] | string | number
  54 + if (typeof obj[key] === 'object' && obj[key] !== null) {
  55 + value = convertToCascadingData(obj[key])
  56 + } else {
  57 + value = String(obj[key])
  58 + }
  59 + result.push({
  60 + label: key,
  61 + value,
  62 + children: Array.isArray(value) ? value : null
  63 + })
  64 + }
  65 + }
  66 + return result
  67 +}
  68 +
  69 +// 递归查找
  70 +export const findItemByLabel = (list:Recordable[], label:string) :Recordable | null => {
  71 + let res = list.find((item) => item.label == label) as Recordable | null;
  72 + if (res) {
  73 + return res;
  74 + } else {
  75 + for (let i = 0; i < list.length; i++) {
  76 + if (list[i].children instanceof Array && list[i].children.length > 0) {
  77 + res = findItemByLabel(list[i].children, label);
  78 + if (res) return res;
  79 + }
  80 + }
  81 + return null;
  82 + }
  83 +};
... ...
... ... @@ -158,7 +158,7 @@ const {
158 158 } = toRefs((props.targetData as RequestDataPondItemType).dataPondRequestConfig)
159 159
160 160 const tabs = [RequestParamsTypeEnum.HEADER]
161   -const requestContentTypeObj = {
  161 +const requestContentTypeObj: Recordable = {
162 162 [RequestContentTypeEnum.DEFAULT]: '普通请求',
163 163 [RequestContentTypeEnum.SQL]: 'SQL 请求'
164 164 }
... ...
... ... @@ -101,7 +101,7 @@ watch(
101 101 )
102 102
103 103 // 打开/编辑
104   -const openPond = (isEditFlag: boolean = false) => {
  104 +const openPond = (isEditFlag = false) => {
105 105 isEdit.value = !!isEditFlag
106 106 requestShow.value = true
107 107 }
... ...
... ... @@ -41,6 +41,14 @@
41 41 编辑配置
42 42 </n-button>
43 43 </setting-item-box>
  44 + <setting-item-box name="配置">
  45 + <setting-item name="Token前缀">
  46 + <n-input :disabled="editDisabled" v-model:value.trim="requestGlobalTokenSuffix" type="text" placeholder="例如:Bearer" />
  47 + </setting-item>
  48 + <setting-item name="Token键值">
  49 + <n-input :disabled="editDisabled" v-model:value.trim="requestGlobalTokenKey" type="text" placeholder="例如:Token" />
  50 + </setting-item>
  51 + </setting-item-box>
44 52 <!-- table 内容体 -->
45 53 <n-collapse-transition :show="showTable">
46 54 <request-global-header-table :editDisabled="editDisabled"></request-global-header-table>
... ... @@ -69,13 +77,13 @@ import { ref, toRefs, computed } from 'vue'
69 77 import { useDesignStore } from '@/store/modules/designStore/designStore'
70 78 import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
71 79 import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
72   -import { selectTypeOptions, selectTimeOptions } from '@/views/chart/ContentConfigurations/components/ChartData/index.d'
  80 +import { selectTimeOptions } from '@/views/chart/ContentConfigurations/components/ChartData/index.d'
73 81 import { RequestGlobalHeaderTable } from '../RequestGlobalHeaderTable'
74 82 import { icon } from '@/plugins'
75 83
76 84 const { PencilIcon, ChevronDownOutlineIcon, ChevronUpOutlineIcon } = icon.ionicons5
77 85 const { chartEditStore } = useTargetData()
78   -const { requestOriginUrl, requestInterval, requestIntervalUnit } = toRefs(chartEditStore.getRequestGlobalConfig)
  86 +const { requestOriginUrl, requestInterval, requestIntervalUnit, requestGlobalTokenSuffix, requestGlobalTokenKey } = toRefs(chartEditStore.getRequestGlobalConfig)
79 87 const editDisabled = ref(true)
80 88
81 89 const designStore = useDesignStore()
... ...
... ... @@ -47,7 +47,7 @@ const emit = defineEmits(['update:modelShow', 'sendHandle'])
47 47 const { chartConfig } = toRefs(props.targetData as CreateComponentType)
48 48 const { requestContentType } = toRefs((props.targetData as CreateComponentType).request)
49 49 const modelShowRef = ref(false)
50   -const requestContentTypeObj = {
  50 +const requestContentTypeObj: Recordable = {
51 51 [RequestContentTypeEnum.DEFAULT]: '普通请求',
52 52 [RequestContentTypeEnum.SQL]: 'SQL 请求'
53 53 }
... ...
... ... @@ -58,16 +58,36 @@
58 58 <NSpace :size="15" vertical>
59 59 <div class="editor-data-show">
60 60 <NSpace>
  61 + <NText depth="3">原始数据:</NText>
  62 + <n-collapse :default-expanded-names="['1']">
  63 + <n-collapse-item name="1">
  64 + <NScrollbar style="max-height: 300px;">
  65 + <NCode :code="toString(cacheConfig) || '暂无'" language="json" :word-wrap="true"></NCode>
  66 + </NScrollbar>
  67 + </n-collapse-item>
  68 + </n-collapse>
  69 + </NSpace>
  70 + </div>
  71 + <div class="editor-data-show">
  72 + <NSpace>
61 73 <NText depth="3">接口返回数据(res):</NText>
62   - <NScrollbar style="max-height: 300px;">
63   - <NCode :code="toString(isSocketRequest ? targetData.wsOriginalMessage : sourceData) || '暂无'" language="json" :word-wrap="true"></NCode>
64   - </NScrollbar>
  74 + <n-collapse>
  75 + <n-collapse-item name="2">
  76 + <NScrollbar style="max-height: 300px;">
  77 + <NCode :code="toString(isSocketRequest ? targetData.wsOriginalMessage : sourceData) || '暂无'" language="json" :word-wrap="true"></NCode>
  78 + </NScrollbar>
  79 + </n-collapse-item>
  80 + </n-collapse>
65 81 </NSpace>
66 82 </div>
67 83 <div class="editor-data-show">
68 84 <NSpace>
69 85 <NText depth="3">过滤器结果:</NText>
70   - <NCode :code="filterRes || '暂无'" language="json" :word-wrap="true"></NCode>
  86 + <n-collapse>
  87 + <n-collapse-item name="3">
  88 + <NCode :code="filterRes || '暂无'" language="json" :word-wrap="true"></NCode>
  89 + </n-collapse-item>
  90 + </n-collapse>
71 91 </NSpace>
72 92 </div>
73 93 </NSpace>
... ... @@ -97,7 +117,7 @@
97 117 </template>
98 118
99 119 <script lang="ts" setup>
100   -import { ref, computed, watch, unref } from 'vue'
  120 +import { ref, computed, watch, unref, onMounted } from 'vue'
101 121 import { MonacoEditor } from '@/components/Pages/MonacoEditor'
102 122 import { icon } from '@/plugins'
103 123 import { goDialog, toString } from '@/utils'
... ... @@ -106,6 +126,7 @@ import { NButton, NCard, NCode, NDivider, NIcon, NModal, NScrollbar, NSpace, NTa
106 126 import { useFilterFn } from '@/hooks/external/useFilterFn'
107 127 import { useFetchTargetData } from '@/hooks/external/useFetchTargetData'
108 128 import { RequestContentTypeEnum } from '@/enums/external/httpEnum'
  129 +import { createComponent } from '@/packages/external/override'
109 130
110 131 const { DocumentTextIcon } = icon.ionicons5
111 132 const { FilterIcon, FilterEditIcon } = icon.carbon
... ... @@ -166,6 +187,20 @@ const closeFilter = () => {
166 187 showModal.value = false
167 188 }
168 189
  190 +// 发送请求
  191 +const sendHandle = async () => {
  192 + try {
  193 + const res = await fetchHandle()
  194 + if (res) {
  195 + const { value } = useFilterFn(targetData.value.filter, res)
  196 + targetData.value.option.dataset = value
  197 + return
  198 + }
  199 + } catch(e) {
  200 + console.error(e)
  201 + }
  202 +}
  203 +
169 204 // 新增过滤器
170 205 const saveFilter = () => {
171 206 if (errorFlag.value) {
... ... @@ -174,6 +209,7 @@ const saveFilter = () => {
174 209 }
175 210 targetData.value.filter = filter.value
176 211 closeFilter()
  212 + sendHandle()
177 213 }
178 214
179 215 watch(
... ... @@ -185,6 +221,19 @@ watch(
185 221 }
186 222 }
187 223 )
  224 +
  225 +const cacheConfig = ref()
  226 +
  227 +const fetchComponentConfig = async () => {
  228 + const config = await createComponent(targetData.value.chartConfig)
  229 + return config
  230 +}
  231 +
  232 +
  233 +onMounted(async ()=> {
  234 + const config = await fetchComponentConfig()
  235 + cacheConfig.value = config?.option?.dataset
  236 +})
188 237 </script>
189 238
190 239 <style lang="scss" scoped>
... ...
  1 +<template>
  2 + <n-table
  3 + :bordered="false"
  4 + :single-line="false"
  5 + size="small"
  6 + style="border-bottom-right-radius: 7px; border-bottom-left-radius: 7px"
  7 + >
  8 + <thead>
  9 + <tr>
  10 + <th>key</th>
  11 + <th>value</th>
  12 + </tr>
  13 + </thead>
  14 + <tbody>
  15 + <tr v-for="(item, index) in tableArray.content" :key="index">
  16 + <td>
  17 + {{ item.key || '暂无'}}
  18 + </td>
  19 + <td>
  20 + {{ item.value || '暂无'}}
  21 + </td>
  22 + </tr>
  23 + </tbody>
  24 + </n-table>
  25 +</template>
  26 +
  27 +<script setup lang="ts">
  28 +import { PropType, reactive, ref, toRefs, watch } from 'vue'
  29 +import { RequestParamsObjType } from '@/enums/httpEnum'
  30 +import noData from '@/assets/images/canvas/noData.png'
  31 +
  32 +const props = defineProps({
  33 + target: Object as PropType<RequestParamsObjType>
  34 +})
  35 +
  36 +// 默认表格
  37 +const defaultItem = {
  38 + key: '',
  39 + value: ''
  40 +}
  41 +const tableArray = reactive<{
  42 + content: typeof defaultItem[]
  43 +}>({ content: [] })
  44 +
  45 +// 监听选项
  46 +watch(
  47 + () => props.target as RequestParamsObjType,
  48 + (target: RequestParamsObjType) => {
  49 + tableArray.content = []
  50 + for (const k in target) {
  51 + tableArray.content.push({
  52 + key: k,
  53 + value: target[k]
  54 + })
  55 + }
  56 + // 默认值
  57 + if (!tableArray.content.length) tableArray.content = [JSON.parse(JSON.stringify(defaultItem))]
  58 + },
  59 + {
  60 + immediate: true,
  61 + deep: true
  62 + }
  63 +)
  64 +</script>
\ No newline at end of file
... ...
  1 +<template>
  2 + <div class="go-chart-data-display">
  3 + <n-scrollbar style="max-height: 570px">
  4 + <div class="go-mr-3">
  5 + <div>
  6 + <setting-item-box name="主体信息">
  7 + <setting-item name="接口名称">
  8 + <n-input size="small" :placeholder="targetData?.dataPondName || '暂无'" :disabled="true"> </n-input>
  9 + </setting-item>
  10 + <setting-item name="接口类型">
  11 + <n-input size="small" :placeholder="pondRequestHttpType || '暂无'" :disabled="true"></n-input>
  12 + </setting-item>
  13 + </setting-item-box>
  14 +
  15 + <setting-item-box>
  16 + <setting-item name="组件间隔">
  17 + <n-input size="small" :placeholder="`${requestInterval || '暂无'}`" :disabled="true">
  18 + <template #suffix>
  19 + {{ targetData && SelectHttpTimeNameObj[requestIntervalUnit] }}
  20 + </template>
  21 + </n-input>
  22 + </setting-item>
  23 + <setting-item name="全局间隔(默认)">
  24 + <n-input size="small" :placeholder="`${globalData?.requestInterval || '暂无'}`" :disabled="true">
  25 + <template #suffix> {{ globalData && SelectHttpTimeNameObj[globalData.requestIntervalUnit] }} </template>
  26 + </n-input>
  27 + </setting-item>
  28 + </setting-item-box>
  29 +
  30 + <setting-item-box name="源地址" :alone="true">
  31 + <n-input size="small" :placeholder="pondRequestOriginUrl || '暂无'" :disabled="true">
  32 + <template #prefix>
  33 + <n-icon :component="PulseIcon" />
  34 + </template>
  35 + </n-input>
  36 + </setting-item-box>
  37 +
  38 + <setting-item-box name="接口地址" :alone="true">
  39 + <n-input
  40 + size="small"
  41 + :placeholder="pondRequestUrl || '暂无'"
  42 + :disabled="true"
  43 + >
  44 + <template #prefix>
  45 + <n-icon :component="FlashIcon" />
  46 + </template>
  47 + </n-input>
  48 + </setting-item-box>
  49 + </div>
  50 + <n-divider />
  51 + <setting-item-box name="类型">
  52 + <setting-item name="配置类型">
  53 + <n-input
  54 + size="small"
  55 + :placeholder="targetData && requestContentTypeObj[pondRequestContentType!]"
  56 + :disabled="true"
  57 + ></n-input>
  58 + </setting-item>
  59 + <setting-item name="body 类型" v-if="pondRequestContentType === RequestContentTypeEnum.DEFAULT">
  60 + <n-input size="small" :placeholder="targetData && requestParamsBodyType" :disabled="true"></n-input>
  61 + </setting-item>
  62 + </setting-item-box>
  63 + <div v-if="pondRequestContentType === RequestContentTypeEnum.DEFAULT">
  64 + <n-tabs type="line" animated v-model:value="tabValue">
  65 + <n-tab v-for="item in RequestParamsTypeEnum" :key="item" :name="item" :tab="item"> {{ item }} </n-tab>
  66 + </n-tabs>
  67 + <!-- 各个页面 -->
  68 + <div class="go-mt-3">
  69 + <div v-if="tabValue !== RequestParamsTypeEnum.BODY">
  70 + <display-table class="go-my-3" :target="pondRequestParams![tabValue]"> </display-table>
  71 + </div>
  72 +
  73 + <!-- 选择了 body -->
  74 + <div v-else>
  75 + <!-- 为 none 时 -->
  76 + <n-card class="go-mt-3 go-pb-3" v-if="pondRequestParamsBodyType === RequestBodyEnum['NONE']">
  77 + <n-text depth="3">该接口没有 Body 体</n-text>
  78 + </n-card>
  79 +
  80 + <!-- 具有对象属性时 -->
  81 + <template
  82 + v-else-if="
  83 + pondRequestParamsBodyType === RequestBodyEnum['FORM_DATA'] ||
  84 + pondRequestParamsBodyType === RequestBodyEnum['X_WWW_FORM_URLENCODED']
  85 + "
  86 + >
  87 + <display-table
  88 + class="go-my-3"
  89 + :target="pondRequestParams![RequestParamsTypeEnum.BODY][pondRequestParamsBodyType]"
  90 + ></display-table>
  91 + </template>
  92 +
  93 + <!-- json -->
  94 + <template v-else-if="pondRequestParamsBodyType === RequestBodyEnum['JSON']">
  95 + <n-card size="small" style="padding-bottom: 7px">
  96 + <n-code
  97 + :code="pondRequestParams![RequestParamsTypeEnum.BODY][pondRequestParamsBodyType] || '暂无内容'"
  98 + language="json"
  99 + ></n-code>
  100 + </n-card>
  101 + </template>
  102 +
  103 + <!-- xml -->
  104 + <template v-else-if="pondRequestParamsBodyType === RequestBodyEnum['XML']">
  105 + <n-code
  106 + :code="pondRequestParams![RequestParamsTypeEnum.BODY][pondRequestParamsBodyType!] || ''"
  107 + language="html"
  108 + ></n-code>
  109 + </template>
  110 + </div>
  111 + </div>
  112 + </div>
  113 + <!-- SQL 请求 -->
  114 + <div v-else>
  115 + <setting-item-box name="键名">
  116 + <n-text>sql</n-text>
  117 + </setting-item-box>
  118 + <setting-item-box name="键值">
  119 + <n-code :code="requestSQLContent.sql || ''" language="sql"></n-code>
  120 + </setting-item-box>
  121 + </div>
  122 + </div>
  123 + </n-scrollbar>
  124 + </div>
  125 +</template>
  126 +
  127 +<script setup lang="ts">
  128 +import { PropType, ref, toRefs } from 'vue'
  129 +import { icon } from '@/plugins'
  130 +import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  131 +import { RequestDataPondItemType, RequestGlobalConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
  132 +import displayTable from './displayTable.vue'
  133 +import {
  134 + RequestBodyEnum,
  135 + RequestParamsTypeEnum,
  136 + SelectHttpTimeNameObj,
  137 + RequestContentTypeEnum,
  138 +} from '@/enums/httpEnum'
  139 +
  140 +const props = defineProps({
  141 + globalData: Object as PropType<RequestGlobalConfigType>,
  142 + targetData: Object as PropType<RequestDataPondItemType>
  143 +})
  144 +
  145 +const { FlashIcon, PulseIcon } = icon.ionicons5
  146 +
  147 +const {
  148 + requestInterval,
  149 + requestSQLContent,
  150 + requestParamsBodyType,
  151 + requestIntervalUnit,
  152 + pondRequestOriginUrl,
  153 + pondRequestUrl,
  154 + pondRequestHttpType,
  155 + pondRequestContentType,
  156 + pondRequestParamsBodyType,
  157 + pondRequestParams,
  158 +} = toRefs((props.targetData as RequestDataPondItemType).dataPondRequestConfig)
  159 +
  160 +const requestContentTypeObj = {
  161 + [RequestContentTypeEnum.DEFAULT]: '普通请求',
  162 + [RequestContentTypeEnum.SQL]: 'SQL 请求'
  163 +} as Recordable
  164 +
  165 +const tabValue = ref<RequestParamsTypeEnum>(RequestParamsTypeEnum.PARAMS)
  166 +
  167 +</script>
  168 +
  169 +<style lang="scss" scoped>
  170 +@include go('chart-data-display') {
  171 + flex: 1;
  172 +}
  173 +</style>
... ...
  1 +import ChartDataPondControl from './index.vue'
  2 +
  3 +export { ChartDataPondControl }
... ...
  1 +<template>
  2 + <n-modal class="go-chart-data-pond-control" v-model:show="modelShow" :mask-closable="false">
  3 + <n-card :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 900px; height: 650px">
  4 + <template #header></template>
  5 + <template #header-extra> </template>
  6 + <div class="pond-content">
  7 + <!-- 展示区域 -->
  8 + <chart-data-display
  9 + v-if="pondData && !loading"
  10 + :targetData="pondData"
  11 + :globalData="chartEditStore.getRequestGlobalConfig"
  12 + ></chart-data-display>
  13 + <!-- 无数据 -->
  14 + <div v-else class="no-data go-flex-center">
  15 + <img :src="noData" alt="暂无数据" />
  16 + <n-text :depth="3">暂未选择公共接口</n-text>
  17 + </div>
  18 + <!-- 左侧列表 -->
  19 + <chart-data-pond-list @createPond="createPond" @deletePond="deletePond"></chart-data-pond-list>
  20 + </div>
  21 + <!-- 底部 -->
  22 + <template #action>
  23 + <n-space justify="space-between">
  24 + <n-button type="info" secondary :disabled="!pondData" @click="openPond(true)">
  25 + 编辑内容
  26 + <template #icon>
  27 + <n-icon>
  28 + <pencil-icon />
  29 + </n-icon>
  30 + </template>
  31 + </n-button>
  32 + <n-button type="primary" @click="closeHandle">保存 & 关闭</n-button>
  33 + </n-space>
  34 + </template>
  35 + </n-card>
  36 + </n-modal>
  37 + <!-- 请求配置model -->
  38 + <pond-data-request
  39 + v-model:modelShow="requestShow"
  40 + :targetDataRequest="editData"
  41 + :isEdit="isEdit"
  42 + @editSaveHandle="saveHandle"
  43 + ></pond-data-request>
  44 +</template>
  45 +
  46 +<script setup lang="ts">
  47 +import { ref, toRefs, computed, nextTick, watch, toRaw } from 'vue'
  48 +import noData from '@/assets/images/canvas/noData.png'
  49 +import { ChartDataPondList } from '../ChartDataPondList'
  50 +import PondDataRequest from '../../../RequestModal/PondDataRequest.vue'
  51 +import { ChartDataDisplay } from '../ChartDataDisplay'
  52 +import { requestConfig } from '@/packages/public/publicConfig'
  53 +import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
  54 +import { RequestDataPondItemType } from '@/store/modules/chartEditStore/chartEditStore.d'
  55 +import { RequestDataTypeEnum } from '@/enums/httpEnum'
  56 +import { icon } from '@/plugins'
  57 +import { getUUID, goDialog } from '@/utils'
  58 +import { cloneDeep } from 'lodash'
  59 +
  60 +defineProps({
  61 + modelShow: Boolean
  62 +})
  63 +
  64 +const emit = defineEmits(['update:modelShow', 'sendHandle'])
  65 +
  66 +const { PencilIcon } = icon.ionicons5
  67 +
  68 +const { chartEditStore, targetData } = useTargetData()
  69 +
  70 +const { requestDataPond } = toRefs(chartEditStore.getRequestGlobalConfig)
  71 +
  72 +const requestShow = ref(false)
  73 +
  74 +const loading = ref(false)
  75 +
  76 +const isEdit = ref(false)
  77 +
  78 +const editData = ref<RequestDataPondItemType>()
  79 +
  80 +// 所选数据池
  81 +const pondData = computed(() => {
  82 + const selectId = targetData?.value?.request?.requestDataPondId
  83 + if (!selectId) return undefined
  84 + const data = requestDataPond.value.filter(item => {
  85 + return selectId === item.dataPondId
  86 + })
  87 + return data[0]
  88 +})
  89 +
  90 +const cacheEditData = ref<RequestDataPondItemType>()
  91 +
  92 +watch(
  93 + () => pondData.value,
  94 + newValue => {
  95 + loading.value = true
  96 + editData.value = newValue
  97 + cacheEditData.value = editData.value
  98 + nextTick(() => {
  99 + loading.value = false
  100 + })
  101 + },
  102 + {
  103 + immediate: true
  104 + }
  105 +)
  106 +
  107 +// 打开/编辑
  108 +const openPond = (isEditFlag = false) => {
  109 + isEdit.value = !!isEditFlag
  110 + requestShow.value = true
  111 + if (isEditFlag) {
  112 + editData.value = cacheEditData.value
  113 + targetData.value.request.pondRequestGlobalIsToken = editData.value?.dataPondRequestConfig.pondRequestGlobalIsToken
  114 + }
  115 +}
  116 +
  117 +// 创建
  118 +const createPond = () => {
  119 + const id = getUUID()
  120 + editData.value = {
  121 + dataPondId: id,
  122 + dataPondName: id,
  123 + dataPondRequestConfig: cloneDeep({ ...requestConfig, requestDataType: RequestDataTypeEnum.AJAX })
  124 + }
  125 + targetData.value.request.pondRequestGlobalIsToken = true
  126 + openPond()
  127 +}
  128 +
  129 +// 完成创建/编辑
  130 +const saveHandle = (newData: RequestDataPondItemType) => {
  131 + // 走创建
  132 + if (isEdit.value) {
  133 + editSaveHandle(newData)
  134 + } else {
  135 + createSaveHandle(newData)
  136 + }
  137 + isEdit.value = false
  138 + requestShow.value = false
  139 +}
  140 +
  141 +// 编辑保存之后
  142 +const editSaveHandle = (newData: RequestDataPondItemType) => {
  143 + try {
  144 + const targetIndex = requestDataPond.value.findIndex(item => item.dataPondId === newData.dataPondId)
  145 + if (targetIndex !== -1) {
  146 + requestDataPond.value.splice(targetIndex, 1, newData)
  147 + // 修改数据池后, 修改所有关联的组件
  148 + chartEditStore.getComponentList.forEach(item => {
  149 + if (
  150 + item.request.requestDataType === RequestDataTypeEnum.Pond &&
  151 + item.request.requestDataPondId === newData.dataPondId
  152 + ) {
  153 + item.request = {
  154 + ...toRaw(newData.dataPondRequestConfig),
  155 + requestDataPondId: newData.dataPondId
  156 + }
  157 + }
  158 + })
  159 + window.$message.success('保存成功!')
  160 + } else {
  161 + window.$message.error('编辑失败,请稍后重试!')
  162 + }
  163 + } catch (error) {
  164 + window.$message.error('编辑失败,请稍后重试!')
  165 + }
  166 +}
  167 +
  168 +// 创建保存成功之后
  169 +const createSaveHandle = (newData: RequestDataPondItemType) => {
  170 + try {
  171 + if (editData.value) {
  172 + requestDataPond.value.unshift(newData)
  173 + window.$message.success('创建成功!')
  174 + } else {
  175 + window.$message.error('创建失败,请稍后重试!')
  176 + }
  177 + } catch (error) {
  178 + window.$message.error('创建失败,请稍后重试!')
  179 + }
  180 +}
  181 +
  182 +// 删除数据池
  183 +const deletePond = (targetData: RequestDataPondItemType) => {
  184 + goDialog({
  185 + message: '删除数据后,需手动处理使用改接口的组件,是否继续?',
  186 + isMaskClosable: true,
  187 + transformOrigin: 'center',
  188 + onPositiveCallback: () => {
  189 + const targetIndex = requestDataPond.value.findIndex(item => item.dataPondId === targetData.dataPondId)
  190 + if (targetIndex !== -1) {
  191 + requestDataPond.value.splice(targetIndex, 1)
  192 + window.$message.success('删除成功!')
  193 + } else {
  194 + window.$message.error('删除失败,请稍后重试!')
  195 + }
  196 + }
  197 + })
  198 +}
  199 +
  200 +// 关闭
  201 +const closeHandle = () => {
  202 + // 将所选内容赋值给对象
  203 + if (pondData.value) {
  204 + // targetData.value.request = {
  205 + // ...toRaw(pondData.value.dataPondRequestConfig),
  206 + // requestDataPondId: pondData.value.dataPondId
  207 + // }
  208 + }
  209 + emit('update:modelShow', false)
  210 +}
  211 +</script>
  212 +
  213 +<style lang="scss" scoped>
  214 +@include go('chart-data-pond-control') {
  215 + /* 中间 */
  216 + .pond-content {
  217 + display: flex;
  218 + }
  219 + .no-data {
  220 + flex-direction: column;
  221 + width: 100%;
  222 + img {
  223 + width: 200px;
  224 + }
  225 + }
  226 + &.n-card.n-modal,
  227 + .n-card {
  228 + @extend .go-background-filter;
  229 + }
  230 + .n-card-shallow {
  231 + background-color: rgba(0, 0, 0, 0) !important;
  232 + }
  233 + @include deep() {
  234 + & > .n-card__content {
  235 + padding-right: 0;
  236 + }
  237 + .n-card__content {
  238 + padding-bottom: 5px;
  239 + }
  240 + }
  241 +}
  242 +</style>
... ...
  1 +<template>
  2 + <div class="go-chart-data-pond-list">
  3 + <n-timeline class="pond-item-timeline" style="width: 20px">
  4 + <n-timeline-item type="info"> </n-timeline-item>
  5 + <n-timeline-item type="success"></n-timeline-item>
  6 + </n-timeline>
  7 + <div class="pond-item-box">
  8 + <!-- 新增 -->
  9 + <n-button class="create-btn go-py-4" ghost @click="createPond">
  10 + <span> 创建 </span>
  11 + <template #icon>
  12 + <n-icon>
  13 + <DuplicateOutlineIcon></DuplicateOutlineIcon>
  14 + </n-icon>
  15 + </template>
  16 + </n-button>
  17 + <n-divider style="margin: 10px 0"></n-divider>
  18 + <n-space v-if="!requestDataPond.length" justify="center">
  19 + <n-text class="not-layer-text" :depth="3">
  20 + 暂无数据内容,
  21 + <n-a @click="createPond">立即创建</n-a>
  22 + </n-text>
  23 + </n-space>
  24 + <n-scrollbar style="max-height: 490px">
  25 + <div
  26 + v-for="item in requestDataPond"
  27 + :key="item.dataPondId"
  28 + :class="{ select: item.dataPondId === selectPondId }"
  29 + class="pond-item"
  30 + @click="clickHandle(item)"
  31 + >
  32 + <div class="item-content">
  33 + <div class="item-content-body">
  34 + <div>
  35 + <n-tag class="go-mr-1" :type="item.dataPondId === selectPondId ? 'warning' : ''" :bordered="false">
  36 + 名称
  37 + </n-tag>
  38 + <n-ellipsis style="max-width: 180px">
  39 + {{ item.dataPondName || '暂无' }}
  40 + </n-ellipsis>
  41 + </div>
  42 + <div>
  43 + <n-tag class="go-mr-1" :type="item.dataPondId === selectPondId ? 'warning' : ''" :bordered="false">
  44 + 地址
  45 + </n-tag>
  46 + <n-ellipsis style="max-width: 180px">
  47 + {{ item.dataPondRequestConfig.pondRequestUrl || '暂无' }}
  48 + </n-ellipsis>
  49 + </div>
  50 + </div>
  51 + <div class="item-content-icon go-transition-quick" @click="deletePond($event, item)">
  52 + <n-icon>
  53 + <trash-icon></trash-icon>
  54 + </n-icon>
  55 + </div>
  56 + </div>
  57 + <div :class="{ 'select-modal': item.dataPondId === selectPondId }"></div>
  58 + </div>
  59 + </n-scrollbar>
  60 + </div>
  61 + </div>
  62 +</template>
  63 +
  64 +<script setup lang="ts">
  65 +import { toRefs, computed } from 'vue'
  66 +import { useTargetData } from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
  67 +import { useDesignStore } from '@/store/modules/designStore/designStore'
  68 +import { RequestDataPondItemType } from '@/store/modules/chartEditStore/chartEditStore.d'
  69 +import { icon } from '@/plugins'
  70 +
  71 +const emit = defineEmits(['createPond', 'deletePond'])
  72 +
  73 +const { DuplicateOutlineIcon, TrashIcon } = icon.ionicons5
  74 +const designStore = useDesignStore()
  75 +const { chartEditStore, targetData } = useTargetData()
  76 +const { requestDataPond } = toRefs(chartEditStore.getRequestGlobalConfig)
  77 +
  78 +// 选中的全局数据
  79 +const selectPondId = computed(() => {
  80 + return targetData.value.request.requestDataPondId
  81 +})
  82 +
  83 +// 颜色
  84 +const themeColor = computed(() => {
  85 + return designStore.getAppTheme
  86 +})
  87 +
  88 +// 创建数据池
  89 +const createPond = () => {
  90 + emit('createPond', true)
  91 +}
  92 +
  93 +// 删除数据池
  94 +const deletePond = (target: Event, targetData: RequestDataPondItemType) => {
  95 + target.stopPropagation()
  96 + target.preventDefault()
  97 + emit('deletePond', targetData)
  98 +}
  99 +
  100 +// 选中
  101 +const clickHandle = (item: RequestDataPondItemType) => {
  102 + targetData.value.request.requestDataPondId = item.dataPondId
  103 + targetData.value.request.pondRequestGlobalIsToken = item.dataPondRequestConfig.pondRequestGlobalIsToken
  104 +}
  105 +</script>
  106 +
  107 +<style scoped lang="scss">
  108 +$height: 530px;
  109 +$listWidth: 280px;
  110 +$centerHeight: 60px;
  111 +$centerMiniHeight: 28px;
  112 +$textSize: 10px;
  113 +
  114 +@include go('chart-data-pond-list') {
  115 + padding-top: 10px;
  116 + padding-bottom: 5px;
  117 + margin-right: 5px;
  118 + display: flex;
  119 + .pond-item-timeline > .n-timeline-item {
  120 + &:first-child {
  121 + height: $height;
  122 + }
  123 + }
  124 + .pond-item-box {
  125 + width: $listWidth;
  126 + position: relative;
  127 + .create-btn {
  128 + width: calc(#{$listWidth - 15px});
  129 + margin-right: 15px;
  130 + }
  131 + .pond-item {
  132 + position: relative;
  133 + height: $centerHeight;
  134 + padding: 5px;
  135 + margin-bottom: 10px;
  136 + margin-right: 15px;
  137 + border-radius: 5px;
  138 + cursor: pointer;
  139 + border: 1px solid rgba(0, 0, 0, 0);
  140 + @include fetch-bg-color('background-color3');
  141 + @extend .go-transition-quick;
  142 + &.hover,
  143 + &:hover {
  144 + @include fetch-bg-color('background-color4');
  145 + }
  146 + &:hover {
  147 + @include deep() {
  148 + .icon-item {
  149 + opacity: 1;
  150 + }
  151 + }
  152 + .item-content-icon {
  153 + opacity: 1 !important;
  154 + }
  155 + }
  156 +
  157 + &.select {
  158 + border: 1px solid v-bind('themeColor');
  159 + background-color: rgba(0, 0, 0, 0);
  160 + .item-content-icon {
  161 + display: none;
  162 + }
  163 + }
  164 +
  165 + .select-modal,
  166 + .item-content {
  167 + position: absolute;
  168 + top: 0;
  169 + left: 0;
  170 + }
  171 +
  172 + .item-content {
  173 + z-index: 1;
  174 + display: flex;
  175 + justify-content: space-between;
  176 + align-items: center;
  177 + padding: 5px;
  178 + .item-content-body {
  179 + width: 230px;
  180 + display: flex;
  181 + flex-direction: column;
  182 + gap: 5px;
  183 + }
  184 + .item-content-icon {
  185 + opacity: 0;
  186 + height: $centerHeight;
  187 + line-height: $centerHeight;
  188 + padding-left: 5px;
  189 + }
  190 + }
  191 +
  192 + .select-modal {
  193 + width: 100%;
  194 + height: 100%;
  195 + opacity: 0.3;
  196 + background-color: v-bind('themeColor');
  197 + }
  198 + }
  199 + }
  200 +}
  201 +</style>
... ...
  1 +import ChartDataPond from './index.vue'
  2 +
  3 +export { ChartDataPond }
... ...