Compare commits

..

116 Commits
v1.0 ... v2.0.0

Author SHA1 Message Date
奔跑的面条
faf2d44fbb chore: 优化页面 UI 2022-06-03 20:21:35 +08:00
奔跑的面条
88516d9491 fix: 修改自动复制粘贴的问题 2022-06-03 18:53:37 +08:00
奔跑的面条
88dbbe03ea fix: 新增发布页面处理 2022-06-03 14:48:58 +08:00
奔跑的面条
ae1fd2e7cf chore: 优化了标题展示和大小样式 2022-06-03 11:19:29 +08:00
奔跑的面条
d3931f47bc type: 修改类型错误 2022-06-01 23:00:28 +08:00
奔跑的面条
bf9bd59b63 fix:处理列表页标题过长的展示问题 2022-06-01 22:58:22 +08:00
奔跑的面条
fb0ff50837 type: 定义全局返回值类型 2022-06-01 22:41:11 +08:00
奔跑的面条
93727a0ac7 build: 修改版本号 0.0.9 2022-06-01 22:28:46 +08:00
奔跑的面条
2641e70c78 chore:优化了路由写法,修改了错误页面的展示,新增未发布提示页面 2022-06-01 22:20:05 +08:00
奔跑的面条
bc44584698 feat: 新增动态预览功能 2022-06-01 22:19:03 +08:00
奔跑的面条
82394dd7a3 fix: 修改组件注册会报错的问题 2022-06-01 22:14:33 +08:00
奔跑的面条
2e688ad686 build:升级依赖包 2022-06-01 22:13:49 +08:00
奔跑的面条
9b998e0c6d fix: 解决列表图片展示缓存问题 2022-06-01 20:16:38 +08:00
奔跑的面条
1045588301 fix: 解决获取数据,但是配置模块不完整的问题 2022-06-01 19:01:05 +08:00
奔跑的面条
ba86399fd3 build: 修改请求地址 2022-05-31 11:19:17 +08:00
奔跑的面条
a89164f885 fix: 修改oss接口不会动态更改的问题 2022-05-31 11:18:34 +08:00
奔跑的面条
7f2344c82c chore:修改请求地址 2022-05-29 16:04:07 +08:00
奔跑的面条
3c8e430533 docs: 修改文档说明 2022-05-29 15:23:04 +08:00
奔跑的面条
f7209fba53 feat: 新增背景图文件上传保存 2022-05-29 14:54:35 +08:00
奔跑的面条
9fae683d8b chore: 去除生成预览图时的标尺 2022-05-28 17:58:07 +08:00
奔跑的面条
79a2b98a1a feat: 新增首页预览图展示 2022-05-28 16:39:27 +08:00
奔跑的面条
98b28a631a Merge branch 'dev' into master-fetch 2022-05-28 15:58:06 +08:00
奔跑的面条
d61769f9b8 chore: 修改拖拽锚点样式 2022-05-28 15:57:44 +08:00
奔跑的面条
6fec64f515 fix: 修改自动保存预览图无法存储的问题 2022-05-28 15:46:07 +08:00
奔跑的面条
01d5890b35 branch: 合并锚点样式修改 2022-05-28 12:46:32 +08:00
奔跑的面条
0ec9fd8534 chore:修改拖拽标点样式 2022-05-28 12:43:07 +08:00
奔跑的面条
fea583eb5b feat: 保存预览图 2022-05-28 11:50:17 +08:00
奔跑的面条
fcf8d9d99d chore: 新增put请求类型 2022-05-28 00:40:22 +08:00
奔跑的面条
bfe5039a1c fix: 解决打包后无法发送请求的bug 2022-05-28 00:32:32 +08:00
奔跑的面条
7a57d944c8 feat: 新增上传文件接口 2022-05-27 20:09:48 +08:00
奔跑的面条
ca27e87241 chore: 修改项目信息结构 2022-05-27 11:49:25 +08:00
奔跑的面条
e674a1ece4 feat: 新增项目信息修改功能 2022-05-26 01:01:59 +08:00
奔跑的面条
6c91fca4e7 fix: 修改导入id重复的问题 2022-05-25 23:04:39 +08:00
奔跑的面条
dfb63346d3 fix: 修改导入组件id会重复的问题 2022-05-25 23:00:36 +08:00
奔跑的面条
4d899d48dc feat: 新增快捷键展示 2022-05-24 18:17:41 +08:00
奔跑的面条
fa3a3dfcb0 faet: 新增保存快捷键 2022-05-24 18:16:33 +08:00
奔跑的面条
e36210aa27 feat: 新增自动同步功能 2022-05-24 17:42:49 +08:00
奔跑的面条
20a599594c feat: 新增数据保存接口 2022-05-24 15:05:51 +08:00
奔跑的面条
70f8dbae53 Merge branch 'dev' into master-fetch 2022-05-24 12:28:14 +08:00
奔跑的面条
e01292376f chore: 优化 error 错误页面 2022-05-24 12:27:39 +08:00
奔跑的面条
d8022b2682 feat: 新增获取项目数据功能,新增同步数据功能 2022-05-23 23:50:35 +08:00
奔跑的面条
0d7c5b8ace Merge branch 'dev' into master-fetch 2022-05-23 16:06:13 +08:00
奔跑的面条
1c5c867a19 schore: 修改屏幕过小,会破坏布局的问题 2022-05-23 16:05:41 +08:00
奔跑的面条
88c9850c44 Merge branch 'dev' into master-fetch 2022-05-22 23:27:39 +08:00
奔跑的面条
dde5ae796e style: 去除多余入参代码 2022-05-22 22:43:06 +08:00
奔跑的面条
f1ed62cdca feat: 新增获取项目数据接口 2022-05-22 22:11:56 +08:00
奔跑的面条
bfac86d5dd feat:新增发布和取消发布接口 2022-05-22 16:38:22 +08:00
奔跑的面条
341015c584 style: 调整代码格式,去除多余代码 2022-05-22 15:39:30 +08:00
奔跑的面条
7c5a66978e feat: 新增删除接口 2022-05-22 15:25:07 +08:00
奔跑的面条
b21fc3f5e7 feat: 新增首页列表接口 2022-05-22 15:06:45 +08:00
奔跑的面条
0e52628842 Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-05-22 14:09:38 +08:00
奔跑的面条
64992c59b7 feat: 新增首页项目列表分页效果 2022-05-22 14:09:20 +08:00
奔跑的面条
c3aae6e5fa fix: 修改vue动画名称错误 2022-05-22 14:06:52 +08:00
奔跑的面条
f7922cafa5 feat: 新增项目列表接口 2022-05-22 14:05:57 +08:00
奔跑的面条
8c5496829e Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-05-22 13:36:30 +08:00
奔跑的面条
2a44fd3ca4 build: 升级naiveUI到2.29 2022-05-22 13:29:01 +08:00
奔跑的面条
8514f051a7 fix: 修改新建项目id错误问题 2022-05-21 21:04:10 +08:00
奔跑的面条
61feb29fe2 fix: 修改i18n错误提示 2022-05-21 19:46:44 +08:00
奔跑的面条
fa29881f04 chore: 修改提示内容 2022-05-21 18:04:52 +08:00
奔跑的面条
46cb8e7d0b feat: 新增创建接口,修改i8n部分内容 2022-05-21 18:03:15 +08:00
奔跑的面条
b6143bc75e feat: 新增退出登录接口,新增全局接口封装,修改登录接口内容 2022-05-21 17:31:01 +08:00
奔跑的面条
92e1ec05d2 Merge branch 'master' of https://gitee.com/MTrun/go-view into master-fetch 2022-05-21 14:01:53 +08:00
奔跑的面条
68512206f7 fix: 修改 pnpm7.x 版本打包时的类型错误 2022-05-21 14:01:26 +08:00
奔跑的面条
88073e97af Merge branch 'dev' 2022-05-21 13:49:52 +08:00
奔跑的面条
75f23bb1bf Merge branch 'dev' into master-fetch 2022-05-21 13:44:25 +08:00
奔跑的面条
e8642d0301 fix: 修改plop模板的错误 2022-05-21 13:43:31 +08:00
奔跑的面条
5f5731f813 feat: 新增登录接口请求 2022-05-20 16:12:27 +08:00
奔跑的面条
55159be0dc fix: 修改plop的问题 2022-05-20 16:12:09 +08:00
奔跑的面条
0c4e1dc7ae Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-05-20 10:25:46 +08:00
奔跑的面条
b4abdeb246 update README.md. 2022-05-19 01:56:30 +00:00
奔跑的面条
7e61dda4aa update README.md. 2022-05-16 10:38:39 +00:00
奔跑的面条
283aafb27d update README.md. 2022-05-16 04:23:10 +00:00
奔跑的面条
aafafdd0aa update README.md. 2022-05-16 04:22:49 +00:00
奔跑的面条
198b839dab update README.md. 2022-05-16 04:21:08 +00:00
奔跑的面条
597b8fb5af chore: 修改下载按钮,修改复制文案为克隆 2022-05-16 00:32:10 +08:00
奔跑的面条
a4cb4cb0ad feat: 新增 sass 循环样式类,新增接口下载提示 2022-05-14 22:40:48 +08:00
奔跑的面条
1bc51a51c2 !10 update README.md.
Merge pull request !10 from Mr.cao/N/A
2022-05-12 04:07:03 +00:00
Mr.cao
8857059da8 update README.md. 2022-05-12 04:06:49 +00:00
奔跑的面条
7939d37fa3 !9 update README.md.
Merge pull request !9 from 雪花酥/N/A
2022-05-12 04:06:18 +00:00
雪花酥
df83385cb0 update README.md. 2022-05-12 04:05:56 +00:00
奔跑的面条
5d69fc4b24 !8 update README.md.
Merge pull request !8 from 雪花酥/N/A
2022-05-12 04:05:24 +00:00
雪花酥
4f1b550fa9 update README.md. 2022-05-12 04:05:11 +00:00
奔跑的面条
782c12d91d !7 update README.md.
Merge pull request !7 from 雪花酥/N/A
2022-05-12 04:04:54 +00:00
雪花酥
4b97d98b3a update README.md. 2022-05-12 04:04:31 +00:00
奔跑的面条
8e3e9b5f50 !6 update README.md.
Merge pull request !6 from Wang Kejiang/N/A
2022-05-12 03:45:32 +00:00
Wang Kejiang
ceed66b7ea update README.md. 2022-05-12 03:45:12 +00:00
奔跑的面条
a8399be4a3 !5 合并dev
Merge pull request !5 from 奔跑的面条/dev
2022-05-12 03:22:08 +00:00
奔跑的面条
19f73d7066 !4 update README.md.
Merge pull request !4 from zhanghan966/N/A
2022-05-12 03:21:01 +00:00
zhanghan966
36d46d0a45 update README.md. 2022-05-12 03:20:36 +00:00
奔跑的面条
323e5505f5 !3 合并master
Merge pull request !3 from 奔跑的面条/master
2022-05-12 03:19:21 +00:00
奔跑的面条
12a2ace498 update README.md. 2022-05-11 02:05:03 +00:00
奔跑的面条
c5eefec24d chore: 修改工具条默认状态为侧边 2022-05-10 19:26:08 +08:00
奔跑的面条
c4c4572885 chore: 新增mock数据返回值 2022-05-10 19:17:30 +08:00
奔跑的面条
8fcd2a9141 !2 fix: 解决文件夹名字问题
Merge pull request !2 from 奔跑的面条/master
2022-05-10 10:24:19 +00:00
奔跑的面条
f0fad0dba7 重命名 src/packages/components/Tables/Tables/tableCommon 为 src/packages/components/Tables/Tables/TableCommon 2022-05-10 10:23:24 +00:00
奔跑的面条
71c7116493 fix: 解决文件名称大小写问题 2022-05-10 18:21:50 +08:00
奔跑的面条
e797879e0d Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-05-10 18:11:24 +08:00
奔跑的面条
2e460ea32a fix: 解决文件夹名称大小写问题 2022-05-10 18:11:12 +08:00
奔跑的面条
ef3b1dce7c style: 去除多余代码 2022-05-10 18:10:54 +08:00
奔跑的面条
22e01a80c1 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-05-10 17:57:00 +08:00
奔跑的面条
770373c48c fix: 修改文件名称大小写的问题 2022-05-10 17:56:45 +08:00
奔跑的面条
77ff376e75 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-05-10 17:50:57 +08:00
奔跑的面条
d5fb56f571 fix: 解决文件名称大小写的问题 2022-05-10 17:50:43 +08:00
奔跑的面条
b37ba41694 !1 fix: 修改文件夹大写不同步的问题
Merge pull request !1 from 奔跑的面条/dev
2022-05-10 09:38:36 +00:00
奔跑的面条
f7084ba3a3 重命名 src/views/chart/contentHeader 为 src/views/chart/ContentHeader 2022-05-10 09:37:00 +00:00
奔跑的面条
f89a64f10e style: 去除多余代码 2022-05-10 14:41:02 +08:00
奔跑的面条
f6fe7816c9 fix: 解决折线图预览不会展示的问题 2022-05-09 18:05:14 +08:00
奔跑的面条
ca8e08f3db build: 升级 naiveUI 到最新版2.28.2 2022-05-09 17:10:01 +08:00
奔跑的面条
1e188dd26b release:升级版本号到 1.0.1 2022-05-09 17:08:03 +08:00
奔跑的面条
59fb22cd0c perf: 修改工作区域默认配置展示逻辑 2022-05-09 09:58:27 +08:00
奔跑的面条
ede7bcce80 perf: 修改位置区域文案,修改水球图颜色文案 2022-05-09 09:47:54 +08:00
奔跑的面条
07e3f227be chore: 修改命令 2022-05-07 10:58:37 +08:00
奔跑的面条
d0070319a9 fix: 修改标尺和水印定位的问题 2022-05-06 20:29:35 +08:00
奔跑的面条
60ec01eb32 docs: 修改文档路径 2022-05-06 20:23:08 +08:00
奔跑的面条
47e04ba6e3 chore: 去除多余依赖和配置 2022-05-06 20:13:49 +08:00
奔跑的面条
c7a2a01f12 fix: 修改item说明 2022-05-05 11:47:22 +08:00
124 changed files with 2258 additions and 996 deletions

12
.env
View File

@@ -1,14 +1,8 @@
# port
VITE_DEV_PORT = '8001'
VITE_DEV_PORT = '8080'
# development path
VITE_DEV_PATH = '/'
VITE_DEV_PATH = 'http://1.117.240.165:8080'
# production path
VITE_PRO_PATH = '/'
# spa-title
VITE_GLOB_APP_TITLE = GoView
# spa shortname
VITE_GLOB_APP_SHORT_NAME = GoView
VITE_PRO_PATH = 'http://1.117.240.165:8080'

163
README.md
View File

