Эх сурвалжийг харах

!2 升级合并goView主分支版本
Merge pull request !2 from EarlySummer/master

芋道源码 1 жил өмнө
parent
commit
4bcf6fd3c7
100 өөрчлөгдсөн 1395 нэмэгдсэн , 258 устгасан
  1. 3 0
      .gitignore
  2. 2 1
      index.html
  3. 25 7
      package.json
  4. 606 202
      pnpm-lock.yaml
  5. 10 0
      preview.yml
  6. 28 0
      src/App.vue
  7. 132 10
      src/api/axios.ts
  8. 100 0
      src/api/mock/graph.json
  9. 12 0
      src/api/mock/index.ts
  10. 86 0
      src/api/mock/sankey.json
  11. 17 1
      src/api/mock/test.mock.ts
  12. BIN
      src/assets/images/chart/charts/bar_line.png
  13. BIN
      src/assets/images/chart/charts/dial.png
  14. BIN
      src/assets/images/chart/charts/graph.png
  15. BIN
      src/assets/images/chart/charts/ground_glass.png
  16. BIN
      src/assets/images/chart/charts/grouped_stacked_rose_chart.png
  17. BIN
      src/assets/images/chart/charts/map_cesium.png
  18. BIN
      src/assets/images/chart/charts/polar_coordinate_axis.png
  19. BIN
      src/assets/images/chart/charts/sankey.png
  20. BIN
      src/assets/images/chart/charts/visactor_bar_line.png
  21. BIN
      src/assets/images/chart/charts/visactor_biax_line.png
  22. BIN
      src/assets/images/chart/charts/visactor_instrument.png
  23. BIN
      src/assets/images/chart/charts/visactor_line.png
  24. BIN
      src/assets/images/chart/charts/weather.png
  25. BIN
      src/assets/images/chart/decorates/Pipeline_H.png
  26. BIN
      src/assets/images/chart/decorates/Pipeline_V.png
  27. BIN
      src/assets/images/chart/decorates/bottom_decorate_1.png
  28. BIN
      src/assets/images/chart/decorates/decorates08.png
  29. BIN
      src/assets/images/chart/decorates/flow-circle.png
  30. BIN
      src/assets/images/chart/decorates/flow-zhexian.png
  31. BIN
      src/assets/images/chart/decorates/fullScreen.png
  32. BIN
      src/assets/images/chart/decorates/right_decorate_1.png
  33. BIN
      src/assets/images/chart/decorates/round_dot.png
  34. BIN
      src/assets/images/chart/decorates/status_lamp.png
  35. BIN
      src/assets/images/chart/icons/icon.png
  36. BIN
      src/assets/images/chart/informations/inputs_date.png
  37. BIN
      src/assets/images/chart/informations/inputs_input.png
  38. BIN
      src/assets/images/chart/informations/inputs_pagination.png
  39. BIN
      src/assets/images/chart/informations/inputs_select.png
  40. BIN
      src/assets/images/chart/informations/inputs_tab.png
  41. BIN
      src/assets/images/chart/informations/photo_carousel.png
  42. BIN
      src/assets/images/chart/informations/text_card.png
  43. BIN
      src/assets/images/chart/photos/upload.png
  44. BIN
      src/assets/images/chart/tables/tables_basic.png
  45. BIN
      src/assets/images/chart_background.png
  46. BIN
      src/assets/images/decoration/background_image_1.jpg
  47. BIN
      src/assets/images/decoration/background_image_2.jpg
  48. BIN
      src/assets/images/decoration/background_image_3.jpg
  49. BIN
      src/assets/images/decoration/background_image_4.png
  50. BIN
      src/assets/images/decoration/background_image_5.png
  51. BIN
      src/assets/images/decoration/big_title_base_image_0.png
  52. BIN
      src/assets/images/decoration/big_title_base_image_2.png
  53. BIN
      src/assets/images/decoration/big_title_base_image_3.png
  54. BIN
      src/assets/images/decoration/big_title_base_image_4.png
  55. BIN
      src/assets/images/decoration/big_title_base_image_5.png
  56. BIN
      src/assets/images/decoration/big_title_base_image_6.png
  57. BIN
      src/assets/images/decoration/big_title_base_image_7.png
  58. BIN
      src/assets/images/decoration/bottom_decorate_1.png
  59. BIN
      src/assets/images/decoration/right_decorate_1.png
  60. BIN
      src/assets/images/decoration/title_base_image_0.png
  61. BIN
      src/assets/images/decoration/title_base_image_11.png
  62. BIN
      src/assets/images/decoration/title_base_image_12.png
  63. BIN
      src/assets/images/decoration/title_base_image_13.png
  64. BIN
      src/assets/images/decoration/title_base_image_14.png
  65. BIN
      src/assets/images/decoration/title_base_image_15.png
  66. BIN
      src/assets/images/decoration/title_base_image_16.png
  67. BIN
      src/assets/images/decoration/title_base_image_3.png
  68. BIN
      src/assets/images/decoration/title_base_image_4.png
  69. BIN
      src/assets/images/decoration/title_base_image_5.png
  70. BIN
      src/assets/images/decoration/title_base_image_6.png
  71. BIN
      src/assets/images/decoration/title_base_image_7.png
  72. BIN
      src/assets/images/decoration/title_base_image_8.png
  73. BIN
      src/assets/images/decoration/title_base_image_9.png
  74. BIN
      src/assets/images/decoration/xm56fRJH.jpg
  75. BIN
      src/assets/images/decoration/上边框.png
  76. BIN
      src/assets/images/decoration/干净小标题底图.png
  77. BIN
      src/assets/images/decoration/底座.png
  78. BIN
      src/assets/images/decoration/模块外框.png
  79. BIN
      src/assets/images/decoration/模块边框2.png
  80. BIN
      src/assets/images/decoration/点位.png
  81. BIN
      src/assets/images/decoration/装饰绿点点.png
  82. BIN
      src/assets/images/decoration/边框.png
  83. BIN
      src/assets/images/decoration/边框流线.webm
  84. BIN
      src/assets/videos/charts-img-db_id_17bwi76fzta800.mp4
  85. BIN
      src/assets/videos/charts-img-db_id_cqlw0qmjt4o00.mp4
  86. BIN
      src/assets/videos/dynamic_circle.mp4
  87. 3 0
      src/components/GoIconify/index.ts
  88. 34 0
      src/components/GoIconify/index.vue
  89. 1 1
      src/components/Pages/ChartGlobImage/index.vue
  90. 45 0
      src/components/Pages/ChartItemSetting/EchartsRendererSetting.vue
  91. 85 3
      src/components/Pages/ChartItemSetting/GlobalSetting.vue
  92. 58 2
      src/components/Pages/ChartItemSetting/StylesSetting.vue
  93. 38 11
      src/components/Pages/Flipper/index.vue
  94. 2 1
      src/components/Pages/ThemeColorSelect/index.vue
  95. 4 1
      src/enums/editPageEnum.ts
  96. 32 4
      src/enums/eventEnum.ts
  97. 9 1
      src/enums/storageEnum.ts
  98. 2 1
      src/hooks/index.ts
  99. 26 0
      src/hooks/useCanvasInitOptions.hook.ts
  100. 35 12
      src/hooks/useChartDataFetch.hook.ts

+ 3 - 0
.gitignore

@@ -4,3 +4,6 @@ dist
 dist-ssr
 dist-ssr
 *.local
 *.local
 .vscode
 .vscode
+.idea
+.workflow
+.husky

+ 2 - 1
index.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8" />
     <meta charset="UTF-8" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
     <meta name="renderer" content="webkit" />
     <meta name="renderer" content="webkit" />
-    <meta name="description" content="GoView 是高效、高性能的拖拽式低代码数据可视化开发平台,将页面元素封装为基础组件,无需编写代码即可完成业务需求。">
+    <meta name="description" content="GoView 是高效、高性能的拖拽式低代码数据可视化开发平台,将页面元素封装为基础组件,无需编写代码即可完成业务需求。 ">
     <meta name="keywords" content="GoView,goview,低代码,可视化">
     <meta name="keywords" content="GoView,goview,低代码,可视化">
     <meta name="author" content="奔跑的面条,面条">
     <meta name="author" content="奔跑的面条,面条">
     <meta
     <meta
@@ -14,6 +14,7 @@
     <link rel="icon" href="./favicon.ico" />
     <link rel="icon" href="./favicon.ico" />
     <title>GoView</title>
     <title>GoView</title>
     <link rel="stylesheet" href="./index.css" />
     <link rel="stylesheet" href="./index.css" />
+      <script src="js/esobjs-xe2-plugin/dist-web/xe2-assets/js/load-common.js"></script>
   </head>
   </head>
   <body>
   <body>
     <div id="appProvider" style="display: none;"></div>
     <div id="appProvider" style="display: none;"></div>

