Compare commits

..

148 Commits

Author SHA1 Message Date
奔跑的面条
fa84ee778c !88 feat-unify-test 试验后端工厂和事件机制
Merge pull request !88 from Kenjjj201377/feat-unify-test
2022-10-25 02:23:17 +00:00
金建
0eb75fbba4 fix: 整理文档 2022-10-25 00:05:52 +08:00
金建
6858f5bd39 fix: 保存进程移除 2022-10-24 23:37:41 +08:00
jinjian
b9f6ed95ab feat: 代码整合 2022-10-24 17:21:58 +08:00
奔跑的面条
8039213380 build: 修改版本号为2.1.0 2022-10-15 17:28:23 +08:00
奔跑的面条
c5a704767d fix: 修改版本号到2.0.10 2022-10-15 17:22:06 +08:00
奔跑的面条
20be7f2e45 Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch-dev 2022-10-15 17:20:05 +08:00
奔跑的面条
d43823794d fix: 修复导入组件数据会错乱的问题 2022-10-09 16:39:10 +08:00
奔跑的面条
5e09105a70 Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch-dev 2022-10-09 09:29:40 +08:00
奔跑的面条
7d2a98ab85 build: 修改正确版本到 2.0.8 2022-10-08 21:27:21 +08:00
奔跑的面条
2d302bb468 build: 升级版本到 2.0.9 2022-10-08 21:09:47 +08:00
奔跑的面条
789328b02e Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch-dev 2022-10-08 21:06:06 +08:00
奔跑的面条
b93a2a516a feat: 合并1.1.1 2022-10-08 21:04:41 +08:00
奔跑的面条
c8662537ca feat: 合并1.1.1,升级版本到2.0.8 2022-09-27 20:28:47 +08:00
奔跑的面条
b083bd9724 style: 去除无用代码,设置默认值 2022-09-27 19:53:55 +08:00
奔跑的面条
5fd6870cfe perf: 优化用户体验,完成接口配置后调用保存接口 2022-09-27 10:33:30 +08:00
奔跑的面条
9004a55b8c Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch-dev 2022-09-22 14:15:18 +08:00
奔跑的面条
c349e6384e Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch-dev 2022-09-21 19:56:56 +08:00
奔跑的面条
4e298efaa0 Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch-dev 2022-09-19 20:46:53 +08:00
奔跑的面条
c7cbb9b72a Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch-dev 2022-09-19 20:14:40 +08:00
奔跑的面条
bd5e06350d perf: 优化滤镜模糊问题,默认不开启 2022-09-19 17:51:12 +08:00
奔跑的面条
c311dd08e3 fix: 修改请求接口 token 名称 2022-09-18 17:45:59 +08:00
奔跑的面条
504a1f4703 build: 升级版本到2.0.7 2022-09-18 17:23:16 +08:00
奔跑的面条
a67cc9f876 !47 修复在编辑项目之前加载数据异常,自动保存导致项目数据清空问题。
Merge pull request !47 from 秋名山路霸/master-fetch
2022-09-18 07:53:47 +00:00
秋名山路霸
e0d2e8031d fix: 修复在编辑项目之前加载数据异常,自动保存导致项目数据清空问题。 2022-09-18 11:56:26 +08:00
奔跑的面条
bcec26374f build: 升级依赖,锁定TS 版本 2022-09-12 01:20:27 +08:00
奔跑的面条
a5981a4387 feat: 升级版本到 2.0.6 2022-09-12 00:49:22 +08:00
奔跑的面条
0d26dce512 fix: 合并1.0.9 2022-09-12 00:31:52 +08:00
奔跑的面条
6359ec15b3 feat: 新增移动撤回 2022-08-30 19:14:52 +08:00
奔跑的面条
32ca138e6a build: 升级版本到 2.0.5 2022-08-30 15:04:29 +08:00
奔跑的面条
171e0aa408 perf: 完善首页预览功能 2022-08-30 15:03:25 +08:00
奔跑的面条
52009a415b Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-08-30 12:19:57 +08:00
奔跑的面条
da809f13b3 fix: 尝试解决背景图片无法截图的问题 2022-08-29 21:35:51 +08:00
奔跑的面条
801aa1f82f update LICENSE.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2022-08-29 10:13:37 +00:00
奔跑的面条
72c26b71f3 perf: 优化参考线的展示方式 2022-08-21 14:52:30 +08:00
奔跑的面条
3b8181ae10 Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-08-21 14:49:32 +08:00
奔跑的面条
c2a9642393 Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-08-19 14:46:49 +08:00
奔跑的面条
3c04f81147 fix: 补充代码合并丢失的枚举 2022-08-19 11:43:23 +08:00
奔跑的面条
ec28ccf09c perf: 优化500错误页重定向 2022-08-19 11:34:38 +08:00
奔跑的面条
fa34300401 feat: 合并多选功能,解决冲突,升级版本到2.0.4 2022-08-19 10:44:44 +08:00
奔跑的面条
f506ccd2e4 Merge branch 'dev' into master-fetch 2022-08-05 08:42:22 +08:00
奔跑的面条
f379f7652c Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-07-26 16:12:31 +08:00
奔跑的面条
e8760c81ac Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-07-21 11:46:54 +08:00
奔跑的面条
a9bb294f60 feat: 合并 1.0.6 版本代码 2022-07-21 11:03:04 +08:00
奔跑的面条
0b5f35752b Merge branch 'dev' into master-fetch 2022-07-08 18:12:33 +08:00
奔跑的面条
7322817cb5 fix: 合并编辑功能的修改 2022-07-07 19:54:53 +08:00
奔跑的面条
437ad1bd9f Merge branch 'dev' into master-fetch 2022-07-07 13:14:53 +08:00
奔跑的面条
cd20e68480 fix: 补充合并代码丢失的icon图标 2022-07-06 22:12:24 +08:00
奔跑的面条
35968475b9 build: 合并dev 1.0.5 版本, 修改fetch分支为2.0.2 2022-07-06 21:58:28 +08:00
奔跑的面条
78eb3ccc3f Merge branch 'dev' into master-fetch 2022-06-27 21:42:24 +08:00
奔跑的面条
7cccbabca4 Merge branch 'dev' into master-fetch 2022-06-27 21:38:27 +08:00
奔跑的面条
cdccfa3e12 fix: 修改合并冲突错误的代码 2022-06-27 20:42:17 +08:00
奔跑的面条
e8c5455748 perf: 合并dev分支,解决组件无法更新数据的问题 2022-06-27 20:37:26 +08:00
奔跑的面条
8e40416e72 style: 去除多余代码 2022-06-24 11:44:26 +08:00
奔跑的面条
d058361e01 docs: 修改文档 2022-06-23 09:53:01 +08:00
奔跑的面条
2491f7ff57 feat: 新增保存按钮 2022-06-22 18:50:15 +08:00
奔跑的面条
c5908f6d92 build: 升级依赖 2022-06-20 15:13:50 +08:00
奔跑的面条
7e64d30258 build: 合并dev分支 2022-06-20 15:11:13 +08:00
奔跑的面条
437818abce feat: 新增排名列表字体大小控制功能 2022-06-17 14:13:14 +08:00
奔跑的面条
5197eb9292 build: 修改版本到 2.0.1 2022-06-16 10:48:42 +08:00
奔跑的面条
3cf01f0c51 fix: 解决打包之后无法加载页面的问题 2022-06-15 17:54:49 +08:00
奔跑的面条
db815661e8 feat: 新增 preview 模式,修改打包后路径指向 2022-06-15 17:48:16 +08:00
奔跑的面条
6edbb7c8a7 feat: 新增commitlint 2022-06-15 17:18:39 +08:00
奔跑的面条
799c445c4b docs: 更新文档 2022-06-15 17:15:29 +08:00
奔跑的面条
70fbf5de3e doc: 文档更新 2022-06-15 17:14:27 +08:00
奔跑的面条
73c7697443 feat: 新增渐变文本组件 2022-06-15 16:20:25 +08:00
奔跑的面条
8092edab81 build:升级依赖 2022-06-15 16:11:58 +08:00
奔跑的面条
ef4f45ddb0 fix: 解决npm,yarn 安装依赖报错的问题 2022-06-15 16:08:59 +08:00
奔跑的面条
3e969e4ae5 fix: 补充丢失的图片 2022-06-14 12:46:07 +08:00
奔跑的面条
bcd1dfd7bd feat:新增数字滚动组件动态获取数据功能 2022-06-14 12:31:46 +08:00
奔跑的面条
c1dfd78d18 feat: 新增表格滚动组件 2022-06-14 12:31:20 +08:00
奔跑的面条
39aa1645c9 fix:解决边框04展示不全的bug 2022-06-14 12:30:29 +08:00
奔跑的面条
d3afea8c5e feat:新增水球图设置项 2022-06-13 17:29:39 +08:00
奔跑的面条
2499cbdd44 fix: 修改列表页展示问题 2022-06-13 14:28:58 +08:00
奔跑的面条
3cc3714e94 feat: 新增环形图,新增NaiveUI-进度组件 2022-06-13 13:18:30 +08:00
奔跑的面条
be0aa6d099 feat: 新增进度条组件 2022-06-12 18:47:47 +08:00
奔跑的面条
34d27c1004 fix: 解决缩放比例展示不全的问题 2022-06-12 18:45:31 +08:00
奔跑的面条
85f3b4e9e3 chore: 优化拖拽锚点 2022-06-11 15:15:38 +08:00
奔跑的面条
0fb9a79df9 fix:修改请求地址为null时引起的异常bug 2022-06-11 14:37:22 +08:00
奔跑的面条
6b805fbdfb chore: 优化发布弹窗 2022-06-11 14:23:16 +08:00
奔跑的面条
abe76aeb59 build: 依赖基本升级 2022-06-11 14:15:28 +08:00
奔跑的面条
5f49bc1aa8 fix: 修改双折线图X轴无法变更的问题 2022-06-11 14:13:32 +08:00
奔跑的面条
71807be01d fix: 解决项目列表信息栏会换行的问题 2022-06-09 08:49:07 +08:00
奔跑的面条
e74f796203 fix:解决截图有白边的问题 2022-06-09 08:48:28 +08:00
奔跑的面条
041d7da9d8 fix: 修改复制失败的提示类型错误的问题 2022-06-06 10:43:14 +08:00
奔跑的面条
a99d949b29 chore: 新增路由白名单 2022-06-06 10:42:55 +08:00
奔跑的面条
c2a9e2a469 chore:优化搜索结果列表UI 2022-06-05 11:41:57 +08:00
奔跑的面条
80b05db764 chore:优化 dialog 的全局封装代码 2022-06-04 16:25:37 +08:00
奔跑的面条
340cab11b7 build:修改 fetch 版本号 2022-06-04 15:44:26 +08:00
奔跑的面条
712233c215 chore: 优化页面 UI 2022-06-03 20:21:35 +08:00
奔跑的面条
b9b915e913 fix: 修改自动复制粘贴的问题 2022-06-03 18:53:37 +08:00
奔跑的面条
044143571f fix: 新增发布页面处理 2022-06-03 14:48:58 +08:00
奔跑的面条
06fe805736 chore: 优化了标题展示和大小样式 2022-06-03 11:19:29 +08:00
奔跑的面条
077881e499 type: 修改类型错误 2022-06-01 23:00:28 +08:00
奔跑的面条
f655a57e61 fix:处理列表页标题过长的展示问题 2022-06-01 22:58:22 +08:00
奔跑的面条
0b04bf4929 type: 定义全局返回值类型 2022-06-01 22:41:11 +08:00
奔跑的面条
2fcd3b1132 build: 修改版本号 0.0.9 2022-06-01 22:28:46 +08:00
奔跑的面条
568fd6c105 chore:优化了路由写法,修改了错误页面的展示,新增未发布提示页面 2022-06-01 22:20:05 +08:00
奔跑的面条
221351ec11 feat: 新增动态预览功能 2022-06-01 22:19:03 +08:00
奔跑的面条
6ab34a0996 fix: 修改组件注册会报错的问题 2022-06-01 22:14:33 +08:00
奔跑的面条
6b551ae68b build:升级依赖包 2022-06-01 22:13:49 +08:00
奔跑的面条
2917cde2e5 fix: 解决列表图片展示缓存问题 2022-06-01 20:16:38 +08:00
奔跑的面条
294a4a6cdf fix: 解决获取数据,但是配置模块不完整的问题 2022-06-01 19:01:05 +08:00
奔跑的面条
1e678b7492 build: 修改请求地址 2022-05-31 11:19:17 +08:00
奔跑的面条
2ceca7287f fix: 修改oss接口不会动态更改的问题 2022-05-31 11:18:34 +08:00
奔跑的面条
7f4dd5295b chore:修改请求地址 2022-05-29 16:04:07 +08:00
奔跑的面条
ffd628fa82 docs: 修改文档说明 2022-05-29 15:23:04 +08:00
奔跑的面条
d639e445eb feat: 新增背景图文件上传保存 2022-05-29 14:54:35 +08:00
奔跑的面条
b263681dda chore: 去除生成预览图时的标尺 2022-05-28 17:58:07 +08:00
奔跑的面条
e16413b570 feat: 新增首页预览图展示 2022-05-28 16:39:27 +08:00
奔跑的面条
63b5186c3e Merge branch 'dev' into master-fetch 2022-05-28 15:58:06 +08:00
奔跑的面条
ba20316761 fix: 修改自动保存预览图无法存储的问题 2022-05-28 15:46:07 +08:00
奔跑的面条
437dd1c411 branch: 合并锚点样式修改 2022-05-28 12:46:32 +08:00
奔跑的面条
d0d5f5b77d feat: 保存预览图 2022-05-28 11:50:17 +08:00
奔跑的面条
efd9228cc9 fix: 解决打包后无法发送请求的bug 2022-05-28 00:32:32 +08:00
奔跑的面条
ebd6132385 feat: 新增上传文件接口 2022-05-27 20:09:48 +08:00
奔跑的面条
9098443c83 chore: 修改项目信息结构 2022-05-27 11:49:25 +08:00
奔跑的面条
423890a4df feat: 新增项目信息修改功能 2022-05-26 01:01:59 +08:00
奔跑的面条
fb2edeb7d2 fix: 修改导入组件id会重复的问题 2022-05-25 23:00:36 +08:00
奔跑的面条
b861587f01 feat: 新增快捷键展示 2022-05-24 18:17:41 +08:00
奔跑的面条
c3738fab45 faet: 新增保存快捷键 2022-05-24 18:16:33 +08:00
奔跑的面条
24fba75f28 feat: 新增自动同步功能 2022-05-24 17:42:49 +08:00
奔跑的面条
00b6b63e1e feat: 新增数据保存接口 2022-05-24 15:05:51 +08:00
奔跑的面条
5dab8fa7d9 Merge branch 'dev' into master-fetch 2022-05-24 12:28:14 +08:00
奔跑的面条
9a5d71fb5c feat: 新增获取项目数据功能,新增同步数据功能 2022-05-23 23:50:35 +08:00
奔跑的面条
c930efba0c Merge branch 'dev' into master-fetch 2022-05-23 16:06:13 +08:00
奔跑的面条
ff7c820b1f Merge branch 'dev' into master-fetch 2022-05-22 23:27:39 +08:00
奔跑的面条
4252725d9d feat: 新增获取项目数据接口 2022-05-22 22:11:56 +08:00
奔跑的面条
deeb3a472c feat:新增发布和取消发布接口 2022-05-22 16:38:22 +08:00
奔跑的面条
763173de44 style: 调整代码格式,去除多余代码 2022-05-22 15:39:30 +08:00
奔跑的面条
f46e6ad8c8 feat: 新增删除接口 2022-05-22 15:25:07 +08:00
奔跑的面条
09b31547e1 feat: 新增首页列表接口 2022-05-22 15:06:45 +08:00
奔跑的面条
dee2ff8dee Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-05-22 14:09:38 +08:00
奔跑的面条
7f315b95ce feat: 新增项目列表接口 2022-05-22 14:05:57 +08:00
奔跑的面条
093e7d1edb Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-05-22 13:36:30 +08:00
奔跑的面条
a4e18f8893 fix: 修改新建项目id错误问题 2022-05-21 21:04:10 +08:00
奔跑的面条
c754a36ee5 fix: 修改i18n错误提示 2022-05-21 19:46:44 +08:00
奔跑的面条
a07d4daed5 chore: 修改提示内容 2022-05-21 18:04:52 +08:00
奔跑的面条
39023832e3 feat: 新增创建接口,修改i8n部分内容 2022-05-21 18:03:15 +08:00
奔跑的面条
5b8dda60bd feat: 新增退出登录接口,新增全局接口封装,修改登录接口内容 2022-05-21 17:31:01 +08:00
奔跑的面条
f7ade54e93 Merge branch 'master' of https://gitee.com/MTrun/go-view into master-fetch 2022-05-21 14:01:53 +08:00
奔跑的面条
4ae7e9dd2e Merge branch 'dev' into master-fetch 2022-05-21 13:44:25 +08:00
奔跑的面条
7e237b508a feat: 新增登录接口请求 2022-05-20 16:12:27 +08:00
奔跑的面条
28bb82e579 fix: 修改plop的问题 2022-05-20 16:12:09 +08:00
奔跑的面条
bcabcb0831 Merge branch 'dev' of https://gitee.com/MTrun/go-view into master-fetch 2022-05-20 10:25:46 +08:00
奔跑的面条
c24b03f3da update README.md. 2022-05-19 01:56:30 +00:00
奔跑的面条
63dd03e755 update README.md. 2022-05-16 10:38:39 +00:00
奔跑的面条
f3f1f57b01 update README.md. 2022-05-16 04:23:10 +00:00
602 changed files with 14957 additions and 30797 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'