@@ -1,113 +1,106 @@
## 总览
![logo](public/logo-t-y.png)
![logo](readme/logo-t-y.png)
GoView 是一个高效的拖拽式低代码数据可视化开发平台,将图表或页面元素封装为基础组件,无需编写代码即可制作数据大屏,减少心智负担。当然低代码也不是 “银弹”,希望所有人员都能理智看待此技术。
**`master-fetch` 分支是带有后端接口请求的分支**
项目-Demo 地址:[https://www.mtruning.club](https://www.mtruning.club)
**后端项目地址:[https://gitee.com/MTrun/go-view-serve](https://gitee.com/MTrun/go-view-serve)**
文档-在线地址:[http://www.mtruning.club:81/](http://www.mtruning.club:81/)
**接口说明地址:[https://docs.apipost.cn/preview/5aa85d10a59d66ce/ddb813732007ad2b?target_id=84dbc5b0-158f-4bcb-8f74-793ac604ada3#3e053622-1e76-43f9-a039-756aee822dbb](https://docs.apipost.cn/preview/5aa85d10a59d66ce/ddb813732007ad2b?target_id=84dbc5b0-158f-4bcb-8f74-793ac604ada3#3e053622-1e76-43f9-a039-756aee822dbb)**
文档-源码地址:[https://gitee.com/MTrun/go-view-doc](https://gitee.com/MTrun/go-view-doc)
## 使用
技术点:
所有的接口地址位置:`src\api\path\*`
- 框架:基于 `Vue3` 框架编写,使用 `hooks` 写法抽离部分逻辑,使代码结构更加清晰;
- 类型:使用 `TypeScript` 进行类型约束,减少未知错误发生概率,可以大胆修改逻辑内容;
- 性能:多处性能优化,使用页面懒加载、组件动态注册、数据滚动加载等方式,提升页面渲染速度;
- 存储:拥有本地记忆,部分配置项采用 `storage` 存储本地,提升使用体验;
- 封装:项目进行了详细的工具类封装如:路由、存储、加/解密、文件处理、主题、NaiveUI 全局方法、组件等
项目截图:
![项目截图](public/goView-canvas.png)
主要技术栈为:
| 名称 | 版本 | 名称 | 版本 |
| ------------------- | ----- | ----------- | ------ |
| Vue | 3.2.x | TypeScript4 | 4.6.x |
| Vite | 2.9.x | NaiveUI | 2.27.x |
| ECharts | 5.3.x | Pinia | 2.0.x |
| 详见 `package.json` | 😁 | 🥰 | 🤗 |
开发环境:
| 名称 | 版本 | 名称 | 版本 |
| ---- | ------- | ------- | ----- |
| node | 16.14.x | npm | 8.5.x |
| pnpm | 6.32.x | windows | 11 |
已完成图表:
| 分类 | 名称 | 名称 | 名称 |
| ------ | ---------------- | ---------- | -------- |
| 图表 | 柱状图 | 横向柱状图 | 折线图 |
| \* | 单/多 折线面积图 | 饼图 | 水球图 |
| 信息 | 文字 | 图片 | 😶 |
| 列表 | 滚动排名列表 | 🤠 | 🤓 |
| 小组件 | 边框-01~13 | 装饰-01~05 | 数字翻牌 |
## 浏览器支持
开发和测试平台均在 Google 和最新版 EDGE 上完成,暂未测试 IE11 等其它浏览器,如有需求请自行测试与兼容。
## 安装
本项目采用 pnpm 进行包管理,若要使用其它管理方式,请删除 `pnpm-lock.yaml` 并安装依赖
接口地址修改:`.env`
```shell
#pnpm建议使用nrm切换到淘宝源
pnpm install
# port
VITE_DEV_PORT = '8080'
# npm
npm install
# yarn
yarn install
# development path
VITE_DEV_PATH = 'http://127.0.0.1:8080'
# production path
VITE_PRO_PATH = 'http://127.0.0.1:8080'
```
## 启动
公共前缀修改:`src\settings\httpSetting.ts`
```shell
#pnpm
pnpm dev
# npm
npm run dev
#yarn
yarn dev
#Makefile
make dev
// 请求前缀
export const axiosPre = '/goview'
```
## 编译
接口封装:`src\api\http.ts`
```shell
#pnpm
pnpm run build
```ts
import axiosInstance from './axios'
import { RequestHttpEnum, ContentTypeEnum } from '@/enums/httpEnum'
# npm
npm run build
export const get = (url: string, params?: object) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.GET,
params: params,
})
}
#yarn
yarn run build
export const post = (url: string, data?: object, headersType?: string) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.POST,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
#Makefile
make dist
export const put = (url: string, data?: object, headersType?: string) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.PUT,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const del = (url: string, params?: object) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.DELETE,
params
})
}
// 获取请求函数默认get
export const http = (type?: RequestHttpEnum) => {
switch (type) {
case RequestHttpEnum.GET:
return get
case RequestHttpEnum.POST:
return post
case RequestHttpEnum.PUT:
return put
case RequestHttpEnum.DELETE:
return del
default:
return get
}
}
```
## 交流
QQ 群1030129384
![QQ群](public/goView-QQ.png)
![QQ群](readme/goView-QQ.png)
![渲染海报](public/logo-poster.png)
![渲染海报](readme/logo-poster.png)

View File

@@ -1,4 +1,5 @@
export const OUTPUT_DIR = 'dist';
// 打包路径
export const OUTPUT_DIR = 'dist'
// chunk 警告大小
export const chunkSizeWarningLimit = 2000

View File

@@ -1,9 +0,0 @@
/**
* Get the configuration file variable name
* @param env
*/
export const getConfigFileName = (env: Record<string, any>) => {
return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__`
.toUpperCase()
.replace(/\s/g, '');
};

View File

@@ -1,10 +1,9 @@
{
"name": "go-view",
"version": "1.0.0",
"version": "0.0.9",
"scripts": {
"dev": "vite --host",
"build": "vue-tsc --noEmit && vite build",
"lint": "eslint \"{src}/**/*.{vue,ts,tsx}\" --fix --ext",
"new": "plop --plopfile ./plop/plopfile.js"
},
"dependencies": {
@@ -19,11 +18,11 @@
"highlight.js": "^11.5.0",
"html2canvas": "^1.4.1",
"keymaster": "^1.6.2",
"naive-ui": "^2.27.0",
"naive-ui": "^2.29.0",
"pinia": "^2.0.13",
"screenfull": "^6.0.1",
"vue": "^3.2.31",
"vue-i18n": "9.1.9",
"vue-i18n": "9.1.10",
"vue-router": "4.0.12",
"vue3-lazyload": "^0.2.5-beta",
"vue3-sketch-ruler": "^1.3.3",
@@ -57,11 +56,7 @@
"vite-plugin-compression": "^0.5.1",
"vite-plugin-importer": "^0.2.5",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-style-import": "^1.4.1",
"vue-echarts": "^6.0.2",
"vue-tsc": "^0.28.10"
},
"lint-staged": {
"*.{vue,js,ts,tsx}": "eslint --fix"
}
}

View File

@@ -5,7 +5,7 @@ import { StorageEnum } from '@/enums/storageEnum'
export const use{{upperDataName}}Store = defineStore({
id: 'use{{upperDataName}}Store',
state: (): {{name}}StoreType => ({}),
state: (): {{upperDataName}}StoreType => ({}),
getters: {},
actions: {}
})

View File

