Commit 912bab9c038663da8a39f4e620ccab5039314b69

Authored by ww
1 parent 4a33f5dd

chore: 合并go-view 代码

Showing 72 changed files with 1934 additions and 211 deletions
... ... @@ -172,7 +172,9 @@ export const customizeHttp = (targetParams: RequestConfigType, globalParams: Req
172 172
173 173 case RequestBodyEnum.JSON:
174 174 headers['Content-Type'] = ContentTypeEnum.JSON
175   - data = translateStr(JSON.parse(targetRequestParams.Body['json']))
  175 + //json对象也能使用'javasctipt:'来动态拼接参数
  176 + data = translateStr(targetRequestParams.Body['json'])
  177 + if(typeof data === 'string') data = JSON.parse(data)
176 178 // json 赋值给 data
177 179 break
178 180
... ...
... ... @@ -25,6 +25,7 @@ import { icon } from '@/plugins'
25 25 import { useUserStore } from '@/store/external/module/user'
26 26 const { ChatboxEllipsesIcon, PersonIcon, LogOutOutlineIcon, SettingsSharpIcon } = icon.ionicons5
27 27
  28 +
28 29 const t = window['$t']
29 30
30 31 const modelShowInfo = ref(false)
... ... @@ -46,7 +47,11 @@ const renderUserInfo = () => {
46 47 style: 'margin-right: 12px;',
47 48 src: Person
48 49 }),
  50 + h('div', null, [
  51 + h('div', null, [
49 52 h('div', null, [h('div', null, [h(NText, { depth: 2 }, { default: () => '奔跑的面条' })])])
  53 + ])
  54 + ])
50 55 ]
51 56 )
52 57 }
... ...
... ... @@ -28,4 +28,9 @@ export const excludeParseEventKeyList = [
28 28 BaseEvent.ON_MOUSE_LEAVE,
29 29 //过滤器
30 30 'filter'
31   -]
\ No newline at end of file
  31 +]
  32 +// 内置字符串函数键值列表
  33 +export const excludeParseEventValueList = [
  34 + // 请求里的函数语句
  35 + 'javascript:'
  36 +]
... ...
... ... @@ -29,6 +29,7 @@ export enum PageEnum {
29 29 RELOAD = '/reload',
30 30 RELOAD_NAME = 'Reload',
31 31
  32 +
32 33 // 首页
33 34 BASE_HOME = '/project',
34 35 BASE_HOME_NAME = 'Project',
... ...
1 1 <template>
2 2 <n-layout-header bordered class="go-header">
3   - <header class="go-header-box">
  3 + <header class="go-header-box" :class="{ 'is-project': isProject }">
4 4 <div class="header-item left">
5 5 <n-space>
6 6 <slot name="left"></slot>
... ... @@ -23,17 +23,29 @@
23 23 </template>
24 24
25 25 <script setup lang="ts">
  26 +import { computed } from 'vue'
  27 +import { useRoute } from 'vue-router'
26 28 import { GoThemeSelect } from '@/components/GoThemeSelect'
27 29 import { GoLangSelect } from '@/components/GoLangSelect'
28 30 import { ThemeColorSelect } from '@/components/Pages/ThemeColorSelect'
  31 +import { PageEnum } from '@/enums/pageEnum'
  32 +
  33 +const route = useRoute()
  34 +
  35 +const isProject = computed(() => {
  36 + return route.fullPath === PageEnum.BASE_HOME_ITEMS
  37 +})
29 38 </script>
30 39
31 40 <style lang="scss" scoped>
32   -$min-width: 400px;
  41 +$min-width: 520px;
33 42 @include go(header) {
34 43 &-box {
35 44 display: grid;
36   - grid-template-columns: repeat(3, 33.33%);
  45 + grid-template-columns: repeat(3, 33%);
  46 + &.is-project {
  47 + grid-template-columns: none;
  48 + }
37 49 .header-item {
38 50 display: flex;
39 51 align-items: center;
... ... @@ -49,7 +61,7 @@ $min-width: 400px;
49 61 }
50 62 }
51 63 height: $--header-height;
52   - padding: 0 60px;
  64 + padding: 0 20px 0 60px;
53 65 }
54 66 }
55 67 </style>
... ...
1 1 import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
2 2 import { LineCommonConfig } from './index'
3 3 import { CreateComponentType } from '@/packages/index.d'
4   -import { defaultTheme, chartColorsSearch } from '@/settings/chartThemes/index'
5 4 import cloneDeep from 'lodash/cloneDeep'
6 5 import dataJson from './data.json'
7 6
... ...
... ... @@ -15,7 +15,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
15 15 import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index'
16 16 import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
17 17 import { useChartDataFetch } from '@/hooks'
18   -import { isPreview } from '@/utils'
  18 +import { isPreview, colorGradientCustomMerge} from '@/utils'