2
.gitignore vendored
View File

@@ -4,5 +4,3 @@ dist
dist-ssr
*.local
.vscode
.idea
pnpm-lock

View File

@@ -1,51 +0,0 @@
version: '1.0'
name: branch-pipeline
displayName: BranchPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
- stage:
name: release
displayName: 发布
steps:
- step: publish@release_artifacts
name: publish_release_artifacts
displayName: '发布'
# 上游上传制品任务的产出
dependArtifact: output
# 发布制品版本号
version: '1.0.0.0'
# 是否开启版本号自增,默认开启
autoIncrement: true
triggers:
push:
branches:
exclude:
- master
include:
- .*

View File

@@ -1,49 +0,0 @@
version: '1.0'
name: master-pipeline
displayName: MasterPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
- stage:
name: release
displayName: 发布
steps:
- step: publish@release_artifacts
name: publish_release_artifacts
displayName: '发布'
# 上游上传制品任务的产出
dependArtifact: output
# 发布制品版本号
version: '1.0.0.0'
# 是否开启版本号自增,默认开启
autoIncrement: true
triggers:
push:
branches:
include:
- master

View File

@@ -1,36 +0,0 @@
version: '1.0'
name: pr-pipeline
displayName: PRPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
triggers:
pr:
branches:
include:
- master

281
README.md
View File

@@ -1,227 +1,74 @@
</p>
<p align="center">
<a
href="https://ai.goviewlink.com/saas/"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
">
<img src="readme/GoViewPro.png" alt="go-view" />
</a>
</p>
## 总览
<p align="center">
<img src="readme/logo-t-y.png" alt="go-view" />
</p>
![logo](readme/logo-t-y.png)
<h4 align="center">
开源、精美、便捷的「数据可视化」低代码开发平台
</h4>
**`master-fetch` 分支是带有后端接口请求的分支**
<h4 align="center">
<img src="https://gitee.com/dromara/go-view/badge/star.svg?theme=gvp" style="position: relative; display: inline-block; top: 6px; border-radius: 0px;" />
<img src="https://gitcode.com/GoView/go-view/star/badge.svg" style="display: inline-block; position: relative; top: 4px;">
</h4>
#### 长期赞助商
### feat-unify-test 分支目标
+ 实现 backend 后端工厂
将后端业务逻辑集中到 backend 了,控制 BackEndFactory 就可以适配不同的后端。
伪代码如下:
export const BackEndFactory = ():IBackend=>{
switch(项目后端配置){
case "无数据库":
return new MockBackend() // 等同: -master ,没有存储
case "indexdb":
return new IndexDbBackend() // 这次开发的,用 indexdb 做测试
case "java":
return new JavaBackend() // 等同: -fetch 没 java 环境,还没做
case "python":
return new PythonBackend() // 自定义开发的后端
。。。 其他 oss 、云平台的后端 。。。
}}
意义:
1 unify 统一 -fetch 和 master 分支,消除分支之间的差异。
2 方便接入不同的自定义后端平台。
3 前端存储功能让测试工作更加方便
<div>
<div align="center" style="column-gap: 20px;">
<a
href="http://www.ccflow.org/?from=goviewGitee"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/ccflow-banner.png" alt="go-view" style="width: 250px;" width="250px" />
</a>
<span> &nbsp;</span>
<a
href="https://fastbee.cn/"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/fb-banner.gif" alt="go-view" style="width: 250px;" width="250px"/>
</a>
<br/>
<br/>
<a
href="https://www.mingdao.com?s=utm_88&utm_source=Goview&utm_medium=banner&utm_campaign=gitee&utm_content=IT%E8%B5%8B%E8%83%BD%E4%B8%9A%E5%8A%A1"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/mdy-banner.png" alt="go-view" style="width: 270px;" width="270px"/>
</a>
<a
href="https://doc.hummingbird.winc-link.com?from=Goview"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/yingchuang-banner.png" alt="go-view" style="width: 270px;" width="270px"/>
</a>
<br/>
<br/>
<a
href="https://www.mtruning.club/chengDan/index.html"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/chengdan-banner.png" alt="go-view" style="width: 270px;" width="270px"/>
</a>
</div>
</div>
+ 完善事件处理机制
在事件中修改图表配置
在事件中修改图表数据
在事件中调用图表 exposed 函数
数据驱动界面
#### 😶 **纯前端** 分支: **`master`**
### 试验功能1Backend 后端工厂
+ 对比 -fetch 分支,梳理后端逻辑到 backend 目录的 ibackend 接口
+ 登录 - login
+ 登出 - logout
+ 预览token 注入或单点登陆 - checkToken
+ 显示项目列表和分页 - projectList
+ 保存、发布、修改名称 - updateProject
+ 复制项目 - copyProject
+ 图表内的图片上传 - uploadFile
+ 上传图片显示处理 - getFileUrl
+ IndexDbBackend 用indexdb浏览器数据库实现了 project 相关所有功能。
+ Todo: 统一后端错误处理
+ Todo开发 javabackend适配现有的后端
#### 👻 携带 **后端** 请求分支: **`master-fetch`**
### 试验功能2事件处理机制
+ 实现最常用的互动:找到图表元素、显示或隐藏、修改数据
+ 核心代码useLifeHandler.hook.ts
+ 在事件代码中通过 runtime 实现运行时刻的图表管理,提供基础函数:
+ selectComponents 选择多个图表
+ selectOneComponent 选择一个图表
+ getChartConfig 读取图表
+ setChartConfig 设置图表
+ callExposed 调用图表 exposed 的函数
+ 以下例子可以在点击事件中加入代码并预览,测试效果。
#### 📚 GoView **文档** 地址:[https://www.mtruning.club/](https://www.mtruning.club/)
+ 例子1 切换显示名称为 饼图 和 柱状图 的图表:
const range = runtime.fn.selectComponents("饼图 柱状图")
const h = runtime.fn.getChartConfig(range, "hide")
runtime.fn.setChartConfig(range, "hide", !h)
项目纯前端-Demo 地址:[https://vue.mtruning.club/](https://vue.mtruning.club/)
+ 例子2 修改一个名称 柱状图001 组件id 2wolqibrx3c000 的图表数据,以下两句等效
runtime.fn.setChartConfig("柱状图001", "dataset", {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":130}]})
runtime.fn.setChartConfig("#2wolqibrx3c000", "dataset", {"dimensions":["product","data1","data2"],"source":[{"product":"Mon","data1":120,"data2":230}]})
项目带后端-Demo 地址:[https://demo.mtruning.club/](https://demo.mtruning.club/)
Cloud IDE 代码在线预览地址:[https://idegitee.com/dromara/go-view](https://idegitee.com/dromara/go-view)
#### 🤯 后端项目看这里!
后端地址(社区实现,仅供参考):
- `JAVA` [https://gitee.com/MTrun/go-view-serve](https://gitee.com/MTrun/go-view-serve) (当前使用)
- `.NET` [https://gitee.com/sun_xiang_yu/go-view-dotnet](https://gitee.com/sun_xiang_yu/go-view-dotnet)
- `NODE` [https://gitee.com/qwdingyu/led](https://gitee.com/qwdingyu/led)
- `Docker 镜像` [https://gitee.com/AHEAD4/go-view-docker](https://gitee.com/AHEAD4/go-view-docker)
- `GO-goframe` [https://gitee.com/bufanyun/go-view-server](https://gitee.com/bufanyun/go-view-server)
- `GO-gin` [https://gitee.com/ls1990/go-view-serve](https://gitee.com/ls1990/go-view-serve)
- `接口文档` [https://docs.apipost.cn](https://docs.apipost.cn/preview/5aa85d10a59d66ce/ddb813732007ad2b?target_id=84dbc5b0-158f-4bcb-8f74-793ac604ada3) (不是最新, 以前端代码为准)
#### 整体介绍
- 框架:基于 `Vue3` 框架编写,使用 `hooks` 写法抽离部分逻辑,使代码结构更加清晰;
- 类型:使用 `TypeScript` 进行类型约束,减少未知错误发生概率,可以大胆修改逻辑内容;
- 性能:多处性能优化,使用页面懒加载、组件动态注册、数据滚动加载等方式,提升页面渲染速度;
- 存储:拥有本地记忆,部分配置项采用 `storage` 存储本地,提升使用体验;
- 封装:项目进行了详细的工具类封装如:路由、存储、加/解密、文件处理、主题、NaiveUI 全局方法、组件等
- 可视化:基于开源图表库[ECharts](https://echarts.apache.org/zh/index.html) 和 [VChart](https://www.visactor.io/vchart) 编写,具有丰富的图表类型和适配大屏的主题效果;
- 入选 NaiveUI 社区精选资源推荐:[查看 NaiveUI 推荐列表](https://www.naiveui.com/zh-CN/light/docs/community)
说明文档:
![说明文档](readme/go-view-doc.png)
工作台:
![工作台](readme/go-view-canvas.png)
请求配置:
![请求配置](readme/go-view-fetch.png)
数据过滤:
![数据过滤](readme/go-view-filter.png)
高级事件编辑:
![高级事件编辑](readme/go-view-event.png)
自定义组件颜色:
![高级事件编辑](readme/go-view-echarts-color.png)
快捷主页:
![快捷主页](readme/go-view-indexpage.png)
主题色:
![主题色](readme/go-view-color.png)
亮白主题:
![亮白主题](readme/go-view-theme.png)
最新动态: 整合字节图表框架 VChart[https://visactor.io/vchart](https://visactor.io/vchart)
![图表框架 VChart](readme/go-view-vcharts.png)
主要技术栈为:
| 名称 | 版本 | 名称 | 版本 |
| ------------------- | ----- | ----------- | ------ |
| Vue | 3.2.x | TypeScript4 | 4.6.x |
| Vite | 4.2.x | NaiveUI | 2.34.x |
| ECharts | 5.3.x | Pinia | 2.0.x |
| 详见 `package.json` | 😁 | 🥰 | 🤗 |
开发环境:
| 名称 | 版本 | 名称 | 版本 |
| ---- | ------- | ------- | ------ |
| node | 18.20.x | npm | 10.7.x |
| pnpm | 8.6.7 | windows | 11 |
已完成图表:
| 分类 | 名称 | 名称 | 名称 | 名称 |
| ------ | ---------------- | ---------- | -------------- | ------------------------ |
| 图表 | 柱状图 | 横向柱状图 | 折线图 | 单/多 折线面积图(渐变色) |
| \* | 饼图 | 环形图 | 水球图 | 雷达图 |
| \* | NaiveUI 多种进度 | 散点图 | 对数回归散点图 | 热力图 |
| \* | 漏斗图 | 中国地图 | 高德地图 | 🦊 |
| 信息 | 文字 | 渐变文字 | 词云 | 嵌套网页 |
| \* | 图片 | 视频 | 😺 | 🐯 |
| 列表 | 滚动排名列表 | 滚动表格 | 🐮 | 🐐 |
| 小组件 | 边框-01~13 | 装饰-01~05 | 数字翻牌 | 通用时间 |
| \* | 数字计数 | 倒计时 | 时钟 | 🦁 |
## 浏览器支持
开发和测试平台均在 `Google` 和最新版 `EDGE` 上完成,暂未测试 `IE11` 等其它浏览器,如有需求请自行测试与兼容。
## 安装
请查看文档:[https://www.mtruning.club/](https://www.mtruning.club/)
## 代码提交
- feat: 新功能
- fix: 修复 Bug
- docs: 文档修改
- perf: 性能优化
- revert: 版本回退
- ci: CICD 集成相关
- test: 添加测试代码
- refactor: 代码重构
- build: 影响项目构建或依赖修改
- style: 不影响程序逻辑的代码修改
- chore: 不属于以上类型的其他类型(日常事务)
## 交流群
QQ 群687586375
<img width="260px" src="readme/go-view-qq.jpg" alt="QQ群" style="border-radius: 20px" />
## Pro 部分功能展示
体验地址: <a href="https://ai.goviewlink.com/saas/" target="_blank">https://ai.goviewlink.com/saas/</a>
![渲染海报](readme/logo-poster.png)
+ 例子3 找到一个组并隐藏
const c = runtime.fn.selectOneComponent("分组")
if(c){
console.log(runtime.fn.getChartConfig(c, "isGroup" ))
runtime.fn.setChartConfig(c, "hide", true)
}

View File

@@ -1,4 +1,3 @@
import path from 'path'
export const OUTPUT_DIR = 'dist'
// monaco-editor 路径
@@ -7,7 +6,7 @@ export const prefix = `monaco-editor/esm/vs`
// chunk 警告大小
export const chunkSizeWarningLimit = 2000
// 禁用 brotliSize 压缩大小报告
// 禁用 brotli 压缩大小报告
export const brotliSize = false
// 分包
@@ -15,12 +14,7 @@ export const rollupOptions = {
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: (chunkInfo) => {
if(['.png', '.jpg', '.jpeg'].includes(path.extname(chunkInfo.name))) {
return `static/[ext]/[name].[ext]`
}
return `static/[ext]/[name]-[hash].[ext]`
},
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
manualChunks: {
jsonWorker: [`${prefix}/language/json/json.worker`],
cssWorker: [`${prefix}/language/css/css.worker`],

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

@@ -7,8 +7,10 @@
<meta name="description" content="GoView 是高效、高性能的拖拽式低代码数据可视化开发平台,将页面元素封装为基础组件,无需编写代码即可完成业务需求。">
<meta name="keywords" content="GoViewgoview低代码可视化">
<meta name="author" content="奔跑的面条,面条">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=0">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=yes" media="(min-width: 769px)">
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
<link rel="icon" href="./favicon.ico" />
<title>GoView</title>
<link rel="stylesheet" href="./index.css" />

View File

@@ -1,12 +1,9 @@
{
"name": "go-view",
"version": "1.3.2",
"engines": {
"node": ">=16.14"
},
"version": "2.1.0",
"scripts": {
"dev": "vite --host",
"build": "vite build",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"new": "plop --plopfile ./plop/plopfile.js",
"postinstall": "husky install",
@@ -14,38 +11,29 @@
"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx,.vue src --fix"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@amap/amap-jsapi-types": "^0.0.8",
"@iconify/json": "^2.2.158",
"@types/color": "^3.0.3",
"@types/crypto-js": "^4.1.1",
"@types/keymaster": "^1.6.30",
"@types/lodash": "^4.14.184",
"@visactor/vchart": "^2.0.0",
"@visactor/vchart-theme": "^1.12.2",
"animate.css": "^4.1.1",
"axios": "^1.4.0",
"axios": "^0.27.2",
"color": "^4.2.3",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.7",
"dom-helpers": "^5.2.1",
"echarts-liquidfill": "^3.1.0",
"echarts-stat": "^1.2.0",
"echarts-wordcloud": "^2.0.0",
"gsap": "^3.11.3",
"highlight.js": "^11.5.0",
"html2canvas": "^1.4.1",
"iconify-icon": "^1.0.8",
"keymaster": "^1.6.2",
"mitt": "^3.0.0",
"monaco-editor": "^0.33.0",
"naive-ui": "2.40.3",
"naive-ui": "2.33.4",
"pinia": "^2.0.13",
"screenfull": "^6.0.1",
"three": "^0.145.0",
"vue": "^3.5.13",
"vue": "^3.2.31",
"vue-demi": "^0.13.1",
"vue-i18n": "9.2.2",
"vue-i18n": "9.1.10",
"vue-router": "4.0.12",
"vue3-lazyload": "^0.2.5-beta",
"vue3-sketch-ruler": "^1.3.3",
@@ -60,8 +48,8 @@
"@typescript-eslint/parser": "^5.18.0",
"@vicons/carbon": "^0.12.0",
"@vicons/ionicons5": "~0.11.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vitejs/plugin-vue": "^1.10.2",
"@vitejs/plugin-vue-jsx": "^1.3.9",
"@vue/compiler-sfc": "^3.2.31",
"@vueuse/core": "^7.7.1",
"commitlint": "^17.0.2",
@@ -77,10 +65,10 @@
"mockjs": "^1.1.0",
"plop": "^3.0.5",
"prettier": "^2.6.2",
"sass": "1.49.11",
"sass": "^1.49.11",
"sass-loader": "^12.6.0",
"typescript": "4.6.3",
"vite": "4.3.6",
"vite": "2.9.9",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-importer": "^0.2.5",
"vite-plugin-mock": "^2.9.6",
@@ -88,4 +76,4 @@
"vue-echarts": "^6.0.2",
"vue-tsc": "^0.28.10"
}
}
}

10420
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

BIN
readme/go-view-qq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

View File

@@ -1,9 +1,9 @@
<template>
<n-config-provider
:locale="zhCN"
:theme="darkTheme"
:hljs="hljsTheme"
:locale="locale"
:date-locale="dateLocale"
:date-locale="dateZhCN"
:theme-overrides="overridesTheme"
>
<go-app-provider>
@@ -14,10 +14,11 @@
</template>
<script lang="ts" setup>
import { NConfigProvider } from 'naive-ui'
import { zhCN, dateZhCN, NConfigProvider } from 'naive-ui'
import { GoAppProvider } from '@/components/GoAppProvider'
import { I18n } from '@/components/I18n'
import { useDarkThemeHook, useThemeOverridesHook, useCode, useLang } from '@/hooks'
import { useSystemInit, useDarkThemeHook, useThemeOverridesHook, useCode } from '@/hooks'
// 暗黑主题
const darkTheme = useDarkThemeHook()
@@ -28,7 +29,6 @@ const overridesTheme = useThemeOverridesHook()
// 代码主题
const hljsTheme = useCode()
// 全局语言
const { locale, dateLocale } = useLang()
//测试提交
// 系统全局数据初始化
useSystemInit()
</script>

View File

@@ -1,4 +1,4 @@
import axios, { AxiosResponse, InternalAxiosRequestConfig, AxiosError } from 'axios'
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
import { ResultEnum } from "@/enums/httpEnum"
import { ErrorPageNameMap } from "@/enums/pageEnum"
import { redirectErrorPage } from '@/utils'
@@ -9,10 +9,10 @@ const axiosInstance = axios.create({
})
axiosInstance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
(config: AxiosRequestConfig) => {
return config
},
(error: AxiosError) => {
(error: AxiosRequestConfig) => {
Promise.reject(error)
}
)
@@ -21,8 +21,7 @@ axiosInstance.interceptors.request.use(
axiosInstance.interceptors.response.use(
(res: AxiosResponse) => {
const { code } = res.data as { code: number }
if (code === undefined || code === null) return Promise.resolve(res.data)
if (code === ResultEnum.DATA_SUCCESS) return Promise.resolve(res.data)
if (code === ResultEnum.SUCCESS) return Promise.resolve(res.data)
// 重定向
if (ErrorPageNameMap.get(code)) redirectErrorPage(code)
return Promise.resolve(res.data)

View File

@@ -116,6 +116,7 @@ export const customizeHttp = (targetParams: RequestConfigType, globalParams: Req
if (!targetParams || !globalParams) {
return
}
// 全局
const {
// 全局请求源地址
@@ -163,6 +164,7 @@ export const customizeHttp = (targetParams: RequestConfigType, globalParams: Req
params = translateStr(params)
// form 类型处理
let formData: FormData = new FormData()
formData.set('default', 'defaultData')
// 类型处理
switch (requestParamsBodyType) {
@@ -171,9 +173,7 @@ export const customizeHttp = (targetParams: RequestConfigType, globalParams: Req
case RequestBodyEnum.JSON:
headers['Content-Type'] = ContentTypeEnum.JSON
//json对象也能使用'javasctipt:'来动态拼接参数
data = translateStr(targetRequestParams.Body['json'])
if(typeof data === 'string') data = JSON.parse(data)
data = translateStr(JSON.parse(targetRequestParams.Body['json']))
// json 赋值给 data
break

View File

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

View File

@@ -1,5 +1,4 @@
import test from './test.mock'
import vchart from './vchart.mock'
import { MockMethod } from 'vite-plugin-mock'
import { RequestHttpEnum } from '@/enums/httpEnum'
@@ -16,14 +15,9 @@ export const radarUrl = '/mock/radarData'
export const heatMapUrl = '/mock/heatMapData'
export const scatterBasicUrl = '/mock/scatterBasic'
export const mapUrl = '/mock/map'
export const capsuleUrl = '/mock/capsule'
export const wordCloudUrl = '/mock/wordCloud'
export const treemapUrl = '/mock/treemap'
export const threeEarth01Url = '/mock/threeEarth01Data'
export const sankeyUrl = '/mock/sankey'
export const graphUrl = '/mock/graphData'
export const vchartBarDataUrl = '/mock/vchart/barDataUrl'
const mockObject: MockMethod[] = [
{
@@ -88,11 +82,6 @@ const mockObject: MockMethod[] = [
method: RequestHttpEnum.GET,
response: () => test.fetchMap
},
{
url: capsuleUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchCapsule
},
{
url: wordCloudUrl,
method: RequestHttpEnum.GET,
@@ -108,21 +97,6 @@ const mockObject: MockMethod[] = [
method: RequestHttpEnum.GET,
response: () => test.threeEarth01Data
},
{
url: sankeyUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchSankey
},
{
url: graphUrl,
method: RequestHttpEnum.GET,
response: () => test.graphData
},
{
url: vchartBarDataUrl,
method: RequestHttpEnum.GET,
response: () => vchart.bar
}
]
export default mockObject

View File

@@ -1,9 +1,79 @@
{
"markers|50": [
"point": [
{
"name": "某某地市",
"value": "@integer(2, 20)",
"position": ["@float(115, 117, 1, 6)", "@float(38, 40, 1, 6)"]
"name": "北京",
"value": [116.405285, 39.904989, 200]
},
{
"name": "郑州",
"value": [113.665412, 34.757975, 888]
},
{
"name": "青海",
"value": [101.778916, 36.623178, 666]
},
{
"name": "宁夏回族自治区",
"value": [106.278179, 38.46637, 66]
},
{
"name": "哈尔滨市",
"value": [126.642464, 45.756967, 101]
}
],
"map": [
{
"name": "北京市",
"value": "@integer(0, 1000)"
},
{
"name": "河北省",
"value": "@integer(0, 1000)"
},
{
"name": "江苏省",
"value": "@integer(0, 1000)"
},
{
"name": "福建省",
"value": "@integer(0, 1000)"
},
{
"name": "山东省",
"value": "@integer(0, 1000)"
},
{
"name": "河南省",
"value": "@integer(0, 1000)"
},
{
"name": "湖北省",
"value": "@integer(0, 1000)"
},
{
"name": "广西壮族自治区",
"value": "@integer(0, 1000)"
},
{
"name": "海南省",
"value": "@integer(0, 1000)"
},
{
"name": "青海省",
"value": "@integer(0, 1000)"
},
{
"name": "新疆维吾尔自治区",
"value": "@integer(0, 1000)"
}
],
"pieces": [
{ "gte": 1000, "label": ">1000" },
{ "gte": 600, "lte": 999, "label": "600-999" },
{ "gte": 200, "lte": 599, "label": "200-599" },
{ "gte": 50, "lte": 199, "label": "49-199" },
{ "gte": 10, "lte": 49, "label": "10-49" },
{ "lte": 9, "label": "<9" }
]
}

View File

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

View File

@@ -2,8 +2,6 @@ import heatmapJson from './heatMapData.json'
import scatterJson from './scatter.json'
import mapJson from './map.json'
import tTreemapJson from './treemap.json'
import sankeyJson from './sankey.json'
import graphDataJson from './graph.json'
export default {
// 单图表
@@ -12,8 +10,28 @@ export default {
status: 200,
msg: '请求成功',
data: {
dimensions: ['product', 'dataOne'],
'source|20': [
dimensions: ['product', 'dataOne'],
source: [
{
product: '@name',
'dataOne|0-900': 3
},
{
product: '@name',
'dataOne|0-900': 3
},
{
product: '@name',
'dataOne|0-900': 3
},
{
product: '@name',
'dataOne|0-900': 3
},
{
product: '@name',
'dataOne|0-900': 3
},
{
product: '@name',
'dataOne|0-900': 3
@@ -21,31 +39,43 @@ export default {
]
}
},
// 胶囊图
fetchCapsule: {
code: 0,
status: 200,
msg: '请求成功',
data: {
dimensions: ['name', 'value'],
"source|2-5": [
{ 'name|+1': ["厦门","福州","北京","上海","新疆","郑州","湖南","内蒙古"], 'value|0-40': 20 },
]
}
},
// 图表
fetchMockData: {
code: 0,
status: 200,
msg: '请求成功',
data: {
dimensions: ['product', 'dataOne', 'dataTwo', 'dataThree'],
'source|20': [
dimensions: ['product', 'dataOne', 'dataTwo'],
source: [
{
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3,
'dataThree|100-900': 3
'dataTwo|100-900': 3
},
{
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3
},
{
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3
},
{
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3
},
{
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3
},
{
product: '@name',
'dataOne|100-900': 3,
'dataTwo|100-900': 3
}
]
}
@@ -55,7 +85,21 @@ export default {
code: 0,
status: 200,
msg: '请求成功',
'data|50': [{ name: '@name', 'value|100-900': 5 }]
data: [
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 },
{ name: '@name', 'value|100-900': 5 }
]
},
// 轮播表格
fetchScrollBoard: {
@@ -218,22 +262,13 @@ export default {
data: [
{
startArray: { name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' },
'endArray|10': [{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' }]
endArray: [
{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' },
{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' },
{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' },
{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' }
]
}
]
},
// 桑基图
fetchSankey: {
code: 0,
status: 200,
msg: '请求成功',
data: sankeyJson
},
// 关系图
graphData: {
code: 0,
status: 200,
msg: '请求成功',
data: graphDataJson
},
}
}

View File

@@ -1,10 +0,0 @@
import bar from './vchart/bar.json'
export default {
bar: {
code: 0,
status: 200,
msg: '请求成功',
data: bar
}
}

View File

@@ -1,16 +0,0 @@
{
"values": [
{ "type": "Nail polish", "year": "Africa", "value|100-900": 3 },
{ "type": "Nail polish", "year": "EU", "value|100-900": 3 },
{ "type": "Nail polish", "year": "China", "value|100-900": 3 },
{ "type": "Nail polish", "year": "USA", "value|100-900": 3 },
{ "type": "Eyebrow pencil", "year": "Africa", "value|100-900": 3 },
{ "type": "Eyebrow pencil", "year": "EU", "value|100-900": 3 },
{ "type": "Eyebrow pencil", "year": "China", "value|100-900": 3 },
{ "type": "Eyebrow pencil", "year": "USA", "value|100-900": 3 },
{ "type": "Rouge", "year": "Africa", "value|100-900": 3 },
{ "type": "Rouge", "year": "EU", "value|100-900": 3 },
{ "type": "Rouge", "year": "China", "value|100-900": 3 },
{ "type": "Rouge", "year": "USA", "value|100-900": 3 }
]
}

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,33 @@
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 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();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

146
src/backend/ibackend.ts Normal file
View File

@@ -0,0 +1,146 @@
/**
* 后端接口,相关功能对应表:
* 登录 - login
* 登出 - logout
* 预览token 注入或单点登陆 - checkToken
* 显示项目列表和分页 - projectList
* 保存、发布、修改名称 - updateProject
* 复制项目 - copyProject
* 图表内的图片上传 - uploadFile
* 上传图片显示处理 - getFileUrl
* 所有接口返回格式MyResponseType
*/
import { IndexDbBackend } from "./indexdb/indexdbbackend";
// import { PythonBackend } from "./python/pythonbackend";
export interface MyResponseType {
code: number; // 状态200 表示接口调用成功参考HttpEnum
msg: string; // 提示信息,配合 data 和 code
data: any; // data = null 表示接口结果错误,错误原因放在 msg
}
export class MyResponse implements MyResponseType {
code: number = 200;
msg: string = "";
data: any = {};
}
/**
* 实现 IBackend 后端接口
* 错误处理:
*/
export interface IBackend {
/**
* 初始化后端系统测试后端连接oss地址等
* @param data 可选,备用
*/
init(data:any):any
/**
* 登陆
* @param data {} .username .password
* @return MyResponseType
* .data 须包含:
* token:{tokenValue:"", tokenName:""},
* userinfo:{nickname:"", username: "", id: 用户ID}
* 错误处理:
* 1 接口错误 .code 不为 200 .msg 可选,后端反馈错误信息
* 2 登陆错误 .code=200 .data = null, msg 可选,反馈不能登陆的原因
* 登陆信息.data 记录:
* setLocalStorage(GO_LOGIN_INFO_STORE, res.data)
*/
login(data:any):any
/**
* 通知后端登出
*/
logout():any
/**
* 检查Token是否有效配合预览页面和单点登陆备用
* @param data {tokenValue, tokenName}
* @return 同 login()
*/
checkToken(data:any):any
/**
* 项目列表
* @param data {} .page, .limit
* @return [项目],字段名称需要进行 map
* id: projectId
* title:projectName
* release,
* label:remarks
* image:indexImage 如果需要挂刷新,在这里处理。如果需要拼接 urlgetFileUrl也在这里处理好。
*/
projectList(data:any):any
/**
* 新增项目
* @param data
* .projectName
* @return id 新项目 ID
*/
createProject(data: any):any
/**
* 获取项目
* @param data .projectId
* @return
id:projectId
projectName,
state: release,
remarks,
content
*/
fetchProject(data: any):any
/**
* 修改项目
* @param data
* .projectId 必须
* .projectName 可选
* .release 可选
* .content 可选
* .object File 可选 对象
* .remarks 可选
* @return
*/
updateProject(data: any):any
/**
* 复制项目
* @param data
* .copyId 需要复制的项目ID
* .projectName
* @return id 新项目ID
*/
copyProject(data: any):any
/**
* 删除项目
* @param data
* .projectId
* @return
*/
deleteProject(data: any):any
/**
* 文件上传
* @param file File 图片对象
* @param params 备用 Todo: 上传文件可带上项目ID和其他附加信息以便后端文件管理
* @return .uri 文件对象 uri。建议在图表中保存相对地址通过 getFileUrl 得到完整地址
*/
uploadFile(file: File, params: any):any
/**
* 文件地址转换,处理 uploadFile 的返回地址。如果是绝对地址,可以不处理
* @param uploadUri 上传返回的 uri
* @return 供 image.src 使用的地址信息
*/
getFileUrl(uploadUri:string):string
}
export const BackEndFactory = new IndexDbBackend();
// export const BackEndFactory = new MockBackend();
// export const BackEndFactory = new PythonBackend();

View File

@@ -0,0 +1,147 @@
/**
* IndexDb 帮助类
*/
const win: { [k: string]: any } = window || globalThis;
const indexedDB =
win.indexedDB || win.mozIndexedDB || win.webkitIndexedDB || win.msIndexedDB;
const dbs: { [k: string]: IDBDatabase } = {};
let databaseName: string;
let request: IDBOpenDBRequest;
interface AnyEvent {
[k: string]: any;
}
export interface TableOption {
storeName: string;
option: { [K: string]: any };
index: { [K: string]: any }[];
}
export const createDB = (
name: string,
version?: string,
options?: TableOption[],
) =>
new Promise<IDBDatabase>((resolve, reject) => {
if (!indexedDB) reject('浏览器不支持indexedDB');
databaseName = name;
if (dbs?.[name]) {
resolve(dbs[name]);
return;
}
request = indexedDB.open(name, version);
createTable(options)?.then((db: IDBDatabase) => resolve(db));
request.onsuccess = (event: AnyEvent) => {
// IDBDatabase
const db = event.target.result;
// 缓存起来
dbs[name] = db;
resolve(db);
};
request.onerror = (event: AnyEvent) => reject(event);
});
export const createTable = (options?: TableOption[]) => {
if (!options) return;
return new Promise<IDBDatabase>((resolve) => {
request.onupgradeneeded = (event: AnyEvent) => {
const db = event.target.result;
dbs[databaseName] = db;
for (const i in options) {
// 判断是否存在表
if (!db.objectStoreNames.contains(options[i].storeName)) {
const objectStore = db.createObjectStore(
options[i].storeName,
options[i].option,
);
for (const j of options[i].index) {
objectStore.createIndex(j.name, j.keyPath, {
unique: j.unique,
});
}
}
}
resolve(db);
};
});
};
const getTransaction = async (name: string, version?: string) => {
let db: IDBDatabase;
// 先从缓存获取
if (dbs[databaseName]) {
db = dbs[databaseName];
} else {
db = await createDB(databaseName, version);
}
return db.transaction(name, 'readwrite');
};
const getObjectStore = async (
name: string,
version?: string,
): Promise<IDBObjectStore> => {
const transaction = await getTransaction(name, version);
return transaction.objectStore(name);
};
const getStore = (name: string, type: string, data: any) =>
new Promise<IDBDatabase>((resolve) => {
getObjectStore(name).then((objectStore: IDBObjectStore | any) => {
const request = objectStore[type](data);
request.onsuccess = (event: AnyEvent) =>
resolve(event.target.result);
});
});
const findStore = (
name: string,
start: any,
end: any,
startInclude: any,
endInclude: any,
) =>
new Promise<IDBDatabase>((resolve, reject) => {
getObjectStore(name).then((objectStore: IDBObjectStore) => {
const request = objectStore.openCursor(
IDBKeyRange.bound(start, end, startInclude, endInclude),
);
request.onsuccess = (event: AnyEvent) =>
resolve(event.target.result);
request.onerror = (event: AnyEvent) => reject(event);
});
});
export interface DBSelect {
add: (data: any) => Promise<IDBDatabase>;
get: (data: any) => Promise<IDBDatabase>;
getAll: () => Promise<IDBDatabase>;
del: (data: any) => Promise<IDBDatabase>;
clear: (data: any) => Promise<IDBDatabase>;
put: (data: any) => Promise<IDBDatabase>;
find: (
start: any,
end: any,
startInclude: any,
endInclude: any,
) => Promise<IDBDatabase>;
}
// 获取一个store
export const onDBSelect = async (
name: string,
version: string
): Promise<DBSelect> => {
const add = (data: any) => getStore(name, 'add', data);
const get = (data: any) => getStore(name, 'get', data);
const getAll = () => getStore(name, 'getAll', null);
const del = (data: any) => getStore(name, 'delete', data);
const clear = (data: any) => getStore(name, 'clear', data);
const put = (data: any) => getStore(name, 'put', data);
const find = (start: any, end: any, startInclude: any, endInclude: any) =>
findStore(name, start, end, startInclude, endInclude);
const options: DBSelect = { add, get, getAll, clear, del, put, find };
getObjectStore(name, version);
return options;
};

View File

@@ -0,0 +1,155 @@
import { MyResponse, IBackend } from '../ibackend'
import { createDB, DBSelect, onDBSelect } from '../indexdb/indexdb'
import { fileToUrl, fileToBlob } from "@/utils"
const PROJECT_TABLE = "project"
const IMAGE_TABLE = "image" // 保存图片未实现Todo
const DB_NAME = "goview"
const DB_VER = "1"
export class IndexDbBackend implements IBackend {
public async init(data: any) {
let rtn:MyResponse = new MyResponse;
const db:IDBDatabase = await createDB(DB_NAME, DB_VER, [
{
storeName: PROJECT_TABLE,
option: {
keyPath: "projectId", autoIncrement:true
},
index: [
{name: 'projectId', keyPath: "projectId", unique: true},
{name: 'projectName', keyPath: "projectName", unique: false},
{name: 'release', keyPath: "release", unique: false},
{name: 'remarks', keyPath: "remarks", unique: false},
{name: 'content', keyPath: "content", unique: false},
{name: 'indexImage', keyPath: "indexImage", unique: false}
]
}
])
return rtn;
}
public async login(data:any) {
let rtn:MyResponse = new MyResponse;
if(data.password == "123456" && data.username == "admin"){
rtn.data = {
token:{tokenValue:"mockToken", tokenName:"name"},
userinfo:{nickname:"nickname", username:data.username, id:1}
}
}else{
rtn.data = null
rtn.msg = "admin 和 123456"
}
return rtn;
}
public async logout() {
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async checkToken(data: any) {
let rtn:MyResponse = new MyResponse;
console.log("CheckToken: " + data.token)
rtn.data = {
token:{tokenValue:"mockToken", tokenName:"name"},
userinfo:{nickname:"nickname", username:data.username, id:1}
}
return rtn;
}
public async projectList(data:any){
let rtn:MyResponse = new MyResponse;
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
const r:any = await db.getAll()
rtn.data = []
r.map(function (item: any) {
let url = ""
if(item.indexImage){
const Url = URL || window.URL || window.webkitURL
url = Url.createObjectURL(item.indexImage)
}
rtn.data.push({
id: item.projectId,
title: item.projectName,
release: item.release == 1,
label:item.remarks,
image:url
})
})
return rtn;
}
public async createProject(data: any){
let rtn:MyResponse = new MyResponse;
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
rtn.data.id = await db.add({ projectName:data.projectName })
return rtn;
}
public async fetchProject(data: any){
let rtn:MyResponse = new MyResponse;
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
const r:any = await db.get(parseInt(data.projectId))
rtn.data = {
id:r.projectId,
projectName: r.projectName,
state: r.release,
remarks: r.remarks,
content: r.content
}
return rtn;
}
public async updateProject(data: any){
let rtn:MyResponse = new MyResponse;
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
const row:any = await db.get(parseInt(data.projectId))
if("content" in data) row.content = data.content
if("projectName" in data) row.projectName = data.projectName
if("release" in data) row.release = data.release
if("remarks" in data) row.remarks = data.remarks
if("object" in data) {
row.indexImage = await fileToBlob(data.object)
}
await db.put(row)
return rtn;
}
public async copyProject(data: any){
let rtn:MyResponse = new MyResponse;
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
const row:any = await db.get(parseInt(data.copyId))
rtn.data.id =await db.add({
projectName:data.projectName,
content:row.content,
indexImage:row.indexImage,
remarks:row.remarks
})
return rtn;
}
public async deleteProject(data: any){
let rtn:MyResponse = new MyResponse;
const db:DBSelect = await onDBSelect(PROJECT_TABLE, DB_VER)
await db.del(parseInt(data.projectId))
return rtn;
}
public async changeProjectRelease(data: any){
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async uploadFile(data: File, params:any){
// Todo: 图片可以保存在表中
let rtn:MyResponse = new MyResponse;
rtn.data.uri = fileToUrl(data)
return rtn;
}
public getFileUrl(uploadUri:string){
return uploadUri;
}
}

View File

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

71
src/backend/java/axios.ts Normal file
View File

@@ -0,0 +1,71 @@
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
import { ResultEnum } 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.PROD ? import.meta.env.VITE_PRO_PATH : ''}${axiosPre}`,
timeout: ResultEnum.TIMEOUT,
})
axiosInstance.interceptors.request.use(
(config: AxiosRequestConfig) => {
// 白名单校验
if (includes(fetchAllowList, config.url)) return config
// 获取 token
const info = getLocalStorage(StorageEnum.GO_SYSTEM_STORE)
// 重新登录
if (!info) {
routerTurnByName(PageEnum.BASE_LOGIN_NAME)
return config
}
const userInfo = info[SystemStoreEnum.USER_INFO]
config.headers = {
...config.headers,
[userInfo[SystemStoreUserInfoEnum.TOKEN_NAME] || 'token']: userInfo[SystemStoreUserInfoEnum.USER_TOKEN] || ''
}
return config
},
(err: AxiosRequestConfig) => {
Promise.reject(err)
}
)
// 响应拦截器
axiosInstance.interceptors.response.use(
(res: AxiosResponse) => {
const { code } = res.data as { code: number }
// 成功
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) => {
Promise.reject(err)
}
)
export default axiosInstance

226
src/backend/java/http.ts Normal file
View File

@@ -0,0 +1,226 @@
import axiosInstance from './axios'
import {
RequestHttpEnum,
ContentTypeEnum,
RequestBodyEnum,
RequestDataTypeEnum,
RequestContentTypeEnum,
RequestParamsObjType
} from '@/enums/httpEnum'
import type { RequestGlobalConfigType, RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
export const get = (url: string, params?: object) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.GET,
params: params,
})
}
export const post = (url: string, data?: object, headersType?: string) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.POST,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
export const patch = (url: string, data?: object, headersType?: string) => {
return axiosInstance({
url: url,
method: RequestHttpEnum.PATCH,
data: data,
headers: {
'Content-Type': headersType || ContentTypeEnum.JSON
}
})
}
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,
params
})
}
// 获取请求函数默认get
export const http = (type?: RequestHttpEnum) => {
switch (type) {
case RequestHttpEnum.GET:
return get
case RequestHttpEnum.POST:
return post
case RequestHttpEnum.PATCH:
return patch
case RequestHttpEnum.PUT:
return put
case RequestHttpEnum.DELETE:
return del
default:
return get
}
}
const prefix = 'javascript:'
// 对输入字符进行转义处理
export const translateStr = (target: string | object) => {
if (typeof target === 'string') {
if (target.startsWith(prefix)) {
const funcStr = target.split(prefix)[1]
let result;
try {
result = new Function(`${funcStr}`)()
} catch (error) {
console.log(error)
window['$message'].error('js内容解析有误')
}
return result
} else {
return target
}
}
for (const key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
const subTarget = (target as any)[key];
(target as any)[key] = translateStr(subTarget)
}
}
return target
}
/**
* * 自定义请求
* @param targetParams 当前组件参数
* @param globalParams 全局参数
*/
export const customizeHttp = (targetParams: RequestConfigType, globalParams: RequestGlobalConfigType) => {
if (!targetParams || !globalParams) {
return
}
// 全局
const {
// 全局请求源地址
requestOriginUrl,
// 全局请求内容
requestParams: globalRequestParams
} = globalParams
// 目标组件(优先级 > 全局组件)
const {
// 请求地址
requestUrl,
// 普通 / sql
requestContentType,
// 获取数据的方式
requestDataType,
// 请求方式 get/post/del/put/patch
requestHttpType,
// 请求体类型 none / form-data / x-www-form-urlencoded / json /xml
requestParamsBodyType,
// SQL 请求对象
requestSQLContent,
// 请求内容 params / cookie / header / body: 同 requestParamsBodyType
requestParams: targetRequestParams
} = targetParams
// 静态排除
if (requestDataType === RequestDataTypeEnum.STATIC) return
if (!requestUrl) {
return
}
// 处理头部
let headers: RequestParamsObjType = {
...globalRequestParams.Header,
...targetRequestParams.Header
}
headers = translateStr(headers)
// data 参数
let data: RequestParamsObjType | FormData | string = {}
// params 参数
let params: RequestParamsObjType = { ...targetRequestParams.Params }
params = translateStr(params)
// form 类型处理
let formData: FormData = new FormData()
formData.set('default', 'defaultData')
// 类型处理
switch (requestParamsBodyType) {
case RequestBodyEnum.NONE:
break
case RequestBodyEnum.JSON:
headers['Content-Type'] = ContentTypeEnum.JSON
data = translateStr(JSON.parse(targetRequestParams.Body['json']))
// json 赋值给 data
break
case RequestBodyEnum.XML:
headers['Content-Type'] = ContentTypeEnum.XML
// xml 字符串赋值给 data
data = translateStr(targetRequestParams.Body['xml'])
break
case RequestBodyEnum.X_WWW_FORM_URLENCODED: {
headers['Content-Type'] = ContentTypeEnum.FORM_URLENCODED
const bodyFormData = targetRequestParams.Body['x-www-form-urlencoded']
for (const i in bodyFormData) formData.set(i, translateStr(bodyFormData[i]))
// FormData 赋值给 data
data = formData
break
}
case RequestBodyEnum.FORM_DATA: {
headers['Content-Type'] = ContentTypeEnum.FORM_DATA
const bodyFormUrlencoded = targetRequestParams.Body['form-data']
for (const i in bodyFormUrlencoded) {
formData.set(i, translateStr(bodyFormUrlencoded[i]))
}
// FormData 赋值给 data
data = formData
break
}
}
// sql 处理
if (requestContentType === RequestContentTypeEnum.SQL) {
headers['Content-Type'] = ContentTypeEnum.JSON
data = requestSQLContent
}
try {
const url = (new Function("return `" + `${requestOriginUrl}${requestUrl}`.trim() + "`"))();
return axiosInstance({
url,
method: requestHttpType,
data,
params,
headers
})
} catch (error) {
console.log(error)
window['$message'].error('URL地址格式有误')
}
}

View File

@@ -0,0 +1,130 @@
import { MyResponse, IBackend } from './ibackend'
import { fileToUrl } from '@/utils'
/**
* MockBackend
* 模拟纯前端,不会保存,也不报错。
*/
export class MockBackend implements IBackend {
public async init(data: any) {
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async login(data:any) {
let rtn:MyResponse = new MyResponse;
if(data.password == "123456" && data.username == "admin"){
rtn.data = {
token:{tokenValue:"mockToken", tokenName:"name"},
userinfo:{nickname:"nickname", username:data.username, id:1}
}
}else{
rtn.data = null
rtn.msg = "用户名或密码错误!"
}
return rtn;
}
public async logout() {
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async checkToken(data:any){
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async projectList(data:any){
let rtn:MyResponse = new MyResponse;
rtn.data =[
{
id: 1,
title: '假数据不可用',
release: true,
label: '官方案例'
},
{
id: 2,
title: '物料2-假数据不可用',
release: false,
label: '官方案例'
},
{
id: 3,
title: '物料3-假数据不可用',
release: false,
label: '官方案例'
},
{
id: 4,
title: '物料4-假数据不可用',
release: false,
label: '官方案例'
},
{
id: 5,
title: '物料5-假数据不可用',
release: false,
label: '官方案例'
}
];
return rtn;
}
public async createProject(data: any){
let rtn:MyResponse = new MyResponse;
rtn.data.id = "newId"
return rtn;
}
public async fetchProject(data: any){
let rtn:MyResponse = new MyResponse;
rtn.data = {
id:data.projectId,
projectName: '假数据不可用',
indexImage:'',
state: 0,
remarks: '官方案例',
content: null
}
return rtn;
}
public async saveProject(data: object){
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async updateProject(data: any){
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async copyProject(data: any){
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async deleteProject(data: any){
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async changeProjectRelease(data: any){
let rtn:MyResponse = new MyResponse;
return rtn;
}
public async uploadFile(data: File, params:any){
let rtn:MyResponse = new MyResponse;
rtn.data.uri = fileToUrl(data)
return rtn;
}
public getFileUrl(uploadUri:string){
return uploadUri;
}
}

View File

@@ -1,5 +1,4 @@
import Flipper from './index.vue'
type FlipType = 'up' | 'down'
export { Flipper, FlipType }

View File

@@ -1,13 +1,19 @@
<template>
<div class="go-flipper" :class="[flipType, { go: isFlipping }]">
<div class="M-Flipper" :class="[flipType, { go: isFlipping }]">
<div class="digital front" :data-front="frontTextFromData"></div>
<div class="digital back" :data-back="backTextFromData"></div>
</div>
</template>
<script lang="ts">
export default {
name: 'Flipper'
}
</script>
<script lang="ts" setup>
import { ref, PropType, watch, nextTick } from 'vue'
import { FlipType } from './index'
import { ref, PropType, watch } from 'vue'
import { FlipType } from '.'
const props = defineProps({
flipType: {
@@ -43,10 +49,6 @@ const props = defineProps({
backColor: {
type: String,
default: '#000000'
},
borderWidth: {
type: Number,
default: 2
}
})
@@ -54,27 +56,19 @@ const isFlipping = ref(false)
const frontTextFromData = ref(props.count || 0)
const backTextFromData = ref(props.count || 0)
let timeoutID: any = 0
//
const flip = async (front: string | number, back: string | number) => {
const flip = (front: string | number, back: string | number) => {
//
if (isFlipping.value) {
isFlipping.value = false //
clearTimeout(timeoutID) //
await nextTick()
await flip(front, back) //
return
}
if (isFlipping.value) return
//
backTextFromData.value = back
frontTextFromData.value = front
// true
isFlipping.value = true
//
timeoutID = setTimeout(() => {
setTimeout(() => {
isFlipping.value = false // false
frontTextFromData.value = back
}, props.duration)
@@ -98,7 +92,6 @@ $radius: v-bind('`${props.radius}px`');
$width: v-bind('`${props.width}px`');
$height: v-bind('`${props.height}px`');
$perspective: v-bind('`${props.height * 2}px`');
$borderWidth: v-bind('`${props.borderWidth * 2}px`');
$speed: v-bind('`${props.duration / 1000}s`');
$shadowColor: #000000;
$lineColor: #4a9ef8;
@@ -138,12 +131,13 @@ $lineColor: #4a9ef8;
}
// #endregion
.go-flipper {
.M-Flipper {
display: inline-block;
position: relative;
width: $width;
height: $height;
line-height: $height;
border: solid 1px $backColor;
border-radius: $radius;
background: $frontColor;
font-size: $width;
@@ -151,17 +145,6 @@ $lineColor: #4a9ef8;
box-shadow: 0 0 6px rgba($color: $shadowColor, $alpha: 0.5); //
text-align: center;
// font-family: 'Helvetica Neue';
&::after {
content: '';
position: absolute;
z-index: 10;
left: 0;
top: 0;
right: 0;
bottom: 0;
box-shadow: inset 0 0 $borderWidth 0 $frontColor; //
border-radius: $radius;
}
.digital:before,
.digital:after {
@@ -209,13 +192,11 @@ $lineColor: #4a9ef8;
&.down.go .front:before {
transform-origin: 50% 100%;
animation: frontFlipDown $speed ease-in-out both;
box-shadow: 0 -2px $borderWidth 0 $frontColor;
box-shadow: 0 -2px 6px rgba($color: $lineColor, $alpha: 0.3);
backface-visibility: hidden;
}
&.down.go .back:after {
animation: backFlipDown $speed ease-in-out both;
box-shadow: 0 2px $borderWidth 0 $frontColor;
backface-visibility: hidden;
}
/*向上翻*/
&.up .front:after {
@@ -233,13 +214,11 @@ $lineColor: #4a9ef8;
&.up.go .front:after {
transform-origin: 50% 0;
animation: frontFlipUp $speed ease-in-out both;
box-shadow: 0 2px $borderWidth 0 $frontColor;
box-shadow: 0 2px 6px rgba($color: $lineColor, $alpha: 0.3);
backface-visibility: hidden;
}
&.up.go .back:before {
animation: backFlipUp $speed ease-in-out both;
box-shadow: 0 -2px $borderWidth 0 $frontColor;
backface-visibility: hidden;
}
}
</style>

View File

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

View File

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

View File

@@ -14,19 +14,16 @@
</template>
<script lang="ts" setup>
import { useI18n } from "vue-i18n";
import { useLangStore } from '@/store/modules/langStore/langStore'
import { langList } from '@/i18n/index'
import { LangEnum } from '@/enums/styleEnum'
import { icon } from '@/plugins'
const { LanguageIcon } = icon.ionicons5
const { locale } = useI18n();
const langStore = useLangStore()
const options = langList
const handleSelect = (key: LangEnum) => {
locale.value = key;
langStore.changeLang(key)
}
</script>

View File

@@ -1,5 +1,5 @@
<template>
<n-modal v-model:show="modelShowRef" @afterLeave="closeHandle">
<n-modal v-model:show="modelShow" @afterLeave="closeHandle">
<n-list bordered class="go-system-info">
<template #header>
<n-space justify="space-between">
@@ -11,7 +11,7 @@
</template>
<n-list-item>
<n-space class="go-my-2" :size="20">
<n-space :size="20">
<n-text class="item-left">版权声明</n-text>
<n-text>
GoView 版权属于
@@ -21,7 +21,8 @@
</n-list-item>
<n-list-item>
<n-space class="go-my-2" :size="20">
<n-divider style="margin-top: 0" />
<n-space :size="20">
<n-text class="item-left">协议备注</n-text>
<n-text>
请遵守开源 MIT 协议以上声明 <n-text type="error">不可删除</n-text>否则视作侵权行为后果自负
@@ -30,7 +31,8 @@
</n-list-item>
<n-list-item>
<n-space class="go-mt-2" :size="20">
<n-divider style="margin-top: 0" />
<n-space :size="20">
<n-text class="item-left">商业授权</n-text>
<n-text>
若不想保留版权声明请通过仓库/交流群 联系项目作者进行授权
@@ -42,19 +44,13 @@
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { icon } from '@/plugins'
const props = defineProps({
modelShow: Boolean
})
const emit = defineEmits(['update:modelShow'])
const { HelpOutlineIcon, CloseIcon } = icon.ionicons5
const modelShowRef = ref(false)
const emit = defineEmits(['update:modelShow'])
watch(() => props.modelShow, (newValue) => {
modelShowRef.value = newValue
defineProps({
modelShow: Boolean
})
const closeHandle = () => {

View File

@@ -1,5 +1,5 @@
<template>
<n-modal v-model:show="modelShowRef" @afterLeave="closeHandle">
<n-modal v-model:show="modelShow" @afterLeave="closeHandle">
<n-list bordered class="go-system-setting">
<template #header>
<n-space justify="space-between">
@@ -69,20 +69,21 @@
</template>
<script script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import { reactive } from 'vue'
import { ListType } from './index.d'
import { useSettingStore } from '@/store/modules/settingStore/settingStore'
import { SettingStoreEnums, ToolsStatusEnum } from '@/store/modules/settingStore/settingStore.d'
import { icon } from '@/plugins'
const props = defineProps({
const { HelpOutlineIcon, CloseIcon } = icon.ionicons5
const emit = defineEmits(['update:modelShow'])
defineProps({
modelShow: Boolean
})
const emit = defineEmits(['update:modelShow'])
const { HelpOutlineIcon, CloseIcon } = icon.ionicons5
const settingStore = useSettingStore()
const modelShowRef = ref(false)
const list = reactive<ListType[]>([
{
@@ -167,10 +168,6 @@ const list = reactive<ListType[]>([
}
])
watch(() => props.modelShow, (newValue) => {
modelShowRef.value = newValue
})
const closeHandle = () => {
emit('update:modelShow', false)
}

View File

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

View File

@@ -1,250 +0,0 @@
<template>
<div
ref="vChartRef"
v-on="{
...Object.fromEntries(event.map((eventName: string) => [eventName, (eventData: MouseEvent) => eventHandlers(eventData, eventName)]))
}"
></div>
</template>
<script setup lang="ts">
import { ref, PropType, watch, onBeforeUnmount, nextTick, toRaw, toRefs } from 'vue'
import { VChart, type IVChart, type IInitOption } from '@visactor/vchart'
import { transformHandler } from './transformProps'
import { IOption } from '@/packages/components/VChart/index.d'
import { registerChartsAndComponents } from './register'
// VChart按需加载: 注册图表及组件
registerChartsAndComponents()
// 事件说明 v1.13.0 https://www.visactor.io/vchart/api/API/event
const event = [
'mousedown',
'mouseup',
'mouseupoutside',
'rightdown',
'rightup',
'rightupoutside',
'click',
'dblclick',
'mousemove',
'mouseover',
'mouseout',
'mouseenter',
'mouseleave',
'wheel',
'touchstart',
'touchend',
'touchendoutside',
'touchmove',
'touchcancel',
'tap',
'dragstart',
'dragend',
'drag',
'dragenter',
'dragleave',
'dragover',
'drop',
'pan',
'panstart',
'panend',
'press',
'pressup',
'pressend',
'pinch',
'pinchstart',
'pinchend',
'swipe',
'dimensionHover',
'dimensionClick',
'dataZoomChange',
'scrollBarChange',
'brushStart',
'brushChange',
'brushEnd',
'brushClear',
'drill',
'legendItemClick',
'legendItemHover',
'legendItemUnHover',
'legendFilter',
'initialized',
'rendered',
'renderFinished',
'animationFinished',
'layoutStart',
'layoutEnd',
'afterResizef'
]
const emit = defineEmits([
'mousedown',
'mouseup',
'mouseupoutside',
'rightdown',
'rightup',
'rightupoutside',
'click',
'dblclick',
'mousemove',
'mouseover',
'mouseout',
'mouseenter',
'mouseleave',
'wheel',
'touchstart',
'touchend',
'touchendoutside',
'touchmove',
'touchcancel',
'tap',
'dragstart',
'dragend',
'drag',
'dragenter',
'dragleave',
'dragover',
'drop',
'pan',
'panstart',
'panend',
'press',
'pressup',
'pressend',
'pinch',
'pinchstart',
'pinchend',
'swipe',
'dimensionHover',
'dimensionClick',
'dataZoomChange',
'scrollBarChange',
'brushStart',
'brushChange',
'brushEnd',
'brushClear',
'drill',
'legendItemClick',
'legendItemHover',
'legendItemUnHover',
'legendFilter',
'initialized',
'rendered',
'renderFinished',
'animationFinished',
'layoutStart',
'layoutEnd',
'afterResizef'
])
const props = defineProps({
option: {
type: Object as PropType<
IOption & {
dataset: any
}
>,
required: true
},
initOptions: {
type: Object as PropType<
IInitOption & {
deepWatch?: boolean | number
}
>,
required: false,
default: () => ({})
}
})
const vChartRef = ref()
let chart: IVChart
// 解构 props.option排除 dataset
const { dataset, ...restOfOption } = toRefs(props.option)
// 排除 data 监听
watch(
() => ({
...restOfOption
}),
() => {
nextTick(() => {
createOrUpdateChart(props.option)
})
},
{
deep: props.initOptions?.deepWatch || true,
immediate: true
}
)
watch(
() => dataset.value,
() => {
nextTick(() => {
createOrUpdateChart(props.option)
})
},
{
deep: false
}
)
// 更新
const createOrUpdateChart = (
chartProps: IOption & {
dataset: any
}
) => {
if (vChartRef.value && !chart) {
const spec = transformHandler[chartProps.category || '']?.(chartProps)
chart = new VChart(
{ ...spec, data: chartProps.dataset },
{
dom: vChartRef.value,
...props.initOptions
}
)
chart.renderSync()
return true
} else if (chart) {
const spec = transformHandler[chartProps.category || '']?.(chartProps)
chart.updateSpec({ ...spec, data: toRaw(chartProps.dataset), dataset: undefined }, false, undefined, {
change: false,
reMake: true,
reAnimate: true
})
return true
}
return false
}
// 刷新
const refresh = () => {
if (chart) {
chart.renderSync()
}
}
// 抛出事件
const eventHandlers = (eventData: MouseEvent, eventName: string) => {
if (event.includes(eventName)) emit(eventName as any, eventData)
}
// 卸载
onBeforeUnmount(() => {
if (chart) {
chart.release()
}
})
defineExpose({
// 重刷新
refresh,
release: () => {
if (chart) {
chart.release()
}
}
})
</script>

View File

@@ -1,29 +0,0 @@
import { VChart } from '@visactor/vchart/esm/core';
import { registerBarChart, registerAreaChart, registerLineChart, registerPieChart, registerFunnelChart, registerWordCloudChart, registerScatterChart } from '@visactor/vchart/esm/chart';
import { registerTooltip, registerCartesianCrossHair, registerDiscreteLegend, registerLabel } from '@visactor/vchart/esm/component';
import { registerDomTooltipHandler } from '@visactor/vchart/esm/plugin/components';
import { registerAnimate } from '@visactor/vchart';
export const registerChartsAndComponents = () => {
VChart.useRegisters([
// 图表
registerBarChart,
registerAreaChart,
registerLineChart,
registerPieChart,
registerScatterChart,
registerFunnelChart,
registerWordCloudChart,
// 组件
registerTooltip,
registerDomTooltipHandler,
registerCartesianCrossHair,
registerDiscreteLegend,
registerLabel,
// 动画
registerAnimate
]);
}

View File

@@ -1,32 +0,0 @@
import { cloneDeep } from "lodash"
export default (chartProps: any) => {
const spec = cloneDeep(chartProps)
delete spec.category
// tooltip
const keyFill = spec.tooltip.style.keyLabel.fill
const valueFill = spec.tooltip.style.valueLabel.fill
const titleFill = spec.tooltip.style.titleLabel.keyFill
delete spec.tooltip.style.keyLabel.fill
delete spec.tooltip.style.valueLabel.fill
delete spec.tooltip.style.titleLabel.keyFill
spec.tooltip.style.keyLabel.fontColor = keyFill
spec.tooltip.style.valueLabel.fontColor = valueFill
spec.tooltip.style.titleLabel.fontColor = titleFill
// axis
const { name: xAxisName, ...restXAxisProps } = chartProps.xAxis
const { name: yAxisName, ...restYAxisProps } = chartProps.yAxis
spec.axes = [{
orient: 'bottom',
...restXAxisProps
}, {
orient: 'left',
...restYAxisProps
}]
delete spec.xAxis
delete spec.yAxis
// console.log('spec-area-transform', spec)
return spec
}

View File

@@ -1,45 +0,0 @@
import { cloneDeep } from 'lodash'
export default (chartProps: any) => {
const spec = cloneDeep(chartProps)
delete spec.category
// tooltip
const keyFill = spec.tooltip.style.keyLabel.fill
const valueFill = spec.tooltip.style.valueLabel.fill
const titleFill = spec.tooltip.style.titleLabel.keyFill
delete spec.tooltip.style.keyLabel.fill
delete spec.tooltip.style.valueLabel.fill
delete spec.tooltip.style.titleLabel.keyFill
spec.tooltip.style.keyLabel.fontColor = keyFill
spec.tooltip.style.valueLabel.fontColor = valueFill
spec.tooltip.style.titleLabel.fontColor = titleFill
// axis
const { name: xAxisName, ...restXAxisProps } = chartProps.xAxis
const { name: yAxisName, ...restYAxisProps } = chartProps.yAxis
spec.axes = [
{
orient: 'bottom',
...restXAxisProps
// paddingInner: 0.5
},
{
orient: 'left',
...restYAxisProps
}
]
delete spec.xAxis
delete spec.yAxis
spec.label = {
...spec.label,
style: {
...spec.label?.style,
lineWidth: 0
}
}
// console.log('spec-bar-transform', spec)
return spec
}

View File

@@ -1,28 +0,0 @@
import { Datum } from "@visactor/vchart/esm/typings"
import { cloneDeep } from "lodash"
const INNER_RADIUS = 0.75
const OUTER_RADIUS = 0.68
export default (chartProps: any) => {
const spec = cloneDeep(chartProps)
// tooltip
const keyFill = spec.tooltip.style.keyLabel.fill
const valueFill = spec.tooltip.style.valueLabel.fill
const titleFill = spec.tooltip.style.titleLabel.keyFill
delete spec.tooltip.style.keyLabel.fill
delete spec.tooltip.style.valueLabel.fill
delete spec.tooltip.style.titleLabel.keyFill
spec.tooltip.style.keyLabel.fontColor = keyFill
spec.tooltip.style.valueLabel.fontColor = valueFill
spec.tooltip.style.titleLabel.fontColor = titleFill
// label
spec.label = {
visible: true,
}
// console.log('spec-funnel-transform', spec)
return spec
}

View File

@@ -1,20 +0,0 @@
import { ChatCategoryEnum, IOption } from "@/packages/components/VChart/index.d";
import bars from './bars'
import pies from './pies'
import lines from './lines'
import areas from './areas'
import funnels from "./funnels";
import wordClouds from "./wordClouds";
import scatters from "./scatters";
export const transformHandler: {
[key: string]: (args: IOption) => any
} = {
[ChatCategoryEnum.BAR]: bars,
[ChatCategoryEnum.PIE]: pies,
[ChatCategoryEnum.LINE]: lines,
[ChatCategoryEnum.AREA]: areas,
[ChatCategoryEnum.FUNNEL]: funnels,
[ChatCategoryEnum.WORDCLOUD]: wordClouds,
[ChatCategoryEnum.SCATTER]: scatters,
// todo: more charts handler
}

View File

@@ -1,43 +0,0 @@
import { cloneDeep } from 'lodash'
export default (chartProps: any) => {
const spec = cloneDeep(chartProps)
delete spec.category
// tooltip
const keyFill = spec.tooltip.style.keyLabel.fill
const valueFill = spec.tooltip.style.valueLabel.fill
const titleFill = spec.tooltip.style.titleLabel.keyFill
delete spec.tooltip.style.keyLabel.fill
delete spec.tooltip.style.valueLabel.fill
delete spec.tooltip.style.titleLabel.keyFill
spec.tooltip.style.keyLabel.fontColor = keyFill
spec.tooltip.style.valueLabel.fontColor = valueFill
spec.tooltip.style.titleLabel.fontColor = titleFill
// axis
const { name: xAxisName, ...restXAxisProps } = chartProps.xAxis
const { name: yAxisName, ...restYAxisProps } = chartProps.yAxis
spec.axes = [
{
orient: 'bottom',
...restXAxisProps
},
{
orient: 'left',
...restYAxisProps
}
]
delete spec.xAxis
delete spec.yAxis
spec.label = {
...spec.label,
style: {
...spec.label?.style,
lineWidth: 0
}
}
// console.log('spec-line-transform', spec)
return spec
}

View File

@@ -1,132 +0,0 @@
import { Datum } from '@visactor/vchart/esm/typings'
import { cloneDeep } from 'lodash'
export default (chartProps: any) => {
const spec = cloneDeep(chartProps)
delete spec.category
// tooltip
const keyFill = spec.tooltip.style.keyLabel.fill
const valueFill = spec.tooltip.style.valueLabel.fill
const titleFill = spec.tooltip.style.titleLabel.keyFill
delete spec.tooltip.style.keyLabel.fill
delete spec.tooltip.style.valueLabel.fill
delete spec.tooltip.style.titleLabel.keyFill
spec.tooltip.style.keyLabel.fontColor = keyFill
spec.tooltip.style.valueLabel.fontColor = valueFill
spec.tooltip.style.titleLabel.fontColor = titleFill
if (spec.extensionMark) {
// extensionMark
spec.extensionMark = [
{
name: 'arc_inner_shadow',
type: 'arc',
dataId: 'id0',
style: {
interactive: false,
startAngle: (datum: Datum) => {
return datum['__VCHART_ARC_START_ANGLE']
},
endAngle: (datum: Datum) => {
return datum['__VCHART_ARC_END_ANGLE']
},
innerRadius: (datum: Datum, context: any) => {
return context.getLayoutRadius() * spec.innerRadius - 30
},
outerRadius: (datum: Datum, context: any) => {
return context.getLayoutRadius() * spec.innerRadius
},
fillOpacity: 0.3,
fill: (datum: Datum, context: any) => {
return context.seriesColor(datum[spec.seriesField])
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x()
},
y: (datum: Datum, context: any) => {
return context.getCenter().y()
}
}
},
{
name: 'arc_inner',
type: 'symbol',
// dataId: 'id0',
style: {
interactive: false,
size: (datum: Datum, context: any) => {
return context.getLayoutRadius() * 2 * spec.innerRadius - 100
},
fillOpacity: 0,
lineWidth: 1,
strokeOpacity: 0.5,
stroke: {
gradient: 'conical',
startAngle: 0,
endAngle: Math.PI * 2,
stops: [
{
offset: 0,
color: '#FFF',
opacity: 0
},
{
offset: 1,
color: '#FFF',
opacity: 1
}
]
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x()
},
y: (datum: Datum, context: any) => {
return context.getCenter().y()
}
}
},
{
name: 'arc_outer',
type: 'symbol',
// dataId: 'id0',
style: {
interactive: false,
size: (datum: Datum, context: any) => {
return context.getLayoutRadius() * 2 * spec.outerRadius + 50
},
fillOpacity: 0,
lineWidth: 1,
strokeOpacity: 0.5,
stroke: {
gradient: 'conical',
startAngle: 0,
endAngle: Math.PI * 2,
stops: [
{
offset: 0,
color: '#FFF',
opacity: 0
},
{
offset: 1,
color: '#FFF',
opacity: 1
}
]
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x()
},
y: (datum: Datum, context: any) => {
return context.getCenter().y()
}
}
}
]
}
return spec
}

View File

@@ -1,35 +0,0 @@
import { cloneDeep } from "lodash"
export default (chartProps: any) => {
const spec = cloneDeep(chartProps)
// tooltip
const keyFill = spec.tooltip.style.keyLabel.fill
const valueFill = spec.tooltip.style.valueLabel.fill
const titleFill = spec.tooltip.style.titleLabel.keyFill
delete spec.tooltip.style.keyLabel.fill
delete spec.tooltip.style.valueLabel.fill
delete spec.tooltip.style.titleLabel.keyFill
spec.tooltip.style.keyLabel.fontColor = keyFill
spec.tooltip.style.valueLabel.fontColor = valueFill
spec.tooltip.style.titleLabel.fontColor = titleFill
// axis
const { name: xAxisName, ...restXAxisProps } = chartProps.xAxis
const { name: yAxisName, ...restYAxisProps } = chartProps.yAxis
spec.axes = [{
orient: 'bottom',
...restXAxisProps,
label: {
formatMethod: (value: string) => Number(value).toFixed(2)
}
}, {
orient: 'left',
...restYAxisProps
}]
delete spec.xAxis
delete spec.yAxis
// console.log('spec-scatter-transform', spec)
return spec
}

View File

@@ -1,21 +0,0 @@
import { Datum } from "@visactor/vchart/esm/typings"
import { cloneDeep } from "lodash"
export default (chartProps: any) => {
const spec = cloneDeep(chartProps)
// tooltip
const keyFill = spec.tooltip.style.keyLabel.fill
const valueFill = spec.tooltip.style.valueLabel.fill
const titleFill = spec.tooltip.style.titleLabel.keyFill
delete spec.tooltip.style.keyLabel.fill
delete spec.tooltip.style.valueLabel.fill
delete spec.tooltip.style.titleLabel.keyFill
spec.tooltip.style.keyLabel.fontColor = keyFill
spec.tooltip.style.valueLabel.fontColor = valueFill
spec.tooltip.style.titleLabel.fontColor = titleFill
// console.log('spec-word-cloud-transform', spec)
return spec
}

View File

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

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