@@ -22,7 +22,7 @@ module.exports = {
const actions = [
{
type: 'add',
path: `${process.cwd()}/src/store/modules/${dataName}Store/${dataName}Store}.ts`, // 这里的name就是上面定义的键
path: `${process.cwd()}/src/store/modules/${dataName}Store/${dataName}Store.ts`, // 这里的name就是上面定义的键
templateFile: './store-template/index.hbs',
data: {
name: data.name,
@@ -32,7 +32,11 @@ module.exports = {
{
type: 'add',
path: `${process.cwd()}/src/store/modules/${dataName}Store/${dataName}Store.d.ts`, // 这里的name就是上面定义的键
templateFile: './store-template/index.d.hbs'
templateFile: './store-template/index.d.hbs',
data: {
name: data.name,
upperDataName,
}
},
]

259
pnpm-lock.yaml generated
View File

@@ -1,4 +1,4 @@
lockfileVersion: 5.3
lockfileVersion: 5.4
specifiers:
'@types/color': ^3.0.3
@@ -30,7 +30,7 @@ specifiers:
keymaster: ^1.6.2
lodash: ~4.17.21
mockjs: ^1.1.0
naive-ui: ^2.27.0
naive-ui: ^2.29.0
pinia: ^2.0.13
plop: ^3.0.5
prettier: ^2.6.2
@@ -42,10 +42,9 @@ specifiers:
vite-plugin-compression: ^0.5.1
vite-plugin-importer: ^0.2.5
vite-plugin-mock: ^2.9.6
vite-plugin-style-import: ^1.4.1
vue: ^3.2.31
vue-echarts: ^6.0.2
vue-i18n: 9.1.9
vue-i18n: 9.1.10
vue-router: 4.0.12
vue-tsc: ^0.28.10
vue3-lazyload: ^0.2.5-beta
@@ -64,20 +63,20 @@ dependencies:
highlight.js: 11.5.0
html2canvas: 1.4.1
keymaster: 1.6.2
naive-ui: 2.27.0_vue@3.2.31
pinia: 2.0.13_typescript@4.6.3+vue@3.2.31
naive-ui: 2.29.0_vue@3.2.31
pinia: 2.0.13_hhks2xcoho7x4jrwn5stbz36vy
screenfull: 6.0.1
vue: 3.2.31
vue-i18n: 9.1.9_vue@3.2.31
vue-i18n: 9.1.10_vue@3.2.31
vue-router: 4.0.12_vue@3.2.31
vue3-lazyload: 0.2.5-beta_4f726de02e89ff745196f225ebb1bbcf
vue3-lazyload: 0.2.5-beta_j5zg3yborh7xiumw6is6xmn3z4
vue3-sketch-ruler: 1.3.3_vue@3.2.31
vuedraggable: 4.1.0_vue@3.2.31
devDependencies:
'@types/node': 16.11.26
'@typescript-eslint/eslint-plugin': 5.18.0_a07dca3bdfc4bfa60f4dda0c1f9e3287
'@typescript-eslint/parser': 5.18.0_eslint@8.12.0+typescript@4.6.3
'@typescript-eslint/eslint-plugin': 5.18.0_ub64uo67ys72md2n3igb7hrsq4
'@typescript-eslint/parser': 5.18.0_thk3xo4exzjr5rl6cnexo7v6re
'@vicons/carbon': 0.12.0
'@vicons/ionicons5': 0.11.0
'@vitejs/plugin-vue': 1.10.2_vite@2.9.5
@@ -88,8 +87,8 @@ devDependencies:
echarts: 5.3.2
eslint: 8.12.0
eslint-config-prettier: 8.5.0_eslint@8.12.0
eslint-plugin-import: 2.26.0_eslint@8.12.0
eslint-plugin-prettier: 4.0.0_f2c91d0f54113167d2bd9214a5ab5a36
eslint-plugin-import: 2.26.0_mzojdsoryzqztjvqj5t7e5xqmq
eslint-plugin-prettier: 4.0.0_6ler2d2uceywpuv5sikklk22gy
eslint-plugin-vue: 8.5.0_eslint@8.12.0
lodash: 4.17.21
mockjs: 1.1.0
@@ -102,7 +101,6 @@ devDependencies:
vite-plugin-compression: 0.5.1_vite@2.9.5
vite-plugin-importer: 0.2.5
vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@2.9.5
vite-plugin-style-import: 1.4.1_vite@2.9.5
vue-echarts: 6.0.2_echarts@5.3.2+vue@3.2.31
vue-tsc: 0.28.10_typescript@4.6.3
@@ -299,7 +297,6 @@ packages:
/@babel/helper-validator-identifier/7.16.7:
resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==}
engines: {node: '>=6.9.0'}
dev: true
/@babel/helper-validator-option/7.16.7:
resolution: {integrity: sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==}
@@ -330,6 +327,8 @@ packages:
resolution: {integrity: sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.17.0
/@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.17.8:
resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
@@ -414,18 +413,17 @@ packages:
dependencies:
'@babel/helper-validator-identifier': 7.16.7
to-fast-properties: 2.0.0
dev: true
/@css-render/plugin-bem/0.15.9_css-render@0.15.9:
resolution: {integrity: sha512-xASEmYIX91Pow7YPzpAZ0eyrRNINVX7j9ITNbLt88gJHRLap3P1dv3hTSLtUZTxYXVHTklZ/SfJQ9FIO3jRahg==}
/@css-render/plugin-bem/0.15.10_css-render@0.15.10:
resolution: {integrity: sha512-V7b08sM2PWJlXI7BJiVIa0Sg30H3u/jHay4AclNXfF2yRFwwb4ZJjggsMfzwj3WSihAdNf2WTqvOU5qsOD80Dg==}
peerDependencies:
css-render: ~0.15.9
css-render: ~0.15.10
dependencies:
css-render: 0.15.9
css-render: 0.15.10
dev: false
/@css-render/vue3-ssr/0.15.9_vue@3.2.31:
resolution: {integrity: sha512-b3wvEIZYjToOEAV/oUqVtcg+MPF/iSZB9VmVF7fMAAAfvVTc2kB4TZDhGZCMkGjGZxOUm1jia7q/Z9FJnJGLKw==}
/@css-render/vue3-ssr/0.15.10_vue@3.2.31:
resolution: {integrity: sha512-keGKnkB2nyVGoA8GezMKNsmvTGXEzgLOGGlgshwOTSEzd1dsROyZ2m/khJ9jV5zbzDM4rWeAWbWF0zwHemsJcw==}
peerDependencies:
vue: ^3.0.11
dependencies:
@@ -484,60 +482,60 @@ packages:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
dev: true
/@intlify/core-base/9.1.9:
resolution: {integrity: sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==}
/@intlify/core-base/9.1.10:
resolution: {integrity: sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==}
engines: {node: '>= 10'}
dependencies:
'@intlify/devtools-if': 9.1.9
'@intlify/message-compiler': 9.1.9
'@intlify/message-resolver': 9.1.9
'@intlify/runtime': 9.1.9
'@intlify/shared': 9.1.9
'@intlify/vue-devtools': 9.1.9
'@intlify/devtools-if': 9.1.10
'@intlify/message-compiler': 9.1.10
'@intlify/message-resolver': 9.1.10
'@intlify/runtime': 9.1.10
'@intlify/shared': 9.1.10
'@intlify/vue-devtools': 9.1.10
dev: false
/@intlify/devtools-if/9.1.9:
resolution: {integrity: sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==}
/@intlify/devtools-if/9.1.10:
resolution: {integrity: sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==}
engines: {node: '>= 10'}
dependencies:
'@intlify/shared': 9.1.9
'@intlify/shared': 9.1.10
dev: false
/@intlify/message-compiler/9.1.9:
resolution: {integrity: sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ==}
/@intlify/message-compiler/9.1.10:
resolution: {integrity: sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==}
engines: {node: '>= 10'}
dependencies:
'@intlify/message-resolver': 9.1.9
'@intlify/shared': 9.1.9
'@intlify/message-resolver': 9.1.10
'@intlify/shared': 9.1.10
source-map: 0.6.1
dev: false
/@intlify/message-resolver/9.1.9:
resolution: {integrity: sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA==}
/@intlify/message-resolver/9.1.10:
resolution: {integrity: sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w==}
engines: {node: '>= 10'}
dev: false
/@intlify/runtime/9.1.9:
resolution: {integrity: sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg==}
/@intlify/runtime/9.1.10:
resolution: {integrity: sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==}
engines: {node: '>= 10'}
dependencies:
'@intlify/message-compiler': 9.1.9
'@intlify/message-resolver': 9.1.9
'@intlify/shared': 9.1.9
'@intlify/message-compiler': 9.1.10
'@intlify/message-resolver': 9.1.10
'@intlify/shared': 9.1.10
dev: false
/@intlify/shared/9.1.9:
resolution: {integrity: sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw==}
/@intlify/shared/9.1.10:
resolution: {integrity: sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA==}
engines: {node: '>= 10'}
dev: false
/@intlify/vue-devtools/9.1.9:
resolution: {integrity: sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==}
/@intlify/vue-devtools/9.1.10:
resolution: {integrity: sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==}
engines: {node: '>= 10'}
dependencies:
'@intlify/message-resolver': 9.1.9
'@intlify/runtime': 9.1.9
'@intlify/shared': 9.1.9
'@intlify/message-resolver': 9.1.10
'@intlify/runtime': 9.1.10
'@intlify/shared': 9.1.10
dev: false
/@jridgewell/resolve-uri/3.0.5:
@@ -556,6 +554,10 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.11
dev: true
/@juggle/resize-observer/3.3.1:
resolution: {integrity: sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==}
dev: false
/@nodelib/fs.scandir/2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -704,7 +706,7 @@ packages:
'@types/node': 17.0.23
dev: true
/@typescript-eslint/eslint-plugin/5.18.0_a07dca3bdfc4bfa60f4dda0c1f9e3287:
/@typescript-eslint/eslint-plugin/5.18.0_ub64uo67ys72md2n3igb7hrsq4:
resolution: {integrity: sha512-tzrmdGMJI/uii9/V6lurMo4/o+dMTKDH82LkNjhJ3adCW22YQydoRs5MwTiqxGF9CSYxPxQ7EYb4jLNlIs+E+A==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -715,10 +717,10 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.18.0_eslint@8.12.0+typescript@4.6.3
'@typescript-eslint/parser': 5.18.0_thk3xo4exzjr5rl6cnexo7v6re
'@typescript-eslint/scope-manager': 5.18.0
'@typescript-eslint/type-utils': 5.18.0_eslint@8.12.0+typescript@4.6.3
'@typescript-eslint/utils': 5.18.0_eslint@8.12.0+typescript@4.6.3
'@typescript-eslint/type-utils': 5.18.0_thk3xo4exzjr5rl6cnexo7v6re
'@typescript-eslint/utils': 5.18.0_thk3xo4exzjr5rl6cnexo7v6re
debug: 4.3.4
eslint: 8.12.0
functional-red-black-tree: 1.0.1
@@ -731,7 +733,7 @@ packages:
- supports-color
dev: true
/@typescript-eslint/parser/5.18.0_eslint@8.12.0+typescript@4.6.3:
/@typescript-eslint/parser/5.18.0_thk3xo4exzjr5rl6cnexo7v6re:
resolution: {integrity: sha512-+08nYfurBzSSPndngnHvFw/fniWYJ5ymOrn/63oMIbgomVQOvIDhBoJmYZ9lwQOCnQV9xHGvf88ze3jFGUYooQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -759,7 +761,7 @@ packages:
'@typescript-eslint/visitor-keys': 5.18.0
dev: true
/@typescript-eslint/type-utils/5.18.0_eslint@8.12.0+typescript@4.6.3:
/@typescript-eslint/type-utils/5.18.0_thk3xo4exzjr5rl6cnexo7v6re:
resolution: {integrity: sha512-vcn9/6J5D6jtHxpEJrgK8FhaM8r6J1/ZiNu70ZUJN554Y3D9t3iovi6u7JF8l/e7FcBIxeuTEidZDR70UuCIfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -769,7 +771,7 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/utils': 5.18.0_eslint@8.12.0+typescript@4.6.3
'@typescript-eslint/utils': 5.18.0_thk3xo4exzjr5rl6cnexo7v6re
debug: 4.3.4
eslint: 8.12.0
tsutils: 3.21.0_typescript@4.6.3
@@ -804,7 +806,7 @@ packages:
- supports-color
dev: true
/@typescript-eslint/utils/5.18.0_eslint@8.12.0+typescript@4.6.3:
/@typescript-eslint/utils/5.18.0_thk3xo4exzjr5rl6cnexo7v6re:
resolution: {integrity: sha512-+hFGWUMMri7OFY26TsOlGa+zgjEy1ssEipxpLjtl4wSll8zy85x0GrUSju/FHdKfVorZPYJLkF3I4XPtnCTewA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1465,6 +1467,8 @@ packages:
finalhandler: 1.1.2
parseurl: 1.3.3
utils-merge: 1.0.1
transitivePeerDependencies:
- supports-color
dev: true
/constant-case/3.0.4:
@@ -1507,8 +1511,8 @@ packages:
utrie: 1.0.2
dev: false
/css-render/0.15.9:
resolution: {integrity: sha512-FMVcWsVipKEBR/mVf1+pIjCRQdztILVKxbp8TN5/Vf0Q/fdTq0OIb8JRW/pk7PP1eeWnB/ejQ0MNBe7ELjLblg==}
/css-render/0.15.10:
resolution: {integrity: sha512-6j5acvm81sXTHJiF47FNNICtDpF74YoWk1xEK3qQvdqgW6vc+OXrPqflL6m8f5GE6XuFYrbACNEd17kraCSBAQ==}
dependencies:
'@emotion/hash': 0.8.0
'@types/node': 17.0.23
@@ -1538,12 +1542,22 @@ packages:
/debug/2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.0.0
dev: true
/debug/3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.3
dev: true
@@ -1743,10 +1757,6 @@ packages:
unbox-primitive: 1.0.1
dev: true
/es-module-lexer/0.9.3:
resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==}
dev: true
/es-to-primitive/1.2.1:
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
engines: {node: '>= 0.4'}
@@ -2003,29 +2013,54 @@ packages:
dependencies:
debug: 3.2.7
resolve: 1.22.0
transitivePeerDependencies:
- supports-color
dev: true
/eslint-module-utils/2.7.3:
/eslint-module-utils/2.7.3_gshgus2jxs3picixh7dqkggb4y:
resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint-import-resolver-node: '*'
eslint-import-resolver-typescript: '*'
eslint-import-resolver-webpack: '*'
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
eslint-import-resolver-node:
optional: true
eslint-import-resolver-typescript:
optional: true
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 5.18.0_thk3xo4exzjr5rl6cnexo7v6re
debug: 3.2.7
eslint-import-resolver-node: 0.3.6
find-up: 2.1.0
transitivePeerDependencies:
- supports-color
dev: true
/eslint-plugin-import/2.26.0_eslint@8.12.0:
/eslint-plugin-import/2.26.0_mzojdsoryzqztjvqj5t7e5xqmq:
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 5.18.0_thk3xo4exzjr5rl6cnexo7v6re
array-includes: 3.1.4
array.prototype.flat: 1.2.5
debug: 2.6.9
doctrine: 2.1.0
eslint: 8.12.0
eslint-import-resolver-node: 0.3.6
eslint-module-utils: 2.7.3
eslint-module-utils: 2.7.3_gshgus2jxs3picixh7dqkggb4y
has: 1.0.3
is-core-module: 2.8.1
is-glob: 4.0.3
@@ -2033,9 +2068,13 @@ packages:
object.values: 1.1.5
resolve: 1.22.0
tsconfig-paths: 3.14.1
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
dev: true
/eslint-plugin-prettier/4.0.0_f2c91d0f54113167d2bd9214a5ab5a36:
/eslint-plugin-prettier/4.0.0_6ler2d2uceywpuv5sikklk22gy:
resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==}
engines: {node: '>=6.0.0'}
peerDependencies:
@@ -2281,6 +2320,8 @@ packages:
parseurl: 1.3.3
statuses: 1.5.0
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
dev: true
/find-up/2.1.0:
@@ -2496,7 +2537,7 @@ packages:
source-map: 0.6.1
wordwrap: 1.0.0
optionalDependencies:
uglify-js: 3.15.4
uglify-js: 3.15.5
dev: true
/has-bigints/1.0.1:
@@ -3117,17 +3158,17 @@ packages:
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
dev: true
/naive-ui/2.27.0_vue@3.2.31:
resolution: {integrity: sha512-g9A2uulbQKMuJpUjAyiAqBHQ4xrcbwRPdv+OS2FeNC5u/SrRWFiO64X10YDyMwQNudrwc3VVqKUrw3ZArxtFCg==}
/naive-ui/2.29.0_vue@3.2.31:
resolution: {integrity: sha512-zZ4ka0Y5QakNyqJIPiAoZ5YJG4mCiSw+HzYtreEmOvBmbP14/iUXarRhI9a3XET8g6ix682TcitamlCyqZ/y2Q==}
peerDependencies:
vue: ^3.0.0
dependencies:
'@css-render/plugin-bem': 0.15.9_css-render@0.15.9
'@css-render/vue3-ssr': 0.15.9_vue@3.2.31
'@css-render/plugin-bem': 0.15.10_css-render@0.15.10
'@css-render/vue3-ssr': 0.15.10_vue@3.2.31
'@types/lodash': 4.14.181
'@types/lodash-es': 4.17.6
async-validator: 4.0.7
css-render: 0.15.9
css-render: 0.15.10
date-fns: 2.28.0
date-fns-tz: 1.3.3_date-fns@2.28.0
evtd: 0.2.3
@@ -3135,12 +3176,11 @@ packages:
lodash: 4.17.21
lodash-es: 4.17.21
seemly: 0.3.3
treemate: 0.3.10
vdirs: 0.1.7_vue@3.2.31
vfonts: 0.0.3
treemate: 0.3.11
vdirs: 0.1.8_vue@3.2.31
vooks: 0.2.12_vue@3.2.31
vue: 3.2.31
vueuc: 0.4.28_vue@3.2.31
vueuc: 0.4.37_vue@3.2.31
dev: false
/nanoid/3.3.2:
@@ -3437,7 +3477,7 @@ packages:
engines: {node: '>=8.6'}
dev: true
/pinia/2.0.13_typescript@4.6.3+vue@3.2.31:
/pinia/2.0.13_hhks2xcoho7x4jrwn5stbz36vy:
resolution: {integrity: sha512-B7rSqm1xNpwcPMnqns8/gVBfbbi7lWTByzS6aPZ4JOXSJD4Y531rZHDCoYWBwLyHY/8hWnXljgiXp6rRyrofcw==}
peerDependencies:
'@vue/composition-api': ^1.4.0
@@ -3655,10 +3695,6 @@ packages:
resolution: {integrity: sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ==}
dev: true
/resize-observer-polyfill/1.5.1:
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
dev: false
/resolve-dir/1.0.1:
resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==}
engines: {node: '>=0.10.0'}
@@ -3989,7 +4025,6 @@ packages:
/to-fast-properties/2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'}
dev: true
/to-regex-range/5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
@@ -4002,8 +4037,8 @@ packages:
resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==}
dev: true
/treemate/0.3.10:
resolution: {integrity: sha512-uxN98H84/zXAkn02rEeip9SNnOR889QIBXfpZnwjaanp8JRElxjdmDaKmVULclrn54J8RcJVCqfeQZsdeMjwow==}
/treemate/0.3.11:
resolution: {integrity: sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==}
dev: false
/tsconfig-paths/3.14.1:
@@ -4060,8 +4095,8 @@ packages:
hasBin: true
dev: true
/uglify-js/3.15.4:
resolution: {integrity: sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==}
/uglify-js/3.15.5:
resolution: {integrity: sha512-hNM5q5GbBRB5xB+PMqVRcgYe4c8jbyZ1pzZhS6jbq54/4F2gFK869ZheiE5A8/t+W5jtTNpWef/5Q9zk639FNQ==}
engines: {node: '>=0.8.0'}
hasBin: true
requiresBuild: true
@@ -4139,8 +4174,8 @@ packages:
engines: {node: '>= 10.13.0'}
dev: true
/vdirs/0.1.7_vue@3.2.31:
resolution: {integrity: sha512-MEUaLhV1jJyUqA2Ar4DfvlQx8jWs+PpCZ2dbM0ILelpMWGOybzt8ddL456VxeIbY/tkuDGT/Wzb8GG4LCuLuHw==}
/vdirs/0.1.8_vue@3.2.31:
resolution: {integrity: sha512-H9V1zGRLQZg9b+GdMk8MXDN2Lva0zx72MPahDKc30v+DtwKjfyOSXWRIX4t2mhDubM1H09gPhWeth/BJWPHGUw==}
peerDependencies:
vue: ^3.0.11
dependencies:
@@ -4148,10 +4183,6 @@ packages:
vue: 3.2.31
dev: false
/vfonts/0.0.3:
resolution: {integrity: sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ==}
dev: false
/vite-plugin-compression/0.5.1_vite@2.9.5:
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
peerDependencies:
@@ -4198,22 +4229,6 @@ packages:
- supports-color
dev: true
/vite-plugin-style-import/1.4.1_vite@2.9.5:
resolution: {integrity: sha512-lJCRvm7+So0hHdnSJiJPg9gD5mxtL6YY0jmhEph+k7ArpsyvqOh6han2kG5htbWWDZxHkUN9d1BuTFL//yCLLQ==}
peerDependencies:
vite: '>=2.0.0'
dependencies:
'@rollup/pluginutils': 4.2.0
change-case: 4.1.2
debug: 4.3.4
es-module-lexer: 0.9.3
fs-extra: 10.0.1
magic-string: 0.25.9
vite: 2.9.5_sass@1.49.11
transitivePeerDependencies:
- supports-color
dev: true
/vite/2.9.5_sass@1.49.11:
resolution: {integrity: sha512-dvMN64X2YEQgSXF1lYabKXw3BbN6e+BL67+P3Vy4MacnY+UzT1AfkHiioFSi9+uiDUiaDy7Ax/LQqivk6orilg==}
engines: {node: '>=12.2.0'}
@@ -4421,15 +4436,15 @@ packages:
- supports-color
dev: true
/vue-i18n/9.1.9_vue@3.2.31:
resolution: {integrity: sha512-JeRdNVxS2OGp1E+pye5XB6+M6BBkHwAv9C80Q7+kzoMdUDGRna06tjC0vCB/jDX9aWrl5swxOMFcyAr7or8XTA==}
/vue-i18n/9.1.10_vue@3.2.31:
resolution: {integrity: sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==}
engines: {node: '>= 10'}
peerDependencies:
vue: ^3.0.0
dependencies:
'@intlify/core-base': 9.1.9
'@intlify/shared': 9.1.9
'@intlify/vue-devtools': 9.1.9
'@intlify/core-base': 9.1.10
'@intlify/shared': 9.1.10
'@intlify/vue-devtools': 9.1.10
'@vue/devtools-api': 6.1.4
vue: 3.2.31
dev: false
@@ -4464,7 +4479,7 @@ packages:
'@vue/shared': 3.2.31
dev: false
/vue3-lazyload/0.2.5-beta_4f726de02e89ff745196f225ebb1bbcf:
/vue3-lazyload/0.2.5-beta_j5zg3yborh7xiumw6is6xmn3z4:
resolution: {integrity: sha512-GVhJfL9Hcu+AvWsYmUwODivvt+gzpT0ztgAzZaUduoiTaGCv/qzhr0VwAQXfjGF3XFYFyOJsHlAi3/WE0P8XTQ==}
peerDependencies:
'@vue/compiler-sfc': '>=3.0.0'
@@ -4499,17 +4514,17 @@ packages:
vue: 3.2.31
dev: false
/vueuc/0.4.28_vue@3.2.31:
resolution: {integrity: sha512-Udr1ROwJocHIThA5G+H5qN1QEFI4pskDvl+w/2Ul2XIjaAeIuQ6ygEOKHOXRJqKX5PxcTi1QQUpb7yQWsDw7ww==}
/vueuc/0.4.37_vue@3.2.31:
resolution: {integrity: sha512-NJVeUet0O2ta95aVYs7lNphG0AQFfNEuXxlIL50ZxQ//HTITkua17Rlh0RdyXG3C37HR/TqKAG5be7QJjJT3Fg==}
peerDependencies:
vue: ^3.0.11
dependencies:
'@css-render/vue3-ssr': 0.15.9_vue@3.2.31
css-render: 0.15.9
'@css-render/vue3-ssr': 0.15.10_vue@3.2.31
'@juggle/resize-observer': 3.3.1
css-render: 0.15.10
evtd: 0.2.3
resize-observer-polyfill: 1.5.1
seemly: 0.3.3
vdirs: 0.1.7_vue@3.2.31
vdirs: 0.1.8_vue@3.2.31
vooks: 0.2.12_vue@3.2.31
vue: 3.2.31
dev: false

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 398 KiB

After

Width:  |  Height:  |  Size: 398 KiB

View File

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 184 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -18,7 +18,7 @@ import { zhCN, dateZhCN, NConfigProvider } from 'naive-ui'
import { GoAppProvider } from '@/components/GoAppProvider'
import { I18n } from '@/components/I18n'
import { useDarkThemeHook, useThemeOverridesHook, useCode } from '@/hooks'
import { useSystemInit, useDarkThemeHook, useThemeOverridesHook, useCode } from '@/hooks'
// 暗黑主题
const darkTheme = useDarkThemeHook()
@@ -28,4 +28,7 @@ const overridesTheme = useThemeOverridesHook()
// 代码主题
const hljsTheme = useCode()
// 系统全局数据初始化
useSystemInit()
</script>

14
src/api/axios.config.ts Normal file
View File

@@ -0,0 +1,14 @@
import { ModuleTypeEnum } from '@/enums/httpEnum'
// 接口白名单(免登录)
export const fetchAllowList = [
// 登录
`${ModuleTypeEnum.SYSTEM}/login`,
// 获取 OSS 接口
`${ModuleTypeEnum.SYSTEM}/getOssInfo`,
// 预览获取数据
`${ModuleTypeEnum.PROJECT}/getData`,
]
// 接口黑名单
export const fetchBlockList = []

View File

@@ -1,20 +1,36 @@
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
import { ResultEnum } from "@/enums/httpEnum"
import { ErrorPageNameMap } from "@/enums/pageEnum"
import { redirectErrorPage } from '@/utils'
import { ResultEnum, RequestHttpHeaderEnum } from "@/enums/httpEnum"
import { PageEnum, ErrorPageNameMap } from "@/enums/pageEnum"
import { StorageEnum } from '@/enums/storageEnum'
import { axiosPre } from '@/settings/httpSetting'
import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d'
import { redirectErrorPage, getLocalStorage, routerTurnByName, httpErrorHandle } from '@/utils'
import { fetchAllowList } from './axios.config'
import includes from 'lodash/includes'
const axiosInstance = axios.create({
baseURL: import.meta.env.DEV ? import.meta.env.VITE_DEV_PATH : import.meta.env.VITE_PRO_PATH,
baseURL: `${import.meta.env.PROD ? import.meta.env.VITE_PRO_PATH : ''}${axiosPre}`,
timeout: ResultEnum.TIMEOUT,
})
axiosInstance.interceptors.request.use(
(config: AxiosRequestConfig) => {
config.headers = {}
// 白名单校验
if (includes(fetchAllowList, config.url)) return config
// 获取 token
const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
// 重新登录
if (!info) {
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
return config
}
config.headers = {
[RequestHttpHeaderEnum.TOKEN]: info[SystemStoreEnum.USER_INFO][SystemStoreUserInfoEnum.USER_TOKEN] || ''
}
return config
},
(error: AxiosRequestConfig) => {
Promise.reject(error)
(err: AxiosRequestConfig) => {
Promise.reject(err)
}
)
@@ -22,15 +38,31 @@ axiosInstance.interceptors.request.use(
axiosInstance.interceptors.response.use(
(res: AxiosResponse) => {
const { code } = res.data as { code: number }
if (code === ResultEnum.DATA_SUCCESS) return Promise.resolve(res.data)
// 重定向
if (ErrorPageNameMap.get(code)) redirectErrorPage(code)
// 成功
if (code === ResultEnum.SUCCESS) {
return Promise.resolve(res.data)
}
// 登录过期
if (code === ResultEnum.TOKEN_OVERDUE) {
window['$message'].error(window['$t']('http.token_overdue_message'))
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
return Promise.resolve(res.data)
}
// 固定错误码重定向
if (ErrorPageNameMap.get(code)) {
redirectErrorPage(code)
return Promise.resolve(res.data)
}
// 提示错误
window['$message'].error(window['$t']((res.data as any).msg))
return Promise.resolve(res.data)
},
(err: AxiosResponse) => {
const { code } = err.data as { code: number }
if (ErrorPageNameMap.get(code)) redirectErrorPage(code)
window['$message'].error('接口异常,请检查!')
httpErrorHandle()
Promise.reject(err)
}
)

View File

@@ -1,25 +1,37 @@
import axiosInstance from './axios'
import { RequestHttpEnum, ContentTypeEnum } from '@/enums/httpEnum'
export const get = (url: string) => {
export const get = (url: string, params?: object) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.GET,
params: params,
})
}
export const post = (url: string, params: object, headersType?: string) => {
export const post = (url: string, data?: object, headersType?: string) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.POST,
data: params,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const del = (url: string, params: object) => {
export const put = (url: string, data?: object, headersType?: ContentTypeEnum) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.PUT,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const del = (url: string, params?: object) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.DELETE,
@@ -29,11 +41,20 @@ export const del = (url: string, params: object) => {
// 获取请求函数默认get
export const http = (type?: RequestHttpEnum) => {
return type === RequestHttpEnum.GET
? get
: type === RequestHttpEnum.POST
? post
: type === RequestHttpEnum.DELETE
? del
: get
switch (type) {
case RequestHttpEnum.GET:
return get
case RequestHttpEnum.POST:
return post
case RequestHttpEnum.PUT:
return put
case RequestHttpEnum.DELETE:
return del
default:
return get
}
}

View File

@@ -1,6 +1,7 @@
export default {
// 图表
fetchMockData: {
code: 0,
status: 200,
msg: '请求成功',
data: {
@@ -41,6 +42,7 @@ export default {
},
// 排名列表
fetchRankList: {
code: 0,
status: 200,
msg: '请求成功',
data: [
@@ -61,6 +63,7 @@ export default {
},
// 获取数字
fetchNumber: {
code: 0,
status: 200,
msg: '请求成功',
data: '@float(0, 0.99)',

2
src/api/path/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from '@/api/path/project.api'
export * from '@/api/path/system.api'

View File

@@ -0,0 +1,84 @@
import { http } from '@/api/http'
import { httpErrorHandle } from '@/utils'
import { ContentTypeEnum, RequestHttpEnum, ModuleTypeEnum } from '@/enums/httpEnum'
// * 项目列表
export const projectListApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.GET)(`${ModuleTypeEnum.PROJECT}/list`, data);
return res;
} catch {
httpErrorHandle();
}
}
// * 新增项目
export const createProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.PROJECT}/create`, data);
return res;
} catch {
httpErrorHandle();
}
}
// * 获取项目
export const fetchProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.GET)(`${ModuleTypeEnum.PROJECT}/getData`, data);
return res;
} catch {
httpErrorHandle();
}
}
// * 保存项目
export const saveProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.PROJECT}/save/data`, data, ContentTypeEnum.FORM_URLENCODED);
return res;
} catch {
httpErrorHandle();
}
}
// * 修改项目基础信息
export const updateProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.PROJECT}/edit`, data);
return res;
} catch {
httpErrorHandle();
}
}
// * 删除项目
export const deleteProjectApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.DELETE)(`${ModuleTypeEnum.PROJECT}/delete`, data);
return res;
} catch {
httpErrorHandle();
}
}
// * 修改发布状态 [-1未发布,1发布]
export const changeProjectReleaseApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.PUT)(`${ModuleTypeEnum.PROJECT}/publish`, data);
return res;
} catch {
httpErrorHandle();
}
}
// * 上传文件
export const uploadFile = async (url:string, data: object) => {
try {
const res = await http(RequestHttpEnum.POST)(url, data, ContentTypeEnum.FORM_DATA);
return res;
} catch {
httpErrorHandle();
}
}

View File

@@ -0,0 +1,42 @@
import { http } from '@/api/http'
import { httpErrorHandle } from '@/utils'
import { RequestHttpEnum, ModuleTypeEnum } from '@/enums/httpEnum'
// * 登录
export const loginApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.SYSTEM}/login`, data);
return res;
} catch(err) {
httpErrorHandle();
}
}
// * 新接口
export const newApi = async (data: object) => {
try {
const resonse = await http(RequestHttpEnum.POST)(`新接口的路劲/xxx/xxx`, data)
} catch (error) {
httpErrorHandle();
}
}
// * 登出
export const logoutApi = async () => {
try {
const res = await http(RequestHttpEnum.GET)(`${ModuleTypeEnum.SYSTEM}/logout`);
return res;
} catch(err) {
httpErrorHandle();
}
}
// * 获取 oss 上传接口
export const ossUrlApi = async (data: object) => {
try {
const res = await http(RequestHttpEnum.GET)(`${ModuleTypeEnum.SYSTEM}/getOssInfo`, data);
return res;
} catch(err) {
httpErrorHandle();
}
}

View File

@@ -12,7 +12,7 @@
</template>
</n-button>
</n-space>
<setting-item-box name="边距">
<setting-item-box name="位置">
<n-input-number
v-model:value="chartAttr.y"
:min="0"

View File

@@ -19,7 +19,8 @@ export enum MenuEnum {
DOWN = 'down',
CLEAR = 'clear',
BACK = 'back',
FORWORD = 'forward'
FORWORD = 'forward',
SAVE = 'save'
}
// Win 键盘枚举
@@ -35,4 +36,16 @@ export enum MacKeyboard {
CTRL = '⌘',
SHIFT = '⇧',
ALT = '⌥',
}
// 同步状态枚举
export enum SyncEnum {
// 等待
PENDING,
// 开始
START,
// 成功
SUCCESS,
// 失败
FAILURE
}

View File

@@ -1,12 +1,17 @@
/**
* @description: 请求结果集
*/
// 模块 Path 前缀分类
export enum ModuleTypeEnum {
SYSTEM = 'sys',
PROJECT = 'project',
}
// 请求结果集
export enum ResultEnum {
DATA_SUCCESS = 0,
SUCCESS = 200,
SERVER_ERROR = 500,
SERVER_FORBIDDEN = 403,
NOT_FOUND = 404,
TOKEN_OVERDUE = 886,
TIMEOUT = 10042,
}
@@ -18,9 +23,13 @@ export enum RequestDataTypeEnum {
AJAX = 1,
}
/**
* @description: 请求方法
*/
// 头部
export enum RequestHttpHeaderEnum {
TOKEN = 'Token',
COOKIE = 'Cookie'
}
// 请求方法
export enum RequestHttpEnum {
GET = 'get',
POST = 'post',
@@ -29,16 +38,14 @@ export enum RequestHttpEnum {
DELETE = 'delete',
}
/**
* @description: 常用的contentTyp类型
*/
// 常用的contentTyp类型
export enum ContentTypeEnum {
// json
JSON = 'application/json;charset=UTF-8',
// json
TEXT = 'text/plain;charset=UTF-8',
JSON = 'application/json; charset=UTF-8',
// text
TEXT = 'text/plain; charset=UTF-8',
// form-data 一般配合qs
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
FORM_URLENCODED = 'application/x-www-form-urlencoded; charset=UTF-8',
// form-data 上传
FORM_DATA = 'multipart/form-data;charset=UTF-8',
FORM_DATA = 'multipart/form-data; charset=UTF-8',
}

View File

@@ -20,10 +20,15 @@ export enum PageEnum {
//重定向
REDIRECT = '/redirect',
REDIRECT_NAME = 'Redirect',
// 未发布
REDIRECT_UN_PUBLISH = '/redirect/unPublish',
REDIRECT_UN_PUBLISH_NAME = 'redirect-un-publish',
// 重载
RELOAD = '/reload',
RELOAD_NAME = 'Reload',
// 首页
BASE_HOME = '/project',
BASE_HOME_NAME = 'Project',

View File

@@ -1,10 +1,8 @@
export enum StorageEnum {
// 全局设置
GO_SYSTEM_SETTING_STORE = 'GO_SYSTEM_SETTING',
// token 等信息
GO_ACCESS_TOKEN_STORE = 'GO_ACCESS_TOKEN',
GO_SETTING_STORE = 'GO_SETTING',
// 登录信息
GO_LOGIN_INFO_STORE = 'GO_LOGIN_INFO',
GO_SYSTEM_STORE = 'GO_SYSTEM',
// 语言
GO_LANG_STORE = 'GO_LANG',
// 当前选择的主题

View File

@@ -1,4 +1,5 @@
export * from '@/hooks/useTheme.hook'
export * from '@/hooks/usePreviewScale.hook'
export * from '@/hooks/useCode.hook'
export * from '@/hooks/useChartDataFetch.hook'
export * from '@/hooks/useChartDataFetch.hook'
export * from '@/hooks/useSystemInit.hook'

View File

@@ -43,7 +43,7 @@ export const useChartDataFetch = (
if (!completePath) return
fetchInterval = setInterval(async () => {
const res:any = await http(requestHttpType.value)(completePath || '', {})
const res = await http(requestHttpType.value)(completePath || '', {}) as unknown as MyResponseType
if (res.data) {
// 是否是 Echarts 组件
const isECharts =

View File

@@ -0,0 +1,23 @@
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
import { SystemStoreEnum } from '@/store/modules/systemStore/systemStore.d'
import { ResultEnum } from '@/enums/httpEnum'
import { ossUrlApi } from '@/api/path/'
// * 初始化
export const useSystemInit = async () => {
const systemStore = useSystemStore()
// 获取 OSS 信息
const getOssUrl = async () => {
const res = await ossUrlApi({}) as unknown as MyResponseType
if (res.code === ResultEnum.SUCCESS) {
systemStore.setItem(SystemStoreEnum.FETCH_INFO, {
OSSUrl: res.data?.bucketURL
})
}
}
// 执行
getOssUrl()
}

View File

@@ -11,13 +11,15 @@ const global = {
help: 'Help',
contact: 'Contact Us',
logout: 'Logout',
logout_success: 'Logout success',
logout_failure: 'Logout Failed',
// system setting
sys_set: 'System Setting',
lang_set: 'Language Setting',
// right key
r_edit: 'Edit',
r_preview: 'Preview',
r_copy: 'Copy',
r_copy: 'Clone',
r_rename: 'Rename',
r_publish: 'Publish',
r_unpublish: 'Unpublish',
@@ -26,8 +28,14 @@ const global = {
r_more: 'More',
}
const http = {
error_message: 'The interface is abnormal, please check the interface!',
token_overdue_message: 'Login expired, please log in again!'
}
export default {
global,
http,
login,
project
}

View File

@@ -2,6 +2,6 @@ export default {
desc: "Login",
form_auto: "Sign in automatically",
form_button: "Login",
login_success: "Login success",
login_message: "Please complete the letter",
login_success: "Login success!",
login_message: "Please complete the letter!",
}

View File

@@ -1,6 +1,8 @@
export default {
create_btn: 'Creat',
create_tip: 'Please select a content for development',
create_success: 'Creat Success!',
create_failure: 'Failed to create, please try again later',
create_tip: 'Please select a content for development!',
project: 'Project',
my: 'My',
new_project: 'New Project',

View File

@@ -11,23 +11,36 @@ const global = {
help: '帮助中心',
contact: '联系我们',
logout: '退出登录',
logout_success: '退出成功!',
logout_failure: '退出失败!',
// 系统设置
sys_set: '系统设置',
lang_set: '语言设置',
// 功能键
r_edit: '编辑',
r_preview: '预览',
r_copy: '复制',
r_copy: '克隆',
r_copy_success: '克隆成功!',
r_rename: '重命名',
r_rename_success: '重命名成功!',
r_publish: '发布',
r_publish_success: '成功发布!',
r_unpublish: '取消发布',
r_unpublish_success: '取消成功!',
r_download: '下载',
r_delete: '删除',
r_delete_success: '删除成功!',
r_more: '更多',
}
const http = {
error_message: '获取数据失败,请稍后重试!',
token_overdue_message: '登录过期,请重新登录!'
}
export default {
global,
http,
login,
project
}

View File

@@ -2,6 +2,6 @@ export default {
desc: "登录",
form_auto: "自动登录",
form_button: "登录",
login_success: "登录成功",
login_message: "请填写完整信息",
login_success: "登录成功!",
}

View File

@@ -1,6 +1,8 @@
export default {
// aside
create_btn: '新建',
create_success: '新建成功!',
create_failure: '新建失败,请稍后重试!',
create_tip: '从哪里出发好呢?',
project: '项目',
my: '我的',

View File

@@ -29,6 +29,7 @@ import { ThemeColorSelect } from '@/components/Pages/ThemeColorSelect'
</script>
<style lang="scss" scoped>
$min-width: 400px;
@include go(header) {
&-box {
display: grid;
@@ -36,6 +37,7 @@ import { ThemeColorSelect } from '@/components/Pages/ThemeColorSelect'
.header-item {
display: flex;
align-items: center;
min-width: $min-width;
&.left {
justify-content: start;
}

View File

@@ -61,9 +61,9 @@ watch(() => chartEditStore.getEditCanvasConfig.chartThemeColor, (newColor: keyof
v.color = themeColor[i]
})
})
option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
props.chartConfig.option = option.value
}
option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
props.chartConfig.option = option.value
}, {
immediate: true,
})

View File

@@ -15,14 +15,14 @@
placeholder="水球数值"
></n-input-number>
</SettingItem>
<SettingItem name="颜色">
<SettingItem name="颜色1">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="item.color[0].colorStops[0].color"
></n-color-picker>
</SettingItem>
<SettingItem name="颜色">
<SettingItem name="颜色2">
<n-color-picker
size="small"
:modes="['hex']"

View File

@@ -2,7 +2,7 @@ import { publicConfig } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { ImageConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
import logo from '@/../public/logo.png'
import logo from '@/assets/logo.png'
export const option = {
// 图片路径

View File

@@ -1,4 +1,3 @@
import Configuration from './config.vue'
import image from '@/assets/images/chart/informations/words_cloud.png'
import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'

View File

@@ -1,4 +1,4 @@
import image from '@/assets/images/chart/Tables/tables_categary.png'
import image from '@/assets/images/chart/tables/tables_categary.png'
import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'

View File

@@ -1,4 +1,4 @@
import image from '@/assets/images/chart/Tables/tables.png'
import image from '@/assets/images/chart/tables/tables.png'
import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'

View File

@@ -1,4 +1,4 @@
import image from '@/assets/images/chart/Tables/tables_list.png'
import image from '@/assets/images/chart/tables/tables_list.png'
import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'

View File

@@ -8,7 +8,10 @@ import { SketchRule } from 'vue3-sketch-ruler'
* @param app
*/
export function setupCustomComponents(app: App) {
// 骨架屏
app.component('GoSkeleton', GoSkeleton)
// 加载
app.component('GoLoading', GoLoading)
// 标尺
app.component('SketchRule', SketchRule)
}

View File

@@ -52,7 +52,8 @@ import {
ArrowBack as ArrowBackIcon,
ArrowForward as ArrowForwardIcon,
Planet as PawIcon,
Search as SearchIcon
Search as SearchIcon,
Reload as ReloadIcon
} from '@vicons/ionicons5'
import {
@@ -190,7 +191,9 @@ const ionicons5 = {
// 狗爪
PawIcon,
// 搜索(放大镜)
SearchIcon
SearchIcon,
// 加载
ReloadIcon
}
const carbon = {

View File

@@ -1,13 +1,13 @@
import { RouteRecordRaw } from 'vue-router'
import type { AppRouteRecordRaw } from '@/router/types';
import { ErrorPage404, ErrorPage403, ErrorPage500, Layout } from '@/router/constant';
import { ErrorPage404, ErrorPage403, ErrorPage500, Layout, RedirectHome, RedirectUnPublish } from '@/router/constant';
import { PageEnum } from '@/enums/pageEnum'
import { GoReload } from '@/components/GoReload'
export const LoginRoute: RouteRecordRaw = {
path: '/login',
name: 'Login',
path: PageEnum.BASE_LOGIN,
name: PageEnum.BASE_LOGIN_NAME,
component: () => import('@/views/login/index.vue'),
meta: {
title: '登录',
@@ -60,22 +60,21 @@ export const ReloadRoute: AppRouteRecordRaw = {
},
}
export const RedirectRoute: AppRouteRecordRaw = {
path: PageEnum.REDIRECT,
name: PageEnum.REDIRECT_NAME,
component: Layout,
meta: {
title: PageEnum.REDIRECT_NAME,
},
children: [
{
path: '/redirect/:path(.*)',
name: PageEnum.REDIRECT_NAME,
component: () => import('@/views/redirect/index.vue'),
meta: {
title: PageEnum.REDIRECT_NAME,
hideBreadcrumb: true,
},
export const RedirectRoute: RouteRecordRaw[] = [
{
path: PageEnum.REDIRECT,
name: PageEnum.REDIRECT_NAME,
component: RedirectHome,
meta: {
title: PageEnum.REDIRECT_NAME,
},
],
};
},
{
path: PageEnum.REDIRECT_UN_PUBLISH,
name: PageEnum.REDIRECT_UN_PUBLISH_NAME,
component: RedirectUnPublish,
meta: {
title: PageEnum.REDIRECT_UN_PUBLISH_NAME,
},
},
]

View File

@@ -4,6 +4,10 @@ export const ErrorPage403 = () => import('@/views/exception/403.vue');
export const ErrorPage500 = () => import('@/views/exception/500.vue');
export const RedirectHome = () => import('@/views/redirect/index.vue');
export const RedirectUnPublish = () => import('@/views/redirect/UnPublish.vue');
export const Layout = () => import('@/layout/index.vue');
export const ParentLayout = () => import('@/layout/parentLayout.vue');

View File

@@ -1,9 +1,8 @@
import type { App } from 'vue'
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import { RedirectRoute } from '@/router/base'
import { createRouterGuards } from './router-guards'
import { PageEnum } from '@/enums/pageEnum'
import { HttpErrorPage, LoginRoute, ReloadRoute } from '@/router/base'
import { HttpErrorPage, LoginRoute, ReloadRoute, RedirectRoute } from '@/router/base'
import { Layout } from '@/router/constant'
import modules from '@/router/modules'
@@ -19,6 +18,7 @@ const RootRoute: Array<RouteRecordRaw> = [
},
children: [
...HttpErrorPage,
...RedirectRoute,
modules.projectRoutes,
modules.chartRoutes,
modules.previewRoutes
@@ -27,7 +27,7 @@ const RootRoute: Array<RouteRecordRaw> = [
]
export const constantRouter: any[] = [LoginRoute, ...RootRoute, RedirectRoute, ReloadRoute];
export const constantRouter: any[] = [LoginRoute, ...RootRoute, ReloadRoute];
const router = createRouter({
history: createWebHashHistory(''),

View File

@@ -48,8 +48,11 @@ export const backgroundImageSize = 5
// 预览展示方式
export const previewScaleType = PreviewScaleEnum.FIT
// 数据请求间隔
// 数据请求间隔s
export const requestInterval = 30
// 工作台自动保存间隔s
export const saveInterval = 30
// 工作区域历史记录存储最大数量
export const editHistoryMax = 100

View File

@@ -0,0 +1,2 @@
// 请求前缀
export const axiosPre = '/api/goview'

View File

@@ -13,5 +13,5 @@ export const systemSetting = {
// 图表拖拽时的吸附距离px
[SettingStoreEnums.CHART_ALIGN_RANGE]: 10,
// 图表工具栏状态(侧边工具状态)
[SettingStoreEnums.CHART_TOOLS_STATUS]: ToolsStatusEnum.DOCK
[SettingStoreEnums.CHART_TOOLS_STATUS]: ToolsStatusEnum.ASIDE
}

View File

@@ -1,12 +1,33 @@
import { CreateComponentType, FilterEnum} from '@/packages/index.d'
import { HistoryActionTypeEnum } from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
import { RequestHttpEnum, RequestDataTypeEnum } from '@/enums/httpEnum'
import { SyncEnum } from '@/enums/editPageEnum'
import { PreviewScaleEnum } from '@/enums/styleEnum'
import type {
ChartColorsNameType,
GlobalThemeJsonType,
} from '@/settings/chartThemes/index'
// 项目数据枚举
export enum ProjectInfoEnum {
// 名称
PROJECT_NAME = 'projectName',
// 描述
REMARKS = 'remarks',
// 缩略图
THUMBNAIL= 'thumbnail',
// 是否公开发布
RELEASE = 'release'
}
// 项目数据
export type ProjectInfoType = {
[ProjectInfoEnum.PROJECT_NAME]: string,
[ProjectInfoEnum.REMARKS]: string,
[ProjectInfoEnum.THUMBNAIL]: string,
[ProjectInfoEnum.RELEASE]: boolean
}
// 编辑画布属性
export enum EditCanvasTypeEnum {
EDIT_LAYOUT_DOM = 'editLayoutDom',
@@ -17,9 +38,10 @@ export enum EditCanvasTypeEnum {
LOCK_SCALE = 'lockScale',
IS_CREATE = 'isCreate',
IS_DRAG = 'isDrag',
SAVE_STATUS = 'saveStatus'
}
// 编辑区域
// 编辑区域(临时)
export type EditCanvasType = {
// 编辑区域 DOM
[EditCanvasTypeEnum.EDIT_LAYOUT_DOM]: HTMLElement | null
@@ -36,9 +58,11 @@ export type EditCanvasType = {
[EditCanvasTypeEnum.IS_CREATE]: boolean
// 拖拽中
[EditCanvasTypeEnum.IS_DRAG]: boolean
// 保存状态
[EditCanvasTypeEnum.SAVE_STATUS]: SyncEnum
}
// 滤镜/背景色/宽高主题等
// 画布数据/滤镜/背景色/宽高主题等
export enum EditCanvasConfigEnum {
WIDTH = 'width',
HEIGHT = 'height',
@@ -50,7 +74,12 @@ export enum EditCanvasConfigEnum {
PREVIEW_SCALE_TYPE = 'previewScaleType',
}
export interface EditCanvasConfigType {
// 画布属性(需保存)
export type EditCanvasConfigType = {
// 项目名称
[EditCanvasConfigEnum.PROJECT_NAME]: string,
// 项目描述
[EditCanvasConfigEnum.REMARKS]: string,
// 滤镜-色相
[FilterEnum.HUE_ROTATE]: number
// 滤镜-饱和度
@@ -118,6 +147,7 @@ export type RecordChartType = {
// Store 枚举
export enum ChartEditStoreEnum {
PROJECT_INFO = 'projectInfo',
EDIT_RANGE = 'editRange',
EDIT_CANVAS = 'editCanvas',
RIGHT_MENU_SHOW = 'rightMenuShow',
@@ -137,6 +167,7 @@ export type RequestGlobalConfigType = {
// 轮询时间
requestInterval: number
}
// 单个图表请求配置
export type RequestConfigType = {
// 获取数据的方式
@@ -149,6 +180,7 @@ export type RequestConfigType = {
// Store 类型
export interface ChartEditStoreType {
[ChartEditStoreEnum.PROJECT_INFO]: ProjectInfoType
[ChartEditStoreEnum.EDIT_CANVAS]: EditCanvasType
[ChartEditStoreEnum.EDIT_CANVAS_CONFIG]: EditCanvasConfigType
[ChartEditStoreEnum.RIGHT_MENU_SHOW]: boolean
@@ -159,6 +191,7 @@ export interface ChartEditStoreType {
[ChartEditStoreEnum.COMPONENT_LIST]: CreateComponentType[]
}
// 需要存储的数据内容
export interface ChartEditStorage {
[ChartEditStoreEnum.EDIT_CANVAS_CONFIG]: EditCanvasConfigType
[ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG]: RequestGlobalConfigType

View File

@@ -9,10 +9,13 @@ import { requestInterval, previewScaleType } from '@/settings/designSetting'
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
// 全局设置
import { useSettingStore } from '@/store/modules/settingStore/settingStore'
// 历史类型
import { HistoryActionTypeEnum, HistoryItemType, HistoryTargetTypeEnum } from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
import { MenuEnum } from '@/enums/editPageEnum'
import { PreviewScaleEnum } from '@/enums/styleEnum'
// 画布枚举
import { MenuEnum, SyncEnum } from '@/enums/editPageEnum'
import {
ProjectInfoType,
ChartEditStoreEnum,
ChartEditStorage,
ChartEditStoreType,
@@ -31,6 +34,13 @@ const settingStore = useSettingStore()
export const useChartEditStore = defineStore({
id: 'useChartEditStore',
state: (): ChartEditStoreType => ({
// 项目数据
projectInfo: {
projectName: '',
remarks: '',
thumbnail: '',
release: false
},
// 画布属性
editCanvas: {
// 编辑区域 Dom
@@ -47,7 +57,9 @@ export const useChartEditStore = defineStore({
// 初始化
isCreate: false,
// 拖拽中
isDrag: false
isDrag: false,
// 同步中
saveStatus: SyncEnum.PENDING
},
// 右键菜单
rightMenuShow: false,
@@ -109,6 +121,9 @@ export const useChartEditStore = defineStore({
componentList: []
}),
getters: {
getProjectInfo(): ProjectInfoType {
return this.projectInfo
},
getMousePosition(): MousePositionType {
return this.mousePosition
},
@@ -143,6 +158,10 @@ export const useChartEditStore = defineStore({
}
},
actions: {
// * 设置 peojectInfo 数据项
setProjectInfo<T extends keyof ProjectInfoType, K extends ProjectInfoType[T]>(key: T, value: K) {
this.projectInfo[key] = value
},
// * 设置 editCanvas 数据项
setEditCanvas<T extends keyof EditCanvasType, K extends EditCanvasType[T]>(key: T, value: K) {
this.editCanvas[key] = value
@@ -517,8 +536,8 @@ export const useChartEditStore = defineStore({
attr.x -= distance
break;
}
},
// ----------------
},
// * 页面缩放设置-----------------
// * 设置页面大小
setPageSize(scale: number): void {
this.setPageStyle('height', `${this.editCanvasConfig.height * scale}px`)

View File

@@ -19,8 +19,8 @@ export const useChartLayoutStore = defineStore({
layers: true,
// 图表组件
charts: true,
// 详情设置
details: true
// 详情设置收缩为true
details: false
},
getters: {
getLayers(): boolean {

View File

@@ -4,10 +4,10 @@ import { asideCollapsedWidth } from '@/settings/designSetting'
import { SettingStoreType, ToolsStatusEnum } from './settingStore.d'
import { setLocalStorage, getLocalStorage } from '@/utils'
import { StorageEnum } from '@/enums/storageEnum'
const { GO_SYSTEM_SETTING_STORE } = StorageEnum
const { GO_SETTING_STORE } = StorageEnum
const storageSetting: SettingStoreType = getLocalStorage(
GO_SYSTEM_SETTING_STORE
GO_SETTING_STORE
)
// 全局设置
@@ -45,7 +45,7 @@ export const useSettingStore = defineStore({
this.$patch(state => {
state[key] = value
})
setLocalStorage(GO_SYSTEM_SETTING_STORE, this.$state)
setLocalStorage(GO_SETTING_STORE, this.$state)
}
}
})

View File

@@ -0,0 +1,29 @@
export enum SystemStoreUserInfoEnum {
USER_TOKEN = 'userToken',
USER_ID = 'userId',
USER_NAME = 'userName',
NICK_NAME = 'nickName',
}
export interface UserInfoType {
[SystemStoreUserInfoEnum.USER_TOKEN]?: string,
[SystemStoreUserInfoEnum.USER_ID]?: string,
[SystemStoreUserInfoEnum.USER_NAME]?: string,
[SystemStoreUserInfoEnum.NICK_NAME]?: string,
}
export interface FetchInfoType {
OSSUrl?: string,
}
export enum SystemStoreEnum {
// 用户
USER_INFO = 'userInfo',
// 请求
FETCH_INFO = 'fetchInfo'
}
export interface SystemStoreType {
[SystemStoreEnum.USER_INFO]: UserInfoType
[SystemStoreEnum.FETCH_INFO]: FetchInfoType
}

View File

@@ -0,0 +1,40 @@
import { defineStore } from 'pinia'
import { SystemStoreType, UserInfoType, FetchInfoType } from './systemStore.d'
import { setLocalStorage, getLocalStorage } from '@/utils'
import { StorageEnum } from '@/enums/storageEnum'
const { GO_SYSTEM_STORE } = StorageEnum
const storageSystem: SystemStoreType = getLocalStorage(GO_SYSTEM_STORE)
// 系统数据记录
export const useSystemStore = defineStore({
id: 'useSystemStore',
state: (): SystemStoreType => storageSystem || {
userInfo: {
userId: undefined,
userName: undefined,
userToken: undefined,
nickName: undefined
},
fetchInfo: {
OSSUrl: undefined
}
},
getters: {
getUserInfo(): UserInfoType {
return this.userInfo
},
getFetchInfo(): FetchInfoType {
return this.fetchInfo
},
},
actions: {
setItem<T extends keyof SystemStoreType, K extends SystemStoreType[T]>(key: T, value: K): void {
this.$patch(state => {
state[key] = value
});
setLocalStorage(GO_SYSTEM_STORE, this.$state)
}
}
})

View File

@@ -1,5 +1,5 @@
// 闪烁
.animation-twinkle {
.go-animation-twinkle {
animation: twinkle 2s ease;
animation-iteration-count: infinite;
opacity: 1;
@@ -44,7 +44,7 @@
}
// 渐变
.fade-enter,
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
@@ -58,7 +58,7 @@
.list-complete-item {
transition: all 1s;
}
.list-complete-enter,
.list-complete-enter-from,
.list-complete-leave-to {
opacity: 0;
transform: translateY(30px);

View File

@@ -80,54 +80,41 @@
word-break: break-all;
}
// todo 使用 scss 循环写一套完整的
// margin
.go-mt-0 {
margin-top: 0 !important;
}
// class:m-1 => margin1em
// class:mt-1 => margin-top1em
// m-0|mt-0|mx-0|my-0|p-0|pt-0|...
.go-mb-0 {
margin-bottom: 0 !important;
}
.go-ml-0 {
margin-left: 0 !important;
}
@each $typekey, $type in $spacing-types {
//.m-1
@each $sizekey, $size in $spacing-sizes {
.go-#{$typekey}-#{$sizekey} {
#{$type}: $size * $spacing-base-size;
}
}
.go-mr-0 {
margin-right: 0 !important;
}
//.mx-1
@each $sizekey, $size in $spacing-sizes {
.go-#{$typekey}x-#{$sizekey} {
#{$type}-left: $size * $spacing-base-size;
#{$type}-right: $size * $spacing-base-size;
}
.go-my-0 {
@extend .go-mt-0;
@extend .go-mb-0;
}
.go-#{$typekey}y-#{$sizekey} {
#{$type}-top: $size * $spacing-base-size;
#{$type}-bottom: $size * $spacing-base-size;
}
}
.go-mx-0 {
@extend .go-ml-0;
@extend .go-mr-0;
}
//.mt-1
@each $directionkey, $direction in $spacing-directions {
@each $sizekey, $size in $spacing-sizes {
.go-#{$typekey}#{$directionkey}-#{$sizekey} {
#{$type}-#{$direction}: $size * $spacing-base-size;
}
}
}
.go-pt-0 {
padding-top: 0 !important;
}
.go-pb-0 {
padding-bottom: 0 !important;
}
.go-pl-0 {
padding-left: 0 !important;
}
.go-pr-0 {
padding-right: 0 !important;
}
.go-py-0 {
@extend .go-pt-0;
@extend .go-pb-0;
}
.go-px-0 {
@extend .go-pl-0;
@extend .go-pr-0;
.go-#{$typekey} {
#{$type}: 0 !important;
}
}

View File

@@ -10,6 +10,31 @@ $--color-text-2: #86909c;
$--color-text-3: #c9cdd4;
$--color-text-4: #f2f3f5;
//.mt-1 => margin top
//spacing
$spacing-base-size: 1em;
$spacing-types: (
m: margin,
p: padding,
);
$spacing-directions: (
t: top,
r: right,
b: bottom,
l: left,
);
$spacing-sizes: (
0: 0,
1: 0.25,
2: 0.5,
3: 1,
4: 1.5,
5: 2.5,
);
// 变亮值
$--light-shalow: 2%;

View File

@@ -1,3 +1,65 @@
/**
* * base64转file
* @param dataurl
* @param fileName
* @returns
*/
export const base64toFile = (dataurl: string, fileName: string) => {
let dataArr = dataurl.split(","),
mime = (dataArr as any[])[0].match(/:(.*?);/)[1],
bstr = atob(dataArr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], fileName, { type: mime });
}
/**
* * file转url
*/
export const fileToUrl = (file: File): string => {
const Url = URL || window.URL || window.webkitURL
const ImageUrl = Url.createObjectURL(file)
return ImageUrl
}
/**
* * url转file
*/
export const urlToFile = (fileUrl: string, fileName = `${new Date().getTime()}`): File => {
const dataArr = fileUrl.split(',')
const mime = (dataArr as any[])[0].match(/:(.*);/)[1]
const originStr = atob(dataArr[1])
return new File([originStr], `${fileName}`, { type: mime })
}
/**
* * file转base64
* @param file 文件数据
* @param callback 回调函数
*/
export const fileTobase64 = (file: File, callback: Function) => {
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function (e: ProgressEvent<FileReader>) {
if (e.target) {
let base64 = e.target.result
callback(base64)
}
}
}
/**
* * canvas转file
* @param canvas
*/
export const canvastoFile = (canvas: HTMLCanvasElement, name?: string) => {
const dataurl = canvas.toDataURL('image/png')
return urlToFile(dataurl, name)
}
/**
* *获取上传的文件数据
* @param { File } file 文件对象
@@ -38,7 +100,7 @@ export const downloadByA = (url: string, filename = new Date().getTime(), fileSu
}
/**
* 下载数据
* * 下载数据
* @param { string } content 数据内容
* @param { ?string } filename 文件名称(默认随机字符)
* @param { ?string } fileSuffix 文件名称(默认随机字符)
@@ -51,4 +113,4 @@ export const downloadTextFile = (
// 字符内容转变成blob地址
const blob = new Blob([content])
downloadByA(URL.createObjectURL(blob), filename, fileSuffix)
}
}

6
src/utils/http.ts Normal file
View File

@@ -0,0 +1,6 @@
/**
* * 请求失败统一处理
*/
export const httpErrorHandle = () => {
window['$message'].error(window['$t']('http.error_message'))
}

View File

@@ -7,3 +7,4 @@ export * from '@/utils/plugin'
export * from '@/utils/componets'
export * from '@/utils/type'
export * from '@/utils/file'
export * from '@/utils/http'

View File

@@ -1,11 +1,12 @@
import { useRoute } from 'vue-router'
import { ResultEnum } from '@/enums/httpEnum'
import { ErrorPageNameMap, PageEnum } from '@/enums/pageEnum'
import { ResultEnum, RequestHttpHeaderEnum } from '@/enums/httpEnum'
import { ErrorPageNameMap, PageEnum, PreviewEnum } from '@/enums/pageEnum'
import { docPath, giteeSourceCodePath } from '@/settings/pathConst'
import { cryptoDecode } from './crypto'
import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d'
import { StorageEnum } from '@/enums/storageEnum'
import { clearLocalStorage, getLocalStorage } from './storage'
import { clearLocalStorage, getLocalStorage, clearCookie } from './storage'
import router from '@/router'
import { logoutApi } from '@/api/path'
/**
* * 根据名字跳转路由
@@ -101,11 +102,20 @@ export const reloadRoutePage = () => {
}
/**
* * 退出
* * 退出登录
*/
export const logout = () => {
clearLocalStorage(StorageEnum.GO_LOGIN_INFO_STORE)
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
export const logout = async () => {
try {
const res = await logoutApi() as unknown as MyResponseType
if(res.code === ResultEnum.SUCCESS) {
window['$message'].success(window['$t']('global.logout_success'))
clearCookie(RequestHttpHeaderEnum.COOKIE)
clearLocalStorage(StorageEnum.GO_SYSTEM_STORE)
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
}
} catch (error) {
window['$message'].success(window['$t']('global.logout_failure'))
}
}
/**
@@ -153,6 +163,19 @@ export const fetchRouteParams = () => {
}
}
/**
* * 通过硬解析获取当前路由下的参数
* @returns object
*/
export const fetchRouteParamsLocation = () => {
try {
return document.location.hash.split('/').pop() || ''
} catch (error) {
window['$message'].warning('查询路由信息失败,请联系管理员!')
return ''
}
}
/**
* * 回到主页面
* @param confirm
@@ -162,19 +185,29 @@ export const goHome = () => {
}
/**
* * 判断是否登录(现阶段是有 login 数据即可)
* * 判断是否登录
* @return boolean
*/
export const loginCheck = () => {
try {
const info = getLocalStorage(StorageEnum.GO_LOGIN_INFO_STORE)
const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
if (!info) return false
const decodeInfo = cryptoDecode(info)
if (decodeInfo) {
if (info[SystemStoreEnum.USER_INFO][SystemStoreUserInfoEnum.USER_TOKEN]) {
return true
}
return false
} catch (error) {
return false
}
}
}
/**
* * 预览地址
* @returns
*/
export const previewPath = () => {
const { origin, pathname } = document.location
const path = fetchPathByName(PreviewEnum.CHART_PREVIEW_NAME, 'href')
const previewPath = `${origin}${pathname}${path}/${fetchRouteParamsLocation()}`
return previewPath
}

View File

@@ -5,7 +5,7 @@
* @param v 键值无需stringiiy
* @returns RemovableRef
*/
export const setLocalStorage = <T>(k: string, v: T) => {
export const setLocalStorage = <T>(k: string, v: T) => {
try {
window.localStorage.setItem(k, JSON.stringify(v))
} catch (error) {
@@ -18,7 +18,7 @@
* @param k 键名
* @returns any
*/
export const getLocalStorage = (k: string) => {
export const getLocalStorage = (k: string) => {
const item = window.localStorage.getItem(k)
try {
return item ? JSON.parse(item) : item
@@ -31,7 +31,7 @@
* * 清除本地会话数据
* @param name
*/
export const clearLocalStorage = (name: string) => {
export const clearLocalStorage = (name: string) => {
window.localStorage.removeItem(name)
}
@@ -68,4 +68,42 @@ export const getSessionStorage: (k: string) => any = (k: string) => {
*/
export const clearSessioStorage = (name: string) => {
window.sessionStorage.removeItem(name)
}
/**
* * 设置 cookie
* @param name 键名
* @param cvalue 键值
* @param exdays 过期时间
*/
export const setCookie = (name: string, cvalue: string, exdays: number) => {
const d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
const expires = "expires=" + d.toUTCString();
document.cookie = name + "=" + cvalue + "; " + expires;
}
/**
* * 获取 cookie
* @param cname 键名
* @returns string
*/
export const getCookie = (cname: string) => {
const name = cname + "=";
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1);
if (c.indexOf(name) != -1) return c.substring(name.length, c.length);
}
return "";
}
/**
* * 清除 cookie
* @param name 键名
* @returns string
*/
export const clearCookie = (name: string) => {
setCookie(name, "", -1);
}

View File

@@ -111,29 +111,6 @@ export const isMac = () => {
return /macintosh|mac os x/i.test(navigator.userAgent)
}
/**
* * file转url
*/
export const fileToUrl = (file: File): string => {
const Url = URL || window.URL || window.webkitURL
const ImageUrl = Url.createObjectURL(file)
return ImageUrl
}
/**
* * file转base64
*/
export const fileTobase64 = (file: File, callback: Function) => {
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function (e: ProgressEvent<FileReader>) {
if (e.target) {
let base64 = e.target.result
callback(base64)
}
}
}
/**
* * 挂载监听
*/

View File

@@ -47,7 +47,7 @@
</template>
<script setup lang="ts">
import { ContentBox } from '../contentBox/index'
import { ContentBox } from '../ContentBox/index'
import { ChartsOptionContent } from './components/ChartsOptionContent'
import { ChartsSearch } from './components/ChartsSearch'
import {

View File

@@ -128,16 +128,20 @@ import { backgroundImageSize } from '@/settings/designSetting'
import { FileTypeEnum } from '@/enums/fileTypeEnum'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
import { StylesSetting } from '@/components/Pages/ChartItemSetting'
import { UploadCustomRequestOptions } from 'naive-ui'
import { fileToUrl, loadAsyncComponent } from '@/utils'
import { fileToUrl, loadAsyncComponent, fetchRouteParamsLocation } from '@/utils'
import { PreviewScaleEnum } from '@/enums/styleEnum'
import { ResultEnum } from '@/enums/httpEnum'
import { icon } from '@/plugins'
import { uploadFile} from '@/api/path'
const { ColorPaletteIcon } = icon.ionicons5
const { ZAxisIcon, ScaleIcon, FitToScreenIcon, FitToHeightIcon, FitToWidthIcon } = icon.carbon
const chartEditStore = useChartEditStore()
const systemStore = useSystemStore()
const canvasConfig = chartEditStore.getEditCanvasConfig
const editCanvas = chartEditStore.getEditCanvas
@@ -270,17 +274,34 @@ const switchSelectColorHandle = () => {
// 自定义上传操作
const customRequest = (options: UploadCustomRequestOptions) => {
const { file } = options
nextTick(() => {
nextTick(async () => {
if(!systemStore.getFetchInfo.OSSUrl) {
window['$message'].error('添加图片失败,请刷新页面重试!')
return
}
if (file.file) {
const ImageUrl = fileToUrl(file.file)
chartEditStore.setEditCanvasConfig(
EditCanvasConfigEnum.BACKGROUND_IAMGE,
ImageUrl
)
chartEditStore.setEditCanvasConfig(
EditCanvasConfigEnum.SELECT_COLOR,
false
// 修改名称
const newNameFile = new File(
[file.file],
`${fetchRouteParamsLocation()}_index_background.png`,
{ type: file.file.type }
)
let uploadParams = new FormData()
uploadParams.append('object', newNameFile)
const uploadRes = await uploadFile(systemStore.getFetchInfo.OSSUrl ,uploadParams) as unknown as MyResponseType
if(uploadRes.code === ResultEnum.SUCCESS) {
chartEditStore.setEditCanvasConfig(
EditCanvasConfigEnum.BACKGROUND_IAMGE,
uploadRes.data.objectContent.httpRequest.uri
)
chartEditStore.setEditCanvasConfig(
EditCanvasConfigEnum.SELECT_COLOR,
false
)
return
}
window['$message'].error('添加图片失败,请稍后重试!')
} else {
window['$message'].error('添加图片失败,请稍后重试!')
}

View File

@@ -73,8 +73,8 @@ const addAnimation = (item: { label: string; value: string }) => {
width: 100%;
}
.animation-item {
height: 50px;
line-height: 50px;
height: 40px;
line-height: 40px;
text-align: center;
cursor: pointer;
border-radius: 5px;

View File

@@ -20,16 +20,10 @@
<help-outline-icon></help-outline-icon>
</n-icon>
</template>
<ul>
<ul class="go-pl-0">
开发环境使用 mock 数据请输入
<li>
<n-text type="info"> 图表{{ chartDataUrl }} </n-text>
</li>
<li>
<n-text type="info"> 表格{{ rankListUrl }} </n-text>
</li>
<li>
<n-text type="info"> 0~1数字{{ numberUrl }} </n-text>
<li v-for="item in apiList" :key="item.value">
<n-text type="info"> {{item.value}} </n-text>
</li>
</ul>
</n-tooltip>
@@ -83,6 +77,18 @@ const { requestOriginUrl } = toRefs(chartEditStore.getRequestGlobalConfig)
const loading = ref(false)
const showMatching = ref(false)
const apiList = [
{
value: `【图表】${ chartDataUrl }`
},
{
value: `【表格】${ rankListUrl }`
},
{
value: `【0~1数字】${ numberUrl }`
}
]
// 选项
const selectOptions: SelectHttpType[] = [
{

View File

@@ -46,14 +46,24 @@
</n-button>
</n-space>
</n-upload>
<n-button class="sourceBtn-item" @click="download">
<template #icon>
<n-icon>
<document-download-icon />
</n-icon>
</template>
下载
</n-button>
<div>
<n-button class="sourceBtn-item" @click="download">
<template #icon>
<n-icon>
<document-download-icon />
</n-icon>
</template>
下载
</n-button>
<n-tooltip trigger="hover">
<template #trigger>
<n-icon class="go-ml-1" size="21" :depth="3">
<help-outline-icon></help-outline-icon>
</n-icon>
</template>
<n-text depth="3">点击下载查看完整数据</n-text>
</n-tooltip>
</div>
</n-space>
<n-card>
<n-code :code="getSource" language="json"></n-code>
@@ -83,7 +93,9 @@ const props = defineProps({
// 表格标题
const tableTitle = ['字段', '映射', '状态']
const { HelpOutlineIcon } = icon.ionicons5
const { DocumentAddIcon, DocumentDownloadIcon } = icon.carbon
const source = ref()
const dimensions = ref()
const dimensionsAndSource = ref()
@@ -140,7 +152,7 @@ watch(() => targetData.value?.option?.dataset, (newData: {
source: any,
dimensions: any
} | null) => {
if (isObject(newData)) {
if (newData && isObject(newData)) {
// 只有 Echarts 数据才有对应的格式
source.value = isCharts.value ? newData.source : newData
if (isCharts.value) {

View File

@@ -95,7 +95,7 @@ const {
LeafIcon
} = icon.ionicons5
const ContentEdit = loadAsyncComponent(() => import('../contentEdit/index.vue'))
const ContentEdit = loadAsyncComponent(() => import('../ContentEdit/index.vue'))
const CanvasPage = loadAsyncComponent(() =>
import('./components/CanvasPage/index.vue')
)

View File

@@ -94,7 +94,7 @@ const canvasPositionList = computed(() => {
// * 监听鼠标移动
watch(
() => chartEditStore.getMousePosition,
throttle(e => {
throttle(() => {
if (!isComputedLine.value) return
// 获取目标组件数据

View File

@@ -1,6 +1,10 @@
<template>
<div class="go-edit-bottom">
<edit-history></edit-history>
<div class="go-flex-items-center">
<edit-history></edit-history>
<n-divider vertical />
<edit-data-sync></edit-data-sync>
</div>
<n-space class="bottom-ri">
<!-- 快捷键提示 -->
@@ -55,7 +59,8 @@
import { reactive, ref, toRefs, watchEffect } from 'vue'
import { icon } from '@/plugins'
import { EditHistory } from '../EditHistory/index'
import EditShortcutKey from '../EditShortcutKey/index.vue'
import { EditShortcutKey } from '../EditShortcutKey/index'
import { EditDataSync } from '../EditDataSync/index'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
@@ -134,12 +139,15 @@ watchEffect(() => {
</script>
<style lang="scss" scoped>
$min-width: 500px;
@include go('edit-bottom') {
width: 100%;
padding: 0 10px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
width: 100%;
min-width: $min-width;
height: 40px;
.bottom-ri {
position: relative;
top: 15px;

View File

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

View File

@@ -0,0 +1,97 @@
<template>
<div class="go-edit-data-sync go-flex-items-center">
<n-tooltip trigger="hover">
<template #trigger>
<n-text class="status-desc go-ml-2" :type="descType" depth="3">
{{ statusDesc }}
</n-text>
</template>
<span>{{saveInterval}}s 更新一次</span>
</n-tooltip>
<n-spin
v-show="statusDesc === statusDescObj[1]['text']"
class="go-ml-2"
size="small"
>
<template #icon>
<n-icon size="13">
<reload-icon />
</n-icon>
</template>
</n-spin>
</div>
</template>
<script lang="ts" setup>
import { ref, toRefs, watch } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useDesignStore } from '@/store/modules/designStore/designStore'
import { SyncEnum } from '@/enums/editPageEnum'
import { icon } from '@/plugins'
import { saveInterval } from '@/settings/designSetting'
const { ReloadIcon } = icon.ionicons5
const chartEditStore = useChartEditStore()
const designStore = useDesignStore()
const { saveStatus } = toRefs(chartEditStore.getEditCanvas)
const themeColor = ref(designStore.getAppTheme)
const statusDesc = ref('')
const descType = ref('')
let setTimeoutIns: NodeJS.Timeout = setTimeout(() => {})
const statusDescObj = {
[SyncEnum.PENDING]: {
text: '等待自动同步',
type: '',
},
[SyncEnum.START]: {
text: '正在同步中',
type: 'success',
},
[SyncEnum.SUCCESS]: {
text: '同步成功!',
type: 'success',
},
[SyncEnum.FAILURE]: {
text: '同步失败!',
type: 'error',
},
}
watch(
() => saveStatus.value,
newData => {
clearTimeout(setTimeoutIns)
statusDesc.value = statusDescObj[newData]['text']
descType.value = statusDescObj[newData]['type']
// 3秒重置展示
setTimeoutIns = setTimeout(() => {
statusDesc.value = statusDescObj[SyncEnum.PENDING]['text']
descType.value = statusDescObj[SyncEnum.PENDING]['type']
}, 3000)
},
{
immediate: true,
}
)
</script>
<style lang="scss" scoped>
@include go('edit-data-sync') {
@include deep() {
.n-spin {
width: 13px;
height: 13px;
}
}
.status-desc {
cursor: default;
color: v-bind('themeColor');
font-size: 12px;
opacity: 0.8;
}
}
</style>

View File

@@ -10,7 +10,7 @@
>
<template #trigger>
<n-button
class="mr-10"
class="go-mr-1"
secondary
size="small"
:disabled="options.length === 0"
@@ -140,9 +140,6 @@ const handleClick = () => {
</script>
<style lang="scss" scoped>
.mr-10 {
margin-right: 10px;
}
.edit-history-popover {
.btn-text {
font-size: 12px;

View File

@@ -41,6 +41,11 @@ const lines = {
/* 使用 SCSS 会报错,直接使用最基础的 CSS 进行修改,
此库有计划 Vue3 版本,但是开发的时候还没发布 */
#mb-ruler {
top: 0;
left: 0;
}
/* 横线 */
#mb-ruler .v-container .lines .line {
/* 最大缩放 200% */
@@ -71,6 +76,7 @@ const lines = {
font-size: 26px;
font-weight: bolder;
}
#mb-ruler .corner{
border-width: 0!important;
}

View File

@@ -3,7 +3,7 @@
<slot></slot>
<!-- 锚点 -->
<div
class="shape-point"
:class="`shape-point ${point}`"
v-for="(point, index) in (select? pointList : [])"
:key="index"
:style="usePointStyle(point, index, item.attr, cursorResize)"
@@ -71,6 +71,26 @@ const select = computed(() => {
border-radius: 5px;
background-color: #fff;
transform: translate(-40%, -30%);
&.t,
&.b {
width: 30px;
transform: translate(-50%, -50%);
}
&.l,
&.r {
height: 30px;
}
&.r {
transform: translate(-20%, -50%);
}
&.l {
transform: translate(-45%, -50%);
}
&.rt,
&.rb
{
transform: translate(-30%, -30%);
}
}
/* 选中 */
.shape-modal {

View File

@@ -99,6 +99,11 @@ const shortcutKeyOptions = [
win: `${WinKeyboard.CTRL.toUpperCase()} + ${WinKeyboard.SHIFT.toUpperCase()} + Z `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + ${MacKeyboard.SHIFT.toUpperCase()} + Z `,
},
{
label: '保存',
win: `${WinKeyboard.CTRL.toUpperCase()} + S `,
mac: `${MacKeyboard.CTRL.toUpperCase()} + S `,
},
]
const closeHandle = () => {
emit('update:modelShow', false)

View File

@@ -1,2 +1,3 @@
import EditShortcutKey from './index.vue'
export { EditShortcutKey }

View File

@@ -1,61 +1,12 @@
import { ref, nextTick } from 'vue'
import { UploadCustomRequestOptions } from 'naive-ui'
import { FileTypeEnum } from '@/enums/fileTypeEnum'
import { fetchChartComponent } from '@/packages/index'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { ChartEditStoreEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { readFile, goDialog } from '@/utils'
import { createComponent } from '@/packages'
// 更新函数
const updateComponent = async (fileData: any, isSplace = false) => {
const chartEditStore = useChartEditStore()
const chartHistoryStore = useChartHistoryStore()
if (isSplace) {
// 清除列表
chartEditStore.componentList = []
// 清除历史记录
chartHistoryStore.clearBackStack()
chartHistoryStore.clearForwardStack()
}
// 列表组件注册
fileData.componentList.forEach(async (e: CreateComponentType) => {
if (!window['$vue'].component(e.chartConfig.chartKey)) {
window['$vue'].component(
e.chartConfig.chartKey,
fetchChartComponent(e.chartConfig)
)
}
})
// 数据赋值
for (const key in fileData) {
// 组件
if (key === ChartEditStoreEnum.COMPONENT_LIST) {
for (const comItem of fileData[key]) {
// 补充 class 上的方法
let newComponent: CreateComponentType = await createComponent(
comItem.chartConfig
)
// 不保存到记录
chartEditStore.addComponentList(
Object.assign(newComponent, comItem),
false,
true
)
}
} else {
// 非组件(顺便排除脏数据)
if(key !== 'editCanvasConfig' && key !== 'requestGlobalConfig') return
Object.assign((chartEditStore as any)[key], fileData[key])
}
}
}
import { useSync } from '@/views/chart/hooks/useSync.hook'
export const useFile = () => {
const importUploadFileListRef = ref()
const { updateComponent } = useSync()
// 上传-前置
//@ts-ignore
const importBeforeUpload = ({ file }) => {

View File

@@ -68,7 +68,7 @@
</template>
<script setup lang="ts">
import { ref, computed, h } from 'vue';
import { ref, computed } from 'vue';
import { useSettingStore } from '@/store/modules/settingStore/settingStore'
import { ToolsStatusEnum } from '@/store/modules/settingStore/settingStore.d'
import { exportHandle } from './utils'

View File

@@ -9,7 +9,7 @@ export const exportHandle = () => {
// 导出数据
downloadTextFile(
JSON.stringify(chartEditStore.getStorageInfo || [], (k, v) => {
JSON.stringify(chartEditStore.getStorageInfo || {}, (k, v) => {
return v === undefined ? null : v
}),
undefined,

View File

@@ -21,6 +21,8 @@ import { watermarkText } from '@/settings/designSetting'
<style lang="scss" scoped>
#go-edit-watermark {
display: none;
position: absolute;
top: 0;
width: 100%;
height: 100%;
}

View File

@@ -71,10 +71,11 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
import { useLayout } from './hooks/useLayout.hook'
import { useAddKeyboard } from '../hooks/useKeyboard.hook'
import { useSync } from '../hooks/useSync.hook'
import { dragHandle, dragoverHandle, useMouseHandle } from './hooks/useDrag.hook'
import { useComponentStyle, useSizeStyle } from './hooks/useStyle.hook'
import { ContentBox } from '../contentBox/index'
import { ContentBox } from '../ContentBox/index'
import { EditRange } from './components/EditRange'
import { EditBottom } from './components/EditBottom'
import { EditShapeBox } from './components/EditShapeBox'
@@ -82,6 +83,7 @@ import { EditTools } from './components/EditTools'
const chartEditStore = useChartEditStore()
const { handleContextMenu } = useContextMenu()
const { dataSyncFetch, intervalDataSyncUpdate } = useSync()
// 布局处理
useLayout()
@@ -121,9 +123,13 @@ const rangeStyle = computed(() => {
}
})
// 键盘事件
onMounted(() => {
// 键盘事件
useAddKeyboard()
// 获取数据
dataSyncFetch()
// 定时更新数据
intervalDataSyncUpdate()
})
</script>

View File

@@ -8,6 +8,7 @@
</template>
</n-button>
<n-space>
<!-- 模块展示按钮 -->
<n-tooltip v-for="item in btnList" :key="item.key" placement="bottom" trigger="hover">
<template #trigger>
<n-button size="small" ghost :type="styleHandle(item)" @click="clickHandle(item)">
@@ -19,6 +20,7 @@
<n-divider vertical />
<!-- 历史记录按钮 -->
<n-tooltip v-for="item in historyList" :key="item.key" placement="bottom" trigger="hover">
<template #trigger>
<n-button size="small" ghost type="primary" :disabled="!item.select" @click="clickHistoryHandle(item)">
@@ -128,7 +130,7 @@ const clickHistoryHandle = (item: ItemType<HistoryStackEnum>) => {
//
const goHomeHandle = () => {
goDialog({
message: '返回将不会保存任何操作',
message: '确定已保存了数据Ctrl / ⌘ + S并返回到首页吗',
isMaskClosable: true,
onPositiveCallback: () => {
goHome()

View File

@@ -0,0 +1,198 @@
<template>
<n-space>
<n-button
v-for="item in btnList"
:key="item.key"
:type="item.type()"
ghost
@click="item.event"
>
<template #icon>
<component :is="item.icon"></component>
</template>
<span>{{ item.title() }}</span>
</n-button>
</n-space>
<!-- 发布管理弹窗 -->
<n-modal v-model:show="modelShow" @afterLeave="closeHandle">
<n-list bordered class="go-system-setting">
<template #header>
<n-space justify="space-between">
<n-h3 class="go-mb-0">发布管理</n-h3>
<n-icon size="20" class="go-cursor-pointer" @click="closeHandle">
<close-icon></close-icon>
</n-icon>
</n-space>
</template>
<n-list-item>
<n-space :size="10">
<n-alert :show-icon="false" title="预览地址:" type="success">
{{ previewPath() }}
</n-alert>
<n-button tertiary type="primary" @click="copyPreviewPath()">
复制地址
</n-button>
</n-space>
</n-list-item>
<n-list-item>
<n-space :size="10">
<n-button @click="modelShowHandle">取消</n-button>
<n-button type="primary" @click="sendHandle">
{{ release ? '取消发布' : '发布' }}
</n-button>
</n-space>
</n-list-item>
</n-list>
</n-modal>
</template>
<script setup lang="ts">
import { ref, shallowReactive, watchEffect } from 'vue'
import { useRoute } from 'vue-router'
import { useClipboard } from '@vueuse/core'
import { PreviewEnum } from '@/enums/pageEnum'
import { StorageEnum } from '@/enums/storageEnum'
import { ResultEnum } from '@/enums/httpEnum'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { ProjectInfoEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { updateProjectApi } from '@/api/path'
import {
previewPath,
renderIcon,
fetchPathByName,
routerTurnByPath,
setSessionStorage,
getLocalStorage,
httpErrorHandle,
fetchRouteParamsLocation,
} from '@/utils'
import { icon } from '@/plugins'
const { BrowsersOutlineIcon, SendIcon, CloseIcon } = icon.ionicons5
const chartEditStore = useChartEditStore()
const previewPathRef = ref(previewPath())
const { copy, isSupported } = useClipboard({ source: previewPathRef })
const routerParamsInfo = useRoute()
const modelShow = ref<boolean>(false)
const release = ref<boolean>(false)
watchEffect(() => {
release.value = chartEditStore.getProjectInfo.release || false
})
// 关闭弹窗
const closeHandle = () => {
modelShow.value = false
}
// 预览
const previewHandle = () => {
const path = fetchPathByName(PreviewEnum.CHART_PREVIEW_NAME, 'href')
if (!path) return
const { id } = routerParamsInfo.params
// id 标识
const previewId = typeof id === 'string' ? id : id[0]
const storageInfo = chartEditStore.getStorageInfo
const sessionStorageInfo =
getLocalStorage(StorageEnum.GO_CHART_STORAGE_LIST) || []
if (sessionStorageInfo?.length) {
const repeateIndex = sessionStorageInfo.findIndex(
(e: { id: string }) => e.id === previewId
)
// 重复替换
if (repeateIndex !== -1) {
sessionStorageInfo.splice(repeateIndex, 1, {
id: previewId,
...storageInfo,
})
setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, sessionStorageInfo)
} else {
sessionStorageInfo.push({
id: previewId,
...storageInfo,
})
setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, sessionStorageInfo)
}
} else {
setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, [
{ id: previewId, ...storageInfo },
])
}
// 跳转
routerTurnByPath(path, [previewId], undefined, true)
}
// 模态弹窗
const modelShowHandle = () => {
modelShow.value = !modelShow.value
}
// 复制预览地址
const copyPreviewPath = (successText?: string, failureText?: string) => {
if(isSupported) {
copy()
window['$message'].success(successText || '复制成功!')
} else {
window['$message'].success(failureText || '复制失败!')
}
}
// 发布
const sendHandle = async () => {
const res = (await updateProjectApi({
id: fetchRouteParamsLocation(),
// 反过来
state: release.value ? -1 : 1,
})) as unknown as MyResponseType
if (res.code === ResultEnum.SUCCESS) {
modelShowHandle()
if (!release.value) {
copyPreviewPath('发布成功!已复制地址到剪贴板~', '发布成功!')
} else {
window['$message'].success(`已取消发布`)
}
chartEditStore.setProjectInfo(ProjectInfoEnum.RELEASE, !release.value)
} else {
httpErrorHandle()
}
}
const btnList = shallowReactive([
{
key: 'preview',
title: () => '预览',
type: () => 'default',
icon: renderIcon(BrowsersOutlineIcon),
event: previewHandle,
},
{
key: 'release',
title: () => (release.value ? '已发布' : '发布'),
icon: renderIcon(SendIcon),
type: () => (release.value ? 'primary' : 'default'),
event: modelShowHandle,
},
])
</script>
<style lang="scss" scoped>
@include go('system-setting') {
@extend .go-background-filter;
min-width: 100px;
max-width: 60vw;
padding-bottom: 20px;
@include deep() {
.n-list-item:not(:last-child) {
border-bottom: 0;
}
}
}
</style>

View File

@@ -0,0 +1,81 @@
<template>
<n-space>
<n-icon size="20" :depth="3">
<fish-icon></fish-icon>
</n-icon>
<n-text @click="handleFocus">
工作空间 -
<n-button v-show="!focus" secondary round size="tiny">
<span class="title">{{ comTitle }}</span>
</n-button>
</n-text>
<n-input
v-show="focus"
ref="inputInstRef"
size="small"
type="text"
maxlength="16"
show-count
round
placeholder="请输入项目名称"
v-model:value.trim="title"
@blur="handleBlur"
></n-input>
</n-space>
</template>
<script setup lang="ts">
import { ref, nextTick, computed, watchEffect } from 'vue'
import { ResultEnum } from '@/enums/httpEnum'
import { fetchRouteParamsLocation, httpErrorHandle } from '@/utils'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { ProjectInfoEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { updateProjectApi } from '@/api/path'
import { useSync } from '../../hooks/useSync.hook'
import { icon } from '@/plugins'
const chartEditStore = useChartEditStore()
const { dataSyncUpdate } = useSync()
const { FishIcon } = icon.ionicons5
const focus = ref<boolean>(false)
const inputInstRef = ref(null)
const title = ref<string>(fetchRouteParamsLocation())
watchEffect(() => {
title.value = chartEditStore.getProjectInfo.projectName || ''
})
const comTitle = computed(() => {
title.value = title.value && title.value.replace(/\s/g, "")
return title.value.length ? title.value : fetchRouteParamsLocation()
})
const handleFocus = () => {
focus.value = true
nextTick(() => {
; (<any>inputInstRef).value.focus()
})
}
const handleBlur = async () => {
focus.value = false
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_NAME, title.value || '')
const res = await updateProjectApi({
id: fetchRouteParamsLocation(),
projectName: title.value,
}) as unknown as MyResponseType
if(res.code === ResultEnum.SUCCESS) {
dataSyncUpdate()
} else {
httpErrorHandle()
}
}
</script>
<style lang="scss" scoped>
.title {
font-size: 15px;
}
</style>

View File

@@ -41,7 +41,7 @@ import { computed, toRaw } from 'vue'
import Draggable from 'vuedraggable'
import cloneDeep from 'lodash/cloneDeep'
import { ContentBox } from '../contentBox/index'
import { ContentBox } from '../ContentBox/index'
import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'

View File

@@ -1,81 +0,0 @@
<template>
<n-space class="go-mt-0">
<n-button v-for="item in btnList" :key="item.title" ghost @click="item.event">
<template #icon>
<component :is="item.icon"></component>
</template>
<span>{{ item.title }}</span>
</n-button>
</n-space>
</template>
<script setup lang="ts">
import { shallowReactive } from 'vue'
import { renderIcon, fetchPathByName, routerTurnByPath, setSessionStorage, getLocalStorage } from '@/utils'
import { PreviewEnum } from '@/enums/pageEnum'
import { StorageEnum } from '@/enums/storageEnum'
import { useRoute } from 'vue-router'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { icon } from '@/plugins'
const { BrowsersOutlineIcon, SendIcon } = icon.ionicons5
const chartEditStore = useChartEditStore()
const routerParamsInfo = useRoute()
// 预览
const previewHandle = () => {
const path = fetchPathByName(PreviewEnum.CHART_PREVIEW_NAME, 'href')
if (!path) return
const { id } = routerParamsInfo.params
// id 标识
const previewId = typeof id === 'string' ? id : id[0]
const storageInfo = chartEditStore.getStorageInfo
const sessionStorageInfo = getLocalStorage(StorageEnum.GO_CHART_STORAGE_LIST) || []
if (sessionStorageInfo?.length) {
const repeateIndex = sessionStorageInfo.findIndex((e: { id: string }) => e.id === previewId)
// 重复替换
if (repeateIndex !== -1) {
sessionStorageInfo.splice(repeateIndex, 1, { id: previewId, ...storageInfo })
setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, sessionStorageInfo)
} else {
sessionStorageInfo.push({
id: previewId, ...storageInfo
})
setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, sessionStorageInfo)
}
} else {
setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, [{ id: previewId, ...storageInfo }])
}
// 跳转
routerTurnByPath(path, [previewId], undefined, true)
}
// 发布
const sendHandle = () => {
window['$message'].warning('该功能暂未实现(因为压根没有后台)')
}
const btnList = shallowReactive([
{
select: true,
title: '预览',
icon: renderIcon(BrowsersOutlineIcon),
event: previewHandle
},
{
select: true,
title: '发布',
icon: renderIcon(SendIcon),
event: sendHandle
}
])
</script>
<style lang="scss" scoped>
.align-center {
margin-top: -4px;
}
</style>

View File

@@ -1,65 +0,0 @@
<template>
<n-space>
<n-icon size="20" :depth="3">
<fish-icon></fish-icon>
</n-icon>
<n-text @click="handleFocus">
工作空间 -
<n-button v-show="!focus" secondary round size="tiny">{{ comTitle }}</n-button>
</n-text>
<n-input
v-show="focus"
ref="inputInstRef"
size="small"
type="text"
maxlength="16"
show-count
round
placeholder="请输入项目名称"
v-model:value.trim="title"
@blur="handleBlur"
></n-input>
</n-space>
</template>
<script setup lang="ts">
import { ref, nextTick, computed } from 'vue'
import { fetchRouteParams } from '@/utils'
import { icon } from '@/plugins'
const { FishIcon } = icon.ionicons5
const focus = ref<boolean>(false)
const inputInstRef = ref(null)
// 根据路由 id 参数获取项目信息
const fetchProhectInfoById = () => {
const routeParamsRes = fetchRouteParams()
if (!routeParamsRes) return
const { id } = routeParamsRes
if (id.length) {
return id[0]
}
return ''
}
const title = ref<string>(fetchProhectInfoById() || '')
const comTitle = computed(() => {
title.value = title.value.replace(/\s/g, "");
return title.value.length ? title.value : '新项目'
})
const handleFocus = () => {
focus.value = true
nextTick(() => {
; (<any>inputInstRef).value.focus()
})
}
const handleBlur = () => {
focus.value = false
}
</script>

View File

@@ -1,4 +1,5 @@
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useSync } from './useSync.hook'
import { WinKeyboard, MacKeyboard, MenuEnum } from '@/enums/editPageEnum'
import throttle from 'lodash/throttle'
import debounce from 'lodash/debounce'
@@ -6,7 +7,7 @@ import debounce from 'lodash/debounce'
import keymaster from 'keymaster'
// Keymaster可以支持识别以下组合键shiftoptionaltctrlcontrolcommand和⌘
const chartEditStore = useChartEditStore()
const useSyncIns = useSync()
const winCtrlMerge = (e: string) => `${WinKeyboard.CTRL}+${e}`
const winShiftMerge = (e: string) => `${WinKeyboard.SHIFT}+${e}`
const winAltMerge = (e: string) => `${WinKeyboard.ALT}+${e}`
@@ -22,6 +23,7 @@ export const winKeyboardValue = {
[MenuEnum.DELETE]: 'delete',
[MenuEnum.BACK]: winCtrlMerge('z'),
[MenuEnum.FORWORD]: winCtrlMerge(winShiftMerge('z')),
[MenuEnum.SAVE]: winCtrlMerge('s'),
}
// 这个 Ctrl 后面还是换成了 ⌘
@@ -41,6 +43,7 @@ export const macKeyboardValue = {
[MenuEnum.DELETE]: macCtrlMerge('backspace'),
[MenuEnum.BACK]: macCtrlMerge('z'),
[MenuEnum.FORWORD]: macCtrlMerge(macShiftMerge('z')),
[MenuEnum.SAVE]: macCtrlMerge('s'),
}
// Win 快捷键列表
@@ -57,6 +60,8 @@ const winKeyList: Array<string> = [
winKeyboardValue.back,
winKeyboardValue.forward,
winKeyboardValue.save,
]
// Mac 快捷键列表
@@ -73,6 +78,8 @@ const macKeyList: Array<string> = [
macKeyboardValue.back,
macKeyboardValue.forward,
macKeyboardValue.save,
]
// 初始化监听事件
@@ -121,6 +128,11 @@ export const useAddKeyboard = () => {
case keyboardValue.forward:
keymaster(e, throttle(() => { chartEditStore.setForward(); return false }, 200))
break;
// 保存 ct+s
case keyboardValue.save:
keymaster(e, throttle(() => { useSyncIns.dataSyncUpdate(); return false }, 200))
break;
}
}
winKeyList.forEach((key: string) => {

View File

@@ -0,0 +1,187 @@
import { onUnmounted } from 'vue';
import html2canvas from 'html2canvas'
import { getUUID, httpErrorHandle, fetchRouteParamsLocation, base64toFile } from '@/utils'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { EditCanvasTypeEnum, ChartEditStoreEnum, ProjectInfoEnum, ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
import { fetchChartComponent, fetchConfigComponent, createComponent } from '@/packages/index'
import { CreateComponentType } from '@/packages/index.d'
import { saveInterval } from '@/settings/designSetting'
// 接口状态
import { ResultEnum } from '@/enums/httpEnum'
// 接口
import { saveProjectApi, fetchProjectApi, uploadFile, updateProjectApi } from '@/api/path'
// 画布枚举
import { SyncEnum } from '@/enums/editPageEnum'
// 请求处理
export const useSync = () => {
const chartEditStore = useChartEditStore()
const chartHistoryStore = useChartHistoryStore()
const systemStore = useSystemStore()
/**
* * 组件动态注册
* @param projectData 项目数据
* @param isSplace 是否替换数据
* @returns
*/
const updateComponent = async (projectData: ChartEditStorage, isSplace = false) => {
if (isSplace) {
// 清除列表
chartEditStore.componentList = []
// 清除历史记录
chartHistoryStore.clearBackStack()
chartHistoryStore.clearForwardStack()
}
// 列表组件注册
projectData.componentList.forEach(async (e: CreateComponentType) => {
if (!window['$vue'].component(e.chartConfig.chartKey)) {
window['$vue'].component(
e.chartConfig.chartKey,
fetchChartComponent(e.chartConfig)
)
window['$vue'].component(
e.chartConfig.conKey,
fetchConfigComponent(e.chartConfig)
)
}
})
// 数据赋值
for (const key in projectData) {
// 组件
if (key === ChartEditStoreEnum.COMPONENT_LIST) {
for (const comItem of projectData[key]) {
// 补充 class 上的方法
let newComponent: CreateComponentType = await createComponent(
comItem.chartConfig
)
chartEditStore.addComponentList(
Object.assign(newComponent, {...comItem, id: getUUID()}),
false,
true
)
}
} else {
// 非组件(顺便排除脏数据)
if (key !== 'editCanvasConfig' && key !== 'requestGlobalConfig') return
Object.assign((chartEditStore as any)[key], projectData[key])
}
}
}
/**
* * 赋值全局数据
* @param projectData 项目数据
* @returns
*/
const updateStoreInfo = (projectData: {
id: string,
projectName: string,
indexImage: string,
remarks: string,
state: number
}) => {
const { projectName, remarks, indexImage, state } = projectData
// 名称
chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_NAME, projectName)
// 描述
chartEditStore.setProjectInfo(ProjectInfoEnum.REMARKS, remarks)
// 缩略图
chartEditStore.setProjectInfo(ProjectInfoEnum.THUMBNAIL, indexImage)
// 发布
chartEditStore.setProjectInfo(ProjectInfoEnum.RELEASE, state === 1)
}
// * 数据获取
const dataSyncFetch = async () => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.START)
try {
const res = await fetchProjectApi({ projectId: fetchRouteParamsLocation() }) as unknown as MyResponseType
if (res.code === ResultEnum.SUCCESS) {
if (res.data) {
updateStoreInfo(res.data)
// 更新全局数据
await updateComponent(JSON.parse(res.data.content))
return
}
setTimeout(() => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.SUCCESS)
}, 1000)
return
}
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
} catch (error) {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
httpErrorHandle()
}
}
// * 数据保存
const dataSyncUpdate = async () => {
if(!fetchRouteParamsLocation()) return
if(!systemStore.getFetchInfo.OSSUrl) {
window['$message'].error('数据保存失败,请刷新页面重试!')
return
}
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.START)
// 获取缩略图片
const range = document.querySelector('.go-edit-range') as HTMLElement
const ruler = document.getElementById('mb-ruler')
// 生成图片
const canvasImage: HTMLCanvasElement = await html2canvas(range)
// 上传预览图
let uploadParams = new FormData()
uploadParams.append('object', base64toFile(canvasImage.toDataURL(), `${fetchRouteParamsLocation()}_index_preview.png`))
const uploadRes = await uploadFile(systemStore.getFetchInfo.OSSUrl, uploadParams) as unknown as MyResponseType
// 保存预览图
if(uploadRes.code === ResultEnum.SUCCESS) {
await updateProjectApi({
id: fetchRouteParamsLocation(),
indexImage: uploadRes.data.objectContent.httpRequest.uri
})
}
// 保存数据
let params = new FormData()
params.append('projectId', fetchRouteParamsLocation())
params.append('content', JSON.stringify(chartEditStore.getStorageInfo || {}))
const res= await saveProjectApi(params) as unknown as MyResponseType
if (res.code === ResultEnum.SUCCESS) {
// 成功状态
setTimeout(() => {
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.SUCCESS)
}, 1000)
return
}
// 失败状态
chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
}
// * 定时处理
const intervalDataSyncUpdate = () => {
// 定时获取数据
const syncTiming = setInterval(() => {
dataSyncUpdate()
}, saveInterval * 1000)
// 销毁
onUnmounted(() => {
clearInterval(syncTiming)
})
}
return {
updateComponent,
updateStoreInfo,
dataSyncFetch,
dataSyncUpdate,
intervalDataSyncUpdate
}
}

View File

@@ -50,9 +50,9 @@ chartHistoryStoreStore.canvasInit(chartEditStore.getEditCanvas)
const HeaderLeftBtn = loadAsyncComponent(() => import('./ContentHeader/headerLeftBtn/index.vue'))
const HeaderRightBtn = loadAsyncComponent(() => import('./ContentHeader/headerRightBtn/index.vue'))
const HeaderTitle = loadAsyncComponent(() => import('./ContentHeader/headerTitle/index.vue'))
const ContentLayers = loadAsyncComponent(() => import('./contentLayers/index.vue'))
const ContentCharts = loadAsyncComponent(() => import('./contentCharts/index.vue'))
const ContentConfigurations = loadAsyncComponent(() => import('./contentConfigurations/index.vue'))
const ContentLayers = loadAsyncComponent(() => import('./ContentLayers/index.vue'))
const ContentCharts = loadAsyncComponent(() => import('./ContentCharts/index.vue'))
const ContentConfigurations = loadAsyncComponent(() => import('./ContentConfigurations/index.vue'))
// 右键
const {

Some files were not shown because too many files have changed in this diff Show More