+ 25 - 7
package.json

@@ -1,8 +1,9 @@
 {
 {
+  "type": "module",
   "name": "go-view",
   "name": "go-view",
   "version": "2.1.6",
   "version": "2.1.6",
   "engines": {
   "engines": {
-    "node": ">=16.14 <18.0.0"
+    "node": ">=12.0"
   },
   },
   "scripts": {
   "scripts": {
     "dev": "vite --host",
     "dev": "vite --host",
@@ -16,34 +17,48 @@
   "dependencies": {
   "dependencies": {
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@amap/amap-jsapi-types": "^0.0.8",
     "@amap/amap-jsapi-types": "^0.0.8",
+    "@iconify/json": "^2.2.158",
     "@types/color": "^3.0.3",
     "@types/color": "^3.0.3",
     "@types/crypto-js": "^4.1.1",
     "@types/crypto-js": "^4.1.1",
     "@types/keymaster": "^1.6.30",
     "@types/keymaster": "^1.6.30",
     "@types/lodash": "^4.14.184",
     "@types/lodash": "^4.14.184",
+    "@visactor/vchart": "^1.12.3",
+    "@visactor/vchart-theme": "^1.12.1",
     "animate.css": "^4.1.1",
     "animate.css": "^4.1.1",
-    "axios": "^0.27.2",
+    "axios": "^1.4.0",
+    "cesium": "1.99",
     "color": "^4.2.3",
     "color": "^4.2.3",
     "crypto-js": "^4.1.1",
     "crypto-js": "^4.1.1",
+    "dayjs": "^1.11.7",
     "dom-helpers": "^5.2.1",
     "dom-helpers": "^5.2.1",
     "echarts-liquidfill": "^3.1.0",
     "echarts-liquidfill": "^3.1.0",
     "echarts-stat": "^1.2.0",
     "echarts-stat": "^1.2.0",
     "echarts-wordcloud": "^2.0.0",
     "echarts-wordcloud": "^2.0.0",
+    "esobjs-xe2-plugin": "^0.1.126-beta-0.3",
     "gsap": "^3.11.3",
     "gsap": "^3.11.3",
     "highlight.js": "^11.5.0",
     "highlight.js": "^11.5.0",
     "html2canvas": "^1.4.1",
     "html2canvas": "^1.4.1",
+    "iconify-icon": "^1.0.8",
     "keymaster": "^1.6.2",
     "keymaster": "^1.6.2",
+    "mitt": "^3.0.0",
     "monaco-editor": "^0.33.0",
     "monaco-editor": "^0.33.0",
     "naive-ui": "2.34.3",
     "naive-ui": "2.34.3",
     "pinia": "^2.0.13",
     "pinia": "^2.0.13",
+    "pnpm": "^8.7.0",
     "screenfull": "^6.0.1",
     "screenfull": "^6.0.1",
     "three": "^0.145.0",
     "three": "^0.145.0",
+    "vite-plugin-cesium": "^1.2.23",
     "vue": "^3.2.31",
     "vue": "^3.2.31",
     "vue-demi": "^0.13.1",
     "vue-demi": "^0.13.1",
-    "vue-i18n": "^9.2.2",
+    "vue-i18n": "9.2.2",
     "vue-router": "4.0.12",
     "vue-router": "4.0.12",
+    "vue-xe2-plugin": "^0.1.3",
     "vue3-lazyload": "^0.2.5-beta",
     "vue3-lazyload": "^0.2.5-beta",
     "vue3-sketch-ruler": "^1.3.3",
     "vue3-sketch-ruler": "^1.3.3",
-    "vuedraggable": "^4.1.0"
+    "vuedraggable": "^4.1.0",
+    "xbsj-xe2": "^0.1.16",
+    "xbsj-xe2-assets": "^0.1.16",
+    "smplotting-xe2-plugin": "^0.1.3"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@commitlint/cli": "^17.0.2",
     "@commitlint/cli": "^17.0.2",
@@ -54,8 +69,8 @@
     "@typescript-eslint/parser": "^5.18.0",
     "@typescript-eslint/parser": "^5.18.0",
     "@vicons/carbon": "^0.12.0",
     "@vicons/carbon": "^0.12.0",
     "@vicons/ionicons5": "~0.11.0",
     "@vicons/ionicons5": "~0.11.0",
-    "@vitejs/plugin-vue": "^1.10.2",
-    "@vitejs/plugin-vue-jsx": "^1.3.9",
+    "@vitejs/plugin-vue": "^4.2.3",
+    "@vitejs/plugin-vue-jsx": "^3.0.1",
     "@vue/compiler-sfc": "^3.2.31",
     "@vue/compiler-sfc": "^3.2.31",
     "@vueuse/core": "^7.7.1",
     "@vueuse/core": "^7.7.1",
     "commitlint": "^17.0.2",
     "commitlint": "^17.0.2",
@@ -66,6 +81,7 @@
     "eslint-plugin-import": "^2.26.0",
     "eslint-plugin-import": "^2.26.0",
     "eslint-plugin-prettier": "^4.0.0",
     "eslint-plugin-prettier": "^4.0.0",
     "eslint-plugin-vue": "^8.5.0",
     "eslint-plugin-vue": "^8.5.0",
+    "esobjs-xe2-plugin-assets": "^0.1.14",
     "husky": "^8.0.1",
     "husky": "^8.0.1",
     "lodash": "~4.17.21",
     "lodash": "~4.17.21",
     "mockjs": "^1.1.0",
     "mockjs": "^1.1.0",
@@ -74,11 +90,13 @@
     "sass": "^1.49.11",
     "sass": "^1.49.11",
     "sass-loader": "^12.6.0",
     "sass-loader": "^12.6.0",
     "typescript": "4.6.3",
     "typescript": "4.6.3",
-    "vite": "2.9.9",
+    "vite": "4.3.6",
     "vite-plugin-compression": "^0.5.1",
     "vite-plugin-compression": "^0.5.1",
+    "vite-plugin-externals": "^0.6.2",
     "vite-plugin-importer": "^0.2.5",
     "vite-plugin-importer": "^0.2.5",
     "vite-plugin-mock": "^2.9.6",
     "vite-plugin-mock": "^2.9.6",
     "vite-plugin-monaco-editor": "^1.1.0",
     "vite-plugin-monaco-editor": "^1.1.0",
+    "vite-plugin-static-copy": "^1.0.6",
     "vue-echarts": "^6.0.2",
     "vue-echarts": "^6.0.2",
     "vue-tsc": "^0.28.10"
     "vue-tsc": "^0.28.10"
   }
   }

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 606 - 202
pnpm-lock.yaml


+ 10 - 0
preview.yml

@@ -0,0 +1,10 @@
+# preview.yml
+autoOpen: true # 打开工作空间时是否自动开启所有应用的预览
+apps:
+  - port: 3000 # 应用的端口
+    run: npm i --registry=https://registry.npmmirror.com && npm run dev # 应用的启动命令
+    command: # 使用此命令启动服务,且不执行run
+    root: ./ # 应用的启动目录
+    name: GoView # 应用名称
+    description: 开源、精美、便捷的「数据可视化」低代码开发平台 # 应用描述
+    autoOpen: true # 打开工作空间时是否自动开启预览(优先级高于根级 autoOpen)

+ 28 - 0
src/App.vue

@@ -19,6 +19,34 @@ import { GoAppProvider } from '@/components/GoAppProvider'
 import { I18n } from '@/components/I18n'
 import { I18n } from '@/components/I18n'
 import { useSystemInit, useDarkThemeHook, useThemeOverridesHook, useCode, useLang } from '@/hooks'
 import { useSystemInit, useDarkThemeHook, useThemeOverridesHook, useCode, useLang } from '@/hooks'
 
 
+//字节图表全局配置部分
+import vScreenVolcanoBlue from '@visactor/vchart-theme/public/vScreenVolcanoBlue.json';
+import VChart from '@visactor/vchart';
+import {IGlobalMarkThemeByName, IGlobalMarkThemeByType, ITheme} from "@visactor/vchart/esm/theme/interface";
+import {languages} from "monaco-editor";
+import type {IColorKey} from "@visactor/vchart/esm/theme/color-scheme/interface";
+import type {ITokenKey} from "@visactor/vchart/esm/theme/token";
+import type {ISeriesTheme} from "@visactor/vchart/esm/series/interface";
+import type {IComponentTheme} from "@visactor/vchart/esm/component/interface";
+const myVScreenVolcanoBlue: Partial<ITheme> = {
+   ...vScreenVolcanoBlue,
+  type:"dark",
+  background:vScreenVolcanoBlue.background as IColorKey,
+  fontFamily:vScreenVolcanoBlue.fontFamily as ITokenKey,
+  mark:vScreenVolcanoBlue.mark as IGlobalMarkThemeByType,
+  markByName:vScreenVolcanoBlue.markByName as IGlobalMarkThemeByName,
+  series:vScreenVolcanoBlue.series as ISeriesTheme,
+  component: vScreenVolcanoBlue.component as unknown  as IComponentTheme
+  // 其他字段逐个检查和断言
+};
+
+VChart.ThemeManager.registerTheme('vScreenVolcanoBlue',myVScreenVolcanoBlue);
+// apply the theme
+VChart.ThemeManager.setCurrentTheme('vScreenVolcanoBlue');
+//字节图标配置部分END
+
+
+
 // 暗黑主题
 // 暗黑主题
 const darkTheme = useDarkThemeHook()
 const darkTheme = useDarkThemeHook()
 
 

+ 132 - 10
src/api/axios.ts

@@ -1,12 +1,32 @@
 import axios, { AxiosResponse, AxiosRequestConfig, Axios } from 'axios'
 import axios, { AxiosResponse, AxiosRequestConfig, Axios } from 'axios'
 import { ResultEnum, ModuleTypeEnum } from "@/enums/httpEnum"
 import { ResultEnum, ModuleTypeEnum } from "@/enums/httpEnum"
-import { PageEnum, ErrorPageNameMap } from "@/enums/pageEnum"
+import {PageEnum, ErrorPageNameMap, PreviewEnum} from "@/enums/pageEnum"
 import { StorageEnum } from '@/enums/storageEnum'
 import { StorageEnum } from '@/enums/storageEnum'
 import { axiosPre } from '@/settings/httpSetting'
 import { axiosPre } from '@/settings/httpSetting'
 import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d'
 import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d'
-import { redirectErrorPage, getLocalStorage, routerTurnByName, isPreview } from '@/utils'
+import {
+    redirectErrorPage,
+    getLocalStorage,
+    routerTurnByName,
+    isPreview,
+    clearAllSessio,
+    clearAllStorage,
+    setLocalStorage,
+    setSessionStorage, fetchRouteParamsLocation, fetchRouteName, logout, fetchRoutePath
+} from '@/utils'
 import { fetchAllowList } from './axios.config'
 import { fetchAllowList } from './axios.config'
 import includes from 'lodash/includes'
 import includes from 'lodash/includes'
+import {useSystemStore} from "@/store/modules/systemStore/systemStore";
+import { useDialog } from 'naive-ui'
+// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
+// 请求队列
+let requestList: any[] = []
+// 是否正在刷新中
+let isRefreshToken = false
+// 请求路径
+let base_url=`${import.meta.env.PROD ? import.meta.env.VITE_PRO_PATH : ''}${axiosPre}`
+
+const dialog = useDialog()
 
 
 export interface MyResponseType<T> {
 export interface MyResponseType<T> {
   code: ResultEnum
   code: ResultEnum
@@ -19,7 +39,7 @@ export interface MyRequestInstance extends Axios {
 }
 }
 
 
 const axiosInstance = axios.create({
 const axiosInstance = axios.create({
-  baseURL: `${import.meta.env.PROD ? import.meta.env.VITE_PRO_PATH : ''}${axiosPre}`,
+  baseURL: base_url,
   timeout: ResultEnum.TIMEOUT,
   timeout: ResultEnum.TIMEOUT,
 }) as unknown as MyRequestInstance
 }) as unknown as MyRequestInstance
 
 
@@ -27,6 +47,7 @@ axiosInstance.interceptors.request.use(
   (config: AxiosRequestConfig) => {
   (config: AxiosRequestConfig) => {
     // 获取 tenantId
     // 获取 tenantId
     const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
     const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
+      // console.log(window.location)
     const tenantId = info ? info[SystemStoreEnum.TENANT_INFO]['tenantId'] : undefined
     const tenantId = info ? info[SystemStoreEnum.TENANT_INFO]['tenantId'] : undefined
     if (tenantId) {
     if (tenantId) {
       config.headers = {
       config.headers = {
@@ -57,15 +78,18 @@ axiosInstance.interceptors.request.use(
 
 
 // 响应拦截器
 // 响应拦截器
 axiosInstance.interceptors.response.use(
 axiosInstance.interceptors.response.use(
-  (res: AxiosResponse) => {
+    async (res: AxiosResponse<any>) => {
+    const config = res.config
+
+    const { code,msg } = res.data as { code: number,msg:string }
+
+     if (code === undefined || code === null) return Promise.resolve(res)
     // 预览页面错误不进行处理
     // 预览页面错误不进行处理
-    if (isPreview()) {
+    if (isPreview()&&code!==ResultEnum.TOKEN_OVERDUE) {
       return Promise.resolve(res.data)
       return Promise.resolve(res.data)
     }
     }
     // 如果是验证码的返回,直接返回数据
     // 如果是验证码的返回,直接返回数据
-    const { code } = res.data as { code: number }
 
 
-    if (code === undefined || code === null) return Promise.resolve(res)
 
 
     // 成功
     // 成功
     if (code === ResultEnum.SUCCESS) {
     if (code === ResultEnum.SUCCESS) {
@@ -74,9 +98,68 @@ axiosInstance.interceptors.response.use(
 
 
     // 登录过期
     // 登录过期
     if (code === ResultEnum.TOKEN_OVERDUE) {
     if (code === ResultEnum.TOKEN_OVERDUE) {
-      window['$message'].error(window['$t']('http.token_overdue_message'))
-      routerTurnByName(PageEnum.BASE_LOGIN_NAME)
-      return Promise.resolve(res.data)
+        // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
+        console.log('Auth2:-------------------准备刷新令牌-----------------')
+        if (!isRefreshToken) {
+            isRefreshToken = true
+            const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
+            // console.log(window.location)
+            const refreshToken = info ? info[SystemStoreEnum.USER_INFO][SystemStoreUserInfoEnum.USER_REFRESH_TOKEN] : undefined
+            // 1. 如果获取不到刷新令牌,则只能执行登出操作
+
+            if (!refreshToken) {
+                console.log('无刷新令牌,即将返回。')
+                return handleAuthorized()
+            }
+            // 2. 进行刷新访问令牌
+            try {
+                const systemStore = useSystemStore()
+                const refreshTokenRes = await getTefreshToken()
+                // 2.1 刷新成功,则回放队列的请求 + 当前请求
+                systemStore.setItem(SystemStoreEnum.USER_INFO, {
+                    [SystemStoreUserInfoEnum.USER_TOKEN]: (await refreshTokenRes).data.data.accessToken,
+                    [SystemStoreUserInfoEnum.USER_REFRESH_TOKEN]: (await refreshTokenRes).data.data.refreshToken,
+                    [SystemStoreUserInfoEnum.TOKEN_NAME]: 'Authorization'
+                })
+                //修改当前访问令牌
+                // config.headers!.Authorization = 'Bearer ' + (await refreshTokenRes).data.data.accessToken
+                const userInfo = info[SystemStoreEnum.USER_INFO]
+                config.headers = {
+                    ...config.headers,
+                    [userInfo[SystemStoreUserInfoEnum.TOKEN_NAME] || 'token']: 'Bearer ' + userInfo[SystemStoreUserInfoEnum.USER_TOKEN] || ''
+                }
+
+                requestList.forEach((cb: any) => {
+                    cb()
+                })
+                requestList = []
+                console.log('Auth2:-------------------令牌刷新成功-----------------')
+                return axiosInstance(config)
+            } catch (e) {
+                // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
+                // 2.2 刷新失败,只回放队列的请求
+                requestList.forEach((cb: any) => {
+                    cb()
+                })
+                // 提示是否要登出。即不回放当前请求!不然会形成递归
+                return handleAuthorized()
+            } finally {
+                requestList = []
+                isRefreshToken = false
+            }
+        } else {
+            console.log('Auth2:-------------------已添加刷新队列-----------------')
+            const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
+            // 添加到队列,等待刷新获取到新的令牌
+            return new Promise((resolve) => {
+                requestList.push(() => {
+                    const userInfo = info[SystemStoreEnum.USER_INFO]
+                    config.headers!.Authorization = 'Bearer ' + userInfo[SystemStoreUserInfoEnum.USER_TOKEN] // 让每个请求携带自定义token 请根据实际情况自行修改
+                    resolve(axiosInstance(config))
+                })
+            })
+        }
+
     }
     }
 
 
     // 固定错误码重定向
     // 固定错误码重定向
@@ -85,6 +168,17 @@ axiosInstance.interceptors.response.use(
       return Promise.resolve(res.data)
       return Promise.resolve(res.data)
     }
     }
 
 
+        if (code !== 200) {
+            if (msg === '无效的刷新令牌') {
+                // hard coding:忽略这个提示,直接登出
+                console.log(msg)
+                return handleAuthorized()
+            } else {
+                window['$message'].error(msg)
+            }
+            return Promise.reject('error')
+        }
+
     // 提示错误
     // 提示错误
     window['$message'].error(window['$t']((res.data as any).msg))
     window['$message'].error(window['$t']((res.data as any).msg))
     return Promise.resolve(res.data)
     return Promise.resolve(res.data)
@@ -94,4 +188,32 @@ axiosInstance.interceptors.response.use(
   }
   }
 )
 )
 
 
+
+const getTefreshToken = async () => {
+    let tenantData =  getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
+    axios.defaults.headers.common['tenant-id'] = tenantData[SystemStoreEnum.TENANT_INFO]['tenantId'] ?? undefined;
+    return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + tenantData[SystemStoreEnum.USER_INFO][SystemStoreUserInfoEnum.USER_REFRESH_TOKEN] ?? undefined)
+}
+
+
+const handleAuthorized  = () =>{
+    // window['$message'].error(window['$t']('http.token_overdue_message'))
+    console.log(useDialog())
+    window['$dialog'].warning( {title: '登录已超时',
+        content: '登录超时,请重新登录。',
+        positiveText: '确定',
+        negativeText: '取消',
+        onPositiveClick: () => {
+            // session 不需要清除 clearAllSessio() //清除所有Session缓存
+            clearAllStorage() //清除所有Storage缓存
+            //临时缓存跳回目录进行登录重新跳回
+            if('/chart/preview' === fetchRoutePath()){
+                setSessionStorage('setRedirectPath','/chart/preview')
+                setSessionStorage('setRedirectPathId', fetchRouteParamsLocation())
+            }
+            logout()
+            return Promise.resolve(window['$t']('http.token_overdue_message'))
+        }
+    })
+}
 export default axiosInstance
 export default axiosInstance

+ 100 - 0
src/api/mock/graph.json

@@ -0,0 +1,100 @@
+{
+    "nodes": [
+      {
+        "id": "0",
+        "name": "Myriel",
+        "symbolSize": "@integer(0, 50)",
+        "x": -266.82776,
+        "y": 299.6904,
+        "value": "@integer(0, 50)",
+        "category": 3
+      },
+      {
+        "id": "1",
+        "name": "Napoleon",
+        "symbolSize": "@integer(0, 50)",
+        "x": -418.08344,
+        "y": 446.8853,
+        "value": "@integer(0, 50)",
+        "category": 5
+      },
+      {
+        "id": "2",
+        "name": "MlleBaptistine",
+        "symbolSize": "@integer(0, 50)",
+        "x": -212.76357,
+        "y": 245.29176,
+        "value": "@integer(0, 50)",
+        "category": 1
+      },
+      {
+        "id": "3",
+        "name": "MmeMagloire",
+        "symbolSize": "@integer(0, 50)",
+        "x": -242.82404,
+        "y": 235.26283,
+        "value": "@integer(0, 50)",
+        "category": 1
+      },
+      {
+        "id": "4",
+        "name": "CountessDeLo",
+        "symbolSize": "@integer(0, 50)",
+        "x": -379.30386,
+        "y": 429.06424,
+        "value": "@integer(0, 50)",
+        "category": 0
+      }
+    ],
+    "links": [
+      {
+        "source": "1",
+        "target": "@integer(2, 4)"
+      },
+      {
+        "source": "2",
+        "target": "@integer(3, 4)"
+      },
+      {
+        "source": "3",
+        "target": "@integer(0, 2)"
+      },
+      {
+        "source": "3",
+        "target": "@integer(0, 1)"
+      },
+      {
+        "source": "4",
+        "target": "@integer(0, 3)"
+      }
+    ],
+    "categories": [
+      {
+        "name": "A"
+      },
+      {
+        "name": "B"
+      },
+      {
+        "name": "C"
+      },
+      {
+        "name": "D"
+      },
+      {
+        "name": "E"
+      },
+      {
+        "name": "F"
+      },
+      {
+        "name": "G"
+      },
+      {
+        "name": "H"
+      },
+      {
+        "name": "I"
+      }
+    ]
+  }

+ 12 - 0
src/api/mock/index.ts

@@ -19,6 +19,8 @@ export const capsuleUrl = '/mock/capsule'
 export const wordCloudUrl = '/mock/wordCloud'
 export const wordCloudUrl = '/mock/wordCloud'
 export const treemapUrl = '/mock/treemap'
 export const treemapUrl = '/mock/treemap'
 export const threeEarth01Url = '/mock/threeEarth01Data'
 export const threeEarth01Url = '/mock/threeEarth01Data'
+export const sankeyUrl = '/mock/sankey'
+export const graphUrl = '/mock/graphData'
 
 
 const mockObject: MockMethod[] = [
 const mockObject: MockMethod[] = [
   {
   {
@@ -103,6 +105,16 @@ const mockObject: MockMethod[] = [
     method: RequestHttpEnum.GET,
     method: RequestHttpEnum.GET,
     response: () => test.threeEarth01Data
     response: () => test.threeEarth01Data
   },
   },
+  {
+    url: sankeyUrl,
+    method: RequestHttpEnum.GET,
+    response: () => test.fetchSankey
+  },
+  {
+    url: graphUrl,
+    method: RequestHttpEnum.GET,
+    response: () => test.graphData
+  },
 ]
 ]
 
 
 export default mockObject
 export default mockObject

+ 86 - 0
src/api/mock/sankey.json

@@ -0,0 +1,86 @@
+{
+  "label": [
+    {
+      "name": "a"
+    },
+    {
+      "name": "b"
+    },
+    {
+      "name": "a1"
+    },
+    {
+      "name": "a2"
+    },
+    {
+      "name": "b1"
+    },
+    {
+      "name": "b2"
+    }
+  ],
+  "links": [
+    {
+      "source": "a",
+      "target": "a1",
+      "value": "@integer(0, 10)"
+    },
+    {
+      "source": "a",
+      "target": "a2",
+      "value": "@integer(0, 10)"
+    },
+    {
+      "source": "b",
+      "target": "b1",
+      "value": "@integer(0, 10)"
+    },
+    {
+      "source": "a",
+      "target": "b1",
+      "value": "@integer(0, 10)"
+    },
+    {
+      "source": "b1",
+      "target": "a1",
+      "value": "@integer(0, 10)"
+    },
+    {
+      "source": "b1",
+      "target": "b2",
+      "value": "@integer(0, 10)"
+    }
+  ],
+  "levels": [
+    {
+      "depth": 0,
+      "itemStyle": {
+        "color": "#decbe4"
+      },
+      "lineStyle": {
+        "color": "source",
+        "opacity": 0.9
+      }
+    },
+    {
+      "depth": 1,
+      "itemStyle": {
+        "color": "#b3cde3"
+      },
+      "lineStyle": {
+        "color": "source",
+        "opacity": 0.6
+      }
+    },
+    {
+      "depth": 2,
+      "itemStyle": {
+        "color": "#ccebc5"
+      },
+      "lineStyle": {
+        "color": "source",
+        "opacity": 0.6
+      }
+    }
+  ]
+}

+ 17 - 1
src/api/mock/test.mock.ts

@@ -2,6 +2,8 @@ import heatmapJson from './heatMapData.json'
 import scatterJson from './scatter.json'
 import scatterJson from './scatter.json'
 import mapJson from './map.json'
 import mapJson from './map.json'
 import tTreemapJson from './treemap.json'
 import tTreemapJson from './treemap.json'
+import sankeyJson from './sankey.json'
+import graphDataJson from './graph.json'
 
 
 export default {
 export default {
   // 单图表
   // 单图表
@@ -219,5 +221,19 @@ export default {
         'endArray|10': [{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' }]
         'endArray|10': [{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' }]
       }
       }
     ]
     ]
-  }
+  },
+  // 桑基图
+  fetchSankey: {
+    code: 0,
+    status: 200,
+    msg: '请求成功',
+    data: sankeyJson
+  },
+  // 关系图
+  graphData: {
+    code: 0,
+    status: 200,
+    msg: '请求成功',
+    data: graphDataJson
+  },
 }
 }

BIN
src/assets/images/chart/charts/bar_line.png


BIN
src/assets/images/chart/charts/dial.png


BIN
src/assets/images/chart/charts/graph.png


BIN
src/assets/images/chart/charts/ground_glass.png


BIN
src/assets/images/chart/charts/grouped_stacked_rose_chart.png


BIN
src/assets/images/chart/charts/map_cesium.png


BIN
src/assets/images/chart/charts/polar_coordinate_axis.png


BIN
src/assets/images/chart/charts/sankey.png


BIN
src/assets/images/chart/charts/visactor_bar_line.png


BIN
src/assets/images/chart/charts/visactor_biax_line.png


BIN
src/assets/images/chart/charts/visactor_instrument.png


BIN
src/assets/images/chart/charts/visactor_line.png


BIN
src/assets/images/chart/charts/weather.png


BIN
src/assets/images/chart/decorates/Pipeline_H.png


BIN
src/assets/images/chart/decorates/Pipeline_V.png


BIN
src/assets/images/chart/decorates/bottom_decorate_1.png


BIN
src/assets/images/chart/decorates/decorates08.png


BIN
src/assets/images/chart/decorates/flow-circle.png


BIN
src/assets/images/chart/decorates/flow-zhexian.png


BIN
src/assets/images/chart/decorates/fullScreen.png


BIN
src/assets/images/chart/decorates/right_decorate_1.png


BIN
src/assets/images/chart/decorates/round_dot.png


BIN
src/assets/images/chart/decorates/status_lamp.png


BIN
src/assets/images/chart/icons/icon.png


BIN
src/assets/images/chart/informations/inputs_date.png


BIN
src/assets/images/chart/informations/inputs_input.png


BIN
src/assets/images/chart/informations/inputs_pagination.png


BIN
src/assets/images/chart/informations/inputs_select.png


BIN
src/assets/images/chart/informations/inputs_tab.png


BIN
src/assets/images/chart/informations/photo_carousel.png


BIN
src/assets/images/chart/informations/text_card.png


BIN
src/assets/images/chart/photos/upload.png


BIN
src/assets/images/chart/tables/tables_basic.png


BIN
src/assets/images/chart_background.png


BIN
src/assets/images/decoration/background_image_1.jpg


BIN
src/assets/images/decoration/background_image_2.jpg


BIN
src/assets/images/decoration/background_image_3.jpg


BIN
src/assets/images/decoration/background_image_4.png


BIN
src/assets/images/decoration/background_image_5.png


BIN
src/assets/images/decoration/big_title_base_image_0.png


BIN
src/assets/images/decoration/big_title_base_image_2.png


BIN
src/assets/images/decoration/big_title_base_image_3.png


BIN
src/assets/images/decoration/big_title_base_image_4.png


BIN
src/assets/images/decoration/big_title_base_image_5.png


BIN
src/assets/images/decoration/big_title_base_image_6.png


BIN
src/assets/images/decoration/big_title_base_image_7.png


BIN
src/assets/images/decoration/bottom_decorate_1.png


BIN
src/assets/images/decoration/right_decorate_1.png


BIN
src/assets/images/decoration/title_base_image_0.png


BIN
src/assets/images/decoration/title_base_image_11.png


BIN
src/assets/images/decoration/title_base_image_12.png


BIN
src/assets/images/decoration/title_base_image_13.png


BIN
src/assets/images/decoration/title_base_image_14.png


BIN
src/assets/images/decoration/title_base_image_15.png


BIN
src/assets/images/decoration/title_base_image_16.png


BIN
src/assets/images/decoration/title_base_image_3.png


BIN
src/assets/images/decoration/title_base_image_4.png


BIN
src/assets/images/decoration/title_base_image_5.png


BIN
src/assets/images/decoration/title_base_image_6.png


BIN
src/assets/images/decoration/title_base_image_7.png


BIN
src/assets/images/decoration/title_base_image_8.png


BIN
src/assets/images/decoration/title_base_image_9.png


BIN
src/assets/images/decoration/xm56fRJH.jpg


BIN
src/assets/images/decoration/上边框.png


BIN
src/assets/images/decoration/干净小标题底图.png


BIN
src/assets/images/decoration/底座.png


BIN
src/assets/images/decoration/模块外框.png


BIN
src/assets/images/decoration/模块边框2.png


BIN
src/assets/images/decoration/点位.png


BIN
src/assets/images/decoration/装饰绿点点.png


BIN
src/assets/images/decoration/边框.png


BIN
src/assets/images/decoration/边框流线.webm


BIN
src/assets/videos/charts-img-db_id_17bwi76fzta800.mp4


BIN
src/assets/videos/charts-img-db_id_cqlw0qmjt4o00.mp4


BIN
src/assets/videos/dynamic_circle.mp4


+ 3 - 0
src/components/GoIconify/index.ts

@@ -0,0 +1,3 @@
+import GoIconify from './index.vue';
+
+export { GoIconify };

+ 34 - 0
src/components/GoIconify/index.vue

@@ -0,0 +1,34 @@
+<template>
+  <iconify-icon
+    :icon="icon"
+    :rotate="`${rotate}deg`"
+    :width="width"
+    :style="{
+      color: color
+    }"
+  ></iconify-icon>
+</template>
+
+<script setup lang="ts">
+defineProps({
+  icon: {
+    type: String,
+    required: true
+  },
+  color: {
+    type: String,
+    default: '#999999',
+    required: false
+  },
+  width: {
+    type: [String, Number],
+    default: '20',
+    required: false
+  },
+  rotate: {
+    type: [String, Number],
+    default: '0',
+    required: false
+  }
+})
+</script>

+ 1 - 1
src/components/Pages/ChartGlobImage/index.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <img class="list-img" v-lazy="imageInfo" alt="图表图片" />
+  <img class="list-img" v-lazy="imageInfo" :alt="imageInfo" />
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">

+ 45 - 0
src/components/Pages/ChartItemSetting/EchartsRendererSetting.vue

@@ -0,0 +1,45 @@
+<template>
+  <n-radio-group :value="props.modelValue || INHERIT_VALUE" @update:value="handleChange">
+    <n-space>
+      <n-tooltip :show-arrow="false" trigger="hover" v-for="item in rendererList" :key="item.value">
+        <template #trigger>
+          <n-radio :value="item.value">
+            {{ item.value }}
+          </n-radio>
+        </template>
+        {{ item.desc }}
+      </n-tooltip>
+    </n-space>
+  </n-radio-group>
+</template>
+<script setup lang="ts">
+import { type EchartsRenderer } from '@/settings/chartThemes'
+
+const props = defineProps<{ modelValue?: EchartsRenderer; includeInherit?: boolean }>()
+const emits = defineEmits(['update:modelValue'])
+
+const INHERIT_VALUE = 'inherit'
+
+const handleChange = (val: EchartsRenderer & typeof INHERIT_VALUE) => {
+  emits('update:modelValue', val === INHERIT_VALUE ? undefined : val)
+}
+
+const rendererList = [
+  {
+    value: 'svg',
+    desc: '在缩放场景下具有更好的表现'
+  },
+  {
+    value: 'canvas',
+    desc: '数据量较大(经验判断 > 1k)、较多交互时,建议选择'
+  },
+  ...(props.includeInherit
+    ? [
+        {
+          value: INHERIT_VALUE,
+          desc: '默认继承全局配置'
+        }
+      ]
+    : [])
+]
+</script>

+ 85 - 3
src/components/Pages/ChartItemSetting/GlobalSetting.vue

@@ -1,4 +1,34 @@
 <template>
 <template>
+  <collapse-item name="渲染器">
+    <setting-item-box :alone="true">
+      <template #name>
+        <n-text>全局</n-text>
+        <n-tooltip trigger="hover">
+          <template #trigger>
+            <n-icon size="21" :depth="3">
+              <help-outline-icon></help-outline-icon>
+            </n-icon>
+          </template>
+          <n-text>所有echarts图表组件默认都将采用所选的渲染器进行渲染</n-text>
+        </n-tooltip>
+      </template>
+      <EchartsRendererSetting v-model="themeSetting.renderer" />
+    </setting-item-box>
+    <setting-item-box :alone="true">
+      <template #name>
+        <n-text>当前</n-text>
+        <n-tooltip trigger="hover">
+          <template #trigger>
+            <n-icon size="21" :depth="3">
+              <help-outline-icon></help-outline-icon>
+            </n-icon>
+          </template>
+          <n-text>仅当前组件采用指定渲染器渲染</n-text>
+        </n-tooltip>
+      </template>
+      <EchartsRendererSetting v-model="optionData.renderer" includeInherit />
+    </setting-item-box>
+  </collapse-item>
   <collapse-item v-if="title" name="标题">
   <collapse-item v-if="title" name="标题">
     <template #header>
     <template #header>
       <n-switch v-model:value="title.show" size="small"></n-switch>
       <n-switch v-model:value="title.show" size="small"></n-switch>
@@ -227,9 +257,36 @@
       <n-switch v-model:value="legend.show" size="small"></n-switch>
       <n-switch v-model:value="legend.show" size="small"></n-switch>
     </template>
     </template>
     <setting-item-box name="图例文字">
     <setting-item-box name="图例文字">
-      <setting-item>
+      <setting-item name="颜色">
         <n-color-picker size="small" v-model:value="legend.textStyle.color"></n-color-picker>
         <n-color-picker size="small" v-model:value="legend.textStyle.color"></n-color-picker>
       </setting-item>
       </setting-item>
+      <setting-item name="大小">
+        <n-input-number v-model:value="legend.textStyle.fontSize" :min="1" size="small"></n-input-number>
+      </setting-item>
+    </setting-item-box>
+    <setting-item-box name="图例位置">
+      <setting-item name="x轴">
+        <n-select v-model:value="legend.x" size="small" :options="legendConfig.lengendX" />
+      </setting-item>
+      <setting-item name="y轴">
+        <n-select v-model:value="legend.y" size="small" :options="legendConfig.lengendY" />
+      </setting-item>
+    </setting-item-box>
+    <setting-item-box name="图例信息">
+      <setting-item name="方向">
+        <n-select v-model:value="legend.orient" size="small" :options="legendConfig.orient" />
+      </setting-item>
+      <setting-item name="形状">
+        <n-select v-model:value="legend.icon" size="small" :options="legendConfig.shape" />
+      </setting-item>
+    </setting-item-box>
+    <setting-item-box name="图例大小">
+      <setting-item name="宽">
+        <n-input-number v-model:value="legend.itemWidth" :min="1" size="small"></n-input-number>
+      </setting-item>
+      <setting-item name="高">
+        <n-input-number v-model:value="legend.itemHeight" :min="1" size="small"></n-input-number>
+      </setting-item>
     </setting-item-box>
     </setting-item-box>
   </collapse-item>
   </collapse-item>
 
 
@@ -279,10 +336,15 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { PropType, computed } from 'vue'
+import { PropType, computed, watch } from 'vue'
 import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
 import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
-import { axisConfig } from '@/packages/chartConfiguration/echarts/index'
+import { axisConfig, legendConfig } from '@/packages/chartConfiguration/echarts/index'
 import { CollapseItem, SettingItemBox, SettingItem, GlobalSettingPosition } from '@/components/Pages/ChartItemSetting'
 import { CollapseItem, SettingItemBox, SettingItem, GlobalSettingPosition } from '@/components/Pages/ChartItemSetting'
+import { icon } from '@/plugins'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import EchartsRendererSetting from './EchartsRendererSetting.vue'
+
+const { HelpOutlineIcon } = icon.ionicons5
 
 
 const props = defineProps({
 const props = defineProps({
   optionData: {
   optionData: {
@@ -296,6 +358,12 @@ const props = defineProps({
   }
   }
 })
 })
 
 
+const chartEditStore = useChartEditStore()
+const themeSetting = computed(() => {
+  const chartThemeSetting = chartEditStore.getEditCanvasConfig.chartThemeSetting
+  return chartThemeSetting
+})
+
 const title = computed(() => {
 const title = computed(() => {
   return props.optionData.title
   return props.optionData.title
 })
 })
@@ -319,4 +387,18 @@ const grid = computed(() => {
 const visualMap = computed(() => {
 const visualMap = computed(() => {
   return props.optionData.visualMap
   return props.optionData.visualMap
 })
 })
+
+// 监听legend color颜色改变type = scroll的颜色
+watch(() => legend.value && legend.value.textStyle.color, (newVal) => {
+  if (legend.value && newVal) {
+     if (!legend.value.pageTextStyle) {
+      legend.value.pageTextStyle = { color: newVal }
+    } else {
+      legend.value.pageTextStyle.color = newVal
+    }
+  }
+}, {
+  immediate: true,
+  deep: true,
+})
 </script>
 </script>

+ 58 - 2
src/components/Pages/ChartItemSetting/StylesSetting.vue

@@ -69,6 +69,22 @@
       </setting-item>
       </setting-item>
     </setting-item-box>
     </setting-item-box>
 
 
+    <!--  预设滤镜  -->
+    <div v-if="presetImageList.length" class="preset-filter">
+      <n-image
+        class="preset-img"
+        width="46"
+        preview-disabled
+        object-fit="scale-down"
+        v-for="(item, index) in presetImageList"
+        :key="index"
+        :class="{ 'active-preset': item.hueRotate === chartStyles.hueRotate }"
+        :style="{ filter: `hue-rotate(${item.hueRotate}deg)` }"
+        :src="item.src"
+        @click="() => (chartStyles.hueRotate = item.hueRotate)"
+      ></n-image>
+    </div>
+
     <!-- 混合模式 -->
     <!-- 混合模式 -->
     <setting-item-box v-if="!isCanvas" :alone="true">
     <setting-item-box v-if="!isCanvas" :alone="true">
       <template #name>
       <template #name>
@@ -149,10 +165,12 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { PropType } from 'vue'
+import { ref, PropType } from 'vue'
 import { PickCreateComponentType, BlendModeEnumList } from '@/packages/index.d'
 import { PickCreateComponentType, BlendModeEnumList } from '@/packages/index.d'
 import { SettingItemBox, SettingItem, CollapseItem } from '@/components/Pages/ChartItemSetting'
 import { SettingItemBox, SettingItem, CollapseItem } from '@/components/Pages/ChartItemSetting'
 import { icon } from '@/plugins'
 import { icon } from '@/plugins'
+import logoImg from '@/assets/logo.png'
+import { useDesignStore } from '@/store/modules/designStore/designStore'
 
 
 const props = defineProps({
 const props = defineProps({
   isGroup: {
   isGroup: {
@@ -175,10 +193,48 @@ const { HelpOutlineIcon } = icon.ionicons5
 const sliderFormatTooltip = (v: string) => {
 const sliderFormatTooltip = (v: string) => {
   return `${(parseFloat(v) * 100).toFixed(0)}%`
   return `${(parseFloat(v) * 100).toFixed(0)}%`
 }
 }
+
 // 角度格式化
 // 角度格式化
 const degFormatTooltip = (v: string) => {
 const degFormatTooltip = (v: string) => {
   return `${v}deg`
   return `${v}deg`
 }
 }
+
+// 预设滤镜
+interface presetImageData {
+  index: number
+  src: string
+  hueRotate: number
+}
+
+const presetImageList = ref([] as presetImageData[])
+for (let i = 1; i <= 12; i++) {
+  presetImageList.value.push({
+    index: i,
+    src: logoImg,
+    hueRotate: i * 30
+  })
+}
 </script>
 </script>
 
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+// 预设滤镜
+.preset-filter {
+  margin: 20px 0 10px 0;
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  .preset-img {
+    margin-bottom: 10px;
+    padding: 2px;
+    border-radius: 6px;
+    transition: 0.2s all;
+    cursor: pointer;
+    &:hover {
+      box-shadow: 0 0 0 2px #66a9c9;
+    }
+  }
+  .active-preset {
+    box-shadow: 0 0 0 2px #66a9c9;
+  }
+}
+</style>

+ 38 - 11
src/components/Pages/Flipper/index.vue

@@ -1,13 +1,13 @@
 <template>
 <template>
-  <div class="go-Flipper" :class="[flipType, { go: isFlipping }]">
+  <div class="go-flipper" :class="[flipType, { go: isFlipping }]">
     <div class="digital front" :data-front="frontTextFromData"></div>
     <div class="digital front" :data-front="frontTextFromData"></div>
     <div class="digital back" :data-back="backTextFromData"></div>
     <div class="digital back" :data-back="backTextFromData"></div>
   </div>
   </div>
 </template>
 </template>
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
-import { ref, PropType, watch } from 'vue'
-import { FlipType }  from './index'
+import { ref, PropType, watch, nextTick } from 'vue'
+import { FlipType } from './index'
 
 
 const props = defineProps({
 const props = defineProps({
   flipType: {
   flipType: {
@@ -43,6 +43,10 @@ const props = defineProps({
   backColor: {
   backColor: {
     type: String,
     type: String,
     default: '#000000'
     default: '#000000'
+  },
+  borderWidth: {
+    type: Number,
+    default: 2
   }
   }
 })
 })
 
 
@@ -50,19 +54,27 @@ const isFlipping = ref(false)
 const frontTextFromData = ref(props.count || 0)
 const frontTextFromData = ref(props.count || 0)
 const backTextFromData = ref(props.count || 0)
 const backTextFromData = ref(props.count || 0)
 
 
+let timeoutID: any = 0
+
 // 翻牌
 // 翻牌
-const flip = (front: string | number, back: string | number) => {
+const flip = async (front: string | number, back: string | number) => {
   // 如果处于翻转中,则不执行
   // 如果处于翻转中,则不执行
-  if (isFlipping.value) return
+  if (isFlipping.value) {
+    isFlipping.value = false // 立即结束此次动画
+    clearTimeout(timeoutID) // 清除上一个计时器任务
+    await nextTick()
+    await flip(front, back) // 开始最后一次翻牌任务
+    return
+  }
+
   // 设置翻盘前后数据
   // 设置翻盘前后数据
   backTextFromData.value = back
   backTextFromData.value = back
   frontTextFromData.value = front
   frontTextFromData.value = front
-
   // 设置翻转状态为true
   // 设置翻转状态为true
   isFlipping.value = true
   isFlipping.value = true
 
 
   // 翻牌结束的行为
   // 翻牌结束的行为
-  setTimeout(() => {
+  timeoutID = setTimeout(() => {
     isFlipping.value = false // 设置翻转状态为false
     isFlipping.value = false // 设置翻转状态为false
     frontTextFromData.value = back
     frontTextFromData.value = back
   }, props.duration)
   }, props.duration)
@@ -86,6 +98,7 @@ $radius: v-bind('`${props.radius}px`');
 $width: v-bind('`${props.width}px`');
 $width: v-bind('`${props.width}px`');
 $height: v-bind('`${props.height}px`');
 $height: v-bind('`${props.height}px`');
 $perspective: v-bind('`${props.height * 2}px`');
 $perspective: v-bind('`${props.height * 2}px`');
+$borderWidth: v-bind('`${props.borderWidth * 2}px`');
 $speed: v-bind('`${props.duration / 1000}s`');
 $speed: v-bind('`${props.duration / 1000}s`');
 $shadowColor: #000000;
 $shadowColor: #000000;
 $lineColor: #4a9ef8;
 $lineColor: #4a9ef8;
@@ -125,13 +138,12 @@ $lineColor: #4a9ef8;
 }
 }
 // #endregion
 // #endregion
 
 
-.go-Flipper {
+.go-flipper {
   display: inline-block;
   display: inline-block;
   position: relative;
   position: relative;
   width: $width;
   width: $width;
   height: $height;
   height: $height;
   line-height: $height;
   line-height: $height;
-  border: solid 1px $backColor;
   border-radius: $radius;
   border-radius: $radius;
   background: $frontColor;
   background: $frontColor;
   font-size: $width;
   font-size: $width;
@@ -139,6 +151,17 @@ $lineColor: #4a9ef8;
   box-shadow: 0 0 6px rgba($color: $shadowColor, $alpha: 0.5); // 阴影部分
   box-shadow: 0 0 6px rgba($color: $shadowColor, $alpha: 0.5); // 阴影部分
   text-align: center;
   text-align: center;
   // font-family: 'Helvetica Neue';
   // font-family: 'Helvetica Neue';
+  &::after {
+    content: '';
+    position: absolute;
+    z-index: 10;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    box-shadow: inset 0 0 $borderWidth 0 $frontColor; // 内测阴影部分
+    border-radius: $radius;
+  }
 
 
   .digital:before,
   .digital:before,
   .digital:after {
   .digital:after {
@@ -186,11 +209,13 @@ $lineColor: #4a9ef8;
   &.down.go .front:before {
   &.down.go .front:before {
     transform-origin: 50% 100%;
     transform-origin: 50% 100%;
     animation: frontFlipDown $speed ease-in-out both;
     animation: frontFlipDown $speed ease-in-out both;
-    box-shadow: 0 -2px 6px rgba($color: $lineColor, $alpha: 0.3);
+    box-shadow: 0 -2px $borderWidth 0 $frontColor;
     backface-visibility: hidden;
     backface-visibility: hidden;
   }
   }
   &.down.go .back:after {
   &.down.go .back:after {
     animation: backFlipDown $speed ease-in-out both;
     animation: backFlipDown $speed ease-in-out both;
+    box-shadow: 0 2px $borderWidth 0 $frontColor;
+    backface-visibility: hidden;
   }
   }
   /*向上翻*/
   /*向上翻*/
   &.up .front:after {
   &.up .front:after {
@@ -208,11 +233,13 @@ $lineColor: #4a9ef8;
   &.up.go .front:after {
   &.up.go .front:after {
     transform-origin: 50% 0;
     transform-origin: 50% 0;
     animation: frontFlipUp $speed ease-in-out both;
     animation: frontFlipUp $speed ease-in-out both;
-    box-shadow: 0 2px 6px rgba($color: $lineColor, $alpha: 0.3);
+    box-shadow: 0 2px $borderWidth 0 $frontColor;
     backface-visibility: hidden;
     backface-visibility: hidden;
   }
   }
   &.up.go .back:before {
   &.up.go .back:before {
     animation: backFlipUp $speed ease-in-out both;
     animation: backFlipUp $speed ease-in-out both;
+    box-shadow: 0 -2px $borderWidth 0 $frontColor;
+    backface-visibility: hidden;
   }
   }
 }
 }
 </style>
 </style>

+ 2 - 1
src/components/Pages/ThemeColorSelect/index.vue

@@ -36,7 +36,7 @@
       </div>
       </div>
       <div class="model-footer">
       <div class="model-footer">
         中国色列表来自于:
         中国色列表来自于:
-        <n-a href="http://zhongguose.com">http://zhongguose.com</n-a>
+        <n-a href="http://zhongguose.com" target="_blank">http://zhongguose.com</n-a>
       </div>
       </div>
     </div>
     </div>
   </n-modal>
   </n-modal>
@@ -157,6 +157,7 @@ $height: 85vh;
     }
     }
   }
   }
   .model-footer {
   .model-footer {
+    z-index: 1;
     text-align: end;
     text-align: end;
   }
   }
 }
 }

+ 4 - 1
src/enums/editPageEnum.ts

@@ -12,7 +12,9 @@ export enum DragKeyEnum {
 // 不同页面保存操作
 // 不同页面保存操作
 export enum SavePageEnum {
 export enum SavePageEnum {
   CHART = 'SaveChart',
   CHART = 'SaveChart',
-  JSON = 'SaveJSON'
+  CHART_TO_PREVIEW = 'ChartToPreview',
+  JSON = 'SaveJSON',
+  CLOSE = 'close'
 }
 }
 
 
 // 操作枚举
 // 操作枚举
@@ -46,6 +48,7 @@ export enum MenuEnum {
   UN_GROUP = 'unGroup',
   UN_GROUP = 'unGroup',
   // 后退
   // 后退
   BACK = 'back',
   BACK = 'back',
+  // 前进
   FORWORD = 'forward',
   FORWORD = 'forward',
   // 保存
   // 保存
   SAVE = 'save',
   SAVE = 'save',

+ 32 - 4
src/enums/eventEnum.ts

@@ -7,15 +7,38 @@ export enum BaseEvent {
   // 移入
   // 移入
   ON_MOUSE_ENTER = 'mouseenter',
   ON_MOUSE_ENTER = 'mouseenter',
   // 移出
   // 移出
-  ON_MOUSE_LEAVE = 'mouseleave',
+  ON_MOUSE_LEAVE = 'mouseleave'
+}
+
+// 组件交互回调事件
+export enum InteractEvents {
+  INTERACT_ON = 'interactOn',
+  INTERACT_COMPONENT_ID = 'interactComponentId',
+  INTERACT_FN = 'interactFn'
+}
+
+// 全局组件交互回调事件触发的类型(当然可以自定义名称)
+export enum InteractEventOn {
+  CLICK = 'click',
+  CHANGE = 'change'
+}
+
+// 确定交互组件触发类型 key名称
+export const COMPONENT_INTERACT_EVENT_KET = 'componentInteractEventKey'
+
+// 交互式组件的触发配置
+export type InteractActionsType = {
+  interactType: InteractEventOn
+  interactName: string
+  componentEmitEvents: { [T: string]: { value: any; label: string }[] }
 }
 }
 
 
 // vue3 生命周期事件
 // vue3 生命周期事件
-export enum EventLife { 
+export enum EventLife {
   // 渲染之后
   // 渲染之后
   VNODE_MOUNTED = 'vnodeMounted',
   VNODE_MOUNTED = 'vnodeMounted',
   // 渲染之前
   // 渲染之前
-  VNODE_BEFORE_MOUNT = 'vnodeBeforeMount',
+  VNODE_BEFORE_MOUNT = 'vnodeBeforeMount'
 }
 }
 
 
 // 内置字符串函数对象列表
 // 内置字符串函数对象列表
@@ -28,4 +51,9 @@ export const excludeParseEventKeyList = [
   BaseEvent.ON_MOUSE_LEAVE,
   BaseEvent.ON_MOUSE_LEAVE,
   //过滤器
   //过滤器
   'filter'
   'filter'
-]
+]
+// 内置字符串函数键值列表
+export const excludeParseEventValueList = [
+  // 请求里的函数语句
+  'javascript:'
+]

+ 9 - 1
src/enums/storageEnum.ts

@@ -3,6 +3,12 @@ export enum StorageEnum {
   GO_SETTING_STORE = 'GO_SETTING',
   GO_SETTING_STORE = 'GO_SETTING',
   // 登录信息
   // 登录信息
   GO_SYSTEM_STORE = 'GO_SYSTEM',
   GO_SYSTEM_STORE = 'GO_SYSTEM',
+  // 全局设置
+  GO_SYSTEM_SETTING_STORE = 'GO_SYSTEM_SETTING',
+  // token 等信息
+  GO_ACCESS_TOKEN_STORE = 'GO_ACCESS_TOKEN',
+  // 登录信息
+  GO_LOGIN_INFO_STORE = 'GO_LOGIN_INFO',
   // 语言
   // 语言
   GO_LANG_STORE = 'GO_LANG',
   GO_LANG_STORE = 'GO_LANG',
   // 当前选择的主题
   // 当前选择的主题
@@ -10,5 +16,7 @@ export enum StorageEnum {
   // 工作台布局配置
   // 工作台布局配置
   GO_CHART_LAYOUT_STORE = 'GO_CHART_LAYOUT',
   GO_CHART_LAYOUT_STORE = 'GO_CHART_LAYOUT',
   // 工作台需要保存的数据
   // 工作台需要保存的数据
-  GO_CHART_STORAGE_LIST = 'GO_CHART_STORAGE_LIST'
+  GO_CHART_STORAGE_LIST = 'GO_CHART_STORAGE_LIST',
+  // 用户存储的图片媒体
+  GO_USER_MEDIA_PHOTOS = 'GO_USER_MEDIA_PHOTOS'
 }
 }

+ 2 - 1
src/hooks/index.ts

@@ -5,4 +5,5 @@ export * from '@/hooks/useChartDataFetch.hook'
 export * from '@/hooks/useSystemInit.hook'
 export * from '@/hooks/useSystemInit.hook'
 export * from '@/hooks/useChartDataPondFetch.hook'
 export * from '@/hooks/useChartDataPondFetch.hook'
 export * from '@/hooks/useLifeHandler.hook'
 export * from '@/hooks/useLifeHandler.hook'
-export * from '@/hooks/useLang.hook'
+export * from '@/hooks/useLang.hook'
+export * from '@/hooks/useChartInteract.hook'

+ 26 - 0
src/hooks/useCanvasInitOptions.hook.ts

@@ -0,0 +1,26 @@
+import { inject, type Ref } from 'vue'
+import { EchartsRenderer } from '@/settings/chartThemes'
+import { SCALE_KEY } from '@/views/preview/hooks/useScale.hook'
+import { use } from 'echarts/core'
+import { CanvasRenderer, SVGRenderer } from 'echarts/renderers'
+
+use([CanvasRenderer, SVGRenderer])
+
+type InitOptions = {
+  renderer: EchartsRenderer
+  devicePixelRatio?: number
+}
+
+// 获取需要给当前echarts组件设置什么初始值
+export function useCanvasInitOptions(option: any, themeSetting: any) {
+  const renderer = option.renderer || themeSetting.renderer
+  const initOptions: InitOptions = { renderer }
+  const scaleRef = inject<Ref<{ width: number; height: number }>>(SCALE_KEY) || { value: { width: 1, height: 1 } }
+
+  if (renderer === 'canvas') {
+    initOptions.devicePixelRatio = Math.ceil(
+      Math.max(window.devicePixelRatio, scaleRef.value.width, scaleRef.value.height)
+    )
+  }
+  return initOptions
+}

+ 35 - 12
src/hooks/useChartDataFetch.hook.ts

@@ -1,4 +1,4 @@
-import { ref, toRefs, toRaw } from 'vue'
+import { ref, toRefs, toRaw, watch } from 'vue'
 import type VChart from 'vue-echarts'
 import type VChart from 'vue-echarts'
 import { customizeHttp } from '@/api/http'
 import { customizeHttp } from '@/api/http'
 import { useChartDataPondFetch } from '@/hooks/'
 import { useChartDataPondFetch } from '@/hooks/'
@@ -6,6 +6,8 @@ import { CreateComponentType, ChartFrameEnum } from '@/packages/index.d'
 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
 import { RequestDataTypeEnum } from '@/enums/httpEnum'
 import { RequestDataTypeEnum } from '@/enums/httpEnum'
 import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
 import { isPreview, newFunctionHandle, intervalUnitHandle } from '@/utils'
+import { setOption } from '@/packages/public/chart'
+import { isNil } from 'lodash'
 
 
 // 获取类型
 // 获取类型
 type ChartEditStoreType = typeof useChartEditStore
 type ChartEditStoreType = typeof useChartEditStore
@@ -23,7 +25,7 @@ export const useChartDataFetch = (
 ) => {
 ) => {
   const vChartRef = ref<typeof VChart | null>(null)
   const vChartRef = ref<typeof VChart | null>(null)
   let fetchInterval: any = 0
   let fetchInterval: any = 0
-
+  console.log("vChartRef:",vChartRef)
   // 数据池
   // 数据池
   const { addGlobalDataInterface } = useChartDataPondFetch()
   const { addGlobalDataInterface } = useChartDataPondFetch()
 
 
@@ -34,7 +36,7 @@ export const useChartDataFetch = (
   const echartsUpdateHandle = (dataset: any) => {
   const echartsUpdateHandle = (dataset: any) => {
     if (chartFrame === ChartFrameEnum.ECHARTS) {
     if (chartFrame === ChartFrameEnum.ECHARTS) {
       if (vChartRef.value) {
       if (vChartRef.value) {
-        vChartRef.value.setOption({ dataset: dataset })
+        setOption(vChartRef.value, { dataset: dataset }, false)
       }
       }
     }
     }
   }
   }
@@ -71,14 +73,16 @@ export const useChartDataFetch = (
         clearInterval(fetchInterval)
         clearInterval(fetchInterval)
 
 
         const fetchFn = async () => {
         const fetchFn = async () => {
+          console.log("监听到更改")
           const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.getRequestGlobalConfig))
           const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.getRequestGlobalConfig))
           if (res) {
           if (res) {
             try {
             try {
               const filter = targetComponent.filter
               const filter = targetComponent.filter
-              echartsUpdateHandle(newFunctionHandle(res?.data, res, filter))
+              const { data } = res
+              echartsUpdateHandle(newFunctionHandle(data, res, filter))
               // 更新回调函数
               // 更新回调函数
               if (updateCallback) {
               if (updateCallback) {
-                updateCallback(newFunctionHandle(res?.data, res, filter))
+                updateCallback(newFunctionHandle(data, res, filter))
               }
               }
             } catch (error) {
             } catch (error) {
               console.error(error)
               console.error(error)
@@ -86,14 +90,26 @@ export const useChartDataFetch = (
           }
           }
         }
         }
 
 
-        // 立即调用
-        fetchFn()
+        // 普通初始化与组件交互处理监听
+        watch(
+          () => targetComponent.request.requestParams,
+          () => {
+            fetchFn()
+          },
+          {
+            immediate: true,
+            deep: true
+          }
+        )
+
         // 定时时间
         // 定时时间
-        const time = targetInterval && targetInterval.value ? targetInterval.value : globalRequestInterval.value
+        const time = targetInterval && !isNil(targetInterval.value) ? targetInterval.value : globalRequestInterval.value
         // 单位
         // 单位
-        const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
+        const unit = targetInterval && !isNil(targetInterval.value) ? targetUnit.value : globalUnit.value
         // 开启轮询
         // 开启轮询
-        if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
+        if (time) {
+          fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
+        }
       }
       }
       // eslint-disable-next-line no-empty
       // eslint-disable-next-line no-empty
     } catch (error) {
     } catch (error) {
@@ -102,10 +118,17 @@ export const useChartDataFetch = (
   }
   }
 
 
   if (isPreview()) {
   if (isPreview()) {
-    // 判断是否是数据池类型
+    console.log("是否是数据池:",targetComponent.request.requestDataType === RequestDataTypeEnum.Pond)
+    console.log(targetComponent)
     targetComponent.request.requestDataType === RequestDataTypeEnum.Pond
     targetComponent.request.requestDataType === RequestDataTypeEnum.Pond
-      ? addGlobalDataInterface(targetComponent, useChartEditStore, updateCallback || echartsUpdateHandle)
+      ? addGlobalDataInterface(targetComponent, useChartEditStore, (newData: any) => {
+          echartsUpdateHandle(newData)
+          if (updateCallback) updateCallback(newData)
+        })
       : requestIntervalFn()
       : requestIntervalFn()
+  } else {
+    requestIntervalFn()
   }
   }
+  console.log("vChartRef:",vChartRef)
   return { vChartRef }
   return { vChartRef }
 }
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно