Commit fc9dfeffcf2f00aa6d38c99ea6002618157ddd83
Merge branch 'main_dev' into 'main'
Main dev See merge request yunteng/thingskit-view!251
Showing
42 changed files
with
812 additions
and
95 deletions
... | ... | @@ -21,6 +21,7 @@ enum Api { |
21 | 21 | GET_ATTRBUTELIST = '/device/attributes/', |
22 | 22 | GET_DEVICE_LATEST = '/plugins/telemetry/DEVICE/', |
23 | 23 | DEVICE_ATTR = '/device/attributes', |
24 | + ALARM_LIST = '/alarm', | |
24 | 25 | } |
25 | 26 | |
26 | 27 | export const getDictItemByCode = (value: string) => { |
... | ... | @@ -152,3 +153,10 @@ export const getProfileAttrs = (params: { deviceProfileId: string; dataType?: st |
152 | 153 | params: { dataType }, |
153 | 154 | }); |
154 | 155 | }; |
156 | + | |
157 | +//获取告警列表 | |
158 | +export const getAlarmList = (params?: object) => | |
159 | + defHttp.get({ | |
160 | + url: Api.ALARM_LIST, | |
161 | + params | |
162 | + }) | ... | ... |
... | ... | @@ -93,6 +93,7 @@ const extraValue = (object: Recordable) => { |
93 | 93 | } |
94 | 94 | |
95 | 95 | const handleParams = (Params: Recordable) => { |
96 | + Reflect.deleteProperty(Params, 'attrName') | |
96 | 97 | if (Params.keys && Params?.keys?.length) { |
97 | 98 | // 过滤无效参数 |
98 | 99 | Reflect.deleteProperty(Params, 'attrName') | ... | ... |
... | ... | @@ -164,6 +164,14 @@ |
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="范围" v-if="yAxis.showRange"> | |
168 | + <setting-item name="最小值" > | |
169 | + <n-input-number v-model:value="yAxis.min" size="small" min="0"></n-input-number> | |
170 | + </setting-item> | |
171 | + <setting-item name="最大值"> | |
172 | + <n-input-number v-model:value="yAxis.max" size="small" min="0"></n-input-number> | |
173 | + </setting-item> | |
174 | + </setting-item-box> | |
167 | 175 | <setting-item-box name="单位"> |
168 | 176 | <setting-item name="名称"> |
169 | 177 | <n-input v-model:value="yAxis.name" size="small"></n-input> |
... | ... | @@ -290,11 +298,40 @@ |
290 | 298 | </setting-item-box> |
291 | 299 | </collapse-item> |
292 | 300 | |
301 | + <!-- 颜色 --> | |
302 | + <collapse-item name="颜色" expanded> | |
303 | + <n-card | |
304 | + v-for="(value, key) in chartCustomColor" | |
305 | + :key="key" | |
306 | + class="card-box" | |
307 | + size="small" | |
308 | + hoverable | |
309 | + embedded | |
310 | + > | |
311 | + <div class="go-flex-items-center"> | |
312 | + <n-ellipsis style="text-align: left; width: 60px">{{ value?.name }} </n-ellipsis> | |
313 | + <span | |
314 | + class="theme-color-item" | |
315 | + v-for="colorItem in fetchShowColors(value!.color)" | |
316 | + :key="colorItem" | |
317 | + :style="{ backgroundColor: colorItem }" | |
318 | + ></span> | |
319 | + <div @click="createCustomColorHandle"> | |
320 | + <n-icon size="18"> | |
321 | + <add-icon></add-icon> | |
322 | + </n-icon> | |
323 | + </div> | |
324 | + </div> | |
325 | + <div class="theme-bottom" :style="{ backgroundImage: colorBackgroundImage(value!) }"></div> | |
326 | + </n-card> | |
327 | + <!-- 自定义颜色 modal --> | |
328 | + <create-color v-model:modelShow="createColorModelShow" :applicationGroup="applicationGroup"></create-color> | |
329 | + </collapse-item> | |
330 | + | |
293 | 331 | <collapse-item v-if="visualMap" name="视觉映射"> |
294 | 332 | <template #header> |
295 | 333 | <n-switch v-model:value="visualMap.show" size="small"></n-switch> |
296 | 334 | </template> |
297 | - | |
298 | 335 | <setting-item-box name="范围"> |
299 | 336 | <setting-item name="最小值"> |
300 | 337 | <n-input-number v-model:value="visualMap.min" size="small"></n-input-number> |
... | ... | @@ -336,15 +373,19 @@ |
336 | 373 | </template> |
337 | 374 | |
338 | 375 | <script setup lang="ts"> |
339 | -import { PropType, computed, watch } from 'vue' | |
376 | +import { PropType, computed, watch, ref } from 'vue' | |
340 | 377 | import { GlobalThemeJsonType } from '@/settings/chartThemes/index' |
341 | 378 | import { axisConfig, legendConfig } from '@/packages/chartConfiguration/echarts/index' |
342 | 379 | import { CollapseItem, SettingItemBox, SettingItem, GlobalSettingPosition } from '@/components/Pages/ChartItemSetting' |
343 | 380 | import { icon } from '@/plugins' |
344 | 381 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
345 | 382 | import EchartsRendererSetting from './EchartsRendererSetting.vue' |
383 | +import cloneDeep from 'lodash/cloneDeep' | |
384 | +import { loadAsyncComponent, colorCustomMerge } from '@/utils' | |
385 | +import { useDesignStore } from '@/store/modules/designStore/designStore' | |
386 | +import { useTargetData } from "@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook" | |
346 | 387 | |
347 | -const { HelpOutlineIcon } = icon.ionicons5 | |
388 | +const { HelpOutlineIcon, AddIcon } = icon.ionicons5 | |
348 | 389 | |
349 | 390 | const props = defineProps({ |
350 | 391 | optionData: { |
... | ... | @@ -358,6 +399,10 @@ const props = defineProps({ |
358 | 399 | } |
359 | 400 | }) |
360 | 401 | |
402 | +const { targetData } = useTargetData() | |
403 | + | |
404 | +const CreateColor = loadAsyncComponent(() => import('@/views/chart/ContentConfigurations/components/CanvasPage/components/CreateColor/index.vue')) | |
405 | + | |
361 | 406 | const chartEditStore = useChartEditStore() |
362 | 407 | const themeSetting = computed(() => { |
363 | 408 | const chartThemeSetting = chartEditStore.getEditCanvasConfig.chartThemeSetting |
... | ... | @@ -373,6 +418,13 @@ const xAxis = computed(() => { |
373 | 418 | }) |
374 | 419 | |
375 | 420 | 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 | + } | |
376 | 428 | return props.optionData.yAxis |
377 | 429 | }) |
378 | 430 | |
... | ... | @@ -401,4 +453,85 @@ watch(() => legend.value && legend.value.textStyle.color, (newVal) => { |
401 | 453 | immediate: true, |
402 | 454 | deep: true, |
403 | 455 | }) |
456 | + | |
457 | +// 底色 | |
458 | +const colorBackgroundImage = (item: { color: string[] }) => { | |
459 | + return `linear-gradient(to right, ${item.color[0]} 0%, ${item.color[5]} 100%)` | |
460 | +} | |
461 | + | |
462 | +// 获取用来展示的色号 | |
463 | +const fetchShowColors = (colors: Array<string>) => { | |
464 | + return cloneDeep(colors).splice(0, 6) | |
465 | +} | |
466 | + | |
467 | +// 自定义颜色 | |
468 | +const chartCustomColor = computed(() => { | |
469 | + const colorCustomMergeData = colorCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo) | |
470 | + if(Reflect.has(targetData.value, 'colors')){ | |
471 | + return { | |
472 | + 'chartCustom': targetData.value?.colors | |
473 | + } | |
474 | + } else { | |
475 | + return { | |
476 | + 'chartCustom': colorCustomMergeData[chartEditStore.getEditCanvasConfig.chartThemeColor] | |
477 | + } | |
478 | + } | |
479 | +}) | |
480 | + | |
481 | +// 全局颜色 | |
482 | +const designStore = useDesignStore() | |
483 | + | |
484 | +// 颜色 | |
485 | +const themeColor = computed(() => { | |
486 | + return designStore.getAppTheme | |
487 | +}) | |
488 | + | |
489 | +const createColorModelShow = ref(false) | |
490 | + | |
491 | +const applicationGroup = ref(false) | |
492 | + | |
493 | +const createCustomColorHandle = () => { | |
494 | + createColorModelShow.value = true | |
495 | + applicationGroup.value = true | |
496 | +} | |
404 | 497 | </script> |
498 | + | |
499 | +<style lang="scss" scoped> | |
500 | +$radius: 10px; | |
501 | +$itemRadius: 6px; | |
502 | + | |
503 | +.card-box { | |
504 | + cursor: pointer; | |
505 | + margin-top: 15px; | |
506 | + padding: 0; | |
507 | + @include fetch-bg-color('background-color4-shallow'); | |
508 | + border-radius: $radius; | |
509 | + overflow: hidden; | |
510 | + | |
511 | + &.selected { | |
512 | + border: 2px solid v-bind('themeColor'); | |
513 | + border-bottom: 1px solid rgba(0, 0, 0, 0); | |
514 | + } | |
515 | + &:first-child { | |
516 | + margin-top: 5px; | |
517 | + } | |
518 | + .go-flex-items-center { | |
519 | + justify-content: space-between; | |
520 | + align-items: center; | |
521 | + margin-top: -4px; | |
522 | + } | |
523 | + .theme-color-item { | |
524 | + display: inline-block; | |
525 | + width: 20px; | |
526 | + height: 20px; | |
527 | + border-radius: $itemRadius; | |
528 | + } | |
529 | + .theme-bottom { | |
530 | + position: absolute; | |
531 | + left: 0; | |
532 | + bottom: 0px; | |
533 | + width: 100%; | |
534 | + height: 3px; | |
535 | + } | |
536 | +} | |
537 | +</style> | ... | ... |
... | ... | @@ -73,10 +73,11 @@ export const useChartDataFetch = ( |
73 | 73 | let endTsValue = null |
74 | 74 | const {requestParams} = toRaw(targetComponent.request) |
75 | 75 | const {Params} = requestParams |
76 | - const {entityType, startTs, endTs} = Params | |
76 | + const {startTs, endTs, shortcutsSelect} = Params | |
77 | 77 | let days = Math.ceil(((endTs as unknown as number) - (startTs as unknown as number)) / (1 * 60 * 60 * 24 * 1000)) |
78 | 78 | const ShortcutsDays = [1, 7, 30] |
79 | - if (entityType === 'DEVICE') { | |
79 | + // shortcutsSelect为真 | |
80 | + if (shortcutsSelect) { | |
80 | 81 | //等于这三个,说明是从快捷选项里面选的 |
81 | 82 | if(ShortcutsDays.includes(days)) { |
82 | 83 | days = days <= 2 ? 1 : days<= 8 ? 7 : 30 |
... | ... | @@ -85,12 +86,12 @@ export const useChartDataFetch = ( |
85 | 86 | endTsValue = dayjs().endOf('day').valueOf() |
86 | 87 | ;(toRaw(targetComponent.request).requestParams.Params.startTs as unknown as number) = startTsValue as number |
87 | 88 | ;(toRaw(targetComponent.request).requestParams.Params.endTs as unknown as number) = endTsValue |
88 | - } else { | |
89 | - //否则,选择的是什么日期区间就是什么 | |
90 | - (toRaw(targetComponent.request).requestParams.Params.startTs as unknown as number) = startTs as unknown as number | |
91 | - (toRaw(targetComponent.request).requestParams.Params.endTs as unknown as number) = endTs as unknown as number | |
92 | 89 | } |
93 | - } | |
90 | + } else { | |
91 | + //否则,选择的是什么日期区间就是什么 | |
92 | + (toRaw(targetComponent.request).requestParams.Params.startTs as unknown as number) = startTs as unknown as number | |
93 | + (toRaw(targetComponent.request).requestParams.Params.endTs as unknown as number) = endTs as unknown as number | |
94 | + } | |
94 | 95 | const res = await customRequest(toRaw(targetComponent.request)) |
95 | 96 | if (res) { |
96 | 97 | try { | ... | ... |
1 | 1 | /** |
2 | - * 重写select下拉框联动 | |
2 | + * 重写select下拉框联动(下拉选择和输入框共用此hook) | |
3 | 3 | */ |
4 | 4 | import { toRefs } from 'vue' |
5 | 5 | import { CreateComponentType } from '@/packages/index.d' |
... | ... | @@ -13,7 +13,8 @@ export const useChartInteract = ( |
13 | 13 | chartConfig: CreateComponentType, |
14 | 14 | useChartEditStore: ChartEditStoreType, |
15 | 15 | param: { [T: string]: any }, |
16 | - interactEventOn: string | |
16 | + interactEventOn: string, | |
17 | + attrNames?: string[] | |
17 | 18 | ) => { |
18 | 19 | const chartEditStore = useChartEditStore() |
19 | 20 | const { interactEvents } = chartConfig.events |
... | ... | @@ -34,12 +35,13 @@ export const useChartInteract = ( |
34 | 35 | if (groupItem.id === item.interactComponentId) { |
35 | 36 | const { Params, Header } = toRefs(groupItem.request.requestParams) |
36 | 37 | Object.keys(item.interactFn).forEach(key => { |
37 | - if (Params.value[key]) { | |
38 | - Params.value[key] = param[item.interactFn[key]] | |
39 | - } | |
40 | - if (Header.value[key]) { | |
41 | - Header.value[key] = param[item.interactFn[key]] | |
42 | - } | |
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]] | |
44 | + } | |
43 | 45 | }) |
44 | 46 | } |
45 | 47 | }) |
... | ... | @@ -56,12 +58,13 @@ export const useChartInteract = ( |
56 | 58 | } |
57 | 59 | // |
58 | 60 | Object.keys(item.interactFn).forEach(key => { |
59 | - if (Params.value[key]) { | |
60 | - Params.value[key] = param[item.interactFn[key]] | |
61 | - } | |
62 | - if (Header.value[key]) { | |
63 | - Header.value[key] = param[item.interactFn[key]] | |
64 | - } | |
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 | + } | |
65 | 68 | }) |
66 | 69 | } |
67 | 70 | } | ... | ... |
... | ... | @@ -9,7 +9,7 @@ export const seriesItem = { |
9 | 9 | type: 'bar', |
10 | 10 | barWidth: null, |
11 | 11 | label: { |
12 | - show: true, | |
12 | + show: false, | |
13 | 13 | position: 'right', |
14 | 14 | color: '#fff', |
15 | 15 | fontSize: 12 |
... | ... | @@ -33,6 +33,7 @@ export const option = { |
33 | 33 | type: 'value' |
34 | 34 | }, |
35 | 35 | yAxis: { |
36 | + showRange: false, | |
36 | 37 | show: true, |
37 | 38 | type: 'category' |
38 | 39 | }, | ... | ... |
... | ... | @@ -51,7 +51,10 @@ use([DatasetComponent, CanvasRenderer, BarChart, GridComponent, TooltipComponent |
51 | 51 | const replaceMergeArr = ref<string[]>() |
52 | 52 | |
53 | 53 | const option = computed(() => { |
54 | - return mergeTheme(props.chartConfig.option, props.themeSetting, includes) | |
54 | + const mergeThemeData = mergeTheme(props.chartConfig.option, props.themeSetting, includes) | |
55 | + Reflect.deleteProperty(mergeThemeData.yAxis, 'min') | |
56 | + Reflect.deleteProperty(mergeThemeData.yAxis, 'max') | |
57 | + return mergeThemeData | |
55 | 58 | }) |
56 | 59 | |
57 | 60 | // dataset 无法变更条数的补丁 | ... | ... |
... | ... | @@ -11,7 +11,7 @@ export const barSeriesItem = { |
11 | 11 | type: 'bar', |
12 | 12 | barWidth: 15, |
13 | 13 | label: { |
14 | - show: true, | |
14 | + show: false, | |
15 | 15 | position: 'top', |
16 | 16 | color: '#fff', |
17 | 17 | fontSize: 12 |
... | ... | @@ -26,7 +26,7 @@ export const lineSeriesItem = { |
26 | 26 | type: 'line', |
27 | 27 | symbol: 'circle', |
28 | 28 | label: { |
29 | - show: true, | |
29 | + show: false, | |
30 | 30 | position: 'top', |
31 | 31 | color: '#fff', |
32 | 32 | fontSize: 12 | ... | ... |
... | ... | @@ -52,7 +52,10 @@ use([ |
52 | 52 | ]) |
53 | 53 | |
54 | 54 | const option = computed(() => { |
55 | - return mergeTheme(props.chartConfig.option, props.themeSetting, includes) | |
55 | + const mergeThemeData = mergeTheme(props.chartConfig.option, props.themeSetting, includes) as unknown as Recordable | |
56 | + Reflect.deleteProperty(mergeThemeData.yAxis, 'min') | |
57 | + Reflect.deleteProperty(mergeThemeData.yAxis, 'max') | |
58 | + return mergeThemeData | |
56 | 59 | }) |
57 | 60 | |
58 | 61 | const vChartRef = ref<typeof VChart>() | ... | ... |
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | <n-input :style="`width:${w}px;`" type="text" |
4 | 4 | v-model:value="option.value.dataset" |
5 | 5 | placeholder="请输入" |
6 | - @change="onChange"> | |
6 | + @update="onChange"> | |
7 | 7 | |
8 | 8 | </n-input> |
9 | 9 | </div> |
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | import { PropType, toRefs, shallowReactive, watch } from 'vue' |
14 | 14 | import { CreateComponentType } from '@/packages/index.d' |
15 | 15 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
16 | -import { useChartInteract } from '@/hooks' | |
16 | +import { useChartInteract } from '@/hooks/external/useChartSelectInteract.hook' | |
17 | 17 | import { InteractEventOn } from '@/enums/eventEnum' |
18 | 18 | import { ComponentInteractParamsEnum } from './interact' |
19 | 19 | |
... | ... | @@ -33,13 +33,14 @@ const option = shallowReactive({ |
33 | 33 | }) |
34 | 34 | |
35 | 35 | const onChange = (v: string) => { |
36 | - if(v == undefined) return; | |
36 | + // if(v == undefined) return; | |
37 | 37 | // 存储到联动数据 |
38 | 38 | useChartInteract( |
39 | 39 | props.chartConfig, |
40 | 40 | useChartEditStore, |
41 | - { [ComponentInteractParamsEnum.DATA]: v }, | |
42 | - InteractEventOn.CHANGE | |
41 | + { [ComponentInteractParamsEnum.DATA]: encodeURIComponent(option.value.dataset) }, | |
42 | + InteractEventOn.CHANGE, | |
43 | + [] | |
43 | 44 | ) |
44 | 45 | } |
45 | 46 | ... | ... |
... | ... | @@ -112,8 +112,8 @@ watch( |
112 | 112 | props.chartConfig.option.series.push(...seriesArr) |
113 | 113 | } |
114 | 114 | replaceMergeArr.value = ['series'] |
115 | + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) | |
115 | 116 | nextTick(() => { |
116 | - useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) | |
117 | 117 | replaceMergeArr.value = [] |
118 | 118 | }) |
119 | 119 | } |
... | ... | @@ -245,8 +245,10 @@ const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, ne |
245 | 245 | } |
246 | 246 | } |
247 | 247 | }) |
248 | - // | |
249 | - addPieInterval(newData) | |
248 | + //动画为开启才执行动画 | |
249 | + if (props.chartConfig.option.isCarousel) { | |
250 | + addPieInterval(newData) | |
251 | + } | |
250 | 252 | updateVChart(newData) |
251 | 253 | }) |
252 | 254 | ... | ... |
... | ... | @@ -112,8 +112,8 @@ watch( |
112 | 112 | props.chartConfig.option.series.push(...seriesArr) |
113 | 113 | } |
114 | 114 | replaceMergeArr.value = ['series'] |
115 | + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) | |
115 | 116 | nextTick(() => { |
116 | - useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) | |
117 | 117 | replaceMergeArr.value = [] |
118 | 118 | }) |
119 | 119 | } |
... | ... | @@ -244,8 +244,10 @@ const {vChartRef} = useChartDataFetch(props.chartConfig, useChartEditStore, (new |
244 | 244 | } |
245 | 245 | } |
246 | 246 | }) |
247 | - // | |
248 | - addPieInterval(newData) | |
247 | + //动画为开启才执行动画 | |
248 | + if (props.chartConfig.option.isCarousel) { | |
249 | + addPieInterval(newData) | |
250 | + } | |
249 | 251 | updateVChart(newData) |
250 | 252 | }) |
251 | 253 | ... | ... |
1 | 1 | <template> |
2 | - <div> | |
2 | + <div class="device-history-query"> | |
3 | 3 | <n-space vertical> |
4 | 4 | <div class="form"> |
5 | 5 | <n-date-picker size="small" :to="true" clearable v-model:value="queryCondition.timeRange" type="datetimerange" |
... | ... | @@ -96,6 +96,27 @@ const option = computed(() => { |
96 | 96 | return mergeTheme(props.chartConfig.option, props.themeSetting, includes) |
97 | 97 | }) |
98 | 98 | |
99 | +const toolBoxOption = { | |
100 | + show: true, | |
101 | + right: 20, | |
102 | + feature: { | |
103 | + myFullButton: { | |
104 | + show: true, | |
105 | + title: '全屏查看', | |
106 | + icon: 'path://M733.549304 0l116.434359 116.23452-226.402521 226.40252 57.053835 57.068109 226.459617-226.445342 120.616689 120.41685V0H733.549304zM689.513507 619.855586l-57.068108 57.068109 224.232847 224.232847-122.64362 122.843458h293.676657V729.838022l-114.007751 114.207588-224.190025-224.190024zM338.197775 404.144414l57.068109-57.068109L171.033037 122.843458 293.676657 0H0v294.161978l114.022025-114.207588 224.17575 224.190024zM347.076305 624.294851L120.616689 850.754468 0 730.323343v293.676657h294.161978l-116.420084-116.23452 226.40252-226.40252-57.068109-57.068109z', | |
107 | + onclick: () => { | |
108 | + const domName = document.getElementsByClassName('device-history-query')[0] as HTMLElement | |
109 | + const htmlName = document.querySelector('html') as HTMLHtmlElement | |
110 | + useFullScreen(domName, htmlName) | |
111 | + } | |
112 | + } | |
113 | + } | |
114 | +} | |
115 | +props.chartConfig.option = { | |
116 | + ...props.chartConfig.option, | |
117 | + ...{ toolbox: toolBoxOption } | |
118 | +} | |
119 | + | |
99 | 120 | // dataset 无法变更条数的补丁 |
100 | 121 | watch( |
101 | 122 | () => props.chartConfig.option.dataset, |
... | ... | @@ -122,8 +143,8 @@ watch( |
122 | 143 | props.chartConfig.option.series.push(...seriesArr) |
123 | 144 | } |
124 | 145 | replaceMergeArr.value = ['series'] |
146 | + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) | |
125 | 147 | nextTick(() => { |
126 | - useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) | |
127 | 148 | replaceMergeArr.value = [] |
128 | 149 | }) |
129 | 150 | } | ... | ... |
... | ... | @@ -214,8 +214,8 @@ watch( |
214 | 214 | props.chartConfig.option.series.push(...seriesArr) |
215 | 215 | } |
216 | 216 | replaceMergeArr.value = ['series'] |
217 | + useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) | |
217 | 218 | nextTick(() => { |
218 | - useEchartsMapLegend(props.chartConfig, props.chartConfig.option.series) | |
219 | 219 | replaceMergeArr.value = [] |
220 | 220 | }) |
221 | 221 | } |
... | ... | @@ -274,8 +274,10 @@ const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, ne |
274 | 274 | } |
275 | 275 | } |
276 | 276 | }) |
277 | - // | |
278 | - addPieInterval(newData) | |
277 | + //动画为开启才执行动画 | |
278 | + if (props.chartConfig.option.isCarousel) { | |
279 | + addPieInterval(newData) | |
280 | + } | |
279 | 281 | updateVChart(newData) |
280 | 282 | }) |
281 | 283 | ... | ... |
... | ... | @@ -43,13 +43,14 @@ onMounted(async () => { |
43 | 43 | label: '中国', |
44 | 44 | value: 'china' |
45 | 45 | }) |
46 | - onHandleSelectProvince('china') | |
46 | + onHandleSelectProvince(props.optionData?.mapRegion.saveSelect['provinceValue']) | |
47 | 47 | for (let i in selectValues) Reflect.set(selectValues, i, props.optionData?.mapRegion.saveSelect[i]) |
48 | 48 | }) |
49 | 49 | |
50 | 50 | const onHandleSelectProvince = async (value: number | string) => { |
51 | 51 | selectValues.cityValue = null |
52 | 52 | selectValues.countyValue = null |
53 | + selectOptions.cityOptions = [] | |
53 | 54 | if (value === 'china') return (selectValues.levelStr = areaEnum.COUNTRY) |
54 | 55 | selectOptions.cityOptions = await getAreaLists(areaEnum.CITY, value) |
55 | 56 | selectValues.levelStr = areaEnum.PROVINCE | ... | ... |
1 | +/** | |
2 | + * 单个组件全屏 | |
3 | + * @param domName | |
4 | + * @param htmlName | |
5 | + */ | |
6 | + | |
1 | 7 | export const useFullScreen = (domName: any, htmlName: HTMLHtmlElement) => { |
2 | 8 | const isFullScreen = document.fullscreenElement |
9 | + | |
3 | 10 | const currentDatkTheme = htmlName.getAttribute('data-theme') |
4 | 11 | |
12 | + //特殊处理单设备多属性组件全屏显示 | |
13 | + const setDomName = (domName: any,top0: string, top1: string) => { | |
14 | + domName.children[0].style.top = top0 | |
15 | + domName.style.paddingBottom = '80px' | |
16 | + domName.children[1].style.top = top1 | |
17 | + } | |
18 | + | |
19 | + const setDomNameAndStyle = () => { | |
20 | + domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | |
21 | + domName.children[0].style.position = 'relative' | |
22 | + setDomName(domName, '30px','40px') | |
23 | + } | |
24 | + | |
5 | 25 | if (isFullScreen) { |
6 | 26 | if (document.exitFullscreen) { |
7 | 27 | document.exitFullscreen() |
... | ... | @@ -11,18 +31,19 @@ export const useFullScreen = (domName: any, htmlName: HTMLHtmlElement) => { |
11 | 31 | //兼容其他浏览器 |
12 | 32 | if (domName.requestFullscreen) { |
13 | 33 | domName.requestFullscreen() |
14 | - domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | |
34 | + setDomNameAndStyle() | |
15 | 35 | } else if (domName.mozRequestFullScreen) { |
16 | 36 | domName.mozRequestFullScreen() |
17 | - domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | |
37 | + setDomNameAndStyle() | |
18 | 38 | } else if (domName.webkitRequestFullscreen) { |
19 | 39 | domName.webkitRequestFullscreen() |
20 | - domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | |
40 | + setDomNameAndStyle() | |
21 | 41 | } else if (domName.msRequestFullscreen) { |
22 | 42 | domName.msRequestFullscreen() |
23 | - domName.style.background = currentDatkTheme === 'light' ? 'white' : '#18181c' | |
43 | + setDomNameAndStyle() | |
24 | 44 | } |
25 | 45 | } |
46 | + | |
26 | 47 | //fix 浏览器监听esc退出 |
27 | 48 | function exitHandler() { |
28 | 49 | if ( |
... | ... | @@ -33,6 +54,7 @@ export const useFullScreen = (domName: any, htmlName: HTMLHtmlElement) => { |
33 | 54 | domName.style.background = currentDatkTheme === 'light' ? '' : '' |
34 | 55 | } |
35 | 56 | } |
57 | + | |
36 | 58 | // 监听fullscreenchange事件(全屏模式的变化) |
37 | 59 | if (document.addEventListener) { |
38 | 60 | document.addEventListener('webkitfullscreenchange', exitHandler, false) | ... | ... |
... | ... | @@ -10,13 +10,15 @@ |
10 | 10 | </template> |
11 | 11 | |
12 | 12 | <script setup lang="ts"> |
13 | -import { PropType, toRefs, shallowReactive, watch } from 'vue' | |
13 | +import { PropType, toRefs, shallowReactive, watch, ref } from 'vue' | |
14 | 14 | import { CreateComponentType } from '@/packages/index.d' |
15 | 15 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
16 | 16 | import { useChartInteract } from '@/hooks/external/useChartSelectInteract.hook' |
17 | 17 | import { InteractEventOn } from '@/enums/eventEnum' |
18 | 18 | import { ComponentInteractParamsEnum } from './interact' |
19 | 19 | import { useChartDataFetch } from '@/hooks' |
20 | +import { isObject } from '@/utils/external/is' | |
21 | +import { SelectOption } from 'naive-ui' | |
20 | 22 | |
21 | 23 | const props = defineProps({ |
22 | 24 | chartConfig: { |
... | ... | @@ -36,14 +38,23 @@ const option = shallowReactive({ |
36 | 38 | } |
37 | 39 | }) |
38 | 40 | |
41 | +const cacheOptions = ref<string[]>([]) | |
42 | + | |
39 | 43 | // 监听事件改变 |
40 | -const onChange = (v: string[] | string) => { | |
41 | - // 存储到联动数据 | |
42 | - useChartInteract( | |
44 | +const onChange = (v: string[] | string, options: SelectOption | SelectOption[]) => { | |
45 | + const attrName = isObject(options) ? [(options as SelectOption).label] : (options as SelectOption[])?.map(mapItem => mapItem.label) | |
46 | + cacheOptions.value = attrName as unknown as string[] | |
47 | + updateChartInteract(v, cacheOptions.value) | |
48 | +} | |
49 | + | |
50 | +const updateChartInteract = (v: string[] | string, attrName?: string[]) => { | |
51 | + // 存储到联动数据 | |
52 | + useChartInteract( | |
43 | 53 | props.chartConfig, |
44 | 54 | useChartEditStore, |
45 | - { [ComponentInteractParamsEnum.DATA]: v }, | |
46 | - InteractEventOn.CHANGE | |
55 | + { [ComponentInteractParamsEnum.DATA]: encodeURIComponent(v as unknown as string) }, | |
56 | + InteractEventOn.CHANGE, | |
57 | + attrName! | |
47 | 58 | ) |
48 | 59 | // 特殊处理 只针对两个下拉选择器,一个是产品下拉,一个是设备下拉,选择了产品,存储到sessionStorage里,用来判断预览时点击产品下拉,清除设备下拉值 |
49 | 60 | if (window.location.href.includes('preview')) { |
... | ... | @@ -56,7 +67,7 @@ watch( |
56 | 67 | () => props.chartConfig.option, |
57 | 68 | (newData: any) => { |
58 | 69 | option.value = newData |
59 | - onChange(newData.selectValue) | |
70 | + updateChartInteract(newData.selectValue, cacheOptions.value) | |
60 | 71 | }, |
61 | 72 | { |
62 | 73 | immediate: true, | ... | ... |
... | ... | @@ -42,15 +42,14 @@ const checkedKeys = ref([]) |
42 | 42 | |
43 | 43 | const onClick = (v: string[]) => { |
44 | 44 | // nTreeRef.value?.selectedKeys(v) |
45 | - console.log(nTreeRef.value) | |
46 | - console.log(v) | |
47 | 45 | // nTreeRef.value?.onUpdateCheckedKeys(v) |
48 | 46 | if (Array.isArray(v) && v.length == 0) return |
49 | 47 | useChartInteract( |
50 | 48 | props.chartConfig, |
51 | 49 | useChartEditStore, |
52 | 50 | { [ComponentInteractParamsEnum.DATA]: v[0] }, |
53 | - InteractEventOn.CHANGE | |
51 | + InteractEventOn.CHANGE, | |
52 | + [] | |
54 | 53 | ) |
55 | 54 | } |
56 | 55 | </script> | ... | ... |
... | ... | @@ -75,7 +75,7 @@ const getConfigurationOptions = async (params: object) => { |
75 | 75 | watch( |
76 | 76 | () => props.optionData.pages, |
77 | 77 | (newData: any) => { |
78 | - getConfigurationOptions({ page: newData.page, pageSize: newData.pageSize }) | |
78 | + getConfigurationOptions({ page: newData.page, pageSize: newData.pageSize, isTemplate: 0 }) | |
79 | 79 | }, |
80 | 80 | { |
81 | 81 | deep: true, |
... | ... | @@ -84,7 +84,7 @@ watch( |
84 | 84 | ) |
85 | 85 | |
86 | 86 | onMounted(() => { |
87 | - getConfigurationOptions({ page: props.optionData.pages.page, pageSize: props.optionData.pages.pageSize }) | |
87 | + getConfigurationOptions({ page: props.optionData.pages.page, pageSize: props.optionData.pages.pageSize, isTemplate: 0 }) | |
88 | 88 | }) |
89 | 89 | |
90 | 90 | const handleUpdateValue = (value: string, options: ConfigurationItemType) => { | ... | ... |
... | ... | @@ -55,7 +55,7 @@ |
55 | 55 | </template> |
56 | 56 | |
57 | 57 | <script setup lang="ts"> |
58 | -import { PropType, ref, onMounted } from 'vue' | |
58 | +import { PropType, ref, onMounted, watch } from 'vue' | |
59 | 59 | import { AccessMode, option, sourceTypeEnum, videoListInterface, sourceTypeNameEnum, Dataset } from './config' |
60 | 60 | import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' |
61 | 61 | import { NTreeSelect } from 'naive-ui' |
... | ... | @@ -135,6 +135,19 @@ const handleSelect = (_: string, e: videoListInterface) => { |
135 | 135 | } |
136 | 136 | } |
137 | 137 | |
138 | +watch(()=>props.optionData, (newData)=>{ | |
139 | + if (newData.sourceType === sourceTypeEnum.PLATFORM) { | |
140 | + getOriginationList() | |
141 | + if (newData.organization) { | |
142 | + getVideoLists(newData.organization) | |
143 | + } | |
144 | + } | |
145 | +}, | |
146 | +{ | |
147 | + immediate: true, | |
148 | + deep: true | |
149 | +}) | |
150 | + | |
138 | 151 | onMounted(() => { |
139 | 152 | if (props.optionData.sourceType === sourceTypeEnum.PLATFORM) { |
140 | 153 | getOriginationList() | ... | ... |
1 | +import cloneDeep from 'lodash/cloneDeep' | |
2 | +import { PublicConfigClass } from '@/packages/public' | |
3 | +import { CreateComponentType } from '@/packages/index.d' | |
4 | +import { chartInitConfig } from '@/settings/designSetting' | |
5 | +import { OverrideTablesBasicConfig } from './index' | |
6 | +import dataJson from './data.json' | |
7 | + | |
8 | +const { dimensions, source } = dataJson | |
9 | +export const option = { | |
10 | + dynamicForm: { | |
11 | + keys: [ | |
12 | + { | |
13 | + key: '告警设备,deviceName', | |
14 | + } | |
15 | + ] | |
16 | + }, | |
17 | + dataset: { dimensions, source }, | |
18 | + pagination: { | |
19 | + page: 1, | |
20 | + pageSize: 10 | |
21 | + }, | |
22 | + align: 'center', | |
23 | + style: { | |
24 | + border: 'on', | |
25 | + singleColumn: 'off', | |
26 | + singleLine: 'off', | |
27 | + bottomBordered: 'on', | |
28 | + striped: 'on', | |
29 | + fontSize: 16, | |
30 | + borderWidth: 0, | |
31 | + borderColor: 'black', | |
32 | + borderStyle: 'solid' | |
33 | + }, | |
34 | + inputShow: false | |
35 | +} | |
36 | + | |
37 | +export default class Config extends PublicConfigClass implements CreateComponentType { | |
38 | + public key = OverrideTablesBasicConfig.key | |
39 | + public attr = { ...chartInitConfig, w: 600, h: 300, zIndex: -1 } | |
40 | + public chartConfig = cloneDeep(OverrideTablesBasicConfig) | |
41 | + public option = cloneDeep(option) | |
42 | +} | ... | ... |
1 | +<template> | |
2 | + <collapse-item name="表格设置" :expanded="true"> | |
3 | + <n-tag type="primary">配置分页接口查询参数键,以逗号分隔键名和键值</n-tag> | |
4 | + <n-tag type="primary">例如:设备名称,deviceName</n-tag> | |
5 | + <setting-item-box :alone="true" name="搜索字段"> | |
6 | + <SettingItem name="表格搜索" :alone="true"> | |
7 | + <n-switch v-model:value="optionData.inputShow"></n-switch> | |
8 | + </SettingItem> | |
9 | + <setting-item v-if="optionData.inputShow" :alone="true"> | |
10 | + <n-form ref="formRef" :model="dynamicForm" :style="{ maxWidth: '640px' }"> | |
11 | + <n-form-item | |
12 | + v-for="(item, index) in dynamicForm.keys" | |
13 | + :key="index" | |
14 | + :label="`字段${index + 1}`" | |
15 | + :path="`keys[${index}].key`" | |
16 | + > | |
17 | + <n-input v-model:value="item.key" clearable /> | |
18 | + <n-button style="margin-left: 12px" @click="removeItem(index)" v-if="dynamicForm.keys.length > 1"> | |
19 | + 删除 | |
20 | + </n-button> | |
21 | + </n-form-item> | |
22 | + <n-form-item> | |
23 | + <n-space> | |
24 | + <n-button attr-type="button" @click="addItem" v-if="dynamicForm.keys.length < 2"> 增加 </n-button> | |
25 | + </n-space> | |
26 | + </n-form-item> | |
27 | + </n-form> | |
28 | + </setting-item> | |
29 | + </setting-item-box> | |
30 | + <n-tag type="primary">若配置无响应,请在预览页面查看效果</n-tag> | |
31 | + <setting-item-box :alone="true" name="对齐方式"> | |
32 | + <setting-item :alone="true"> | |
33 | + <n-select | |
34 | + v-model:value="optionData.align" | |
35 | + size="small" | |
36 | + :options="[ | |
37 | + { label: '靠左', value: 'left' }, | |
38 | + { label: '居中', value: 'center' }, | |
39 | + { label: '靠右', value: 'right' } | |
40 | + ]" | |
41 | + /> | |
42 | + </setting-item> | |
43 | + </setting-item-box> | |
44 | + <setting-item-box :alone="false" name="分页设置"> | |
45 | + <setting-item name="默认页码" :alone="true"> | |
46 | + <n-input-number v-model:value="optionData.pagination.page" size="small" placeholder="字体大小"></n-input-number> | |
47 | + </setting-item> | |
48 | + <setting-item name="分页" :alone="true"> | |
49 | + <n-select v-model:value="optionData.pagination.pageSize" size="small" :options="page" /> | |
50 | + </setting-item> | |
51 | + </setting-item-box> | |
52 | + <setting-item-box :alone="false" name="表格样式"> | |
53 | + <SettingItem name="显示边框" :alone="true"> | |
54 | + <n-select v-model:value="(optionData as any).style.border" size="small" :options="borderFlag" /> | |
55 | + </SettingItem> | |
56 | + <SettingItem name="底部边框" :alone="true"> | |
57 | + <n-select | |
58 | + v-model:value="(optionData as any).style.bottomBordered" | |
59 | + size="small" | |
60 | + :options="bottom_borderedFlag" | |
61 | + /> | |
62 | + </SettingItem> | |
63 | + <SettingItem name="列分割线" :alone="true"> | |
64 | + <n-select v-model:value="(optionData as any).style.singleLine" size="small" :options="columnFlag" /> | |
65 | + </SettingItem> | |
66 | + <SettingItem name="行分割线" :alone="true"> | |
67 | + <n-select v-model:value="(optionData as any).style.singleColumn" size="small" :options="lineFlag" /> | |
68 | + </SettingItem> | |
69 | + <SettingItem name="斑马条纹" :alone="true"> | |
70 | + <n-select v-model:value="(optionData as any).style.striped" size="small" :options="stripedFlag" /> | |
71 | + </SettingItem> | |
72 | + <setting-item name="字体大小" :alone="true"> | |
73 | + <n-input-number | |
74 | + v-model:value="optionData.style.fontSize" | |
75 | + :min="12" | |
76 | + size="small" | |
77 | + placeholder="字体大小" | |
78 | + ></n-input-number> | |
79 | + </setting-item> | |
80 | + <setting-item name="边框宽度" :alone="true"> | |
81 | + <n-input-number | |
82 | + v-model:value="optionData.style.borderWidth" | |
83 | + :min="0" | |
84 | + size="small" | |
85 | + placeholder="字体大小" | |
86 | + ></n-input-number> | |
87 | + </setting-item> | |
88 | + <setting-item name="边框颜色" :alone="true"> | |
89 | + <n-color-picker size="small" :modes="['rgb']" v-model:value="optionData.style.borderColor"></n-color-picker> | |
90 | + </setting-item> | |
91 | + <setting-item name="边框样式" :alone="true"> | |
92 | + <n-select v-model:value="optionData.style.borderStyle" size="small" :options="borderStyleFlag" /> | |
93 | + </setting-item> | |
94 | + </setting-item-box> | |
95 | + </collapse-item> | |
96 | +</template> | |
97 | + | |
98 | +<script setup lang="ts"> | |
99 | +import { PropType, watch, ref, toRefs } from 'vue' | |
100 | +import { option } from './config' | |
101 | +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' | |
102 | +import { FormInst } from 'naive-ui' | |
103 | + | |
104 | +const page = [ | |
105 | + { label: '2', value: 2 }, | |
106 | + { label: '5', value: 5 }, | |
107 | + { label: '10', value: 10 }, | |
108 | + { label: '15', value: 15 }, | |
109 | + { label: '30', value: 30 } | |
110 | +] | |
111 | +const borderFlag = [ | |
112 | + { label: '显示', value: 'on' }, | |
113 | + { label: '不显示', value: 'off' } | |
114 | +] | |
115 | +const columnFlag = [ | |
116 | + { label: '显示', value: 'off' }, | |
117 | + { label: '不显示', value: 'on' } | |
118 | +] | |
119 | +const lineFlag = [ | |
120 | + { label: '显示', value: 'off' }, | |
121 | + { label: '不显示', value: 'on' } | |
122 | +] | |
123 | +const bottom_borderedFlag = [ | |
124 | + { label: '显示', value: 'on' }, | |
125 | + { label: '不显示', value: 'off' } | |
126 | +] | |
127 | +const stripedFlag = [ | |
128 | + { label: '显示', value: 'on' }, | |
129 | + { label: '不显示', value: 'off' } | |
130 | +] | |
131 | +const borderStyleFlag = [ | |
132 | + { label: '实线边框', value: 'solid' }, | |
133 | + { label: '虚线边框', value: 'dashed' }, | |
134 | + { label: '点状边框', value: 'dotted' }, | |
135 | + { label: '双线边框', value: 'double' } | |
136 | +] | |
137 | +const props = defineProps({ | |
138 | + optionData: { | |
139 | + type: Object as PropType<typeof option>, | |
140 | + required: true | |
141 | + } | |
142 | +}) | |
143 | + | |
144 | +const header = ref() | |
145 | +const median = ref<string[]>([]) | |
146 | +props.optionData.dataset.dimensions.forEach(item => { | |
147 | + median.value.push(item.title) | |
148 | +}) | |
149 | + | |
150 | +const { dynamicForm } = toRefs(props.optionData) | |
151 | + | |
152 | +const formRef = ref<FormInst | null>(null) | |
153 | + | |
154 | +const removeItem = (index: number) => { | |
155 | + dynamicForm.value.keys.splice(index, 1) | |
156 | +} | |
157 | + | |
158 | +const addItem = () => { | |
159 | + dynamicForm.value.keys.push({ key: '' }) | |
160 | +} | |
161 | + | |
162 | +//转string | |
163 | +watch( | |
164 | + () => props.optionData, | |
165 | + () => { | |
166 | + median.value = [] | |
167 | + props.optionData.dataset.dimensions.forEach(item => { | |
168 | + median.value.push(item.title) | |
169 | + }) | |
170 | + header.value = median.value.toString() | |
171 | + }, | |
172 | + { | |
173 | + deep: false, | |
174 | + immediate: true | |
175 | + } | |
176 | +) | |
177 | + | |
178 | +//更新columns | |
179 | +watch([header], ([headerNew], [headerOld]) => { | |
180 | + if (headerNew !== headerOld) { | |
181 | + headerNew.split(',').forEach((item: string, index: number) => { | |
182 | + if (index + 1 <= props.optionData.dataset.dimensions.length) { | |
183 | + props.optionData.dataset.dimensions[index].title = headerNew.split(',')[index] | |
184 | + } | |
185 | + }) | |
186 | + } | |
187 | +}) | |
188 | +</script> | ... | ... |
1 | +{ | |
2 | + "dimensions": [ | |
3 | + { | |
4 | + "title": "产品名称", | |
5 | + "key": "productName" | |
6 | + }, | |
7 | + { | |
8 | + "title": "产品销量(万)", | |
9 | + "key": "totalSum" | |
10 | + }, | |
11 | + { | |
12 | + "title": "销售额(万)", | |
13 | + "key": "totalAmount" | |
14 | + } | |
15 | + ], | |
16 | + "source": [ | |
17 | + { | |
18 | + "key": 0, | |
19 | + "productName": "产品A1", | |
20 | + "totalSum": 10, | |
21 | + "totalAmount": 10 | |
22 | + }, | |
23 | + { | |
24 | + "key": 1, | |
25 | + "productName": "产品B1", | |
26 | + "totalSum": 10, | |
27 | + "totalAmount": 10 | |
28 | + }, | |
29 | + { | |
30 | + "key": 2, | |
31 | + "productName": "产品C1", | |
32 | + "totalSum": 10, | |
33 | + "totalAmount": 10 | |
34 | + }, | |
35 | + { | |
36 | + "key": 3, | |
37 | + "productName": "产品D1", | |
38 | + "totalSum": 10, | |
39 | + "totalAmount": 10 | |
40 | + }, | |
41 | + { | |
42 | + "key": 4, | |
43 | + "productName": "产品A2", | |
44 | + "totalSum": 10, | |
45 | + "totalAmount": 10 | |
46 | + }, | |
47 | + { | |
48 | + "key": 5, | |
49 | + "productName": "产品D2", | |
50 | + "totalSum": 10, | |
51 | + "totalAmount": 10 | |
52 | + }, | |
53 | + { | |
54 | + "key": 6, | |
55 | + "productName": "产品A3", | |
56 | + "totalSum": 10, | |
57 | + "totalAmount": 10 | |
58 | + } | |
59 | + ] | |
60 | +} | ... | ... |
1 | +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d' | |
2 | +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Tables/index.d' | |
3 | +import { useWidgetKey } from '@/packages/external/useWidgetKey' | |
4 | + | |
5 | +const { key, conKey, chartKey } = useWidgetKey('OverrideTablesBasic', true) | |
6 | + | |
7 | +export const OverrideTablesBasicConfig: ConfigType = { | |
8 | + key, | |
9 | + chartKey, | |
10 | + conKey, | |
11 | + title: '分页表格(适合告警或者设备列表)', | |
12 | + category: ChatCategoryEnum.TABLE, | |
13 | + categoryName: ChatCategoryEnumName.TABLE, | |
14 | + package: PackagesCategoryEnum.TABLES, | |
15 | + chartFrame: ChartFrameEnum.COMMON, | |
16 | + image: 'tables_basic.png' | |
17 | +} | ... | ... |
1 | +<template> | |
2 | + <div class="go-tables-basic"> | |
3 | + <n-space> | |
4 | + <n-form v-if="inputShow" :model="dynamicForm" :style="{ maxWidth: '640px' }" inline> | |
5 | + <n-form-item v-for="(item, index) in dynamicForm.keys" :key="index" > | |
6 | + <n-input v-model:value="item.value" clearable :placeholder=" `请输入${item.key.split(',').at(-2)}`"> | |
7 | + <template #prefix> | |
8 | + <n-icon :component="SearchIcon" /> | |
9 | + </template> | |
10 | + </n-input> | |
11 | + </n-form-item> | |
12 | + </n-form> | |
13 | + </n-space> | |
14 | + <n-data-table | |
15 | + remote | |
16 | + :style="` | |
17 | + width: ${w}px; | |
18 | + height: ${h}px; | |
19 | + font-size: ${option.style.fontSize}px; | |
20 | + border-width: ${option.style.border === 'on' ? option.style.borderWidth : 0}px; | |
21 | + border-color: ${option.style.borderColor}; | |
22 | + border-style: ${option.style.borderStyle}`" | |
23 | + :bordered="option.style.border === 'on'" | |
24 | + :single-column="option.style.singleColumn === 'on'" | |
25 | + :single-line="option.style.singleLine === 'on'" | |
26 | + :bottom-bordered="option.style.bottomBordered === 'on'" | |
27 | + :striped="option.style.striped === 'on'" | |
28 | + :max-height="h" | |
29 | + size="small" | |
30 | + :columns="option.dataset.dimensions" | |
31 | + :data="option.dataset.source" | |
32 | + :pagination="pagination" | |
33 | + /> | |
34 | + </div> | |
35 | +</template> | |
36 | + | |
37 | +<script setup lang="ts"> | |
38 | +import { PropType, toRefs, watch, reactive, ref, onMounted } from 'vue' | |
39 | +import { CreateComponentType } from '@/packages/index.d' | |
40 | +import { icon } from '@/plugins' | |
41 | +import { getAlarmList, getDeviceList } from '@/api/external/common' | |
42 | +import { useFilterFn } from '@/hooks/external/useFilterFn' | |
43 | +import dataJson from './data.json' | |
44 | + | |
45 | +const props = defineProps({ | |
46 | + chartConfig: { | |
47 | + type: Object as PropType<CreateComponentType>, | |
48 | + required: true | |
49 | + } | |
50 | +}) | |
51 | + | |
52 | +const { SearchIcon } = icon.ionicons5 | |
53 | + | |
54 | +const { align, pagination, inputShow, dynamicForm } = toRefs(props.chartConfig.option) | |
55 | + | |
56 | +pagination.value.onChange = (page: number) => { | |
57 | + pagination.value.page = page | |
58 | +} | |
59 | + | |
60 | +const { w, h } = toRefs(props.chartConfig.attr) | |
61 | + | |
62 | +const option = reactive({ | |
63 | + dataset: props.chartConfig.option.dataset, | |
64 | + style: props.chartConfig.option.style | |
65 | +}) | |
66 | + | |
67 | +watch( | |
68 | + () => props.chartConfig.option.dataset, | |
69 | + (newData: Recordable) => { | |
70 | + option.dataset = newData | |
71 | + option?.dataset?.dimensions?.forEach((header: Recordable) => { | |
72 | + header.align = align.value | |
73 | + }) | |
74 | + }, | |
75 | + { | |
76 | + immediate: true, | |
77 | + deep: true | |
78 | + } | |
79 | +) | |
80 | + | |
81 | +const alarmParams = ref({}) | |
82 | + | |
83 | +watch( | |
84 | + () => props.chartConfig.option, | |
85 | + newData => { | |
86 | + const { dynamicForm } = newData | |
87 | + const { keys } = dynamicForm | |
88 | + alarmParams.value = keys.reduce((acc: Recordable, curr: Recordable) => { | |
89 | + const param = { | |
90 | + [curr.key.split(',').at(-1)]: curr.value | |
91 | + } | |
92 | + Object.assign(acc, param) | |
93 | + return acc | |
94 | + }, {}) | |
95 | + fetchAlarmList(props.chartConfig.filter!, props.chartConfig.request!, { | |
96 | + ...alarmParams.value, | |
97 | + page: pagination.value.page, | |
98 | + pageSize: pagination.value.pageSize | |
99 | + }) | |
100 | + }, | |
101 | + { | |
102 | + deep: true | |
103 | + } | |
104 | +) | |
105 | + | |
106 | +const fetchAlarmList = async (filterStr: string, request: Recordable, params: Recordable) => { | |
107 | + const { requestUrl } = request | |
108 | + let res = null | |
109 | + if (requestUrl === '/api/yt/alarm') { | |
110 | + res = await getAlarmList(params) | |
111 | + } else if (requestUrl === '/api/yt/device') { | |
112 | + const { page, pageSize, ...rest } = params | |
113 | + res = await getDeviceList( | |
114 | + { | |
115 | + page: params.page, | |
116 | + pageSize: params.pageSize | |
117 | + }, | |
118 | + Object.keys(rest).length === 0 ? {"name": ""} : rest | |
119 | + ) | |
120 | + } | |
121 | + if (filterStr) { | |
122 | + const filterRes = useFilterFn(filterStr, res) | |
123 | + const { value } = filterRes | |
124 | + option.dataset = value | |
125 | + pagination.value.itemCount = res.total | |
126 | + } else { | |
127 | + option.dataset = dataJson | |
128 | + } | |
129 | +} | |
130 | + | |
131 | +onMounted(() => { | |
132 | + fetchAlarmList(props.chartConfig.filter!, props.chartConfig.request!, { | |
133 | + page: pagination.value.page, | |
134 | + pageSize: pagination.value.pageSize | |
135 | + }) | |
136 | +}) | |
137 | +</script> | |
138 | + | |
139 | +<style lang="scss" scoped> | |
140 | +@include go('tables-basic') { | |
141 | + display: flex; | |
142 | + flex-direction: column; | |
143 | + gap: 15px; | |
144 | + align-items: flex-end; | |
145 | +} | |
146 | +</style> | ... | ... |
... | ... | @@ -69,6 +69,7 @@ import { Decorates24Config } from '@/packages/components/external/Decorates/Deco |
69 | 69 | import { Decorates25Config } from '@/packages/components/external/Decorates/Decorates/Decorates25' |
70 | 70 | import { Decorates26Config } from '@/packages/components/external/Decorates/Decorates/Decorates26' |
71 | 71 | import { OverrideTableScrollBoardConfig } from '@/packages/components/external/Tables/Tables/OverrideTableScrollBoard' |
72 | +import { OverrideTablesBasicConfig } from '@/packages/components/external/Tables/Tables/OverrideTablesBasic' | |
72 | 73 | |
73 | 74 | |
74 | 75 | /** |
... | ... | @@ -156,6 +157,7 @@ export function useInjectLib(packagesList: EPackagesType) { |
156 | 157 | |
157 | 158 | //列表 |
158 | 159 | addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.TABLES, OverrideTableScrollBoardConfig)//重写列表下的轮播列表 |
160 | + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.TABLES, OverrideTablesBasicConfig)//重写列表下的轮播列表 | |
159 | 161 | // |
160 | 162 | } |
161 | 163 | ... | ... |
... | ... | @@ -185,6 +185,12 @@ export interface PublicConfigType { |
185 | 185 | } |
186 | 186 | } |
187 | 187 | |
188 | +export interface ChartCustomColor { | |
189 | + name: string | |
190 | + color: string[] | |
191 | +} | |
192 | + | |
193 | + | |
188 | 194 | export interface CreateComponentType extends PublicConfigType, requestConfig { |
189 | 195 | key: string |
190 | 196 | chartConfig: ConfigType |
... | ... | @@ -192,6 +198,7 @@ export interface CreateComponentType extends PublicConfigType, requestConfig { |
192 | 198 | groupList?: Array<CreateComponentType> |
193 | 199 | saveHistoryInput?: string // THINGS_KIT 新增一个接口字段 saveHistoryInput,用于记录当前组件id和输入框的内容,这里不能重写,有很多地方引用到的,这里升级版本有冲突 |
194 | 200 | wsOriginalMessage?: any |
201 | + colors?: ChartCustomColor // THINGS_KIT 新增一个接口字段 用于组件自定义颜色,一般是图表组件 | |
195 | 202 | } |
196 | 203 | |
197 | 204 | // 组件成组实例类 | ... | ... |
... | ... | @@ -40,7 +40,7 @@ import { ref, computed } from 'vue' |
40 | 40 | import cloneDeep from 'lodash/cloneDeep' |
41 | 41 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
42 | 42 | import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d' |
43 | -import { chartColors, ChartColorsNameType } from '@/settings/chartThemes/index' | |
43 | +import { ChartColorsNameType } from '@/settings/chartThemes/index' | |
44 | 44 | import { useDesignStore } from '@/store/modules/designStore/designStore' |
45 | 45 | import { loadAsyncComponent, colorCustomMerge } from '@/utils' |
46 | 46 | import { icon } from '@/plugins' | ... | ... |
... | ... | @@ -93,7 +93,8 @@ |
93 | 93 | <!-- 底部 --> |
94 | 94 | <template #action> |
95 | 95 | <n-space justify="end"> |
96 | - <n-button @click="closeHandle">操作完成</n-button> | |
96 | + <n-button @click="applicationGroupHandle" v-if="applicationGroup">应用此分组</n-button> | |
97 | + <n-button v-if="!applicationGroup" @click="closeHandle">操作完成</n-button> | |
97 | 98 | </n-space> |
98 | 99 | </template> |
99 | 100 | </n-card> |
... | ... | @@ -101,22 +102,27 @@ |
101 | 102 | </template> |
102 | 103 | |
103 | 104 | <script setup lang="ts"> |
104 | -import { ref, watch, computed, reactive, nextTick, onMounted } from 'vue' | |
105 | +import { ref, watch, computed, reactive, nextTick } from 'vue' | |
105 | 106 | import cloneDeep from 'lodash/cloneDeep' |
106 | 107 | import noData from '@/assets/images/canvas/noData.png' |
107 | 108 | import { getUUID, goDialog } from '@/utils' |
108 | 109 | import { icon } from '@/plugins' |
109 | -import { UvIndex } from '@vicons/carbon' | |
110 | 110 | import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' |
111 | 111 | import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d' |
112 | 112 | import { CreateColorRender } from '../CreateColorRender/index' |
113 | +import { useTargetData } from "@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook" | |
114 | + | |
115 | + | |
113 | 116 | |
114 | 117 | const props = defineProps({ |
115 | - modelShow: Boolean | |
118 | + modelShow: Boolean, | |
119 | + applicationGroup: Boolean, | |
116 | 120 | }) |
117 | 121 | const emit = defineEmits(['update:modelShow', 'editSaveHandle']) |
118 | 122 | const { DuplicateOutlineIcon, TrashIcon, ArrowDownIcon } = icon.ionicons5 |
119 | 123 | |
124 | +const { targetData } = useTargetData() | |
125 | + | |
120 | 126 | type ColorType = { |
121 | 127 | id: string |
122 | 128 | name: string |
... | ... | @@ -161,6 +167,7 @@ const selectThemeColor = computed(() => chartEditStore.getEditCanvasConfig.chart |
161 | 167 | |
162 | 168 | // 选择 |
163 | 169 | const selectHandle = (item: ColorType) => { |
170 | + targetData.value.colors = item | |
164 | 171 | if (item.id === selectColorId.value) return |
165 | 172 | if (updateColor.value !== undefined) { |
166 | 173 | goDialog({ |
... | ... | @@ -281,6 +288,11 @@ const closeHandle = () => { |
281 | 288 | const colorBackgroundImage = (item: ColorType) => { |
282 | 289 | return `linear-gradient(to right, ${item.color[0]} 0%, ${item.color[5]} 100%)` |
283 | 290 | } |
291 | + | |
292 | +//应用此分组 | |
293 | +const applicationGroupHandle = () => { | |
294 | + closeHandle() | |
295 | +} | |
284 | 296 | </script> |
285 | 297 | |
286 | 298 | <style scoped lang="scss"> | ... | ... |
... | ... | @@ -11,6 +11,7 @@ interface Value { |
11 | 11 | startTs?: Nullable<number> |
12 | 12 | endTs?: Nullable<number> |
13 | 13 | limit?: Nullable<number> |
14 | + shortcutsSelect?: Nullable<boolean> | |
14 | 15 | } |
15 | 16 | |
16 | 17 | const props = withDefaults( |
... | ... | @@ -32,24 +33,43 @@ const timePeriod = ref<Nullable<[number, number]>>(null) |
32 | 33 | const agg = ref() |
33 | 34 | const interval = ref() |
34 | 35 | const limit = ref(7) |
36 | +//区分是否是从快捷选项里选择的 | |
37 | +const shortcutsSelect = ref(false) | |
35 | 38 | const rangeShortcuts = { |
36 | 39 | 昨天: () => { |
40 | + shortcutsSelect.value = true | |
37 | 41 | return [ |
38 | 42 | dayjs().startOf('day').valueOf(), |
39 | 43 | dayjs().endOf('day').valueOf() |
40 | 44 | ] as const |
41 | 45 | }, |
42 | 46 | 最近7天: () => { |
47 | + shortcutsSelect.value = true | |
43 | 48 | return [ |
44 | 49 | dayjs().subtract(6, 'day').startOf('day').valueOf(), |
45 | 50 | dayjs().endOf('day').valueOf() |
46 | 51 | ] as const |
47 | 52 | }, |
48 | 53 | 最近30天: () => { |
54 | + shortcutsSelect.value = true | |
49 | 55 | return [ |
50 | 56 | dayjs().subtract(29, 'day').startOf('day').valueOf(), |
51 | 57 | dayjs().endOf('day').valueOf() |
52 | 58 | ] as const |
59 | + }, | |
60 | + 本周: () => { | |
61 | + shortcutsSelect.value = true | |
62 | + return [ | |
63 | + dayjs().startOf('week').add(1, 'day').valueOf(), | |
64 | + dayjs().endOf('week').add(1, 'day').valueOf(), | |
65 | + ] as const | |
66 | + }, | |
67 | + 本月: () => { | |
68 | + shortcutsSelect.value = true | |
69 | + return [ | |
70 | + dayjs().startOf('month').valueOf(), | |
71 | + dayjs().endOf('month').valueOf(), | |
72 | + ] as const | |
53 | 73 | } |
54 | 74 | } |
55 | 75 | |
... | ... | @@ -74,10 +94,15 @@ const getIntervalTimeOptions = computed(() => { |
74 | 94 | return getRangeOptions(diff) |
75 | 95 | }) |
76 | 96 | |
97 | +const handleTimeRangeBlur = () => { | |
98 | + //从面板里面选择 | |
99 | + shortcutsSelect.value = false | |
100 | +} | |
101 | + | |
77 | 102 | const handleTimePerionChange = (value: number[]) => { |
78 | 103 | const [startTs, endTs] = value || [] |
79 | - emit('update:value', {...props.value, startTs, endTs, interval: null}) | |
80 | - emit('change', {...props.value || {}, startTs, endTs, interval: null}) | |
104 | + emit('update:value', {...props.value, startTs, endTs, interval: null, shortcutsSelect: shortcutsSelect.value}) | |
105 | + emit('change', {...props.value || {}, startTs, endTs, interval: null, shortcutsSelect: shortcutsSelect.value}) | |
81 | 106 | } |
82 | 107 | |
83 | 108 | const handleAggChange = (value: string) => { |
... | ... | @@ -120,6 +145,7 @@ watch(() => props.value, (target) => { |
120 | 145 | <NFormItem :show-label="false"> |
121 | 146 | <NDatePicker :shortcuts="rangeShortcuts" v-model:value="timePeriod" type="datetimerange" |
122 | 147 | placeholder="请选择时间范围" |
148 | + @blur="handleTimeRangeBlur" | |
123 | 149 | @update-value="handleTimePerionChange" clearable |
124 | 150 | :default-time="['00:00:00', '23:59:59']"></NDatePicker> |
125 | 151 | </NFormItem> | ... | ... |
... | ... | @@ -6,10 +6,6 @@ |
6 | 6 | <n-code word-wrap :code="toString(targetData.option.dataset)" language="json"></n-code> |
7 | 7 | </n-card> |
8 | 8 | <n-tag type="info"> 目前支持实时多属性 </n-tag> |
9 | - <!-- <n-tag type="warning">示例:res.xxxx</n-tag> --> | |
10 | - <!-- <span>目前支持实时多属性</span> --> | |
11 | - <!-- <n-input type="textarea" @input="handleTestInput($event, option)" size="small" placeholder="请输入"></n-input> | |
12 | - <n-code word-wrap :code="toString(testInputValue)" language="json"></n-code> --> | |
13 | 9 | <n-divider /> |
14 | 10 | <div v-for="(item, index) in groupList" :key="item.key + index"> |
15 | 11 | <n-space justify="space-between"> |
... | ... | @@ -28,7 +24,6 @@ |
28 | 24 | </n-space> |
29 | 25 | <n-space vertical justify="space-between"> |
30 | 26 | <n-ellipsis>数据内容 </n-ellipsis> |
31 | - <!-- @update:value="handleInput(groupList!, item.id, $event)" --> | |
32 | 27 | <n-input |
33 | 28 | type="textarea" |
34 | 29 | size="small" |
... | ... | @@ -52,11 +47,11 @@ import { SelectOption } from 'naive-ui' |
52 | 47 | |
53 | 48 | const { targetData } = useTargetData() |
54 | 49 | |
55 | -const { groupList, option } = toRefs(targetData.value) | |
50 | +const { groupList, option } = toRefs(targetData.value as unknown as Recordable) | |
56 | 51 | |
57 | 52 | const saveHistoryInputValueList = ref<saveHistoryInputValueListType>([]) |
58 | 53 | |
59 | -const handleSelectDataKey = (key:string, options:SelectOption[], currentComponentId:string, groupList:CreateComponentType[]) => { | |
54 | +const handleSelectDataKey = (key:string, _:SelectOption[], currentComponentId:string, groupList:CreateComponentType[]) => { | |
60 | 55 | saveHistoryInputValueList.value.unshift({ |
61 | 56 | id:currentComponentId, |
62 | 57 | inputValue:key |
... | ... | @@ -64,14 +59,6 @@ const handleSelectDataKey = (key:string, options:SelectOption[], currentComponen |
64 | 59 | handleGroupListById(groupList, currentComponentId, key, option.value.dataset) |
65 | 60 | } |
66 | 61 | |
67 | -// const handleInput = (groupList: CreateComponentType[], id: string, inputValue: string) => { | |
68 | -// saveHistoryInputValueList.value.unshift({ | |
69 | -// id, | |
70 | -// inputValue | |
71 | -// }) | |
72 | -// handleGroupListById(groupList, id, inputValue, option.value.dataset) | |
73 | -// } | |
74 | - | |
75 | 62 | const executeFn = (inputValue: string, dataset: any) => { |
76 | 63 | try { |
77 | 64 | return Function('res', `return ${dataset[inputValue]}`)(dataset) | ... | ... |
... | ... | @@ -38,7 +38,7 @@ |
38 | 38 | :is="item.chartConfig.chartKey" |
39 | 39 | :chartConfig="item" |
40 | 40 | :themeSetting="themeSetting" |
41 | - :themeColor="themeColor" | |
41 | + :themeColor="item.colors ? item.colors : themeColor" | |
42 | 42 | :style="{ |
43 | 43 | ...useSizeStyle(item.attr), |
44 | 44 | ...getFilterStyle(item.styles), | ... | ... |
... | ... | @@ -28,7 +28,7 @@ |
28 | 28 | @contextmenu="handleContextMenu($event, item, optionsHandle)"> |
29 | 29 | <component class="edit-content-chart" :class="animationsClass(item.styles.animations)" |
30 | 30 | :is="item.chartConfig.chartKey" :chartConfig="item" :themeSetting="themeSetting" |
31 | - :themeColor="themeColor" :style="{ | |
31 | + :themeColor="item.colors ? item.colors : themeColor" :style="{ | |
32 | 32 | ...useSizeStyle(item.attr), |
33 | 33 | ...getFilterStyle(item.styles), |
34 | 34 | ...getTransformStyle(item.styles), | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | :groupData="(item as CreateComponentGroupType)" |
21 | 21 | :groupIndex="index" |
22 | 22 | :themeSetting="themeSetting" |
23 | - :themeColor="themeColor" | |
23 | + :themeColor="item.colors ? item.colors : themeColor" | |
24 | 24 | ></preview-render-group> |
25 | 25 | |
26 | 26 | <!-- 单组件 --> |
... | ... | @@ -30,7 +30,7 @@ |
30 | 30 | :id="item.id" |
31 | 31 | :chartConfig="item" |
32 | 32 | :themeSetting="themeSetting" |
33 | - :themeColor="themeColor" | |
33 | + :themeColor="item.colors ? item.colors : themeColor" | |
34 | 34 | :style="{ |
35 | 35 | ...getSizeStyle(item.attr), |
36 | 36 | ...getFilterStyle(item.styles), | ... | ... |