19 19
20 20 const props = defineProps({
21 21 themeSetting: {
... ... @@ -45,7 +45,9 @@ watch(
45 45 (newColor: keyof typeof chartColorsSearch) => {
46 46 try {
47 47 if (!isPreview()) {
48   - const themeColor = chartColorsSearch[newColor] || chartColorsSearch[defaultTheme]
  48 + const themeColor =
  49 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[newColor] ||
  50 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[defaultTheme]
49 51 props.chartConfig.option.series.forEach((value: any, index: number) => {
50 52 value.areaStyle.color = new graphic.LinearGradient(0, 0, 0, 1, [
51 53 {
... ...
... ... @@ -14,7 +14,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
14 14 import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index'
15 15 import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
16 16 import { useChartDataFetch } from '@/hooks'
17   -import { isPreview } from '@/utils'
  17 +import { isPreview, colorGradientCustomMerge} from '@/utils'
18 18
19 19 const props = defineProps({
20 20 themeSetting: {
... ... @@ -43,8 +43,9 @@ watch(
43 43 () => chartEditStore.getEditCanvasConfig.chartThemeColor,
44 44 (newColor: keyof typeof chartColorsSearch) => {
45 45 try {
46   - if (!isPreview()) {
  46 + if (!isPreview()) {
47 47 const themeColor = chartColorsSearch[newColor] || chartColorsSearch[defaultTheme]
  48 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[defaultTheme]
48 49 props.chartConfig.option.series.forEach((value: any, index: number) => {
49 50 value.areaStyle.color = new graphic.LinearGradient(0, 0, 0, 1, [
50 51 {
... ...
... ... @@ -15,7 +15,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
15 15 import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index'
16 16 import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
17 17 import { useChartDataFetch } from '@/hooks'
18   -import { isPreview } from '@/utils'
  18 +import { isPreview, colorGradientCustomMerge } from '@/utils'
19 19
20 20 const props = defineProps({
21 21 themeSetting: {
... ... @@ -45,7 +45,9 @@ watch(
45 45 (newColor: keyof typeof chartColorsSearch) => {
46 46 try {
47 47 if (!isPreview()) {
48   - const themeColor = chartColorsSearch[newColor] || chartColorsSearch[defaultTheme]
  48 + const themeColor =
  49 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[newColor] ||
  50 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[defaultTheme]
49 51 props.chartConfig.option.series.forEach((value: any) => {
50 52 value.lineStyle.shadowColor = themeColor[2]
51 53 value.lineStyle.color.colorStops.forEach((v: { color: string }, i: number) => {
... ...
... ... @@ -59,13 +59,14 @@ const getGeojson = (regionId: string) => {
59 59 }
60 60
61 61 //异步时先注册空的 保证初始化不报错
62   -registerMap(props.chartConfig.option.mapRegion.adcode, { geoJSON: {} as any, specialAreas: {} })
  62 +registerMap(`${props.chartConfig.option.mapRegion.adcode}`, { geoJSON: {} as any, specialAreas: {} })
63 63
64 64 // 进行更换初始化地图 如果为china 单独处理
65 65 const registerMapInitAsync = async () => {
66 66 await nextTick()
67   - if (props.chartConfig.option.mapRegion.adcode != 'china') {
68   - await getGeojson(props.chartConfig.option.mapRegion.adcode)
  67 + const adCode = `${props.chartConfig.option.mapRegion.adcode}`;
  68 + if (adCode !== 'china') {
  69 + await getGeojson(adCode)
69 70 } else {
70 71 await hainanLandsHandle(props.chartConfig.option.mapRegion.showHainanIsLands)
71 72 }
... ... @@ -127,7 +128,7 @@ watch(
127 128
128 129 //监听地图展示区域发生变化
129 130 watch(
130   - () => props.chartConfig.option.mapRegion.adcode,
  131 + () => `${props.chartConfig.option.mapRegion.adcode}`,
131 132 async newData => {
132 133 try {
133 134 await getGeojson(newData)
... ...
... ... @@ -10,7 +10,7 @@ import 'echarts-liquidfill/src/liquidFill.js'
10 10 import { CanvasRenderer } from 'echarts/renderers'
11 11 import { GridComponent } from 'echarts/components'
12 12 import config from './config'
13   -import { isPreview, isString, isNumber } from '@/utils'
  13 +import { isPreview, isString, isNumber, colorGradientCustomMerge } from '@/utils'
14 14 import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index'
15 15 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
16 16 import { useChartDataFetch } from '@/hooks'
... ... @@ -44,7 +44,9 @@ watch(
44 44 (newColor: keyof typeof chartColorsSearch) => {
45 45 try {
46 46 if (!isPreview()) {
47   - const themeColor = chartColorsSearch[newColor] || chartColorsSearch[defaultTheme]
  47 + const themeColor =
  48 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[newColor] ||
  49 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[defaultTheme]
48 50 // 背景颜色
49 51 props.chartConfig.option.series[0].backgroundStyle.color = themeColor[2]
50 52 // 水球颜色
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { CreateComponentType } from '@/packages/index.d'
  3 +import { CarouselConfig } from './index'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import logo from '@/assets/logo.png'
  6 +
  7 +// 示例图片资源
  8 +const modules = import.meta.globEager("./images/*");
  9 +const dataset = [logo]
  10 +for (var item in modules) {
  11 + dataset.push(modules[item].default)
  12 +}
  13 +
  14 +export const option = {
  15 + // 图片资源列表
  16 + dataset: dataset,
  17 + // 自动播放
  18 + autoplay: true,
  19 + // 自动播放的间隔(ms)
  20 + interval: 5000,
  21 + // 每页显示的图片数量
  22 + slidesPerview: 1,
  23 + // 轮播方向
  24 + direction: "horizontal",
  25 + // 拖曳切换
  26 + draggable: true,
  27 + // 居中显示
  28 + centeredSlides: false,
  29 + // 过渡效果
  30 + effect: "slide",
  31 + // 是否显示指示点
  32 + showDots: true,
  33 + // 指示器样式
  34 + dotType: "dot",
  35 + // 指示器位置
  36 + dotPlacement: "bottom",
  37 + // 显示箭头
  38 + showArrow: false,
  39 + // 图片样式
  40 + fit: "contain",
  41 +}
  42 +
  43 +export default class Config extends PublicConfigClass implements CreateComponentType {
  44 + public key = CarouselConfig.key
  45 + public chartConfig = cloneDeep(CarouselConfig)
  46 + public option = cloneDeep(option)
  47 +}
... ...
  1 +<template>
  2 + <collapse-item name="属性" :expanded="true">
  3 + <setting-item-box name="路径" :alone="true">
  4 + <setting-item v-for="item, index in optionData.dataset" :key="index">
  5 + <n-input-group>
  6 + <n-input v-model:value="optionData.dataset[index]" size="small" placeholder="请输入图片地址"></n-input>
  7 + <n-button ghost @click="optionData.dataset.splice(index, 1)">
  8 + -
  9 + </n-button>
  10 + </n-input-group>
  11 + </setting-item>
  12 + <setting-item>
  13 + <n-button size="small" @click="optionData.dataset.push('')">
  14 + +
  15 + </n-button>
  16 + </setting-item>
  17 + </setting-item-box>
  18 + <setting-item-box name="播放器">
  19 + <setting-item>
  20 + <n-space>
  21 + <n-switch v-model:value="optionData.autoplay" size="small" />
  22 + <n-text>自动播放</n-text>
  23 + </n-space>
  24 + </setting-item>
  25 + <!-- 开启自动播放时,设置间隔时间 -->
  26 + <setting-item name="间隔时间">
  27 + <n-input-number v-model:value="optionData.interval" size="small" placeholder=""></n-input-number>
  28 + </setting-item>
  29 + <setting-item name="轮播方向">
  30 + <n-select v-model:value="optionData.direction" :options="directions" placeholder="选择方向" />
  31 + </setting-item>
  32 + <setting-item name="过渡效果">
  33 + <n-select v-model:value="optionData.effect" :options="effects" placeholder="效果" />
  34 + </setting-item>
  35 + <setting-item name="每页数量">
  36 + <n-input-number v-model:value="optionData.slidesPerview" size="small" placeholder=""></n-input-number>
  37 + </setting-item>
  38 + <setting-item>
  39 + <n-space>
  40 + <n-switch v-model:value="optionData.centeredSlides" size="small" />
  41 + <n-text>居中显示</n-text>
  42 + </n-space>
  43 + </setting-item>
  44 + <setting-item name="图片样式">
  45 + <n-select v-model:value="optionData.fit" :options="fitList" placeholder="样式" />
  46 + </setting-item>
  47 + </setting-item-box>
  48 +
  49 + <setting-item-box name="指示器">
  50 + <setting-item name="样式">
  51 + <n-select v-model:value="optionData.dotType" :options="dotTypes" placeholder="选择样式" />
  52 + </setting-item>
  53 + <setting-item name="位置">
  54 + <n-select v-model:value="optionData.dotPlacement" :options="dotPlacements" placeholder="选择位置" />
  55 + </setting-item>
  56 + <setting-item>
  57 + <n-space>
  58 + <n-switch v-model:value="optionData.showDots" size="small" />
  59 + <n-text>显示</n-text>
  60 + </n-space>
  61 + </setting-item>
  62 + <setting-item>
  63 + <n-space>
  64 + <n-switch v-model:value="optionData.showArrow" size="small" />
  65 + <n-text>箭头</n-text>
  66 + </n-space>
  67 + </setting-item>
  68 + <setting-item>
  69 + <n-space>
  70 + <n-switch v-model:value="optionData.draggable" size="small" />
  71 + <n-text>拖曳切换</n-text>
  72 + </n-space>
  73 + </setting-item>
  74 + </setting-item-box>
  75 +
  76 + </collapse-item>
  77 +</template>
  78 +
  79 +<script setup lang="ts">
  80 +import { PropType } from 'vue'
  81 +import { option } from './config'
  82 +import {
  83 + CollapseItem,
  84 + SettingItemBox,
  85 + SettingItem
  86 +} from '@/components/Pages/ChartItemSetting'
  87 +
  88 +const props = defineProps({
  89 + optionData: {
  90 + type: Object as PropType<typeof option>,
  91 + required: true
  92 + }
  93 +})
  94 +
  95 +// 字典
  96 +const dotTypes = [
  97 + {
  98 + label: "点",
  99 + value: "dot"
  100 + },
  101 + {
  102 + label: "线",
  103 + value: "line"
  104 + }
  105 +]
  106 +const directions = [
  107 + {
  108 + label: "水平方向",
  109 + value: "horizontal"
  110 + },
  111 + {
  112 + label: "垂直方向",
  113 + value: "vertical"
  114 + }
  115 +]
  116 +const effects = [
  117 + {
  118 + label: "slide",
  119 + value: "slide"
  120 + },
  121 + {
  122 + label: "fade",
  123 + value: "fade"
  124 + },
  125 + {
  126 + label: "card",
  127 + value: "card"
  128 + },
  129 + {
  130 + label: "custom",
  131 + value: "custom"
  132 + }
  133 +]
  134 +const dotPlacements = [
  135 + {
  136 + label: "上边",
  137 + value: "top"
  138 + },
  139 + {
  140 + label: "下边",
  141 + value: "bottom"
  142 + },
  143 + {
  144 + label: "左边",
  145 + value: "left"
  146 + },
  147 + {
  148 + label: "右边",
  149 + value: "right"
  150 + }
  151 +]
  152 +
  153 +// 适应类型
  154 +const fitList = [
  155 + {
  156 + value: 'fill',
  157 + label: 'fill'
  158 + },
  159 + {
  160 + value: 'contain',
  161 + label: 'contain'
  162 + },
  163 + {
  164 + value: 'cover',
  165 + label: 'cover'
  166 + },
  167 + {
  168 + value: 'scale-down',
  169 + label: 'scale-down'
  170 + },
  171 + {
  172 + value: 'none',
  173 + label: 'none'
  174 + },
  175 +]
  176 +</script>
... ...
  1 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  2 +import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'
  3 +
  4 +export const CarouselConfig: ConfigType = {
  5 + key: 'Carousel',
  6 + chartKey: 'VCarousel',
  7 + conKey: 'VCCarousel',
  8 + title: '轮播图',
  9 + category: ChatCategoryEnum.MORE,
  10 + categoryName: ChatCategoryEnumName.MORE,
  11 + package: PackagesCategoryEnum.INFORMATIONS,
  12 + chartFrame: ChartFrameEnum.NAIVE_UI,
  13 + image: 'photo.png'
  14 +}
... ...
  1 +<template>
  2 + <div>
  3 + <n-carousel :autoplay="autoplay" :interval="interval" :centered-slides="centeredSlides" :direction="direction"
  4 + :dot-placement="dotPlacement" :dot-type="dotType" :draggable="draggable" :effect="effect"
  5 + :slides-per-view="slidesPerview" :show-arrow="showArrow" :show-dots="showDots">
  6 + <n-image v-for="url in option.dataset" :object-fit="fit" preview-disabled :src="url"
  7 + :fallback-src="requireErrorImg()" :width="w" :height="h"></n-image>
  8 + </n-carousel>
  9 + </div>
  10 +</template>
  11 +<script setup lang="ts">
  12 +import { PropType, toRefs, shallowReactive, watch } from 'vue'
  13 +import { CreateComponentType } from '@/packages/index.d'
  14 +import { requireErrorImg } from '@/utils'
  15 +import { useChartDataFetch } from '@/hooks'
  16 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  17 +import { option as configOption } from './config'
  18 +
  19 +const props = defineProps({
  20 + chartConfig: {
  21 + type: Object as PropType<CreateComponentType>,
  22 + required: true
  23 + }
  24 +})
  25 +
  26 +const option = shallowReactive({
  27 + dataset: configOption.dataset
  28 +})
  29 +
  30 +const { w, h } = toRefs(props.chartConfig.attr)
  31 +const { autoplay, interval, slidesPerview, direction, draggable, centeredSlides, effect, dotType, dotPlacement, showArrow, showDots, fit } = toRefs(props.chartConfig.option)
  32 +
  33 +watch(
  34 + () => props.chartConfig.option.dataset,
  35 + (newData: any) => {
  36 + option.dataset = newData
  37 + },
  38 + {
  39 + immediate: true,
  40 + deep: false
  41 + }
  42 +)
  43 +
  44 +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
  45 + option.dataset = newData
  46 +})
  47 +</script>
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { CreateComponentType } from '@/packages/index.d'
  3 +import { ImageCarouselConfig } from './index'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import logo from '@/assets/logo.png'
  6 +
  7 +export const option = {
  8 + // 图片资源列表
  9 + dataset: [
  10 + 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel1.jpeg',
  11 + 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel2.jpeg',
  12 + 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel3.jpeg',
  13 + ],
  14 + // 自动播放
  15 + autoplay: true,
  16 + // 自动播放的间隔(豪秒)
  17 + interval: 5000,
  18 + // 每页显示的图片数量
  19 + slidesPerview: 1,
  20 + // 轮播方向
  21 + direction: "horizontal",
  22 + // 拖曳切换
  23 + draggable: true,
  24 + // 居中显示
  25 + centeredSlides: false,
  26 + // 过渡效果
  27 + effect: "slide",
  28 + // 是否显示指示点
  29 + showDots: true,
  30 + // 指示器样式
  31 + dotType: "dot",
  32 + // 指示器位置
  33 + dotPlacement: "bottom",
  34 + // 显示箭头
  35 + showArrow: false,
  36 + // 图片样式
  37 + fit: "contain",
  38 +}
  39 +
  40 +export default class Config extends PublicConfigClass implements CreateComponentType {
  41 + public key = ImageCarouselConfig.key
  42 + public chartConfig = cloneDeep(ImageCarouselConfig)
  43 + public option = cloneDeep(option)
  44 +}
... ...
  1 +<template>
  2 + <collapse-item name="路径" :expanded="true">
  3 + <setting-item v-for="(item, index) in optionData.dataset" :key="index">
  4 + <n-input-group>
  5 + <n-input v-model:value="optionData.dataset[index]" size="small" placeholder="请输入图片地址"></n-input>
  6 + <n-button ghost @click="optionData.dataset.splice(index, 1)"> - </n-button>
  7 + </n-input-group>
  8 + </setting-item>
  9 + <setting-item>
  10 + <n-button size="small" @click="optionData.dataset.push('')"> + 新增</n-button>
  11 + </setting-item>
  12 + </collapse-item>
  13 + <collapse-item name="轮播属性" :expanded="true">
  14 + <setting-item-box name="播放器">
  15 + <setting-item>
  16 + <n-space>
  17 + <n-switch v-model:value="optionData.autoplay" size="small" />
  18 + <n-text>自动播放</n-text>
  19 + </n-space>
  20 + </setting-item>
  21 + <!-- 开启自动播放时,设置间隔时间 -->
  22 + <setting-item name="间隔时间">
  23 + <n-input-number v-model:value="optionData.interval" size="small" placeholder="">
  24 + <template #suffix> 毫秒 </template>
  25 + </n-input-number>
  26 + </setting-item>
  27 + <setting-item name="轮播方向">
  28 + <n-select v-model:value="optionData.direction" :options="directions" placeholder="选择方向" />
  29 + </setting-item>
  30 + <setting-item name="过渡效果">
  31 + <n-select v-model:value="optionData.effect" :options="effects" placeholder="效果" />
  32 + </setting-item>
  33 + <setting-item name="每页数量">
  34 + <n-input-number v-model:value="optionData.slidesPerview" size="small" placeholder=""></n-input-number>
  35 + </setting-item>
  36 + <setting-item>
  37 + <n-space>
  38 + <n-switch v-model:value="optionData.centeredSlides" size="small" />
  39 + <n-text>居中显示</n-text>
  40 + </n-space>
  41 + </setting-item>
  42 + <setting-item name="图片样式">
  43 + <n-select v-model:value="optionData.fit" :options="fitList" placeholder="样式" />
  44 + </setting-item>
  45 + </setting-item-box>
  46 + <setting-item-box name="指示器">
  47 + <setting-item name="样式">
  48 + <n-select v-model:value="optionData.dotType" :options="dotTypes" placeholder="选择样式" />
  49 + </setting-item>
  50 + <setting-item name="位置">
  51 + <n-select v-model:value="optionData.dotPlacement" :options="dotPlacements" placeholder="选择位置" />
  52 + </setting-item>
  53 + <setting-item>
  54 + <n-space>
  55 + <n-switch v-model:value="optionData.showDots" size="small" />
  56 + <n-text>显示</n-text>
  57 + </n-space>
  58 + </setting-item>
  59 + <setting-item>
  60 + <n-space>
  61 + <n-switch v-model:value="optionData.showArrow" size="small" />
  62 + <n-text>箭头</n-text>
  63 + </n-space>
  64 + </setting-item>
  65 + <setting-item>
  66 + <n-space>
  67 + <n-switch v-model:value="optionData.draggable" size="small" />
  68 + <n-text>拖曳切换</n-text>
  69 + </n-space>
  70 + </setting-item>
  71 + </setting-item-box>
  72 + </collapse-item>
  73 +</template>
  74 +
  75 +<script setup lang="ts">
  76 +import { PropType } from 'vue'
  77 +import { option } from './config'
  78 +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  79 +
  80 +const props = defineProps({
  81 + optionData: {
  82 + type: Object as PropType<typeof option>,
  83 + required: true
  84 + }
  85 +})
  86 +
  87 +// 字典
  88 +const dotTypes = [
  89 + {
  90 + label: '点',
  91 + value: 'dot'
  92 + },
  93 + {
  94 + label: '线',
  95 + value: 'line'
  96 + }
  97 +]
  98 +const directions = [
  99 + {
  100 + label: '水平方向',
  101 + value: 'horizontal'
  102 + },
  103 + {
  104 + label: '垂直方向',
  105 + value: 'vertical'
  106 + }
  107 +]
  108 +const effects = [
  109 + {
  110 + label: 'slide',
  111 + value: 'slide'
  112 + },
  113 + {
  114 + label: 'fade',
  115 + value: 'fade'
  116 + },
  117 + {
  118 + label: 'card',
  119 + value: 'card'
  120 + },
  121 + {
  122 + label: 'custom',
  123 + value: 'custom'
  124 + }
  125 +]
  126 +const dotPlacements = [
  127 + {
  128 + label: '上边',
  129 + value: 'top'
  130 + },
  131 + {
  132 + label: '下边',
  133 + value: 'bottom'
  134 + },
  135 + {
  136 + label: '左边',
  137 + value: 'left'
  138 + },
  139 + {
  140 + label: '右边',
  141 + value: 'right'
  142 + }
  143 +]
  144 +
  145 +// 适应类型
  146 +const fitList = [
  147 + {
  148 + value: 'fill',
  149 + label: 'fill'
  150 + },
  151 + {
  152 + value: 'contain',
  153 + label: 'contain'
  154 + },
  155 + {
  156 + value: 'cover',
  157 + label: 'cover'
  158 + },
  159 + {
  160 + value: 'scale-down',
  161 + label: 'scale-down'
  162 + },
  163 + {
  164 + value: 'none',
  165 + label: 'none'
  166 + }
  167 +]
  168 +</script>
... ...
  1 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  2 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  3 +
  4 +export const ImageCarouselConfig: ConfigType = {
  5 + key: 'ImageCarousel',
  6 + chartKey: 'VImageCarousel',
  7 + conKey: 'VCImageCarousel',
  8 + title: '轮播图',
  9 + category: ChatCategoryEnum.MORE,
  10 + categoryName: ChatCategoryEnumName.MORE,
  11 + package: PackagesCategoryEnum.INFORMATIONS,
  12 + chartFrame: ChartFrameEnum.NAIVE_UI,
  13 + image: 'photo_carousel.png'
  14 +}
... ...
  1 +<template>
  2 + <div>
  3 + <n-carousel
  4 + :autoplay="autoplay"
  5 + :interval="interval"
  6 + :centered-slides="centeredSlides"
  7 + :direction="direction"
  8 + :dot-placement="dotPlacement"
  9 + :dot-type="dotType"
  10 + :draggable="draggable"
  11 + :effect="effect"
  12 + :slides-per-view="slidesPerview"
  13 + :show-arrow="showArrow"
  14 + :show-dots="showDots"
  15 + >
  16 + <n-image
  17 + v-for="(url, index) in option.dataset"
  18 + preview-disabled
  19 + :key="index"
  20 + :object-fit="fit"
  21 + :src="url"
  22 + :fallback-src="requireErrorImg()"
  23 + :width="w"
  24 + :height="h"
  25 + ></n-image>
  26 + </n-carousel>
  27 + </div>
  28 +</template>
  29 +<script setup lang="ts">
  30 +import { PropType, toRefs, shallowReactive, watch } from 'vue'
  31 +import { CreateComponentType } from '@/packages/index.d'
  32 +import { requireErrorImg } from '@/utils'
  33 +import { useChartDataFetch } from '@/hooks'
  34 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  35 +import { option as configOption } from './config'
  36 +
  37 +const props = defineProps({
  38 + chartConfig: {
  39 + type: Object as PropType<CreateComponentType>,
  40 + required: true
  41 + }
  42 +})
  43 +
  44 +const option = shallowReactive({
  45 + dataset: configOption.dataset
  46 +})
  47 +
  48 +const { w, h } = toRefs(props.chartConfig.attr)
  49 +const {
  50 + autoplay,
  51 + interval,
  52 + slidesPerview,
  53 + direction,
  54 + draggable,
  55 + centeredSlides,
  56 + effect,
  57 + dotType,
  58 + dotPlacement,
  59 + showArrow,
  60 + showDots,
  61 + fit
  62 +} = toRefs(props.chartConfig.option)
  63 +
  64 +watch(
  65 + () => props.chartConfig.option.dataset,
  66 + (newData: any) => {
  67 + option.dataset = newData
  68 + },
  69 + {
  70 + immediate: true,
  71 + deep: false
  72 + }
  73 +)
  74 +
  75 +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
  76 + option.dataset = newData
  77 +})
  78 +</script>
... ...
1 1 import { ImageConfig } from './Image/index'
  2 +import { ImageCarouselConfig } from './ImageCarousel/index'
2 3 import { IframeConfig } from './Iframe/index'
3 4 import { VideoConfig } from './Video/index'
4 5 import { WordCloudConfig } from './WordCloud/index'
  6 +import { CarouselConfig } from './Carousel/index'
5 7
6   -export default [WordCloudConfig, ImageConfig, VideoConfig, IframeConfig]
  8 +export default [ImageConfig, ImageCarouselConfig, VideoConfig, IframeConfig, WordCloudConfig]
... ...
... ... @@ -149,7 +149,7 @@ export enum PackagesCategoryEnum {
149 149 CHARTS = 'Charts',
150 150 TABLES = 'Tables',
151 151 INFORMATIONS = 'Informations',
152   - DECORATES = 'Decorates',
  152 + DECORATES = 'Decorates'
153 153 }
154 154
155 155 // 包分类名称
... ... @@ -157,7 +157,7 @@ export enum PackagesCategoryName {
157 157 CHARTS = '图表',
158 158 TABLES = '列表',
159 159 INFORMATIONS = '信息',
160   - DECORATES = '小组件',
  160 + DECORATES = '小组件'
161 161 }
162 162
163 163 // 获取组件
... ...
1 1 import {
  2 + Add as AddIcon,
2 3 Close as CloseIcon,
3 4 Remove as RemoveIcon,
4 5 Resize as ResizeIcon,
... ... @@ -52,6 +53,7 @@ import {
52 53 ColorWand as ColorWandIcon,
53 54 ArrowBack as ArrowBackIcon,
54 55 ArrowForward as ArrowForwardIcon,
  56 + ArrowDown as ArrowDownIcon,
55 57 Planet as PawIcon,
56 58 Search as SearchIcon,
57 59 ChevronUpOutline as ChevronUpOutlineIcon,
... ... @@ -64,7 +66,9 @@ import {
64 66 List as ListIcon,
65 67 EyeOutline as EyeOutlineIcon,
66 68 EyeOffOutline as EyeOffOutlineIcon,
67   - Albums as AlbumsIcon
  69 + Albums as AlbumsIcon,
  70 + Analytics as AnalyticsIcon,
  71 + SaveOutline as SaveIcon
68 72 } from '@vicons/ionicons5'
69 73
70 74 import {
... ... @@ -97,12 +101,12 @@ import {
97 101 Carbon3DSoftware as Carbon3DSoftwareIcon,
98 102 Filter as FilterIcon,
99 103 FilterEdit as FilterEditIcon,
100   - Laptop as LaptopIcon,
101   - // THINGS_KIT
102   - Save as SaveIcon
  104 + Laptop as LaptopIcon
103 105 } from '@vicons/carbon'
104 106
105 107 const ionicons5 = {
  108 + // 新增
  109 + AddIcon,
106 110 // 帮助(问号)
107 111 HelpOutlineIcon,
108 112 // 添加
... ... @@ -208,6 +212,8 @@ const ionicons5 = {
208 212 ArrowBackIcon,
209 213 // 前进
210 214 ArrowForwardIcon,
  215 + // 向下
  216 + ArrowDownIcon,
211 217 // 狗爪
212 218 PawIcon,
213 219 // 搜索(放大镜)
... ... @@ -233,8 +239,10 @@ const ionicons5 = {
233 239 // 眼睛
234 240 EyeOutlineIcon,
235 241 EyeOffOutlineIcon,
236   - // 图表列表
237   - AlbumsIcon
  242 + // 图表列表
  243 + AlbumsIcon,
  244 + // 分析
  245 + AnalyticsIcon
238 246 }
239 247
240 248 const carbon = {
... ...
... ... @@ -57,6 +57,7 @@ import {
57 57 NProgress,
58 58 NDatePicker,
59 59 NGrid,
  60 + NGi,
60 61 NGridItem,
61 62 NList,
62 63 NListItem,
... ... @@ -160,6 +161,7 @@ const naive = create({
160 161 NProgress,
161 162 NDatePicker,
162 163 NGrid,
  164 + NGi,
163 165 NGridItem,
164 166 NList,
165 167 NListItem,
... ...
... ... @@ -31,38 +31,20 @@ export const chartColors = {
31 31 // 默认主题
32 32 export const defaultTheme = 'dark'
33 33
34   -// 主题色列表
35   -export type ChartColorsNameType = keyof typeof chartColorsName
36   -export const chartColorsName = {
37   - dark: '明亮',
38   - customed: '暗淡',
39   - macarons: '马卡龙',
40   - walden: '蓝绿',
41   - purplePassion: '深紫',
42   - vintage: '复古',
43   - chalk: '粉青',
44   - westeros: '灰粉',
45   - wonderland: '青草',
46   - essos: '橘红',
47   - shine: '深色',
48   - roma: '罗马红'
49   -}
  34 +// 默认展示的选择器颜色列表
  35 +export const swatchesColors = ['#232324', '#2a2a2b', '#313132', '#373739', '#757575', '#e0e0e0', '#eeeeee', '#fafafa']
50 36
51   -// 主题色列表
52   -export const chartColorsshow = {
53   - dark: 'linear-gradient(to right, #4992ff 0%, #7cffb2 100%)',
54   - customed: 'linear-gradient(to right, #5470c6 0%, #91cc75 100%)',
55   - macarons: 'linear-gradient(to right, #2ec7c9 0%, #b6a2de 100%)',
56   - walden: 'linear-gradient(to right, #3fb1e3 0%, #6be6c1 100%)',
57   - purplePassion: 'linear-gradient(to right, #9b8bba 0%, #e098c7 100%)',
58   - vintage: 'linear-gradient(to right, #d87c7c 0%, #919e8b 100%)',
59   - chalk: 'linear-gradient(to right, #fc97af 0%, #87f7cf 100%)',
60   - westeros: 'linear-gradient(to right, #516b91 0%, #edafda 100%)',
61   - wonderland: 'linear-gradient(to right, #4ea397 0%, #22c3aa 100%)',
62   - essos: 'linear-gradient(to right, #893448 0%, #d95850 100%)',
63   - shine: 'linear-gradient(to right, #c12e34 0%, #0098d9 100%)',
64   - roma: 'linear-gradient(to right, #e01f54 0%, #5e4ea5 100%)'
  37 +// 自定义颜色
  38 +export type CustomColorsType = {
  39 + id: string,
  40 + name: string,
  41 + color: string[]
65 42 }
  43 +
  44 +// 主题色列表, 自定义的颜色使用的是 UUID 作为标识,因为两者数据结构不一致
  45 +export type ChartColorsNameType = keyof typeof chartColors
  46 +
  47 +
66 48 // 渐变主题色列表(主色1、主色2、阴影、渐变1、渐变2)
67 49 export const chartColorsSearch = {
68 50 dark: ['#4992ff', '#7cffb2', 'rgba(68, 181, 226, 0.3)', 'rgba(73, 146, 255, 0.5)', 'rgba(124, 255, 178, 0.5)'],
... ...
... ... @@ -8,5 +8,6 @@
8 8 "#d4a4eb",
9 9 "#d2f5a6",
10 10 "#76f2f2"
11   - ]
  11 + ],
  12 + "name": "粉青"
12 13 }
\ No newline at end of file
... ...
... ... @@ -9,5 +9,6 @@
9 9 "#fc8452",
10 10 "#9a60b4",
11 11 "#ea7ccc"
12   - ]
  12 + ],
  13 + "name": "暗淡"
13 14 }
\ No newline at end of file
... ...
... ... @@ -9,5 +9,6 @@
9 9 "#ff8a45",
10 10 "#8d48e3",
11 11 "#dd79ff"
12   - ]
  12 + ],
  13 + "name": "明亮"
13 14 }
\ No newline at end of file
... ...
... ... @@ -6,5 +6,6 @@
6 6 "#ffb248",
7 7 "#f2d643",
8 8 "#ebdba4"
9   - ]
  9 + ],
  10 + "name": "橘红"
10 11 }
\ No newline at end of file
... ...
... ... @@ -20,5 +20,6 @@
20 20 "#7eb00a",
21 21 "#6f5553",
22 22 "#c14089"
23   - ]
  23 + ],
  24 + "name": "马卡龙"
24 25 }
\ No newline at end of file
... ...
... ... @@ -6,5 +6,6 @@
6 6 "#71669e",
7 7 "#cc70af",
8 8 "#7cb4cc"
9   - ]
  9 + ],
  10 + "name": "深紫"
10 11 }
\ No newline at end of file
... ...
... ... @@ -20,5 +20,6 @@
20 20 "#3cb371",
21 21 "#d5b158",
22 22 "#38b6b6"
23   - ]
  23 + ],
  24 + "name": "罗马红"
24 25 }
\ No newline at end of file
... ...
... ... @@ -8,5 +8,6 @@
8 8 "#339ca8",
9 9 "#cda819",
10 10 "#32a487"
11   - ]
  11 + ],
  12 + "name": "深色"
12 13 }
\ No newline at end of file
... ...
... ... @@ -10,5 +10,6 @@
10 10 "#cc7e63",
11 11 "#724e58",
12 12 "#4b565b"
13   - ]
14   -}
\ No newline at end of file
  13 + ],
  14 + "name": "复古"
  15 +}
... ...
... ... @@ -6,5 +6,6 @@
6 6 "#a0a7e6",
7 7 "#c4ebad",
8 8 "#96dee8"
9   - ]
10   -}
\ No newline at end of file
  9 + ],
  10 + "name": "蓝绿"
  11 +}
... ...
... ... @@ -6,5 +6,6 @@
6 6 "#93b7e3",
7 7 "#a5e7f0",
8 8 "#cbb0e3"
9   - ]
10   -}
\ No newline at end of file
  9 + ],
  10 + "name": "灰粉"
  11 +}
... ...
... ... @@ -6,5 +6,6 @@
6 6 "#d0648a",
7 7 "#f58db2",
8 8 "#f2b3c9"
9   - ]
  9 + ],
  10 + "name": "青草"
10 11 }
\ No newline at end of file
... ...
... ... @@ -22,7 +22,8 @@ export enum EditCanvasTypeEnum {
22 22 LOCK_SCALE = 'lockScale',
23 23 IS_CREATE = 'isCreate',
24 24 IS_DRAG = 'isDrag',
25   - IS_SELECT = 'isSelect'
  25 + IS_SELECT = 'isSelect',
  26 + IS_CODE_EDIT="isCodeEdit"
26 27 }
27 28
28 29 // 编辑区域
... ... @@ -44,6 +45,8 @@ export type EditCanvasType = {
44 45 [EditCanvasTypeEnum.IS_DRAG]: boolean
45 46 // 框选中
46 47 [EditCanvasTypeEnum.IS_SELECT]: boolean
  48 + // 代码编辑中
  49 + [EditCanvasTypeEnum.IS_CODE_EDIT]: boolean
47 50 }
48 51
49 52 // 滤镜/背景色/宽高主题等
... ... @@ -52,6 +55,7 @@ export enum EditCanvasConfigEnum {
52 55 WIDTH = 'width',
53 56 HEIGHT = 'height',
54 57 CHART_THEME_COLOR = 'chartThemeColor',
  58 + CHART_CUSTOM_THEME_COLOR_INFO = 'chartCustomThemeColorInfo',
55 59 CHART_THEME_SETTING = 'chartThemeSetting',
56 60 BACKGROUND = 'background',
57 61 BACKGROUND_IMAGE = 'backgroundImage',
... ... @@ -87,9 +91,12 @@ export interface EditCanvasConfigType {
87 91 [EditCanvasConfigEnum.HEIGHT]: number
88 92 // 背景色
89 93 [EditCanvasConfigEnum.BACKGROUND]?: string
  94 + // 背景图片
90 95 [EditCanvasConfigEnum.BACKGROUND_IMAGE]?: string | null
91 96 // 图表主题颜色
92 97 [EditCanvasConfigEnum.CHART_THEME_COLOR]: ChartColorsNameType
  98 + // 自定义图表主题颜色
  99 + [EditCanvasConfigEnum.CHART_CUSTOM_THEME_COLOR_INFO]?: CustomColorsType[]
93 100 // 图表全局配置
94 101 [EditCanvasConfigEnum.CHART_THEME_SETTING]: GlobalThemeJsonType
95 102 // 图表主题颜色
... ...
... ... @@ -54,7 +54,9 @@ export const useChartEditStore = defineStore({
54 54 // 拖拽中
55 55 isDrag: false,
56 56 // 框选中
57   - isSelect: false
  57 + isSelect: false,
  58 + // 代码编辑中
  59 + isCodeEdit: false
58 60 },
59 61 // 右键菜单
60 62 rightMenuShow: false,
... ... @@ -108,6 +110,8 @@ export const useChartEditStore = defineStore({
108 110 selectColor: true,
109 111 // chart 主题色
110 112 chartThemeColor: defaultTheme || 'dark',
  113 + // 自定义颜色列表
  114 + chartCustomThemeColorInfo: undefined,
111 115 // 全局配置
112 116 chartThemeSetting: globalThemeJson,
113 117 // 适配方式
... ... @@ -185,7 +189,7 @@ export const useChartEditStore = defineStore({
185 189 this.targetChart.hoverId = hoverId
186 190 },
187 191 // * 设置目标数据 select
188   - setTargetSelectChart(selectId?: string | string[], push = false) {
  192 + setTargetSelectChart(selectId?: string | string[], push: boolean = false) {
189 193 // 重复选中
190 194 if (this.targetChart.selectId.find((e: string) => e === selectId)) return
191 195
... ... @@ -538,7 +542,7 @@ export const useChartEditStore = defineStore({
538 542 this.setTargetSelectChart()
539 543
540 544 // 重新选中
541   - const historyData = HistoryItem.historyData as Array<CreateComponentType | CreateComponentGroupType>
  545 + let historyData = HistoryItem.historyData as Array<CreateComponentType | CreateComponentGroupType>
542 546 if (isArray(historyData)) {
543 547 // 选中目标元素,支持多个
544 548 historyData.forEach((item: CreateComponentType | CreateComponentGroupType) => {
... ... @@ -835,7 +839,7 @@ export const useChartEditStore = defineStore({
835 839 }
836 840 },
837 841 // * 锁定
838   - setLock(status = true, isHistory = true) {
  842 + setLock(status: boolean = true, isHistory: boolean = true) {
839 843 try {
840 844 // 暂不支持多选
841 845 if (this.getTargetChart.selectId.length > 1) return
... ... @@ -864,11 +868,11 @@ export const useChartEditStore = defineStore({
864 868 }
865 869 },
866 870 // * 解除锁定
867   - setUnLock(isHistory = true) {
  871 + setUnLock(isHistory: boolean = true) {
868 872 this.setLock(false, isHistory)
869 873 },
870 874 // * 隐藏
871   - setHide(status = true, isHistory = true) {
  875 + setHide(status: boolean = true, isHistory: boolean = true) {
872 876 try {
873 877 // 暂不支持多选
874 878 if (this.getTargetChart.selectId.length > 1) return
... ...
... ... @@ -17,7 +17,7 @@
17 17 }
18 18
19 19 @mixin deep() {
20   - :deep(*) {
  20 + :deep() {
21 21 @content;
22 22 }
23 23 }
... ...
... ... @@ -4,8 +4,8 @@ import { AsyncLoading, AsyncSkeletonLoading } from '@/components/GoLoading'
4 4 /**
5 5 * * 动态注册组件
6 6 */
7   -export const componentInstall = <T>(key: string, node: T) => {
8   - if (!window['$vue'].component(key) && node) {
  7 +export const componentInstall = <T> (key:string, node: T) => {
  8 + if(!window['$vue'].component(key) && node) {
9 9 window['$vue'].component(key, node)
10 10 }
11 11 }
... ...
... ... @@ -2,6 +2,7 @@ import Color from 'color'
2 2 import { useDesignStore } from '@/store/modules/designStore/designStore'
3 3 import { PickCreateComponentType } from '@/packages/index.d'
4 4 import { EditCanvasConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
  5 +import { chartColors, chartColorsSearch, CustomColorsType } from '@/settings/chartThemes/index'
5 6
6 7 type AttrType = PickCreateComponentType<'attr'>
7 8 type StylesType = PickCreateComponentType<'styles'>
... ... @@ -87,6 +88,21 @@ export function darken(color: string, concentration: number) {
87 88 }
88 89
89 90 /**
  91 + * * hsl 转成16进制
  92 + * @param hsl
  93 + * @returns
  94 + */
  95 +export function hslToHexa(hslString: string): string {
  96 + const color = Color(hslString)
  97 + return color.hexa()
  98 +}
  99 +
  100 +export function hslToHex(hslString: string): string {
  101 + const color = Color(hslString)
  102 + return color.hex()
  103 +}
  104 +
  105 +/**
90 106 * * 修改主题色
91 107 * @param themeName 主题名称
92 108 * @returns
... ... @@ -100,3 +116,48 @@ export const setHtmlTheme = (themeName?: string) => {
100 116 const designStore = useDesignStore()
101 117 e.setAttribute('data-theme', designStore.themeName)
102 118 }
  119 +
  120 +/**
  121 + * * 合并基础颜色和自定义颜色
  122 + * @param chartDefaultColors
  123 + * @param customColor
  124 + * @returns
  125 + */
  126 +export const colorCustomMerge = (customColor?: CustomColorsType[]) => {
  127 + type FormateCustomColorType = {
  128 + [T: string]: {
  129 + color: string[]
  130 + name: string
  131 + }
  132 + }
  133 + const formateCustomColor: FormateCustomColorType = {}
  134 + customColor?.forEach(item => {
  135 + formateCustomColor[item.id] = {
  136 + color: item.color,
  137 + name: item.name
  138 + }
  139 + })
  140 + return { ...formateCustomColor, ...chartColors }
  141 +}
  142 +
  143 +/**
  144 + * * 合并基础渐变颜色和自定义渐变颜色
  145 + * @param customColor
  146 + */
  147 +export const colorGradientCustomMerge = (customColor?: CustomColorsType[]) => {
  148 + type FormateGradientCustomColorType = {
  149 + [T: string]: string[]
  150 + }
  151 + const formateGradientCustomColor: FormateGradientCustomColorType = {}
  152 + customColor?.forEach(item => {
  153 + formateGradientCustomColor[item.id] = [
  154 + item.color[0],
  155 + item.color[1],
  156 + fade(item.color[0], 0.3),
  157 + fade(item.color[0], 0.5),
  158 + fade(item.color[1], 0.5)
  159 + ]
  160 + })
  161 +
  162 + return { ...formateGradientCustomColor, ...chartColorsSearch }
  163 +}
... ...
... ... @@ -10,7 +10,7 @@ import cloneDeep from 'lodash/cloneDeep'
10 10 import { WinKeyboard } from '@/enums/editPageEnum'
11 11 import { RequestHttpIntervalEnum, RequestParamsObjType } from '@/enums/httpEnum'
12 12 import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
13   -import { excludeParseEventKeyList } from '@/enums/eventEnum'
  13 +import { excludeParseEventKeyList, excludeParseEventValueList } from '@/enums/eventEnum'
14 14
15 15 /**
16 16 * * 判断是否是开发环境
... ... @@ -320,10 +320,17 @@ export const JSONStringify = <T>(data: T) => {
320 320 */
321 321 export const JSONParse = (data: string) => {
322 322 return JSON.parse(data, (k, v) => {
  323 + // 过滤函数字符串
323 324 if (excludeParseEventKeyList.includes(k)) return v
  325 + // 过滤函数值表达式
  326 + if (typeof v === 'string') {
  327 + const someValue = excludeParseEventValueList.some(excludeValue => v.indexOf(excludeValue) > -1)
  328 + if (someValue) return v
  329 + }
  330 + // 还原函数值
324 331 if (typeof v === 'string' && v.indexOf && (v.indexOf('function') > -1 || v.indexOf('=>') > -1)) {
325 332 return eval(`(function(){return ${v}})()`)
326   - } else if (typeof v === 'string' && v.indexOf && (v.indexOf('return ') > -1)) {
  333 + } else if (typeof v === 'string' && v.indexOf && v.indexOf('return ') > -1) {
327 334 const baseLeftIndex = v.indexOf('(')
328 335 if (baseLeftIndex > -1) {
329 336 const newFn = `function ${v.substring(baseLeftIndex)}`
... ...
... ... @@ -5,7 +5,7 @@
5 5 class="go-content-charts-item-box"
6 6 :class="[chartMode === ChartModeEnum.DOUBLE ? 'double' : 'single']"
7 7 >
8   - <!-- 每一项组件的渲染 -->
  8 + <!-- 每一项组件的渲染 -->
9 9 <div
10 10 class="item-box"
11 11 v-for="(item, index) in menuOptions"
... ...
... ... @@ -5,7 +5,6 @@
5 5 v-show="hidePackageOneCategory"
6 6 class="chart-menu-width"
7 7 v-model:value="selectValue"
8   - style="width: 80px"
9 8 :options="packages.menuOptions"
10 9 :icon-size="16"
11 10 :indent="18"
... ...
1 1 <template>
2 2 <div class="go-chart-theme-color">
  3 + <n-card class="card-box" size="small" hoverable embedded @click="createColorHandle">
  4 + <n-text class="go-flex-items-center">
  5 + <span>自定义颜色</span>
  6 + <n-icon size="16">
  7 + <add-icon></add-icon>
  8 + </n-icon>
  9 + </n-text>
  10 + </n-card>
  11 +
3 12 <n-card
4   - v-for="(value, key) in chartColors"
  13 + v-for="(value, key) in comChartColors"
5 14 :key="key"
6 15 class="card-box"
7 16 :class="{ selected: key === selectName }"
... ... @@ -11,41 +20,51 @@
11 20 @click="selectTheme(key)"
12 21 >
13 22 <div class="go-flex-items-center">
14   - <n-text>{{ chartColorsName[key] }}</n-text>
  23 + <n-ellipsis style="text-align: left; width: 60px">{{ value.name }} </n-ellipsis>
15 24 <span
16 25 class="theme-color-item"
17 26 v-for="colorItem in fetchShowColors(value.color)"
18 27 :key="colorItem"
19 28 :style="{ backgroundColor: colorItem }"
20   - ></span>
  29 + ></span>
21 30 </div>
22   - <div
23   - class="theme-bottom"
24   - :style="{ backgroundImage: chartColorsshow[key] }"
25   - ></div>
  31 + <div class="theme-bottom" :style="{ backgroundImage: colorBackgroundImage(value) }"></div>
26 32 </n-card>
  33 + <!-- 自定义颜色 modal -->
  34 + <create-color v-model:modelShow="createColorModelShow"></create-color>
27 35 </div>
28 36 </template>
29 37
30 38 <script setup lang="ts">
31   -import { computed } from 'vue'
  39 +import { ref, computed } from 'vue'
  40 +import cloneDeep from 'lodash/cloneDeep'
32 41 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
33 42 import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
34   -import {
35   - chartColors,
36   - chartColorsName,
37   - chartColorsshow,
38   - ChartColorsNameType
39   -} from '@/settings/chartThemes/index'
  43 +import { chartColors, ChartColorsNameType } from '@/settings/chartThemes/index'
40 44 import { useDesignStore } from '@/store/modules/designStore/designStore'
41   -import cloneDeep from 'lodash/cloneDeep'
  45 +import { loadAsyncComponent, colorCustomMerge } from '@/utils'
42 46 import { icon } from '@/plugins'
43 47
44   -const { SquareIcon } = icon.ionicons5
  48 +type FormateCustomColorType = {
  49 + [T: string]: {
  50 + color: string[]
  51 + name: string
  52 + }
  53 +}
  54 +
  55 +const CreateColor = loadAsyncComponent(() => import('../CreateColor/index.vue'))
  56 +
  57 +const { SquareIcon, AddIcon } = icon.ionicons5
45 58 const chartEditStore = useChartEditStore()
46 59
47 60 // 全局颜色
48 61 const designStore = useDesignStore()
  62 +const createColorModelShow = ref(false)
  63 +
  64 +// 合并默认颜色和自定义颜色
  65 +const comChartColors = computed(() => {
  66 + return colorCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)
  67 +})
49 68
50 69 // 颜色
51 70 const themeColor = computed(() => {
... ... @@ -57,6 +76,16 @@ const selectName = computed(() => {
57 76 return chartEditStore.getEditCanvasConfig.chartThemeColor
58 77 })
59 78
  79 +// 创建颜色
  80 +const createColorHandle = () => {
  81 + createColorModelShow.value = true
  82 +}
  83 +
  84 +// 底色
  85 +const colorBackgroundImage = (item: { color: string[] }) => {
  86 + return `linear-gradient(to right, ${item.color[0]} 0%, ${item.color[5]} 100%)`
  87 +}
  88 +
60 89 // 获取用来展示的色号
61 90 const fetchShowColors = (colors: Array<string>) => {
62 91 return cloneDeep(colors).splice(0, 6)
... ... @@ -69,36 +98,34 @@ const selectTheme = (theme: ChartColorsNameType) => {
69 98 </script>
70 99
71 100 <style lang="scss" scoped>
72   -@include go(chart-theme-color) {
73   - padding-top: 20px;
  101 +$radius: 10px;
  102 +$itemRadius: 6px;
  103 +
  104 +@include go('chart-theme-color') {
74 105 .card-box {
75 106 cursor: pointer;
76 107 margin-top: 15px;
77 108 padding: 0;
78 109 @include fetch-bg-color('background-color4-shallow');
79   - border-radius: 23px;
  110 + border-radius: $radius;
80 111 overflow: hidden;
81   - @include deep() {
82   - .n-card__content {
83   - padding-top: 5px;
84   - padding-bottom: 10px;
85   - }
86   - }
  112 +
87 113 &.selected {
88   - border: 1px solid v-bind('themeColor');
  114 + border: 2px solid v-bind('themeColor');
89 115 border-bottom: 1px solid rgba(0, 0, 0, 0);
90 116 }
91 117 &:first-child {
92   - margin-top: 0;
  118 + margin-top: 5px;
93 119 }
94 120 .go-flex-items-center {
95 121 justify-content: space-between;
  122 + margin-top: -4px;
96 123 }
97 124 .theme-color-item {
98 125 display: inline-block;
99 126 width: 20px;
100 127 height: 20px;
101   - border-radius: 50%;
  128 + border-radius: $itemRadius;
102 129 }
103 130 .theme-bottom {
104 131 position: absolute;
... ... @@ -106,7 +133,6 @@ const selectTheme = (theme: ChartColorsNameType) => {
106 133 bottom: 0px;
107 134 width: 100%;
108 135 height: 3px;
109   - background-image: linear-gradient(to right, #e0c3fc 0%, #8ec5fc 100%);
110 136 }
111 137 }
112 138 }
... ...
  1 +<template>
  2 + <n-modal class="go-chart-create-color" v-model:show="modelShowRef" :mask-closable="false" :closeOnEsc="false">
  3 + <n-card :bordered="false" role="dialog" size="small" aria-modal="true" style="width: 900px; height: 720px">
  4 + <template #header></template>
  5 + <template #header-extra> </template>
  6 + <div class="create-content">
  7 + <div class="create-color-setting-box">
  8 + <create-color-render
  9 + v-if="selectColorId"
  10 + :selectColor="selectColor.selectInfo"
  11 + @updateColor="updateColorHandle"
  12 + ></create-color-render>
  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 + </div>
  19 + <div class="color-list-box">
  20 + <n-timeline class="pond-item-timeline" style="width: 20px">
  21 + <n-timeline-item type="info"> </n-timeline-item>
  22 + <n-timeline-item type="success"></n-timeline-item>
  23 + </n-timeline>
  24 + <div class="color-list">
  25 + <n-space>
  26 + <!-- 新增 -->
  27 + <n-button
  28 + class="create-btn"
  29 + :class="{ 'is-full': !!!selectColorId }"
  30 + type="primary"
  31 + :ghost="!!!selectColorId"
  32 + :secondary="!!selectColorId"
  33 + @click="createColor"
  34 + >
  35 + <span> 创建 </span>
  36 + <template #icon>
  37 + <n-icon>
  38 + <duplicate-outline-icon></duplicate-outline-icon>
  39 + </n-icon>
  40 + </template>
  41 + </n-button>
  42 + <n-badge v-if="selectColorId" :show="updateColor !== undefined" dot>
  43 + <n-button class="create-btn" type="info" secondary @click="saveHandle">
  44 + <span> 应用数据 </span>
  45 + <template #icon>
  46 + <n-icon>
  47 + <arrow-down-icon></arrow-down-icon>
  48 + </n-icon>
  49 + </template>
  50 + </n-button>
  51 + </n-badge>
  52 + </n-space>
  53 + <n-divider style="margin: 10px 0"></n-divider>
  54 + <n-text v-if="!selectColorId" class="not-data-text" :depth="3">
  55 + 暂无自定义颜色,
  56 + <n-a @click="createColor">立即创建</n-a>
  57 + </n-text>
  58 + <!-- 列表 -->
  59 + <div class="color-card-box" v-for="(item, index) in colorList" :key="index">
  60 + <n-card
  61 + class="color-card"
  62 + :class="{ selected: item.id === selectColorId }"
  63 + size="small"
  64 + hoverable
  65 + embedded
  66 + @click="selectHandle(item)"
  67 + >
  68 + <div class="go-flex-items-center">
  69 + <n-ellipsis style="text-align: left; width: 70px">{{ item.name }} </n-ellipsis>
  70 + <span
  71 + class="theme-color-item"
  72 + v-for="(colorItem, index) in item.color"
  73 + :key="index"
  74 + :style="{ backgroundColor: colorItem }"
  75 + ></span>
  76 + </div>
  77 + <div class="theme-bottom" :style="{ backgroundImage: colorBackgroundImage(item) }"></div>
  78 + </n-card>
  79 + <n-tooltip trigger="hover">
  80 + <template #trigger>
  81 + <n-button text :disabled="item.id === selectThemeColor" @click="deleteHandle(index)">
  82 + <n-icon class="go-ml-1 go-cursor-pointer" size="16" :depth="3">
  83 + <trash-icon></trash-icon>
  84 + </n-icon>
  85 + </n-button>
  86 + </template>
  87 + 删除自定义颜色
  88 + </n-tooltip>
  89 + </div>
  90 + </div>
  91 + </div>
  92 + </div>
  93 + <!-- 底部 -->
  94 + <template #action>
  95 + <n-space justify="end">
  96 + <n-button @click="closeHandle">操作完成</n-button>
  97 + </n-space>
  98 + </template>
  99 + </n-card>
  100 + </n-modal>
  101 +</template>
  102 +
  103 +<script setup lang="ts">
  104 +import { ref, watch, computed, reactive, nextTick, onMounted } from 'vue'
  105 +import cloneDeep from 'lodash/cloneDeep'
  106 +import noData from '@/assets/images/canvas/noData.png'
  107 +import { getUUID, goDialog } from '@/utils'
  108 +import { icon } from '@/plugins'
  109 +import { UvIndex } from '@vicons/carbon'
  110 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  111 +import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
  112 +import { CreateColorRender } from '../CreateColorRender/index'
  113 +
  114 +const props = defineProps({
  115 + modelShow: Boolean
  116 +})
  117 +const emit = defineEmits(['update:modelShow', 'editSaveHandle'])
  118 +const { DuplicateOutlineIcon, TrashIcon, ArrowDownIcon } = icon.ionicons5
  119 +
  120 +type ColorType = {
  121 + id: string
  122 + name: string
  123 + color: string[]
  124 +}
  125 +
  126 +// 默认颜色组
  127 +const defaultColor: ColorType = {
  128 + id: getUUID(),
  129 + name: '未命名',
  130 + color: ['#6ae5bb', '#69e3de', '#5ac5ee', '#5ac4ee', '#4498ec', '#3c7ddf']
  131 +}
  132 +const chartEditStore = useChartEditStore()
  133 +const modelShowRef = ref(false)
  134 +// 颜色列表
  135 +let colorList = reactive<Array<ColorType>>(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo || [])
  136 +// 子组件更新过的数据
  137 +const updateColor = ref<ColorType | undefined>(undefined)
  138 +// 所选颜色
  139 +const selectColor = reactive<{
  140 + selectInfo: ColorType | undefined
  141 +}>({
  142 + selectInfo: colorList[0]
  143 +})
  144 +
  145 +watch(
  146 + () => props.modelShow,
  147 + newValue => {
  148 + modelShowRef.value = newValue
  149 + if (newValue) {
  150 + // 默认选中
  151 + if (colorList.length) selectColor.selectInfo = colorList[0]
  152 + }
  153 + }
  154 +)
  155 +
  156 +// 当前选中的 ID
  157 +const selectColorId = computed(() => selectColor?.selectInfo?.id)
  158 +
  159 +// 全局选择的主题
  160 +const selectThemeColor = computed(() => chartEditStore.getEditCanvasConfig.chartThemeColor)
  161 +
  162 +// 选择
  163 +const selectHandle = (item: ColorType) => {
  164 + if (item.id === selectColorId.value) return
  165 + if (updateColor.value !== undefined) {
  166 + goDialog({
  167 + message: '当前有变动未保存,是否直接放弃修改?',
  168 + onPositiveCallback: () => {
  169 + updateColor.value = undefined
  170 + selectColor.selectInfo = item
  171 + }
  172 + })
  173 + } else {
  174 + selectColor.selectInfo = item
  175 + }
  176 +}
  177 +
  178 +// 创建
  179 +const createColor = () => {
  180 + const positiveHandle = () => {
  181 + const newData = { ...cloneDeep(defaultColor), id: getUUID() }
  182 + selectColor.selectInfo = newData
  183 + colorList.push(newData)
  184 + selectHandle(newData)
  185 + updateColor.value = newData
  186 + saveHandle(false)
  187 + }
  188 + if (updateColor.value !== undefined) {
  189 + goDialog({
  190 + message: '当前有变动未保存,是否直接放弃修改?',
  191 + onPositiveCallback: () => {
  192 + updateColor.value = undefined
  193 + positiveHandle()
  194 + }
  195 + })
  196 + } else {
  197 + positiveHandle()
  198 + }
  199 +}
  200 +
  201 +// 删除
  202 +const deleteHandle = (index: number) => {
  203 + const positiveHandle = () => {
  204 + colorList.splice(index, 1)
  205 + chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.CHART_CUSTOM_THEME_COLOR_INFO, cloneDeep(colorList))
  206 + nextTick(() => {
  207 + if (colorList.length) {
  208 + selectHandle(colorList[index - 1 > -1 ? index - 1 : index])
  209 + } else {
  210 + // 已清空
  211 + selectColor.selectInfo = undefined
  212 + }
  213 + })
  214 + }
  215 + if (updateColor.value !== undefined) {
  216 + goDialog({
  217 + message: '当前有变动未保存,是否直接放弃修改?',
  218 + onPositiveCallback: () => {
  219 + updateColor.value = undefined
  220 + positiveHandle()
  221 + }
  222 + })
  223 + } else {
  224 + goDialog({
  225 + message: `是否删除此颜色?`,
  226 + onPositiveCallback: () => {
  227 + positiveHandle()
  228 + }
  229 + })
  230 + }
  231 +}
  232 +
  233 +// 存储更新数据的值
  234 +const updateColorHandle = (newColor: ColorType) => {
  235 + updateColor.value = newColor
  236 +}
  237 +
  238 +// 保存数据
  239 +const saveHandle = (onMessage = true) => {
  240 + if (!updateColor.value) return
  241 + const index = colorList.findIndex(item => item.id === updateColor.value?.id)
  242 + if (index !== -1) {
  243 + onMessage && window.$message.success('数据应用成功!')
  244 + const updateColorPrefix = cloneDeep({ ...updateColor.value, name: updateColor.value.name || '未定义' })
  245 + colorList.splice(index, 1, updateColorPrefix)
  246 + updateColor.value = undefined
  247 + const selectTheme = chartEditStore.getEditCanvasConfig.chartThemeColor
  248 + // 变换主题强制渐变色更新
  249 + chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.CHART_THEME_COLOR, 'dark')
  250 + // 存储到全局数据中
  251 + nextTick(() => {
  252 + chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.CHART_CUSTOM_THEME_COLOR_INFO, cloneDeep(colorList))
  253 + chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.CHART_THEME_COLOR, selectTheme)
  254 + })
  255 + } else {
  256 + window.$message.error('数据应用失败!')
  257 + }
  258 +}
  259 +
  260 +// 关闭
  261 +const closeHandle = () => {
  262 + const positiveHandle = () => {
  263 + updateColor.value = undefined
  264 + selectColor.selectInfo = undefined
  265 + emit('update:modelShow', false)
  266 + }
  267 +
  268 + if (updateColor.value !== undefined) {
  269 + goDialog({
  270 + message: '当前有变动未保存,是否直接放弃修改?',
  271 + onPositiveCallback: () => {
  272 + positiveHandle()
  273 + }
  274 + })
  275 + } else {
  276 + positiveHandle()
  277 + }
  278 +}
  279 +
  280 +// 底色
  281 +const colorBackgroundImage = (item: ColorType) => {
  282 + return `linear-gradient(to right, ${item.color[0]} 0%, ${item.color[5]} 100%)`
  283 +}
  284 +</script>
  285 +
  286 +<style scoped lang="scss">
  287 +$height: 600px;
  288 +$listWidth: 280px;
  289 +$color-radius: 8px;
  290 +$color-item-radius: 4px;
  291 +
  292 +@include go('chart-create-color') {
  293 + .create-content {
  294 + display: flex;
  295 + /* 左侧 */
  296 + .create-color-setting-box {
  297 + flex: 1;
  298 + .no-data {
  299 + flex-direction: column;
  300 + width: 100%;
  301 + height: 100%;
  302 + img {
  303 + width: 200px;
  304 + }
  305 + }
  306 + }
  307 + /* 列表 */
  308 + .color-list-box {
  309 + display: flex;
  310 + padding-top: 10px;
  311 + margin-right: 5px;
  312 + .pond-item-timeline > .n-timeline-item {
  313 + &:first-child {
  314 + height: $height;
  315 + }
  316 + }
  317 + .color-list {
  318 + width: $listWidth;
  319 + position: relative;
  320 + padding-right: 8px;
  321 + .create-btn {
  322 + width: 133px;
  323 + &.is-full {
  324 + width: 280px;
  325 + }
  326 + }
  327 + .not-data-text {
  328 + display: block;
  329 + text-align: center;
  330 + }
  331 + .color-card-box {
  332 + display: flex;
  333 + align-items: center;
  334 + justify-content: space-between;
  335 + margin-top: 15px;
  336 + &:first-child {
  337 + margin-top: 0;
  338 + }
  339 + .color-card {
  340 + overflow: hidden;
  341 + cursor: pointer;
  342 + border-radius: $color-radius;
  343 + border: 2px solid rgba(0, 0, 0, 0);
  344 + border-bottom: 1px solid rgba(0, 0, 0, 0);
  345 + @include fetch-bg-color('background-color4-shallow');
  346 +
  347 + @include deep() {
  348 + & > .n-card__content {
  349 + padding: 7px;
  350 + padding-top: 10px;
  351 + padding-bottom: 10px;
  352 + }
  353 + }
  354 + &.selected {
  355 + border: 2px solid var(--n-color-target);
  356 + border-bottom: 1px solid rgba(0, 0, 0, 0);
  357 + }
  358 + .go-flex-items-center {
  359 + justify-content: space-between;
  360 + margin-top: -4px;
  361 + }
  362 + .theme-color-item {
  363 + display: inline-block;
  364 + width: 16px;
  365 + height: 16px;
  366 + border-radius: $color-item-radius;
  367 + }
  368 + .theme-bottom {
  369 + position: absolute;
  370 + left: 0;
  371 + bottom: 0px;
  372 + width: 100%;
  373 + height: 3px;
  374 + }
  375 + }
  376 + }
  377 + }
  378 + }
  379 + }
  380 + &.n-card.n-modal,
  381 + .n-card {
  382 + @extend .go-background-filter;
  383 + }
  384 + .n-card-shallow {
  385 + background-color: rgba(0, 0, 0, 0) !important;
  386 + }
  387 + @include deep() {
  388 + & > .n-card__content {
  389 + padding-right: 0;
  390 + }
  391 + }
  392 +}
  393 +</style>
... ...
  1 +import CreateColorRender from './index.vue'
  2 +
  3 +export { CreateColorRender }
... ...
  1 +<template>
  2 + <div class="create-color-setting" v-if="editColor">
  3 + <n-card :bordered="false" role="dialog" size="small" aria-modal="true">
  4 + <n-space justify="space-between">
  5 + <!-- 名称 -->
  6 + <n-input-group>
  7 + <n-input-group-label>名称:</n-input-group-label>
  8 + <n-input
  9 + class="create-color-name"
  10 + v-model:value.trim="editColor.name"
  11 + maxlength="8"
  12 + show-count
  13 + clearable
  14 + @change="titleChangeHandle"
  15 + />
  16 + </n-input-group>
  17 + <n-tag type="warning">底部图表仅展示 7 条数据</n-tag>
  18 + </n-space>
  19 + <!-- 颜色 -->
  20 + <n-scrollbar style="max-height: 132px">
  21 + <div class="color-list-box go-mt-3" :x-gap="12" :y-gap="12" :cols="4">
  22 + <div class="color-list-item" v-for="(item, index) in editColor.color" :key="index">
  23 + <div class="go-flex-items-center" :class="{ select: index === targetColor.index }">
  24 + <n-color-picker
  25 + style="width: 95px"
  26 + v-model:value="editColor.color[index]"
  27 + :show-preview="true"
  28 + :modes="['hex']"
  29 + @complete="completeHandle($event, index)"
  30 + @update:show="selectHandle(item, index)"
  31 + />
  32 + <div v-show="index > 5">
  33 + <n-tooltip trigger="hover">
  34 + <template #trigger>
  35 + <n-icon class="go-ml-1 go-cursor-pointer" size="16" :depth="3" @click="deleteColor(index)">
  36 + <trash-icon></trash-icon>
  37 + </n-icon>
  38 + </template>
  39 + 删除颜色
  40 + </n-tooltip>
  41 + </div>
  42 + </div>
  43 + </div>
  44 + <div>
  45 + <n-button type="primary" secondary @click="addColor">
  46 + <div class="go-flex-items-center">
  47 + <span class="go-mr-4">添加</span>
  48 + <n-icon size="16">
  49 + <add-icon></add-icon>
  50 + </n-icon>
  51 + </div>
  52 + </n-button>
  53 + </div>
  54 + </div>
  55 + </n-scrollbar>
  56 + </n-card>
  57 +
  58 + <!-- 扩展色 -->
  59 + <div class="expend-color-box">
  60 + <n-card class="go-mt-3 expend-color" :bordered="false" role="dialog" size="small" aria-modal="true">
  61 + <n-text>默认扩展色:</n-text>
  62 + <n-divider style="margin: 10px 0"></n-divider>
  63 + <n-space :size="[4, 0]" justify="center">
  64 + <div
  65 + class="color-computed-item"
  66 + v-for="(item, index) in expandColorList.default"
  67 + :key="index"
  68 + @click="selectExpandColor(item, false)"
  69 + >
  70 + <div class="n-color-picker-checkboard"></div>
  71 + <div :style="getRenderBackgroundColor(item)"></div>
  72 + </div>
  73 + </n-space>
  74 + </n-card>
  75 + <n-card class="go-mt-3 expend-color" :bordered="false" role="dialog" size="small" aria-modal="true">
  76 + <n-text>透明扩展色:</n-text>
  77 + <n-divider style="margin: 10px 0"></n-divider>
  78 + <n-space :size="[4, 0]" justify="center">
  79 + <div
  80 + class="color-computed-item"
  81 + v-for="(item, index) in expandColorList.fade"
  82 + :key="index"
  83 + @click="selectExpandColor(item, true)"
  84 + >
  85 + <div class="n-color-picker-checkboard"></div>
  86 + <div :style="getRenderBackgroundColor(item)"></div>
  87 + </div>
  88 + </n-space>
  89 + </n-card>
  90 + </div>
  91 +
  92 + <!-- 展示图表 -->
  93 + <create-color-render-chart :color="cloneDeep(editColor.color).splice(0, 7)"></create-color-render-chart>
  94 + </div>
  95 +</template>
  96 +
  97 +<script setup lang="ts">
  98 +import { PropType, ref, watch, computed, reactive, nextTick } from 'vue'
  99 +import cloneDeep from 'lodash/cloneDeep'
  100 +import { darken, lighten, fade, hslToHex, hslToHexa, loadAsyncComponent } from '@/utils'
  101 +import { icon } from '@/plugins'
  102 +
  103 +type ColorType = {
  104 + id: string
  105 + name: string
  106 + color: string[]
  107 +}
  108 +
  109 +const props = defineProps({
  110 + selectColor: Object as PropType<ColorType>
  111 +})
  112 +
  113 +const emit = defineEmits(['updateColor'])
  114 +
  115 +const { AddIcon, TrashIcon } = icon.ionicons5
  116 +const CreateColorRenderChart = loadAsyncComponent(() => import('../CreateColorRenderChart/index.vue'))
  117 +
  118 +// 拷贝的一份数据
  119 +const editColor = ref<ColorType | undefined>()
  120 +// 目标颜色
  121 +const targetColor = reactive<{
  122 + index: number
  123 + color?: string
  124 +}>({
  125 + // -1 表示无选中元素
  126 + index: -1,
  127 + color: ''
  128 +})
  129 +
  130 +// 监听值
  131 +watch(
  132 + () => props.selectColor?.id,
  133 + () => {
  134 + editColor.value = cloneDeep(props.selectColor)
  135 + targetColor.index = 0
  136 + targetColor.color = editColor.value?.color[0]
  137 + },
  138 + {
  139 + immediate: true,
  140 + deep: false
  141 + }
  142 +)
  143 +
  144 +// 扩展色
  145 +const expandColorList = computed(() => {
  146 + return computedColorList(targetColor.color)
  147 +})
  148 +
  149 +// 计算背景色
  150 +const computedColorList = (color?: string) => {
  151 + if (!color)
  152 + return {
  153 + default: [],
  154 + fade: []
  155 + }
  156 + const num: number = 36
  157 + const comDarkenArr: string[] = []
  158 + const comLightenArr: string[] = []
  159 + const comDarkenFadeArr: string[] = []
  160 +
  161 + for (let i = 0; i < num; i++) {
  162 + comLightenArr.unshift(lighten(color, (1 / 100) * (i + 1)))
  163 + comDarkenArr.push(darken(color, (3.5 / 100) * (i + 1)))
  164 + }
  165 +
  166 + // 透明
  167 + comDarkenArr.forEach((item, i) => {
  168 + comDarkenFadeArr.unshift(fade(item, (1 / 100) * (i + 1)))
  169 + })
  170 +
  171 + return {
  172 + default: [
  173 + ...comLightenArr.reverse().splice(0, parseInt(`${num / 2}`) - 9),
  174 + ...comDarkenArr.splice(0, parseInt(`${num / 2}`))
  175 + ],
  176 + fade: comDarkenFadeArr.reverse().splice(0, 27)
  177 + }
  178 +}
  179 +
  180 +// 渲染背景色
  181 +const getRenderBackgroundColor = (color?: string) => {
  182 + return {
  183 + backgroundColor: color
  184 + }
  185 +}
  186 +
  187 +// 点击颜色
  188 +const selectHandle = (color: string, index: number) => {
  189 + targetColor.color = color
  190 + targetColor.index = index
  191 +}
  192 +
  193 +// 顶部改变颜色
  194 +const completeHandle = (color?: string, index?: number) => {
  195 + color && (targetColor.color = color)
  196 + index && (targetColor.index = index)
  197 + nextTick(() => {
  198 + emit('updateColor', editColor.value)
  199 + })
  200 +}
  201 +
  202 +// 选择扩展色
  203 +const selectExpandColor = (color: string, isHexa: boolean) => {
  204 + const hexColor = isHexa ? hslToHexa(color) : hslToHex(color)
  205 + editColor.value && (editColor.value.color[targetColor.index] = hexColor)
  206 + nextTick(() => {
  207 + emit('updateColor', editColor.value)
  208 + })
  209 +}
  210 +
  211 +// 新增颜色
  212 +const addColor = () => {
  213 + const lastData = editColor.value?.color[editColor.value?.color.length - 1] || '#2c2c31'
  214 + editColor.value?.color.push(lastData)
  215 + nextTick(() => {
  216 + emit('updateColor', editColor.value)
  217 + })
  218 +}
  219 +
  220 +// 删除颜色
  221 +const deleteColor = (index: number) => {
  222 + editColor.value?.color.splice(index, 1)
  223 + if (index === targetColor.index) {
  224 + completeHandle(editColor.value?.color[index - 1], index - 1)
  225 + }
  226 +}
  227 +
  228 +// 修改名称
  229 +const titleChangeHandle = () => {
  230 + nextTick(() => {
  231 + emit('updateColor', editColor.value)
  232 + })
  233 +}
  234 +</script>
  235 +
  236 +<style scoped lang="scss">
  237 +.create-color-setting {
  238 + display: flex;
  239 + flex-direction: column;
  240 + justify-content: space-between;
  241 + height: 100%;
  242 + padding-right: 10px;
  243 + .create-color-name {
  244 + width: 200px;
  245 + }
  246 + .color-list-box {
  247 + display: flex;
  248 + flex-wrap: wrap;
  249 + row-gap: 8px;
  250 + .color-list-item {
  251 + width: calc(100% / 4);
  252 + .select {
  253 + .n-color-picker {
  254 + border: 2px solid v-bind('targetColor.color');
  255 + border-radius: 5px;
  256 + }
  257 + }
  258 + }
  259 + }
  260 + .expend-color-box {
  261 + display: flex;
  262 + justify-content: space-between;
  263 + align-items: center;
  264 + .expend-color {
  265 + width: calc(50% - 5px);
  266 + .color-computed-item {
  267 + position: relative;
  268 + display: inline-block;
  269 + height: 22px;
  270 + width: 22px;
  271 + cursor: pointer;
  272 + overflow: hidden;
  273 + border-radius: 4px;
  274 + & div {
  275 + position: absolute;
  276 + display: inline-block;
  277 + height: 22px;
  278 + width: 22px;
  279 + }
  280 + }
  281 + }
  282 + }
  283 +}
  284 +</style>
... ...
  1 +import { echartOptionProfixHandle } from '@/packages/public'
  2 +
  3 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  4 +
  5 +const seriesHandle = (color: string[]) => {
  6 + const numHandle = (numsi: number, i: number) => parseInt(`${numsi * Math.random()}`, 10) * 2
  7 + const nums = [260, 251, 200, 334, 366, 256, 253]
  8 +
  9 + return color.map((item, index) => ({
  10 + name: `data${index + 1}`,
  11 + type: 'bar',
  12 + data: nums.map((numsItem, numsi) => numHandle(numsItem, index))
  13 + }))
  14 +}
  15 +
  16 +export const option = (color: string[]) => {
  17 + return echartOptionProfixHandle(
  18 + {
  19 + tooltip: {
  20 + trigger: 'axis',
  21 + showContent: false,
  22 + axisPointer: {
  23 + type: 'shadow'
  24 + }
  25 + },
  26 + grid: {
  27 + left: '3%',
  28 + right: '4%',
  29 + bottom: '3%',
  30 + containLabel: true
  31 + },
  32 + xAxis: {
  33 + type: 'category',
  34 + data: color.map((e, i) => `data${i + 1}`),
  35 + axisTick: {
  36 + alignWithLabel: true
  37 + }
  38 + },
  39 + yAxis: {
  40 + show: true,
  41 + type: 'value'
  42 + },
  43 + series: seriesHandle(color || [])
  44 + },
  45 + includes
  46 + )
  47 +}
... ...
  1 +import CreateColorRenderChart from './index.vue'
  2 +
  3 +export { CreateColorRenderChart }
... ...
  1 +<template>
  2 + <n-space>
  3 + <n-card v-if="barOption" class="go-mt-3" :bordered="false" role="dialog" size="small" aria-modal="true">
  4 + <n-tabs type="segment" size="small" animated>
  5 + <n-tab-pane name="柱状图" tab="柱状图">
  6 + <v-chart
  7 + ref="vChartRefBar"
  8 + :theme="{ color }"
  9 + :option="barOption"
  10 + :manual-update="true"
  11 + autoresize
  12 + :style="chartStyle"
  13 + ></v-chart>
  14 + </n-tab-pane>
  15 + <n-tab-pane name="折线图" tab="折线图">
  16 + <v-chart
  17 + ref="vChartRefLine"
  18 + :theme="{ color }"
  19 + :option="lineOption"
  20 + :manual-update="true"
  21 + autoresize
  22 + :style="chartStyle"
  23 + ></v-chart>
  24 + </n-tab-pane>
  25 + </n-tabs>
  26 + </n-card>
  27 + </n-space>
  28 +</template>
  29 +
  30 +<script setup lang="ts">
  31 +import { ref, watch, PropType } from 'vue'
  32 +import VChart from 'vue-echarts'
  33 +import { CanvasRenderer } from 'echarts/renderers'
  34 +import { BarChart, LineChart } from 'echarts/charts'
  35 +import { use } from 'echarts/core'
  36 +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
  37 +import { option as barOptions } from './barOptions'
  38 +import { option as lineOptions } from './lineOptions'
  39 +
  40 +const props = defineProps({
  41 + color: {
  42 + type: Array as PropType<string[]>,
  43 + required: true
  44 + }
  45 +})
  46 +use([DatasetComponent, CanvasRenderer, BarChart, LineChart, GridComponent, TooltipComponent, LegendComponent])
  47 +
  48 +const barOption = ref()
  49 +const lineOption = ref()
  50 +
  51 +const chartStyle = {
  52 + width: '528px',
  53 + height: '200px'
  54 +}
  55 +
  56 +watch(
  57 + () => props.color,
  58 + (newData: string[]) => {
  59 + barOption.value = barOptions(newData)
  60 + lineOption.value = lineOptions(newData)
  61 + },
  62 + {
  63 + immediate: true,
  64 + deep: true
  65 + }
  66 +)
  67 +</script>
\ No newline at end of file
... ...
  1 +import { echartOptionProfixHandle } from '@/packages/public'
  2 +import { graphic } from 'echarts/core'
  3 +import { fade, hslToHex } from '@/utils'
  4 +
  5 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  6 +
  7 +const seriesHandle = (color: string[]) => {
  8 + const numHandle = (numsi: number, i: number) => parseInt(`${numsi * Math.random()}`, 10) * 2
  9 + const nums = [130, 251, 200, 334, 366, 456, 223]
  10 +
  11 + return color.map((item, index) => ({
  12 + name: `data${index + 1}`,
  13 + type: 'line',
  14 + smooth: true,
  15 + lineStyle: {
  16 + width: 1,
  17 + type: 'solid'
  18 + },
  19 + emphasis: {
  20 + focus: 'series'
  21 + },
  22 + areaStyle: {
  23 + opacity: 0.8,
  24 + color: new graphic.LinearGradient(0, 0, 0, 1, [
  25 + {
  26 + offset: 1,
  27 + color: item
  28 + },
  29 + {
  30 + offset: 0,
  31 + color: item
  32 + }
  33 + ])
  34 + },
  35 + showSymbol: false,
  36 + data: nums.reverse().map((numsItem, numsi) => numHandle(numsItem, index))
  37 + }))
  38 +}
  39 +
  40 +export const option = (color: string[]) => {
  41 + return echartOptionProfixHandle(
  42 + {
  43 + tooltip: {
  44 + trigger: 'axis',
  45 + showContent: false,
  46 + axisPointer: {
  47 + type: 'shadow'
  48 + }
  49 + },
  50 + grid: {
  51 + left: '3%',
  52 + right: '4%',
  53 + bottom: '3%',
  54 + containLabel: true
  55 + },
  56 + xAxis: {
  57 + type: 'category',
  58 + boundaryGap: false,
  59 + data: color.map((e, i) => `data${i + 1}`),
  60 + axisTick: {
  61 + alignWithLabel: true
  62 + }
  63 + },
  64 + yAxis: {
  65 + show: true,
  66 + type: 'value'
  67 + },
  68 + series: seriesHandle(color || [])
  69 + },
  70 + includes
  71 + )
  72 +}
... ...
... ... @@ -21,7 +21,8 @@
21 21 ></n-input-number>
22 22 </n-form-item>
23 23 </n-form>
24   - <n-card class="upload-box">
  24 +
  25 + <div class="upload-box">
25 26 <n-upload
26 27 v-model:file-list="uploadFileListRef"
27 28 :show-file-list="false"
... ... @@ -38,7 +39,7 @@
38 39 </div>
39 40 </n-upload-dragger>
40 41 </n-upload>
41   - </n-card>
  42 + </div>
42 43 <n-space vertical :size="12">
43 44 <n-space>
44 45 <n-text>背景选择</n-text>
... ... @@ -138,11 +139,12 @@
138 139 <script setup lang="ts">
139 140 import { ref, nextTick, watch } from 'vue'
140 141 import { backgroundImageSize } from '@/settings/designSetting'
  142 +import { swatchesColors } from '@/settings/chartThemes/index'
141 143 import { FileTypeEnum } from '@/enums/fileTypeEnum'
142 144 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
143 145 import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
144 146 import { StylesSetting } from '@/components/Pages/ChartItemSetting'
145   -import { UploadCustomRequestOptions, SelectOption } from 'naive-ui'
  147 +import { UploadCustomRequestOptions } from 'naive-ui'
146 148 import { fileToUrl, loadAsyncComponent } from '@/utils'
147 149 import { PreviewScaleEnum } from '@/enums/styleEnum'
148 150 import { icon } from '@/plugins'
... ... @@ -187,9 +189,6 @@ const selectColorOptions = [
187 189 }
188 190 ]
189 191
190   -// 默认展示颜色列表
191   -const swatchesColors = ['#232324', '#2a2a2b', '#313132', '#373739', '#757575', '#e0e0e0', '#eeeeee', '#fafafa']
192   -
193 192 const globalTabList = [
194 193 {
195 194 key: 'ChartTheme',
... ... @@ -317,7 +316,7 @@ const selectPreviewType = (key: PreviewScaleEnum) => {
317 316 </script>
318 317
319 318 <style lang="scss" scoped>
320   -$uploadWidth: 280px;
  319 +$uploadWidth: 326px;
321 320 $uploadHeight: 193px;
322 321 @include go(canvas-setting) {
323 322 padding-top: 20px;
... ... @@ -325,13 +324,10 @@ $uploadHeight: 193px;
325 324 cursor: pointer;
326 325 margin-bottom: 20px;
327 326 @include deep() {
328   - .n-card__content {
329   - padding: 0;
330   - overflow: hidden;
331   - }
332 327 .n-upload-dragger {
333 328 padding: 5px;
334 329 width: $uploadWidth;
  330 + background-color: rgba(0, 0, 0, 0);
335 331 }
336 332 }
337 333 .upload-show {
... ...
1 1 <template>
2 2 <div class="go-chart-data-pond-list">
3   - <n-timeline style="width: 20px">
  3 + <n-timeline class="pond-item-timeline" style="width: 20px">
4 4 <n-timeline-item type="info"> </n-timeline-item>
5 5 <n-timeline-item type="success"></n-timeline-item>
6 6 </n-timeline>
... ... @@ -115,11 +115,9 @@ $textSize: 10px;
115 115 padding-bottom: 5px;
116 116 margin-right: 5px;
117 117 display: flex;
118   - @include deep() {
119   - .n-timeline > .n-timeline-item {
120   - &:first-child {
121   - height: $height;
122   - }
  118 + .pond-item-timeline > .n-timeline-item {
  119 + &:first-child {
  120 + height: $height;
123 121 }
124 122 }
125 123 .pond-item-box {
... ...
... ... @@ -56,7 +56,7 @@ import { MenuEnum } from '@/enums/editPageEnum'
56 56 import { chartColors } from '@/settings/chartThemes/index'
57 57 import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
58 58 import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
59   -import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } from '@/utils'
  59 +import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle, colorCustomMerge } from '@/utils'
60 60 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
61 61 import { useContextMenu, divider } from '@/views/chart/hooks/useContextMenu.hook'
62 62 import { useMouseHandle } from '../../hooks/useDrag.hook'
... ... @@ -117,8 +117,8 @@ const optionsHandle = (
117 117
118 118 // 配置项
119 119 const themeColor = computed(() => {
120   - const chartThemeColor = chartEditStore.getEditCanvasConfig.chartThemeColor
121   - return chartColors[chartThemeColor]
  120 + const colorCustomMergeData = colorCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)
  121 + return colorCustomMergeData[chartEditStore.getEditCanvasConfig.chartThemeColor]
122 122 })
123 123
124 124 // 主题色
... ...
... ... @@ -55,7 +55,7 @@ const rangeModelStyle = computed(() => {
55 55 position: relative;
56 56 transform-origin: left top;
57 57 background-size: cover;
58   - border-radius: 20px;
  58 + border-radius: 10px;
59 59 overflow: hidden;
60 60 @include fetch-border-color('hover-border-color');
61 61 @include fetch-bg-color('background-color2');
... ...
1 1 import { watch } from 'vue'
2 2 import { useRoute } from 'vue-router'
  3 +import throttle from 'lodash/throttle'
3 4 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  5 +import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
4 6 import { useSync } from '@/views/chart/hooks/useSync.hook'
5 7 import { ChartEnum } from '@/enums/pageEnum'
6 8 import { SavePageEnum } from '@/enums/editPageEnum'
7 9 import { editToJsonInterval } from '@/settings/designSetting'
  10 +import { goDialog } from '@/utils'
8 11
9 12 const { updateComponent } = useSync()
10 13 const chartEditStore = useChartEditStore()
11 14
  15 +export const syncData = () => {
  16 + goDialog({
  17 + message: '是否覆盖源视图内容,此操作不可撤回?',
  18 + isMaskClosable: true,
  19 + transformOrigin: 'center',
  20 + onPositiveCallback: () => {
  21 + window['$message'].success('正在同步编辑器...')
  22 + dispatchEvent(new CustomEvent(SavePageEnum.CHART, { detail: chartEditStore.getStorageInfo }))
  23 + }
  24 + })
  25 +}
  26 +
12 27 // 侦听器更新
13 28 const useSyncUpdateHandle = () => {
14 29 // 定义侦听器变量
15 30 let timer: any
16   - const updateFn = (e: any) => updateComponent(e!.detail, true, false)
17   - const syncData = async () => {
18   - dispatchEvent(new CustomEvent(SavePageEnum.CHART, { detail: chartEditStore.getStorageInfo }))
  31 +
  32 + // 更新处理
  33 + const updateFn = (e: any) => {
  34 + window['$message'].success('正在进行更新...')
  35 + updateComponent(e!.detail, true)
  36 + }
  37 +
  38 + // 页面关闭处理
  39 + const closeFn = () => {
  40 + chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_CODE_EDIT, false)
19 41 }
20 42
21 43 // 开启侦听
22 44 const use = () => {
23   - // // 1、定时同步数据
  45 + // 定时同步数据(暂不开启)
24 46 // timer = setInterval(() => {
25 47 // // 窗口激活并且处于工作台
26 48 // document.hasFocus() && syncData()
27 49 // }, editToJsonInterval)
  50 +
28 51 // 2、失焦同步数据
29 52 addEventListener('blur', syncData)
30 53
31 54 // 【监听JSON代码 刷新工作台图表】
32 55 addEventListener(SavePageEnum.JSON, updateFn)
  56 +
  57 + // 监听编辑页关闭
  58 + addEventListener(SavePageEnum.CLOSE, throttle(closeFn, 1000))
33 59 }
34 60
35 61 // 关闭侦听
36 62 const unUse = () => {
37 63 // clearInterval(timer)
  64 + // removeEventListener('blur', syncData)
38 65 removeEventListener(SavePageEnum.JSON, updateFn)
39   - removeEventListener('blur', syncData)
40 66 }
41 67
42 68 // 路由变更时处理
... ...
... ... @@ -66,7 +66,14 @@ import { ref, computed } from 'vue'
66 66 import { useSettingStore } from '@/store/modules/settingStore/settingStore'
67 67 import { ToolsStatusEnum } from '@/store/modules/settingStore/settingStore.d'
68 68 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
69   -import { fetchRouteParamsLocation, fetchPathByName, routerTurnByPath, setSessionStorage, getLocalStorage } from '@/utils'
  69 +import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
  70 +import {
  71 + fetchRouteParamsLocation,
  72 + fetchPathByName,
  73 + routerTurnByPath,
  74 + setSessionStorage,
  75 + getLocalStorage
  76 +} from '@/utils'
70 77 import { EditEnum } from '@/enums/pageEnum'
71 78 import { StorageEnum } from '@/enums/storageEnum'
72 79 import { useRoute } from 'vue-router'
... ... @@ -137,8 +144,8 @@ const toolsMouseoutHandle = () => {
137 144
138 145 // 编辑处理
139 146 const editHandle = () => {
140   - window['$message'].warning('将开启失焦更新!')
141   -// window['$message'].warning('将开启失焦更新与 5 秒同步更新!')
  147 + window['$message'].warning('请通过顶部【同步内容】按钮同步最新数据!')
  148 + chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_CODE_EDIT, true)
142 149 setTimeout(() => {
143 150 // 获取id路径
144 151 const path = fetchPathByName(EditEnum.CHART_EDIT_NAME, 'href')
... ... @@ -146,7 +153,7 @@ const editHandle = () => {
146 153 const id = fetchRouteParamsLocation()
147 154 updateToSession(id)
148 155 routerTurnByPath(path, [id], undefined, true)
149   - }, 1000)
  156 + }, 2000)
150 157 }
151 158
152 159 // 把内存中的数据同步到SessionStorage 便于传递给新窗口初始化数据
... ...
... ... @@ -57,7 +57,7 @@ import { onMounted, computed } from 'vue'
57 57 import { chartColors } from '@/settings/chartThemes/index'
58 58 import { MenuEnum } from '@/enums/editPageEnum'
59 59 import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
60   -import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } from '@/utils'
  60 +import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle, colorCustomMerge } from '@/utils'
61 61 import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
62 62 import { MenuOptionsItemType } from '@/views/chart/hooks/useContextMenu.hook.d'
63 63 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
... ... @@ -120,8 +120,8 @@ const themeSetting = computed(() => {
120 120
121 121 // 配置项
122 122 const themeColor = computed(() => {
123   - const chartThemeColor = chartEditStore.getEditCanvasConfig.chartThemeColor
124   - return chartColors[chartThemeColor]
  123 + const colorCustomMergeData = colorCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)
  124 + return colorCustomMergeData[chartEditStore.getEditCanvasConfig.chartThemeColor]
125 125 })
126 126
127 127 // 是否展示渲染
... ...
... ... @@ -120,6 +120,7 @@ const historyList = reactive<ItemType<HistoryStackEnum>[]>([
120 120 }
121 121 ])
122 122
  123 +
123 124 // store 描述的是展示的值,所以和 ContentConfigurations 的 collapsed 是相反的
124 125 const styleHandle = (item: ItemType<ChartLayoutStoreEnum>) => {
125 126 if (item.key === ChartLayoutStoreEnum.DETAILS) {
... ...
1 1 <template>
2 2 <n-space class="go-mt-0">
3   - <n-button v-for="item in btnList" :key="item.title" ghost @click="item.event">
  3 + <n-button v-for="item in comBtnList" :key="item.title" :type="item.type" ghost @click="item.event">
4 4 <template #icon>
5 5 <component :is="item.icon"></component>
6 6 </template>
... ... @@ -10,16 +10,17 @@
10 10 </template>
11 11
12 12 <script setup lang="ts">
13   -import { shallowReactive } from 'vue'
  13 +import { computed, shallowReactive } from 'vue'
14 14 import { renderIcon, goDialog, fetchPathByName, routerTurnByPath, setSessionStorage, getLocalStorage } from '@/utils'
15 15 import { PreviewEnum } from '@/enums/pageEnum'
16 16 import { StorageEnum } from '@/enums/storageEnum'
17 17 import { useRoute } from 'vue-router'
18 18 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
19   -import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
  19 +import { syncData } from '../../ContentEdit/components/EditTools/hooks/useSyncUpdate.hook'
20 20 import { icon } from '@/plugins'
  21 +import { cloneDeep } from 'lodash'
21 22
22   -const { BrowsersOutlineIcon, SendIcon } = icon.ionicons5
  23 +const { BrowsersOutlineIcon, SendIcon, AnalyticsIcon } = icon.ionicons5
23 24 const chartEditStore = useChartEditStore()
24 25
25 26 const routerParamsInfo = useRoute()
... ... @@ -42,7 +43,8 @@ const previewHandle = () => {
42 43 setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, sessionStorageInfo)
43 44 } else {
44 45 sessionStorageInfo.push({
45   - id: previewId, ...storageInfo
  46 + id: previewId,
  47 + ...storageInfo
46 48 })
47 49 setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, sessionStorageInfo)
48 50 }
... ... @@ -66,6 +68,13 @@ const sendHandle = () => {
66 68 const btnList = shallowReactive([
67 69 {
68 70 select: true,
  71 + title: '同步内容',
  72 + type: 'primary',
  73 + icon: renderIcon(AnalyticsIcon),
  74 + event: syncData
  75 + },
  76 + {
  77 + select: true,
69 78 title: '预览',
70 79 icon: renderIcon(BrowsersOutlineIcon),
71 80 event: previewHandle
... ... @@ -78,7 +87,16 @@ const btnList = shallowReactive([
78 87 }
79 88 ])
80 89
  90 +const comBtnList = computed(() => {
  91 + if (chartEditStore.getEditCanvas.isCodeEdit) {
  92 + return btnList
  93 + }
  94 + const cloneList = cloneDeep(btnList)
  95 + cloneList.shift()
  96 + return cloneList
  97 +})
81 98 </script>
  99 +
82 100 <style lang="scss" scoped>
83 101 .align-center {
84 102 margin-top: -4px;
... ...
... ... @@ -5,15 +5,25 @@
5 5 </n-icon>
6 6 <n-text @click="handleFocus">
7 7 工作空间 -
8   - <n-button v-show="!focus" secondary round size="tiny">
  8 + <n-button v-show="!focus" secondary size="tiny">
9 9 <span class="title">
10 10 {{ comTitle }}
11 11 </span>
12 12 </n-button>
13 13 </n-text>
14 14
15   - <n-input v-show="focus" ref="inputInstRef" size="small" type="text" maxlength="16" show-count round
16   - placeholder="请输入项目名称" v-model:value.trim="title" @keyup.enter="handleBlur" @blur="handleBlur"></n-input>
  15 + <n-input
  16 + v-show="focus"
  17 + ref="inputInstRef"
  18 + size="small"
  19 + type="text"
  20 + maxlength="16"
  21 + show-count
  22 + placeholder="请输入项目名称"
  23 + v-model:value.trim="title"
  24 + @keyup.enter="handleBlur"
  25 + @blur="handleBlur"
  26 + ></n-input>
17 27 </n-space>
18 28 </template>
19 29
... ... @@ -63,6 +73,8 @@ const handleBlur = () => {
63 73 </script>
64 74 <style lang="scss" scoped>
65 75 .title {
  76 + padding-left: 5px;
  77 + padding-right: 5px;
66 78 font-size: 15px;
67 79 }
68 80 </style>
... ...
... ... @@ -14,8 +14,17 @@
14 14 </n-button>
15 15 </div>
16 16 <n-space>
17   - <n-tag :bordered="false" type="warning"> 「页面失焦保存」 </n-tag>
18   - <n-tag :bordered="false" type="warning"> 「ctrl + s 保存」 </n-tag>
  17 + <!-- 暂时关闭 -->
  18 + <!-- <n-tag :bordered="false" type="warning"> 「页面失焦保存」 </n-tag> -->
  19 + <n-tag :bordered="false" type="warning"> 「Ctrl + S 更新视图」 </n-tag>
  20 + <n-button v-if="showOpenFilePicker" class="go-mr-3" size="medium" @click="updateSync">
  21 + <template #icon>
  22 + <n-icon>
  23 + <analytics-icon></analytics-icon>
  24 + </n-icon>
  25 + </template>
  26 + 保存
  27 + </n-button>
19 28 </n-space>
20 29 </n-layout-header>
21 30 <n-layout-content>
... ... @@ -26,28 +35,31 @@
26 35 lineNumbers: 'on',
27 36 minimap: { enabled: true }
28 37 }"
29   - />
  38 + />
30 39 </n-layout-content>
31 40 </n-layout>
32 41 </div>
33 42 </template>
34 43
35 44 <script setup lang="ts">
36   -import { computed, ref, watch } from 'vue'
  45 +import { ref } from 'vue'
37 46 import { MonacoEditor } from '@/components/Pages/MonacoEditor'
38 47 import { SavePageEnum } from '@/enums/editPageEnum'
39 48 import { getSessionStorageInfo } from '../preview/utils'
40   -import type { ChartEditStorageType } from '../preview/index.d'
41   -import { setSessionStorage, JSONStringify, JSONParse, setTitle } from '@/utils'
  49 +import { setSessionStorage, JSONStringify, JSONParse, setTitle, goDialog } from '@/utils'
42 50 import { StorageEnum } from '@/enums/storageEnum'
43 51 import { icon } from '@/plugins'
  52 +import type { ChartEditStorageType } from '../preview/index.d'
44 53
45   -const { ChevronBackOutlineIcon, DownloadIcon } = icon.ionicons5
  54 +const { ChevronBackOutlineIcon, DownloadIcon, AnalyticsIcon } = icon.ionicons5
46 55 const showOpenFilePicker: Function = (window as any).showOpenFilePicker
47 56 const content = ref('')
  57 +
  58 +window['$message'].warning('请不要刷新此窗口!')
  59 +
48 60 // 从sessionStorage 获取数据
49 61 async function getDataBySession() {
50   - const localStorageInfo: ChartEditStorageType = await getSessionStorageInfo() as unknown as ChartEditStorageType
  62 + const localStorageInfo: ChartEditStorageType = (await getSessionStorageInfo()) as unknown as ChartEditStorageType
51 63 setTitle(`编辑-${localStorageInfo.editCanvasConfig.projectName}`)
52 64 content.value = JSONStringify(localStorageInfo)
53 65 }
... ... @@ -60,44 +72,75 @@ function back() {
60 72 }
61 73
62 74 // 导入json文本
63   -async function importJSON() {
64   - const files = await showOpenFilePicker()
65   - const file = await files[0].getFile()
66   - const fr = new FileReader()
67   - fr.readAsText(file)
68   - fr.onloadend = () => {
69   - content.value = (fr.result || '').toString()
70   - }
  75 +function importJSON() {
  76 + goDialog({
  77 + message: '导入数据将覆盖内容,此操作不可撤回,是否继续?',
  78 + isMaskClosable: true,
  79 + transformOrigin: 'center',
  80 + onPositiveCallback: async () => {
  81 + try {
  82 + const files = await showOpenFilePicker()
  83 + const file = await files[0].getFile()
  84 + const fr = new FileReader()
  85 + fr.readAsText(file)
  86 + fr.onloadend = () => {
  87 + content.value = (fr.result || '').toString()
  88 + }
  89 + window['$message'].success('导入成功!')
  90 + } catch (error) {
  91 + window['$message'].error('导入失败,请检查文件是否损坏!')
  92 + console.log(error)
  93 + }
  94 + }
  95 + })
71 96 }
72 97
73   -// 同步 [画布页失去焦点时同步数据到JSON页,JSON页Ctrl+S 时同步数据到画布页]
  98 +// 同步数据编辑页
74 99 window.opener.addEventListener(SavePageEnum.CHART, (e: any) => {
  100 + window['$message'].success('正在进行更新...')
75 101 setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, [e.detail])
76 102 content.value = JSONStringify(e.detail)
77 103 })
78 104
79   -// 窗口失焦 + 保存 => 同步数据
  105 +// 保存按钮同步数据
80 106 document.addEventListener('keydown', function (e) {
81 107 if (e.keyCode == 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
82 108 e.preventDefault()
83 109 updateSync()
84 110 }
85 111 })
86   -addEventListener('blur', updateSync)
  112 +
  113 +// 失焦保存(暂时关闭)
  114 +// addEventListener('blur', updateSync)
87 115
88 116 // 同步更新
89 117 async function updateSync() {
90 118 if (!window.opener) {
91   - return window['$message'].error('源窗口已关闭,视图同步失败')
  119 + return window['$message'].error('源窗口已关闭,视图同步失败')
92 120 }
93   - try {
94   - const detail = JSONParse(content.value)
95   - delete detail.id
96   - // 保持id不变
97   - window.opener.dispatchEvent(new CustomEvent(SavePageEnum.JSON, { detail }))
98   - } catch (e) {
99   - window['$message'].error('内容格式有误')
100   - console.log(e)
  121 + goDialog({
  122 + message: '是否覆盖源视图内容? 此操作不可撤!',
  123 + isMaskClosable: true,
  124 + transformOrigin: 'center',
  125 + onPositiveCallback: () => {
  126 + try {
  127 + const detail = JSONParse(content.value)
  128 + delete detail.id
  129 + // 保持id不变
  130 + window.opener.dispatchEvent(new CustomEvent(SavePageEnum.JSON, { detail }))
  131 + window['$message'].success('正在同步内容...')
  132 + } catch (e) {
  133 + window['$message'].error('内容格式有误')
  134 + console.log(e)
  135 + }
  136 + }
  137 + })
  138 +}
  139 +
  140 +// 关闭页面发送关闭事件
  141 +window.onbeforeunload = () => {
  142 + if (window.opener) {
  143 + window.opener.dispatchEvent(new CustomEvent(SavePageEnum.CLOSE))
101 144 }
102 145 }
103 146 </script>
... ...
... ... @@ -24,9 +24,18 @@
24 24 </layout-header>
25 25 <div class="go-login">
26 26 <div class="go-login-carousel">
27   - <n-carousel autoplay dot-type="line" :interval="Number(carouselInterval)">
28   - <img v-for="(item, i) in carouselImgList" :key="i" class="go-login-carousel-img"
29   - :src="getImageUrl(item, 'login')" alt="image" />
  27 + <n-carousel
  28 + autoplay
  29 + dot-type="line"
  30 + :interval="Number(carouselInterval)"
  31 + >
  32 + <img
  33 + v-for="(item, i) in carouselImgList"
  34 + :key="i"
  35 + class="go-login-carousel-img"
  36 + :src="getImageUrl(item, 'login')"
  37 + alt="image"
  38 + />
30 39 </n-carousel>
31 40 </div>
32 41 <div class="login-account">
... ... @@ -34,11 +43,24 @@
34 43 <n-collapse-transition :appear="true" :show="show">
35 44 <n-card class="login-account-card" :title="$t('login.desc')">
36 45 <div class="login-account-top">
37   - <img class="login-account-top-logo" src="~@/assets/images/login/input.png" alt="展示图片" />
  46 + <img
  47 + class="login-account-top-logo"
  48 + src="~@/assets/images/login/input.png"
  49 + alt="展示图片"
  50 + />
38 51 </div>
39   - <n-form ref="formRef" label-placement="left" size="large" :model="formInline" :rules="rules">
  52 + <n-form
  53 + ref="formRef"
  54 + label-placement="left"
  55 + size="large"
  56 + :model="formInline"
  57 + :rules="rules"
  58 + >
40 59 <n-form-item path="username">
41   - <n-input v-model:value="formInline.username" :placeholder="$t('global.form_account')">
  60 + <n-input
  61 + v-model:value="formInline.username"
  62 + :placeholder="$t('global.form_account')"
  63 + >
42 64 <template #prefix>
43 65 <n-icon size="18">
44 66 <PersonOutlineIcon></PersonOutlineIcon>
... ... @@ -47,8 +69,12 @@
47 69 </n-input>
48 70 </n-form-item>
49 71 <n-form-item path="password">
50   - <n-input v-model:value="formInline.password" type="password" show-password-on="click"
51   - :placeholder="$t('global.form_password')">
  72 + <n-input
  73 + v-model:value="formInline.password"
  74 + type="password"
  75 + show-password-on="click"
  76 + :placeholder="$t('global.form_password')"
  77 + >
52 78 <template #prefix>
53 79 <n-icon size="18">
54 80 <LockClosedOutlineIcon></LockClosedOutlineIcon>
... ... @@ -208,12 +234,10 @@ $carousel-image-height: 60vh;
208 234 * {
209 235 box-sizing: border-box;
210 236 }
211   -
212 237 @include go(login-box) {
213 238 height: $go-login-height;
214 239 overflow: hidden;
215 240 @include background-image('background-image');
216   -
217 241 &-header {
218 242 display: flex;
219 243 justify-content: space-between;
... ... @@ -221,7 +245,6 @@ $carousel-image-height: 60vh;
221 245 padding: 0 40px;
222 246 height: $--header-height;
223 247 }
224   -
225 248 &-divider {
226 249 margin: 0;
227 250 padding-top: 0;
... ...
... ... @@ -43,12 +43,14 @@ import { ChartEditStorageType } from '../../index.d'
43 43 import { PreviewRenderGroup } from '../PreviewRenderGroup/index'
44 44 import { CreateComponentGroupType } from '@/packages/index.d'
45 45 import { chartColors } from '@/settings/chartThemes/index'
46   -import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle } from '@/utils'
  46 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  47 +import { animationsClass, getFilterStyle, getTransformStyle, getBlendModeStyle, colorCustomMerge } from '@/utils'
47 48 import { getSizeStyle, getComponentAttrStyle, getStatusStyle, getPreviewConfigStyle } from '../../utils'
48 49 import { useLifeHandler } from '@/hooks'
49 50
50 51 // 初始化数据池
51 52 const { initDataPond, clearMittDataPondMap } = useChartDataPondFetch()
  53 +const chartEditStore = useChartEditStore()
52 54
53 55 const props = defineProps({
54 56 localStorageInfo: {
... ... @@ -63,10 +65,11 @@ const themeSetting = computed(() => {
63 65 return chartThemeSetting
64 66 })
65 67
  68 +
66 69 // 配置项
67 70 const themeColor = computed(() => {
68   - const chartThemeColor = props.localStorageInfo.editCanvasConfig.chartThemeColor
69   - return chartColors[chartThemeColor]
  71 + const colorCustomMergeData = colorCustomMerge(props.localStorageInfo.editCanvasConfig.chartCustomThemeColorInfo)
  72 + return colorCustomMergeData[props.localStorageInfo.editCanvasConfig.chartThemeColor]
70 73 })
71 74
72 75 // 组件渲染结束初始化数据池
... ...
... ... @@ -26,7 +26,7 @@
26 26 </div>
27 27 </template>
28 28
29   -<script setup lang="ts" >
  29 +<script setup lang="ts">
30 30 import { computed } from 'vue'
31 31 import { PreviewRenderList } from './components/PreviewRenderList'
32 32 import { getFilterStyle, setTitle } from '@/utils'
... ... @@ -68,19 +68,16 @@ const { show } = useComInstall(localStorageInfo)
68 68 height: 100vh;
69 69 width: 100vw;
70 70 @include background-image('background-image');
71   -
72 71 &.fit,
73 72 &.full {
74 73 display: flex;
75 74 align-items: center;
76 75 justify-content: center;
77 76 overflow: hidden;
78   -
79 77 .go-preview-scale {
80 78 transform-origin: center center;
81 79 }
82 80 }
83   -
84 81 &.scrollY {
85 82 overflow-x: hidden;
86 83
... ...
... ... @@ -27,8 +27,8 @@
27 27 </div>
28 28 <template #action>
29 29 <div class="go-flex-items-center list-footer" justify="space-between">
30   - <n-text class="go-ellipsis-1" :title="cardData.name">
31   - {{ cardData.name || '' }}
  30 + <n-text class="go-ellipsis-1" :title="cardData.title">
  31 + {{ cardData.title || '' }}
32 32 </n-text>
33 33 <!-- 工具 -->
34 34 <div class="go-flex-items-center list-footer-ri">
... ... @@ -37,12 +37,12 @@
37 37 <n-badge
38 38 class="go-animation-twinkle"
39 39 dot
40   - :color="cardData.state===0 ? '#34c749' : '#fcbc40'"
  40 + :color="cardData.release ? '#34c749' : '#fcbc40'"
41 41 ></n-badge>
42 42 {{
43   - cardData.state===0
44   - ?'未发布'
45   - : '已发布'
  43 + cardData.release
  44 + ? $t('project.release')
  45 + : $t('project.unreleased')
46 46 }}
47 47 </n-text>
48 48
... ...
... ... @@ -6,7 +6,7 @@ import { ChartList } from '../../..'
6 6 export const useDataListInit = () => {
7 7 const list = ref<ChartList>([
8 8 {
9   - id: 1,
  9 + id: 1,
10 10 title: '物料1-假数据不可用',
11 11 release: true,
12 12 label: '官方案例'
... ...
1 1 /// <reference types="vite/client" />
2 2
3   -declare interface GlobEnvConfig {
  3 +interface ImportMetaEnv {
4 4 // 标题
5 5 VITE_GLOB_APP_TITLE: string;
6 6 // 公共路径
... ...