Compare commits

...

139 Commits

Author SHA1 Message Date
奔跑的面条
9cf023fcc8 Merge branch 'dev' 2023-07-09 15:54:38 +08:00
奔跑的面条
7076c4deb7 feat: 新增预览拖拽 2023-07-09 15:54:01 +08:00
奔跑的面条
28f0585a5c Merge branch 'dev' 2023-07-08 22:00:35 +08:00
奔跑的面条
e979149cfb feat: 不符合接口格式时添加拦截 2023-07-08 21:59:41 +08:00
奔跑的面条
5fc43d1d02 build: 升级版本到1.2.7 2023-07-08 21:52:07 +08:00
奔跑的面条
084441d365 Merge branch 'dev' 2023-07-08 21:48:53 +08:00
奔跑的面条
d0d031d1bb feat: 还原修改成组旋转的问题,优化预览放大的交互 2023-07-08 21:33:50 +08:00
奔跑的面条
9127e6f44c feat: 新增预览放大功能 2023-07-08 21:18:37 +08:00
xlys999
bb610ff7ae update src/views/chart/ContentEdit/components/EditRule/index.vue.
坐标尺刻度错位问题

Signed-off-by: xlys999 <xlys998@163.com>
2023-07-08 18:45:03 +08:00
奔跑的面条
2dc12b1f0b !177 update src/views/chart/ContentEdit/components/EditRule/index.vue.
Merge pull request !177 from xlys999/N/A
2023-07-08 10:42:13 +00:00
奔跑的面条
c575cff727 perf: 优化滤镜预设展示 2023-07-08 18:36:36 +08:00
奔跑的面条
5443c9647b !176 新增预设滤镜功能
Merge pull request !176 from 张江胜/dev_feat
2023-07-08 10:35:31 +00:00
xlys999
ace6b0f0d2 update src/views/chart/ContentEdit/components/EditRule/index.vue.
坐标尺刻度错位问题

Signed-off-by: xlys999 <xlys998@163.com>
2023-07-03 14:10:00 +00:00
张江胜
271a02ff12 feat: 增加预设滤镜功能
1.滤镜变换:新增了快捷预设滤镜
2023-06-29 18:45:59 +08:00
张江胜
f747fd3506 fix: 解决单个组件旋转后,再组合分组渲染预览会错位的问题
1.解决单个组件旋转后,和其他组件组合分组后再次旋转,进行预览后该分组会错位的问题
2.解决TS类型报错
2023-06-29 17:39:17 +08:00
奔跑的面条
b59c28b8ae fix: 解决 TS 类型错误问题 2023-06-27 18:11:37 +08:00
奔跑的面条
b1a0e7b5e2 fix: 修改 axios 类型错误 2023-06-27 17:54:17 +08:00
奔跑的面条
0d762f7d30 style: 优化 pr_173 的问题 2023-06-27 17:48:08 +08:00
奔跑的面条
cc156a0a6b !173 1.时间选择器增加默认值类型选项
Merge pull request !173 from dingxs/dingxs
2023-06-27 09:47:39 +00:00
奔跑的面条
a77f4d6bf4 !174 feat: 为 naive-ui 组件配置感知、属性提示、自动完成功能
Merge pull request !174 from dodu/dev-commet
2023-06-25 01:32:43 +00:00
tnt group
9e5676e5ed feat: 为 naive-ui 组件提供感知能力 2023-06-23 11:54:52 +08:00
dingxs
bc79e2f01f fix:用in判断对象是否具有某个特定的key,而不是value,解决当value为null时永远得不到修改 2023-06-19 14:39:00 +08:00
dingxs
80f06afa02 feat:时间选择器增加默认值类型选项 2023-06-19 14:35:17 +08:00
奔跑的面条
58ab3dee6d !172 环形饼图增加轨道宽度设置,并优化数字显示(如无小数位,则不强制显示小数位)
Merge pull request !172 from dodu/dev-commet
2023-06-15 11:52:47 +00:00
奔跑的面条
d7a3bb7ba0 !169 feat:标签选择器增加默认值选项
Merge pull request !169 from h5coder/dev-h5coder
2023-06-15 19:50:27 +08:00
奔跑的面条
5387a7ad90 !171 fix: 修复旧版本没有legend配置导致报settting color错误
Merge pull request !171 from h5coder/h5coder-fix
2023-06-15 19:46:13 +08:00
tnt group
fe37435f79 chore: 设置选择框size 2023-06-14 07:54:36 +08:00
tnt group
1ef6d9797a feat: 环形饼图增加轨道宽度设置,并优化数字显示 2023-06-13 10:27:08 +08:00
奔跑的面条
c70d54c622 style: 删除冗余代码 2023-06-08 16:39:18 +08:00
Ming
d74645d7b0 feat: 组件交互对公共api支持配置页 2023-06-07 15:13:48 +08:00
Ming
86910de3b2 fix: 数据初始化 2023-06-07 15:08:52 +08:00
Ming
47636ee680 feat: 支持对公共api进行交互 2023-06-07 15:06:51 +08:00
Ming
9485931f5d feat: 更新公共api对组件动态绑定交互 2023-06-07 15:03:59 +08:00
Ming
20fa9e4afe fix: declare module '@iconify/vue' 2023-06-07 15:00:28 +08:00
Ming
cbd629d7f8 feat: 更新交互组件更新方式 2023-06-07 15:00:06 +08:00
Ming
1551aa9ded fix: 语言转换为英文后,创建按钮的英文拼写错误 2023-05-29 10:29:44 +08:00
奔跑的面条
471610963b build: 升级版本到1.2.6 2023-05-28 17:29:19 +08:00
奔跑的面条
f6424245fd Merge branch 'dev' 2023-05-28 17:28:34 +08:00
奔跑的面条
6afbe59828 Merge branch 'dev' 2023-05-28 17:20:36 +08:00
奔跑的面条
adfd8c63e2 !159 地图组件新增卫星地图主题
Merge pull request !159 from tanhao/feat-map-theme
2023-05-24 12:58:20 +00:00
tanhao
11af941590 feat: 在地图组件基础上新增卫星地图主题 2023-05-24 14:44:46 +08:00
奔跑的面条
66e376a87d docs: update 2023-05-13 14:21:49 +08:00
奔跑的面条
318821680a docs: update 2023-05-13 14:19:52 +08:00
奔跑的面条
114fe5626a update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-05-13 05:55:38 +00:00
奔跑的面条
afb364b362 docs: add sponsors 2023-05-13 13:52:52 +08:00
奔跑的面条
5c1af11788 build: 升级版本到 1.2.5 2023-05-08 20:42:22 +08:00
奔跑的面条
c953ccd238 Merge branch 'dev' 2023-05-08 20:37:17 +08:00
奔跑的面条
697542f804 perf: 优化发布的提示文案 2023-05-08 20:27:53 +08:00
奔跑的面条
7b9da32215 Merge branch 'dev' 2023-04-23 21:14:43 +08:00
奔跑的面条
9b8cf36135 Merge branch 'dev' 2023-04-23 21:09:21 +08:00
奔跑的面条
465fbf713c fix: update readme 2023-04-11 09:23:33 +08:00
奔跑的面条
3b41bf480c Merge branch 'dev' 2023-04-05 16:39:25 +08:00
奔跑的面条
234755cd34 Merge branch 'dev' 2023-04-03 20:11:09 +08:00
奔跑的面条
c289252546 style: 去除多余代码 2023-04-02 18:16:27 +08:00
奔跑的面条
5207a98ce4 build: 升级版本号到 1.2.4 2023-04-02 18:15:12 +08:00
奔跑的面条
e411cb9b09 style: 去除多余代码 2023-04-02 18:14:22 +08:00
奔跑的面条
a2f32b0289 Merge branch 'dev' 2023-04-02 18:00:55 +08:00
奔跑的面条
5676a323d7 build: 升级版本到1.2.3 2023-03-16 20:51:57 +08:00
奔跑的面条
b435366ac4 Merge branch 'dev' 2023-03-16 20:51:31 +08:00
奔跑的面条
b5738f5cf4 Merge branch 'dev' 2023-03-04 17:32:10 +08:00
奔跑的面条
032956e03b build: 升级版本到1.2.2 2023-03-04 17:06:28 +08:00
奔跑的面条
b94b44090b Merge branch 'dev' 2023-03-04 17:05:46 +08:00
奔跑的面条
22924eb36f !131 feat: 新增轮播图组件
Merge pull request !131 from Ryker/dev
2023-03-04 09:02:34 +00:00
ryker
35e5374628 feat: 轮播图 2023-03-02 12:25:21 +08:00
奔跑的面条
432cceed2a docs: 优化说明文档 2023-02-28 20:16:50 +08:00
奔跑的面条
5b828d4982 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-02-28 12:00:26 +00:00
奔跑的面条
605fd14b3d build: 新增1.2.1版本 2023-02-27 18:59:59 +08:00
奔跑的面条
1b2b319467 Merge branch 'dev' 2023-02-27 18:59:18 +08:00
奔跑的面条
bcf0417624 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-02-18 10:22:05 +00:00
奔跑的面条
4b81a09293 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-02-18 10:16:27 +00:00
奔跑的面条
bcaffd1579 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-02-18 10:15:56 +00:00
奔跑的面条
7309d603f5 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-02-18 10:14:53 +00:00
奔跑的面条
ada4ce9885 docs: 修改文档 2023-02-18 17:48:32 +08:00
奔跑的面条
7758fb30d0 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-02-18 09:32:19 +00:00
奔跑的面条
6ddea30289 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-02-18 09:29:41 +00:00
奔跑的面条
ac42782f12 docs: 修改文档说明 2023-02-18 17:27:30 +08:00
奔跑的面条
4348688e34 docs: 修改文档 2023-02-18 17:27:01 +08:00
奔跑的面条
d447c85830 docs: 新增合作伙伴说明 2023-02-18 17:22:18 +08:00
奔跑的面条
0a3c1b3438 Merge branch 'dev' 2023-02-17 18:15:26 +08:00
奔跑的面条
d90e0953b9 build: 修改版本到1.2.0 2023-02-17 14:30:40 +08:00
奔跑的面条
ba04005b09 Merge branch 'dev' 2023-02-17 14:26:52 +08:00
奔跑的面条
16d7ae8176 docs: 修改文档 2023-02-14 18:39:33 +08:00
奔跑的面条
0e77b196b6 docs: 修改群二维码 2023-02-14 18:29:47 +08:00
奔跑的面条
0ea81aeaee docs: 更换群二维码 2023-02-14 18:26:43 +08:00
奔跑的面条
cf85574c67 Merge remote-tracking branch 'origin/dev' 2023-01-17 15:35:25 +08:00
奔跑的面条
cec39d693a update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-01-17 03:12:32 +00:00
奔跑的面条
c250f9d4d8 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2023-01-17 03:10:59 +00:00
奔跑的面条
97ca3e8664 Merge branch 'dev' 2023-01-16 17:58:43 +08:00
奔跑的面条
01d971b902 build: 升级版本到 1.1.9 2023-01-13 16:52:10 +08:00
奔跑的面条
855d810d0d Merge branch 'dev' 2023-01-13 16:51:21 +08:00
奔跑的面条
bc10d06c78 !122 update src/packages/components/Decorates/Three/ThreeEarth01/index.vue.
Merge pull request !122 from CarnivalO/N/A
2023-01-12 06:32:55 +00:00
CarnivalO
fa2530634d update src/packages/components/Decorates/Three/ThreeEarth01/index.vue.
Edge浏览器不行 Edg应该也是<-1

Signed-off-by: CarnivalO <xmwjn@qq.com>
2023-01-12 05:54:12 +00:00
奔跑的面条
fb93d35c91 build: 修改版本号到1.1.8 2023-01-08 20:05:31 +08:00
奔跑的面条
fc2b1fc42e Merge branch 'dev' 2023-01-08 20:02:23 +08:00
奔跑的面条
8fd121a335 build: 修改版本号到1.1.7 2022-12-31 20:57:56 +08:00
奔跑的面条
d183c5815b build: 修改版本号到1.1.12 2022-12-31 20:53:29 +08:00
奔跑的面条
661f56e773 build: 1.1.12 2022-12-31 20:53:02 +08:00
奔跑的面条
f9c715c72c build: 升级版本到1.1.6 2022-12-16 14:01:47 +08:00
奔跑的面条
e2b3118d9d Merge branch 'dev' 2022-12-16 13:57:02 +08:00
奔跑的面条
f4c3a2b04f docs: 修改首页说明 2022-12-16 10:04:25 +08:00
奔跑的面条
31a8957de9 !106 docs: add Cloud IDE preview link
Merge pull request !106 from aresn/master
2022-12-16 01:49:34 +00:00
奔跑的面条
46f20f61b5 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2022-12-09 08:11:47 +00:00
aresn
dba5ab3ef3 update README.md.
Signed-off-by: aresn <admin@aresn.com>
2022-12-07 09:51:33 +00:00
aresn
2251bebee6 add preview.yml.
Signed-off-by: aresn <admin@aresn.com>
2022-12-07 09:49:48 +00:00
奔跑的面条
3ac9ffc73c Merge branch 'dev' 2022-11-22 12:44:51 +08:00
奔跑的面条
c420ae467f Merge branch 'dev' 2022-11-21 10:49:25 +08:00
奔跑的面条
8334fe5bcc build: 升级版本到 1.1.5 2022-11-19 21:04:53 +08:00
奔跑的面条
f99edce6f4 Merge branch 'dev' 2022-11-19 21:04:32 +08:00
奔跑的面条
f47acca703 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2022-11-10 10:13:19 +00:00
奔跑的面条
73a6c6b920 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2022-11-10 10:10:58 +00:00
奔跑的面条
672f7a0a7c Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-11-05 21:46:26 +08:00
奔跑的面条
de78fb2149 docs: 新增文档截图 2022-11-05 18:19:33 +08:00
奔跑的面条
4a59e69bbe docs: 修改首页地址 2022-11-02 19:46:19 +08:00
奔跑的面条
a442e13a7b feat: 升级版本到1.1.4 2022-11-02 19:05:16 +08:00
奔跑的面条
4d093a4a80 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-11-02 19:02:38 +08:00
奔跑的面条
7e59d8d36c docs: 修改链接地址 2022-11-02 09:57:28 +08:00
奔跑的面条
8241077495 update README.md.
Signed-off-by: 奔跑的面条 <1262327911@qq.com>
2022-10-29 12:09:36 +00:00
奔跑的面条
82b29a2f8b docs: 优化说明文档 2022-10-29 19:57:02 +08:00
奔跑的面条
b789d80f98 fix: 修改主页说明 2022-10-29 19:51:33 +08:00
奔跑的面条
a8c80e2366 docs: 修改主页说明 2022-10-29 19:50:30 +08:00
奔跑的面条
bdbdd37789 build: 升级版本到1.1.3 2022-10-15 17:17:34 +08:00
奔跑的面条
c8fb5b9152 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-10-15 17:12:13 +08:00
奔跑的面条
aef155e039 fix: 修复组件导入数据错乱的问题 2022-10-09 16:37:30 +08:00
奔跑的面条
443573455b Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-10-09 09:28:38 +08:00
奔跑的面条
d811ab7dfa build: 撤回错误版本号 2022-10-08 21:12:58 +08:00
奔跑的面条
5f79ab6e6d build: 升级版本到1.1.2 2022-10-08 21:12:27 +08:00
奔跑的面条
502edbca5d Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-10-08 21:05:48 +08:00
奔跑的面条
1a04267cb7 build: 升级版本到1.1.1 2022-10-08 20:59:55 +08:00
奔跑的面条
9c2c1bdfa1 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-10-08 20:59:25 +08:00
奔跑的面条
72e93f3768 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-09-27 20:16:07 +08:00
奔跑的面条
e6f2066d42 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-09-22 14:15:00 +08:00
奔跑的面条
2812c39524 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-09-21 19:54:29 +08:00
奔跑的面条
491485856e Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-09-19 20:46:37 +08:00
奔跑的面条
abde7e176d Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-09-19 20:13:50 +08:00
奔跑的面条
bab8faadee add default pipeline template yaml 2022-09-19 11:58:32 +00:00
奔跑的面条
427d72fb8b Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-09-18 16:48:28 +08:00
奔跑的面条
dc5b20a329 build: 升级版本到1.1.0 2022-09-18 16:33:26 +08:00
奔跑的面条
4cb934eef3 Merge branch 'dev' of https://gitee.com/MTrun/go-view 2022-09-18 16:32:34 +08:00
奔跑的面条
35e8cea0b5 docs: 更新已完成图表说明 2022-09-17 23:00:51 +08:00
44 changed files with 1128 additions and 588 deletions

185
README.md
View File

@@ -1,30 +1,89 @@
## 总览
#### 总览
![logo](readme/logo-t-y.png)
<p align="center">
<img src="readme/logo-t-y.png" alt="go-view" />
</p>
GoView 是一个高效的拖拽式低代码数据可视化开发平台,将图表或页面元素封装为基础组件,无需编写代码即可制作数据大屏,减少心智负担。
<h4 align="center">开源、精美、便捷的「数据可视化」低代码开发平台</h4>
### 😶 纯 **前端** 分支: **`master`**
#### 长期赞助商
### 👻 携带 **后端** 请求分支: **`master-fetch`**
<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.qeasy.cloud/"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/qyy-banner.png" alt="go-view" style="width: 250px;" width="250px"/>
</a>
<span> &nbsp;</span>
<a
href="http://doc.zyplayer.com/#/integrate/zyplayer-doc?utm=goview"
target="_blank"
style="
padding: 10px 20px;
display: inline-block;
border-radius: 10px;
background: #f9f9f9;
">
<img src="readme/sponsors/zyplayer-banner.png" alt="go-view" style="width: 250px;" width="250px"/>
</a>
</div>
</div>
### 📚 GoView **文档** 地址:[http://www.mtruning.club:81/](http://www.mtruning.club:81/)
#### 😶 **纯前端** 分支: **`master`**
项目纯前端-Demo 地址:[https://www.mtruning.club](https://www.mtruning.club)
#### 👻 携带 **后端** 请求分支: **`master-fetch`**
项目带后端-Demo 地址:[后端 Demo 地址](http://1.117.240.165:8080/goview/#/login)
#### 📚 GoView **文档** 地址:[https://www.mtruning.club/](https://www.mtruning.club/)
文档-在线地址:[http://www.mtruning.club:81/](http://www.mtruning.club:81/)
项目纯前端-Demo 地址:[https://vue.mtruning.club/](https://vue.mtruning.club/)
文档-源码地址:[https://gitee.com/MTrun/go-view-doc](https://gitee.com/MTrun/go-view-doc)
项目带后端-Demo 地址:[https://demo.mtruning.club/](https://demo.mtruning.club/)
### 🤯 后端项目
Cloud IDE 代码在线预览地址:[https://idegitee.com/dromara/go-view](https://idegitee.com/dromara/go-view)
后端项目 gitee 地址:[https://gitee.com/MTrun/go-view-serve](https://gitee.com/MTrun/go-view-serve)
#### 🤯 后端项目看这里!
接口说明地址:[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)
后端地址(社区实现,仅供参考):
技术点:
- `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)
- `接口文档`[https://docs.apipost.cn](https://docs.apipost.cn/preview/5aa85d10a59d66ce/ddb813732007ad2b?target_id=84dbc5b0-158f-4bcb-8f74-793ac604ada3) (不是最新, 以前端代码为准)
#### 整体介绍
- 框架:基于 `Vue3` 框架编写,使用 `hooks` 写法抽离部分逻辑,使代码结构更加清晰;
@@ -36,17 +95,34 @@ GoView 是一个高效的拖拽式低代码数据可视化开发平台,将图
- 封装:项目进行了详细的工具类封装如:路由、存储、加/解密、文件处理、主题、NaiveUI 全局方法、组件等
- 入选 NaiveUI 社区精选资源推荐:[查看 NaiveUI 推荐列表](https://www.naiveui.com/zh-CN/light/docs/community)
说明文档:
![说明文档](readme/go-view-doc.png)
工作台:
![项目截图](readme/go-view-canvas.png)
![工作台](readme/go-view-canvas.png)
请求配置:
![项目截图](readme/go-view-fetch.png)
![请求配置](readme/go-view-fetch.png)
数据过滤:
![项目截图](readme/go-view-filter.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-color.png)
亮白主题:
![亮白主题](readme/go-view-theme.png)
主要技术栈为:
@@ -66,14 +142,17 @@ GoView 是一个高效的拖拽式低代码数据可视化开发平台,将图
已完成图表:
| 分类 | 名称 | 名称 | 名称 |
| ------ | ---------------- | ---------------- | -------- |
| 图表 | 柱状图 | 横向柱状图 | 折线图 |
| \* | 单/多 折线面积图 | 饼图 | 水球图 |
| \* | 环形图 | NaiveUI 多种进度 | 🤠 |
| 信息 | 文字 | 图 | 😶 |
| 列表 | 滚动排名列表 | 滚动表格 | 🤓 |
| 小组件 | 边框-01~13 | 装饰-01~05 | 数字翻牌 |
| 分类 | 名称 | 名称 | 名称 | 名称 |
| ------ | ---------------- | ---------- | -------------- | ------------------------ |
| 图表 | 柱状图 | 横向柱状图 | 折线图 | 单/多 折线面积图(渐变色) |
| \* | 饼图 | 环形图 | 水球图 | 雷达图 |
| \* | NaiveUI 多种进度 | 散点图 | 对数回归散点图 | 热力图 |
| \* | 漏斗图 | 中国地图 | 高德地 | 🦊 |
| 信息 | 文字 | 渐变文字 | 词云 | 嵌套网页 |
| \* | 图片 | 视频 | 😺 | 🐯 |
| 列表 | 滚动排名列表 | 滚动表格 | 🐮 | 🐐 |
| 小组件 | 边框-01~13 | 装饰-01~05 | 数字翻牌 | 通用时间 |
| \* | 数字计数 | 倒计时 | 时钟 | 🦁 |
## 浏览器支持
@@ -81,52 +160,7 @@ GoView 是一个高效的拖拽式低代码数据可视化开发平台,将图
## 安装
本项目采用` pnpm` 进行包管理
```shell
#建议使用 nrm 切换到淘宝源 https://registry.npmmirror.com/
#pnpm
pnpm install
#yarn
yarn install
#npm
npm install
```
## 启动
```shell
#pnpm
pnpm dev
# npm
npm run dev
#yarn
yarn dev
#Makefile
make dev
```
## 编译
```shell
#pnpm
pnpm run build
# npm
npm run build
#yarn
yarn run build
#Makefile
make dist
```
请查看文档:[https://www.mtruning.club/](https://www.mtruning.club/)
## 代码提交
@@ -142,10 +176,9 @@ make dist
- style: 不影响程序逻辑的代码修改
- chore: 不属于以上类型的其他类型(日常事务)
## 交流
## 交流
QQ 群:1030129384
![QQ群](readme/go-view-qq.png)
QQ 群:663629294
<img width="260px" src="readme/go-view-qq.png" alt="QQ群" style="border-radius: 20px" />
![渲染海报](readme/logo-poster.png)

View File

@@ -1,8 +1,8 @@
{
"name": "go-view",
"version": "1.1.11",
"version": "1.2.7",
"engines": {
"node": ">=16.14 <18.0.0"
"node": ">=12.0"
},
"scripts": {
"dev": "vite --host",

10
preview.yml Normal file
View File

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 70 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,4 +1,4 @@
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
import axios, { AxiosResponse, InternalAxiosRequestConfig, AxiosError } 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: AxiosRequestConfig) => {
(config: InternalAxiosRequestConfig) => {
return config
},
(error: AxiosRequestConfig) => {
(error: AxiosError) => {
Promise.reject(error)
}
)

View File

@@ -163,7 +163,6 @@ export const customizeHttp = (targetParams: RequestConfigType, globalParams: Req
params = translateStr(params)
// form 类型处理
let formData: FormData = new FormData()
formData.set('default', 'defaultData')
// 类型处理
switch (requestParamsBodyType) {

View File

@@ -391,8 +391,12 @@ const visualMap = computed(() => {
// 监听legend color颜色改变type = scroll的颜色
watch(() => legend.value && legend.value.textStyle.color, (newVal) => {
if (legend.value && newVal) {
legend.value.pageTextStyle.color = newVal
}
if (!legend.value.pageTextStyle) {
legend.value.pageTextStyle = { color: newVal }
} else {
legend.value.pageTextStyle.color = newVal
}
}
}, {
immediate: true,
deep: true,

View File

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

View File

@@ -90,12 +90,12 @@ export const useChartDataFetch = (
// 普通初始化与组件交互处理监听
watch(
() => targetComponent.request,
() => targetComponent.request.requestParams,
() => {
fetchFn()
},
{
immediate: true,
immediate: false,
deep: true
}
)
@@ -105,7 +105,11 @@ export const useChartDataFetch = (
// 单位
const unit = targetInterval && targetInterval.value ? targetUnit.value : globalUnit.value
// 开启轮询
if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
if (time) {
fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
} else {
fetchFn()
}
}
// eslint-disable-next-line no-empty
} catch (error) {
@@ -114,10 +118,11 @@ export const useChartDataFetch = (
}
if (isPreview()) {
// 判断是否是数据池类型
targetComponent.request.requestDataType === RequestDataTypeEnum.Pond
? addGlobalDataInterface(targetComponent, useChartEditStore, updateCallback || echartsUpdateHandle)
: requestIntervalFn()
} else {
requestIntervalFn()
}
return { vChartRef }
}

View File

@@ -1,4 +1,4 @@
import { toRaw } from 'vue'
import { toRaw, watch, computed, ComputedRef } from 'vue'
import { customizeHttp } from '@/api/http'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@@ -20,7 +20,7 @@ const mittDataPondMap = new Map<string, DataPondMapType[]>()
// 创建单个数据项轮询接口
const newPondItemInterval = (
requestGlobalConfig: RequestGlobalConfigType,
requestDataPondItem: RequestDataPondItemType,
requestDataPondItem: ComputedRef<RequestDataPondItemType>,
dataPondMapItem?: DataPondMapType[]
) => {
if (!dataPondMapItem) return
@@ -31,8 +31,7 @@ const newPondItemInterval = (
// 请求
const fetchFn = async () => {
try {
const res = await customizeHttp(toRaw(requestDataPondItem.dataPondRequestConfig), toRaw(requestGlobalConfig))
const res = await customizeHttp(toRaw(requestDataPondItem.value.dataPondRequestConfig), toRaw(requestGlobalConfig))
if (res) {
try {
// 遍历更新回调函数
@@ -49,19 +48,32 @@ const newPondItemInterval = (
}
}
watch(
() => requestDataPondItem.value.dataPondRequestConfig.requestParams.Params,
() => {
fetchFn()
},
{
immediate: false,
deep: true
}
)
// 立即调用
fetchFn()
const targetInterval = requestDataPondItem.dataPondRequestConfig.requestInterval
const targetUnit = requestDataPondItem.dataPondRequestConfig.requestIntervalUnit
const targetInterval = requestDataPondItem.value.dataPondRequestConfig.requestInterval
const targetUnit = requestDataPondItem.value.dataPondRequestConfig.requestIntervalUnit
const globalRequestInterval = requestGlobalConfig.requestInterval
const globalUnit = requestGlobalConfig.requestIntervalUnit
// 定时时间
const time = targetInterval ? targetInterval : globalRequestInterval
const time = targetInterval ? targetInterval : globalRequestInterval
// 单位
const unit = targetInterval ? targetUnit : globalUnit
const unit = targetInterval ? targetUnit : globalUnit
// 开启轮询
if (time) fetchInterval = setInterval(fetchFn, intervalUnitHandle(time, unit))
}
@@ -96,13 +108,16 @@ export const useChartDataPondFetch = () => {
}
// 初始化数据池
const initDataPond = (requestGlobalConfig: RequestGlobalConfigType) => {
const { requestDataPond } = requestGlobalConfig
const initDataPond = (useChartEditStore: ChartEditStoreType) => {
const { requestGlobalConfig } = useChartEditStore()
const chartEditStore = useChartEditStore()
// 根据 mapId 查找对应的数据池配置
for (let pondKey of mittDataPondMap.keys()) {
const requestDataPondItem = requestDataPond.find(item => item.dataPondId === pondKey)
const requestDataPondItem = computed(() => {
return requestGlobalConfig.requestDataPond.find(item => item.dataPondId === pondKey)
}) as ComputedRef<RequestDataPondItemType>
if (requestDataPondItem) {
newPondItemInterval(requestGlobalConfig, requestDataPondItem, mittDataPondMap.get(pondKey))
newPondItemInterval(chartEditStore.requestGlobalConfig, requestDataPondItem, mittDataPondMap.get(pondKey))
}
}
}

View File

@@ -1,4 +1,5 @@
import { toRefs } from 'vue'
import { isPreview } from '@/utils'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@@ -12,6 +13,7 @@ export const useChartInteract = (
param: { [T: string]: any },
interactEventOn: string
) => {
if (!isPreview()) return
const chartEditStore = useChartEditStore()
const { interactEvents } = chartConfig.events
const fnOnEvent = interactEvents.filter(item => {
@@ -20,20 +22,37 @@ export const useChartInteract = (
if (fnOnEvent.length === 0) return
fnOnEvent.forEach(item => {
const index = chartEditStore.fetchTargetIndex(item.interactComponentId)
if (index === -1) return
const { Params, Header } = toRefs(chartEditStore.componentList[index].request.requestParams)
Object.keys(item.interactFn).forEach(key => {
if (Params.value[key]) {
Params.value[key] = param[item.interactFn[key]]
}
if (Header.value[key]) {
Header.value[key] = param[item.interactFn[key]]
}
})
const globalConfigPindAprndex = chartEditStore.requestGlobalConfig.requestDataPond.findIndex(cItem =>
cItem.dataPondId === item.interactComponentId
)
if (globalConfigPindAprndex !== -1) {
const { Params, Header } = toRefs(chartEditStore.requestGlobalConfig.requestDataPond[globalConfigPindAprndex].dataPondRequestConfig.requestParams)
Object.keys(item.interactFn).forEach(key => {
if (key in Params.value) {
Params.value[key] = param[item.interactFn[key]]
}
if (key in Header.value) {
Header.value[key] = param[item.interactFn[key]]
}
})
} else {
const index = chartEditStore.fetchTargetIndex(item.interactComponentId)
if (index === -1) return
const { Params, Header } = toRefs(chartEditStore.componentList[index].request.requestParams)
Object.keys(item.interactFn).forEach(key => {
if (key in Params.value) {
Params.value[key] = param[item.interactFn[key]]
}
if (key in Header.value) {
Header.value[key] = param[item.interactFn[key]]
}
})
}
})
}
// 联动事件触发的 type 变更时,清除当前绑定内容
export const clearInteractEvent = (chartConfig: CreateComponentType) => {

View File

@@ -1,218 +1,218 @@
import throttle from 'lodash/throttle'
// 拆出来是为了更好的分离单独复用
// * 屏幕缩放适配(两边留白)
export const usePreviewFitScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
// 当前屏幕宽高比
const currentRate = parseFloat(
(window.innerWidth / window.innerHeight).toFixed(5)
)
if (scaleDom) {
if (currentRate > baseProportion) {
// 表示更宽
scale.width = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
scale.height = parseFloat((window.innerHeight / baseHeight).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
} else {
// 表示更高
scale.height = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
scale.width = parseFloat((window.innerWidth / baseWidth).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
}
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 改变窗口大小重新绘制
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * X轴撑满Y轴滚动条
export const usePreviewScrollYScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
if (scaleDom) {
scale.height = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
scale.width = parseFloat((window.innerWidth / baseWidth).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 改变窗口大小重新绘制
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * Y轴撑满X轴滚动条
export const usePreviewScrollXScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
height: 1,
width: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
if (scaleDom) {
scale.width = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
scale.height = parseFloat((window.innerHeight / baseHeight).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 改变窗口大小重新绘制
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * 变形内容,宽高铺满
export const usePreviewFullScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
const calcRate = () => {
if (scaleDom) {
scale.width = parseFloat((window.innerWidth / width).toFixed(5))
scale.height = parseFloat((window.innerHeight / height).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 改变窗口大小重新绘制
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
import throttle from 'lodash/throttle'
// 拆出来是为了更好的分离单独复用
// * 屏幕缩放适配(两边留白)
export const usePreviewFitScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
// 当前屏幕宽高比
const currentRate = parseFloat(
(window.innerWidth / window.innerHeight).toFixed(5)
)
if (scaleDom) {
if (currentRate > baseProportion) {
// 表示更宽
scale.width = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
scale.height = parseFloat((window.innerHeight / baseHeight).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
} else {
// 表示更高
scale.height = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
scale.width = parseFloat((window.innerWidth / baseWidth).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
}
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 卸载监听
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * X轴撑满Y轴滚动条
export const usePreviewScrollYScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
if (scaleDom) {
scale.height = parseFloat(((window.innerWidth / baseProportion) / baseHeight).toFixed(5))
scale.width = parseFloat((window.innerWidth / baseWidth).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 卸载监听
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * Y轴撑满X轴滚动条
export const usePreviewScrollXScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 画布尺寸px
const baseWidth = width
const baseHeight = height
// * 默认缩放值
const scale = {
height: 1,
width: 1,
}
// * 需保持的比例
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
const calcRate = () => {
if (scaleDom) {
scale.width = parseFloat(((window.innerHeight * baseProportion) / baseWidth).toFixed(5))
scale.height = parseFloat((window.innerHeight / baseHeight).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 卸载监听
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}
// * 变形内容,宽高铺满
export const usePreviewFullScale = (
width: number,
height: number,
scaleDom: HTMLElement | null,
callback?: (scale: {
width: number;
height: number;
}) => void
) => {
// * 默认缩放值
const scale = {
width: 1,
height: 1,
}
const calcRate = () => {
if (scaleDom) {
scale.width = parseFloat((window.innerWidth / width).toFixed(5))
scale.height = parseFloat((window.innerHeight / height).toFixed(5))
scaleDom.style.transform = `scale(${scale.width}, ${scale.height})`
if (callback) callback(scale)
}
}
const resize = throttle(() => {
calcRate()
}, 200)
// * 改变窗口大小重新绘制
const windowResize = () => {
window.addEventListener('resize', resize)
}
// * 卸载监听
const unWindowResize = () => {
window.removeEventListener('resize', resize)
}
return {
calcRate,
windowResize,
unWindowResize,
}
}

View File

@@ -1,5 +1,5 @@
export default {
create_btn: 'Creat',
create_btn: 'Create',
create_tip: 'Please select a content for development',
project: 'Project',
my: 'My',

View File

@@ -7,6 +7,22 @@
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- 中心标题 -->
<SettingItemBox v-if="config.title" name="标题">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="config.title.textStyle.color"></n-color-picker>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number
v-model:value="config.title.textStyle.fontSize"
:min="0"
:step="1"
size="small"
placeholder="字体大小"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- Echarts 全局设置 -->
<SettingItemBox name="进度条">
<SettingItem name="颜色">
@@ -31,24 +47,8 @@
></n-color-picker>
</SettingItem>
</SettingItemBox>
<!-- 中心标题 -->
<SettingItemBox v-if="config.title" name="标题">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="config.title.textStyle.color"></n-color-picker>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number
v-model:value="config.title.textStyle.fontSize"
:min="0"
:step="1"
size="small"
placeholder="字体大小"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- 其他样式 -->
<SettingItemBox name="轨道样式">
<SettingItemBox name="轨道">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="item.data[1].itemStyle.color"></n-color-picker>
</SettingItem>
@@ -69,6 +69,18 @@
v-model:value="item.data[1].itemStyle.shadowColor"
></n-color-picker>
</SettingItem>
<SettingItem name="轨道宽度">
<n-select
v-model:value="item.radius[0]"
size="small"
:options="[
{ label: '窄', value: '75%' },
{ label: '中', value: '60%' },
{ label: '宽', value: '45%' },
{ label: '更宽', value: '30%' }
]"
/>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>

View File

@@ -41,7 +41,7 @@ const option = reactive({
const dataHandle = (newData: any) => {
const d = parseFloat(`${newData}`) * 100
let config = props.chartConfig.option
config.title.text = d.toFixed(2) + '%'
config.title.text = `${+d.toFixed(2)}%`
config.series[0].data[0].value[0] = d
config.series[0].data[1].value[0] = 100 - d
option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
@@ -68,7 +68,7 @@ watch(
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: number) => {
let d = parseFloat(`${resData}`) * 100
// @ts-ignore
option.value.title.text = d.toFixed(2) + '%'
option.value.title.text = `${+d.toFixed(2)}%`
// @ts-ignore
option.value.series[0].data[0].value[0] = d
// @ts-ignore

View File

@@ -63,7 +63,7 @@ watch(
() => props.chartConfig.option,
newVal => {
try {
updateDatasetHandler((newVal as OptionType).dataset)
updateDatasetHandler((newVal as any as OptionType).dataset)
} catch (error) {
console.log(error)
}

View File

@@ -4,7 +4,7 @@ import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { chartInitConfig } from '@/settings/designSetting'
import { COMPONENT_INTERACT_EVENT_KET } from '@/enums/eventEnum'
import { interactActions, ComponentInteractEventEnum } from './interact'
import { interactActions, ComponentInteractEventEnum, DefaultTypeEnum, DifferUnitEnum } from './interact'
import { InputsDateConfig } from './index'
export const option = {
@@ -12,9 +12,14 @@ export const option = {
[COMPONENT_INTERACT_EVENT_KET]: ComponentInteractEventEnum.DATE,
// 下拉展示
isPanel: 0,
dataset: dayjs().valueOf(),
differValue: 0
// 默认值
dataset: dayjs().valueOf() as number | number[] | null,
// 默认值类型
defaultType: DefaultTypeEnum.STATIC,
// 动态默认值偏移单位
differUnit: [DifferUnitEnum.DAY, DifferUnitEnum.DAY],
// 动态默认值偏移值
differValue: [0, 0]
}
export default class Config extends PublicConfigClass implements CreateComponentType {

View File

@@ -8,39 +8,67 @@
<collapse-item name="时间配置" :expanded="true">
<setting-item-box name="基础">
<setting-item name="类型">
<n-select v-model:value="optionData.componentInteractEventKey" size="small" :options="datePickerTypeOptions" />
<n-select v-model:value="optionData.componentInteractEventKey" size="small" :options="datePickerTypeOptions"
@update:value="datePickerTypeUpdate"/>
</setting-item>
</setting-item-box>
<setting-item-box name="默认值" :alone="true">
<n-date-picker size="small" v-model:value="optionData.dataset" :type="optionData.componentInteractEventKey" />
</setting-item-box>
<setting-item-box name="默认值">
<setting-item name="类型">
<n-select v-model:value="optionData.defaultType" size="small" :options="defaultTypeOptions"
@update:value="defaultTypeUpdate" />
</setting-item>
<setting-item-box :alone="true">
</setting-item-box>
<setting-item-box v-if="optionData.defaultType === DefaultTypeEnum.STATIC" :alone="true">
<setting-item name="静态默认值">
<n-date-picker size="small" clearable v-model:value="optionData.dataset" :type="optionData.componentInteractEventKey" />
</setting-item>
</setting-item-box>
<setting-item-box v-if="optionData.defaultType === DefaultTypeEnum.DYNAMIC" >
<template #name>
<n-text>动态</n-text>
<n-text></n-text>
<n-tooltip trigger="hover">
<template #trigger>
<n-icon size="21" :depth="3">
<help-outline-icon></help-outline-icon>
</n-icon>
</template>
<n-text>动态值不为0时默认值:取当天时间相加当前值</n-text>
<span>打开页面时浏览器操作系统的系统时间+偏移量(单位)</span>
</n-tooltip>
</template>
<n-input-number v-model:value="optionData.differValue" class="input-num-width" size="small" :min="-40" :max="40">
<template #suffix> </template>
</n-input-number>
<setting-item :name="differValueName">
<n-input-number v-model:value="optionData.differValue[0]" class="input-num-width" size="small">
<template #suffix>
{{DifferUnitObject[optionData.differUnit[0]]}}
</template>
</n-input-number>
</setting-item>
<setting-item :name="differUnitName">
<n-select v-model:value="optionData.differUnit[0]" size="small" :options="differUnitOptions" />
</setting-item>
<setting-item v-if="isRange" name="结束值动态偏移量">
<n-input-number v-model:value="optionData.differValue[1]" class="input-num-width" size="small">
<template #suffix>
{{DifferUnitObject[optionData.differUnit[1]]}}
</template>
</n-input-number>
</setting-item>
<setting-item v-if="isRange" name="结束值偏移单位">
<n-select v-model:value="optionData.differUnit[1]" size="small" :options="differUnitOptions" />
</setting-item>
</setting-item-box>
</collapse-item>
</template>
<script lang="ts" setup>
import { PropType } from 'vue'
import { PropType, computed } from 'vue'
import { icon } from '@/plugins'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option } from './config'
import { ComponentInteractEventEnum } from './interact'
import { ComponentInteractEventEnum, DefaultTypeEnum, DifferUnitEnum, DifferUnitObject } from './interact'
import dayjs from "dayjs";
const { HelpOutlineIcon } = icon.ionicons5
@@ -100,4 +128,87 @@ const datePickerTypeOptions = [
value: ComponentInteractEventEnum.QUARTER_RANGE
}
]
const defaultTypeOptions = [
{
label: '静态',
value: DefaultTypeEnum.STATIC
},
{
label: '动态',
value: DefaultTypeEnum.DYNAMIC
},
{
label: '无',
value: DefaultTypeEnum.NONE
}
]
const differUnitOptions = [
// ManipulateType
{
value: DifferUnitEnum.DAY,
label: DifferUnitObject[DifferUnitEnum.DAY]
},
{
value: DifferUnitEnum.WEEK,
label: DifferUnitObject[DifferUnitEnum.WEEK]
},
{
value: DifferUnitEnum.MONTH,
label: DifferUnitObject[DifferUnitEnum.MONTH]
},
{
value: DifferUnitEnum.QUARTER,
label: DifferUnitObject[DifferUnitEnum.QUARTER]
},
{
value: DifferUnitEnum.YEAR,
label: DifferUnitObject[DifferUnitEnum.YEAR]
},
{
value: DifferUnitEnum.HOUR,
label: DifferUnitObject[DifferUnitEnum.HOUR]
},
{
value: DifferUnitEnum.MINUTE,
label: DifferUnitObject[DifferUnitEnum.MINUTE]
},
{
value: DifferUnitEnum.SECOND,
label: DifferUnitObject[DifferUnitEnum.SECOND]
},
{
value: DifferUnitEnum.MILLISECOND,
label: DifferUnitObject[DifferUnitEnum.MILLISECOND]
}
]
const isRange = computed(() => {
return props.optionData.componentInteractEventKey.endsWith('range')
})
const differValueName = computed(() => {
return isRange.value ? '开始值动态偏移量' : '动态偏移量'
})
const differUnitName = computed(() => {
return isRange.value ? '开始值偏移单位' : '偏移单位'
})
const datePickerTypeUpdate = () => {
props.optionData.dataset = isRange.value ? [dayjs().valueOf(), dayjs().valueOf()] : dayjs().valueOf()
}
const defaultTypeUpdate = (v: string) => {
if (v === DefaultTypeEnum.STATIC) {
datePickerTypeUpdate()
} else {
// DefaultTypeEnum.
props.optionData.dataset = null
}
}
</script>

View File

@@ -1,6 +1,7 @@
<template>
<n-date-picker
v-model:value="option.dataset"
clearable
:panel="!!chartConfig.option.isPanel"
:type="chartConfig.option.componentInteractEventKey"
:style="`width:${w}px;`"
@@ -9,13 +10,15 @@
</template>
<script setup lang="ts">
import { PropType, toRefs, ref, shallowReactive, watch } from 'vue'
import dayjs from 'dayjs'
import { computed, PropType, ref, shallowReactive, toRefs, watch } from 'vue'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useChartInteract } from '@/hooks'
import { InteractEventOn } from '@/enums/eventEnum'
import { ComponentInteractParamsEnum } from './interact'
import {ComponentInteractEventEnum, ComponentInteractParamsEnum, DefaultTypeEnum} from './interact'
import dayjs, {ManipulateType} from 'dayjs'
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
const props = defineProps({
chartConfig: {
@@ -31,61 +34,107 @@ const option = shallowReactive({
dataset: props.chartConfig.option.dataset
})
const isRange = computed(() => {
return props.chartConfig.option.componentInteractEventKey.endsWith('range')
})
// 监听事件改变
const onChange = (v: number | number[]) => {
if (v instanceof Array) {
const onChange = (v: number | number[] | null) => {
if (isRange.value) {
let dateStart = null
let dateEnd = null
let daterange = null
if(v instanceof Array){
dateStart = v[0]
dateEnd = v[1]
daterange = `${v[0]}-${v[1]}`
}
// 存储到联动数据
useChartInteract(
props.chartConfig,
useChartEditStore,
{
[ComponentInteractParamsEnum.DATE_START]: v[0] || dayjs().valueOf(),
[ComponentInteractParamsEnum.DATE_END]: v[1] || dayjs().valueOf(),
[ComponentInteractParamsEnum.DATE_RANGE]: `${v[0] || dayjs().valueOf()}-${v[1] || dayjs().valueOf()}`
},
InteractEventOn.CHANGE
props.chartConfig,
useChartEditStore,
{
[ComponentInteractParamsEnum.DATE_START]: dateStart,
[ComponentInteractParamsEnum.DATE_END]: dateEnd,
[ComponentInteractParamsEnum.DATE_RANGE]: daterange
},
InteractEventOn.CHANGE
)
} else {
// 存储到联动数据
useChartInteract(
props.chartConfig,
useChartEditStore,
{ [ComponentInteractParamsEnum.DATE]: v || dayjs().valueOf() },
InteractEventOn.CHANGE
props.chartConfig,
useChartEditStore,
{ [ComponentInteractParamsEnum.DATE]: v },
InteractEventOn.CHANGE
)
}
}
watch(
() => props.chartConfig.option.dataset,
(newData: number | number[]) => {
option.dataset = newData
// 关联目标组件首次请求带上默认内容
onChange(newData)
},
{
immediate: true
const getDiffDate = (type: ComponentInteractEventEnum, date: dayjs.Dayjs) => {
// 注册 quarterOfYear 插件
dayjs.extend(quarterOfYear)
switch (type) {
case ComponentInteractEventEnum.DATE:
case ComponentInteractEventEnum.DATE_RANGE:
date = date.startOf('day')
break
case ComponentInteractEventEnum.MONTH:
case ComponentInteractEventEnum.MONTH_RANGE:
date = date.startOf('month')
break
case ComponentInteractEventEnum.YEAR:
case ComponentInteractEventEnum.YEAR_RANGE:
date = date.startOf('year')
break
case ComponentInteractEventEnum.QUARTER:
case ComponentInteractEventEnum.QUARTER_RANGE:
date = date.startOf('quarter')
break
default:
break
}
)
return date
}
// 手动更新
watch(
() => props.chartConfig.option.differValue,
(newData: number) => {
if (props.chartConfig.option.differValue === 0) return
if (typeof option.dataset === 'object') {
option.dataset[0] = dayjs().add(newData, 'day').valueOf()
option.dataset[1] = dayjs().add(newData, 'day').valueOf()
} else {
option.dataset = dayjs().add(newData, 'day').valueOf()
() => {
return {
type: props.chartConfig.option.componentInteractEventKey as ComponentInteractEventEnum,
defaultType: props.chartConfig.option.defaultType as string,
differValue: props.chartConfig.option.differValue as number[],
differUnit: props.chartConfig.option.differUnit as ManipulateType[],
dataset: props.chartConfig.option.dataset as number | number[] | null,
};
},
(newData, oldData) => {
const hasTypeChanged = newData.type !== oldData?.type;
const hasDefaultTypeChanged = newData.defaultType !== oldData?.defaultType;
const hasDifferValueChanged = newData.differValue !== oldData?.differValue;
const hasDifferUnitChanged = newData.differUnit !== oldData?.differUnit;
if (hasTypeChanged || hasDefaultTypeChanged || hasDifferValueChanged || hasDifferUnitChanged) {
if (newData.defaultType === DefaultTypeEnum.NONE) {
props.chartConfig.option.dataset = null;
} else if (newData.defaultType === DefaultTypeEnum.DYNAMIC) {
let date = dayjs();
if (isRange.value) {
props.chartConfig.option.dataset = [
getDiffDate(newData.type,date.add(newData.differValue[0], newData.differUnit[0])).valueOf(),
getDiffDate(newData.type,date.add(newData.differValue[1], newData.differUnit[1])).valueOf(),
];
} else {
props.chartConfig.option.dataset = getDiffDate(newData.type,date.add(newData.differValue[0], newData.differUnit[0])).valueOf()
}
}
}
option.dataset = props.chartConfig.option.dataset;
onChange(option.dataset);
},
{
immediate: true,
}
// 关联目标组件首次请求带上默认内容
onChange(newData)
},
{
immediate: true
}
)
);
</script>
<style lang="scss" scoped>

View File

@@ -22,6 +22,37 @@ export enum ComponentInteractParamsEnum {
DATE_RANGE = 'daterange'
}
export enum DefaultTypeEnum {
NONE = "none",
STATIC = "static",
DYNAMIC = "dynamic"
}
export enum DifferUnitEnum {
DAY = 'd',
WEEK = 'w',
MONTH = 'M',
QUARTER = 'Q',
YEAR = 'y',
HOUR = 'h',
MINUTE = 'm',
SECOND = 's',
MILLISECOND = 'ms',
}
export const DifferUnitObject = {
// https://day.js.org/docs/en/manipulate/add
[DifferUnitEnum.DAY]: '天',
[DifferUnitEnum.WEEK]: '周',
[DifferUnitEnum.MONTH]: '月',
[DifferUnitEnum.QUARTER]: '季度',
[DifferUnitEnum.YEAR]: '年',
[DifferUnitEnum.HOUR]: '小时',
[DifferUnitEnum.MINUTE]: '分钟',
[DifferUnitEnum.SECOND]: '秒',
[DifferUnitEnum.MILLISECOND]: '毫秒',
}
const time = [
{
value: ComponentInteractParamsEnum.DATE,

View File

@@ -1,8 +1,11 @@
<template>
<collapse-item name="标签页配置" :expanded="true">
<setting-item-box name="默认值" :alone="true">
<setting-item-box name="标签类型" :alone="true">
<n-select size="small" v-model:value="optionData.tabType" :options="tabTypeOptions" />
</setting-item-box>
<setting-item-box name="默认值" :alone="true">
<n-select size="small" v-model:value="optionData.tabLabel" value-field="label" :options="optionData.dataset" />
</setting-item-box>
</collapse-item>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<n-tabs :type="option.value.tabType" @update:value="onChange">
<n-tabs :type="option.value.tabType" @update:value="onChange" :default-value="option.value.tabLabel">
<n-tab v-for="(item, index) in option.value.dataset" :name="item.label" :key="index"> {{ item.label }} </n-tab>
</n-tabs>
</template>

View File

@@ -1,78 +1,84 @@
@import './config.scss';
@import './function.scss';
@import '../theme.scss';
@mixin go($block) {
$B: $namespace + '-' + $block;
.#{$B} {
@content;
}
}
@mixin goId($block) {
$B: $namespace + '-' + $block;
##{$B} {
@content;
}
}
@mixin deep() {
:deep() {
@content;
}
}
@mixin when($state) {
@at-root {
&.#{$state-prefix + $state} {
@content;
}
}
}
@mixin themeify {
@each $theme-name, $theme-map in $themes {
$theme-map: $theme-map !global;
[data-theme='#{$theme-name}'] & {
@content;
}
}
}
@mixin fetch-theme($param) {
@include themeify {
#{$param}: themed($param);
}
}
@mixin fetch-theme-custom ($key, $value) {
@include themeify {
#{$key}: themed($value);
}
}
//获取背景颜色
@mixin fetch-bg-color($target) {
@include themeify {
background-color: themed($target);
}
}
//获取背景渐变颜色
@mixin background-image($target) {
@include themeify {
background-image: themed($target);
}
}
//设置边框颜色
@mixin fetch-border-color($target) {
@include themeify {
border-color: themed($target);
}
}
@mixin hover-border-color($target) {
@include themeify {
border: 1px solid themed($target);
}
}
@import './config.scss';
@import './function.scss';
@import '../theme.scss';
@mixin go($block) {
$B: $namespace + '-' + $block;
.#{$B} {
@content;
}
}
@mixin dark {
[data-theme='dark'] {
@content;
}
}
@mixin goId($block) {
$B: $namespace + '-' + $block;
##{$B} {
@content;
}
}
@mixin deep() {
:deep() {
@content;
}
}
@mixin when($state) {
@at-root {
&.#{$state-prefix + $state} {
@content;
}
}
}
@mixin themeify {
@each $theme-name, $theme-map in $themes {
$theme-map: $theme-map !global;
[data-theme='#{$theme-name}'] & {
@content;
}
}
}
@mixin fetch-theme($param) {
@include themeify {
#{$param}: themed($param);
}
}
@mixin fetch-theme-custom ($key, $value) {
@include themeify {
#{$key}: themed($value);
}
}
//获取背景颜色
@mixin fetch-bg-color($target) {
@include themeify {
background-color: themed($target);
}
}
//获取背景渐变颜色
@mixin background-image($target) {
@include themeify {
background-image: themed($target);
}
}
//设置边框颜色
@mixin fetch-border-color($target) {
@include themeify {
border-color: themed($target);
}
}
@mixin hover-border-color($target) {
@include themeify {
border: 1px solid themed($target);
}
}

View File

@@ -1,9 +1,15 @@
// 页面全局样式
// 去除高德地图 logo
.amap-logo {
display: none !important;
opacity: 0 !important;
}
.amap-copyright {
opacity: 0 !important;
}
// 页面全局样式
// 去除高德地图 logo
.amap-logo {
display: none !important;
opacity: 0 !important;
}
.amap-copyright {
opacity: 0 !important;
}
[data-theme='dark'] {
body {
background-color: #18181c;
}
}

View File

@@ -131,7 +131,11 @@ const sendHandle = async () => {
loading.value = false
if (res) {
const { data } = res
if (!data && !targetData.value.filter) window['$message'].warning('您的数据不符合默认格式,请配置过滤器!')
if (!data && !targetData.value.filter) {
window['$message'].warning('您的数据不符合默认格式,请配置过滤器!')
showMatching.value = true
return
}
targetData.value.option.dataset = newFunctionHandle(data, res, targetData.value.filter)
showMatching.value = true
return

View File

@@ -117,7 +117,11 @@ const sendHandle = async () => {
const res = await customizeHttp(toRaw(targetData.value.request), toRaw(chartEditStore.getRequestGlobalConfig))
loading.value = false
if (res) {
if (!res?.data && !targetData.value.filter) window['$message'].warning('您的数据不符合默认格式,请配置过滤器!')
if (!res?.data && !targetData.value.filter) {
window['$message'].warning('您的数据不符合默认格式,请配置过滤器!')
showMatching.value = true
return
}
targetData.value.option.dataset = newFunctionHandle(res?.data, res, targetData.value.filter)
showMatching.value = true
return

View File

@@ -58,7 +58,7 @@
<help-outline-icon></help-outline-icon>
</n-icon>
</template>
<n-text>不支持静态组件</n-text>
<n-text>不支持静态组件支持组件公共APi</n-text>
</n-tooltip>
</template>
<n-select
@@ -89,7 +89,7 @@
</n-table>
</setting-item-box>
<n-tag :bordered="false" type="primary"> 关联目标组件请求参数 </n-tag>
<n-tag :bordered="false" type="primary"> 关联目标请求参数 </n-tag>
<setting-item-box
:name="requestParamsItem"
@@ -125,7 +125,7 @@ import { VNodeChild, computed } from 'vue'
import { SelectOption, SelectGroupOption } from 'naive-ui'
import { SettingItemBox, SettingItem, CollapseItem } from '@/components/Pages/ChartItemSetting'
import { CreateComponentType, CreateComponentGroupType, ChartFrameEnum } from '@/packages/index.d'
import { RequestParamsTypeEnum } from '@/enums/httpEnum'
import { RequestParamsTypeEnum, RequestDataTypeEnum } from '@/enums/httpEnum'
import { InteractEventOn, COMPONENT_INTERACT_EVENT_KET } from '@/enums/eventEnum'
import { icon } from '@/plugins'
import noData from '@/assets/images/canvas/noData.png'
@@ -154,6 +154,11 @@ const option = computed(() => {
// 绑定组件数据 request
const fnGetRequest = (id: string | undefined, key: RequestParamsTypeEnum) => {
if (!id) return {}
const globalConfigPindApr = chartEditStore.requestGlobalConfig.requestDataPond.find(item => {
return item.dataPondId === id
})?.dataPondRequestConfig.requestParams
if (globalConfigPindApr) return globalConfigPindApr[key]
return chartEditStore.componentList[chartEditStore.fetchTargetIndex(id)]?.request.requestParams[key]
}
@@ -178,12 +183,10 @@ const fnEventsOptions = (): Array<SelectOption | SelectGroupOption> => {
iter: Array<CreateComponentType | CreateComponentGroupType>,
val: CreateComponentType | CreateComponentGroupType
) => {
if (val.groupList && val.groupList.length > 0) {
iter.push(val)
} else {
if (!val.groupList && val.request.requestDataType === RequestDataTypeEnum.AJAX && val.request.requestUrl) {
iter.push(val)
}
return val.groupList ? [...iter, ...fnFlattern(val.groupList)] : iter
return val.groupList && val.groupList.length > 0 ? [...iter, ...fnFlattern(val.groupList)] : iter
},
[]
)
@@ -203,18 +206,26 @@ const fnEventsOptions = (): Array<SelectOption | SelectGroupOption> => {
const mapOptionList = filterOptionList.map(item => ({
id: item.id,
title: item.chartConfig.title,
disabled: false
disabled: false,
type: 'componentList'
}))
const requestDataPond = chartEditStore.requestGlobalConfig.requestDataPond.map(item => ({
id: item.dataPondId,
title: item.dataPondName,
disabled: false,
type: 'requestDataPond'
}))
const tarArr = requestDataPond.concat(mapOptionList)
targetData.value.events.interactEvents?.forEach(iaItem => {
mapOptionList.forEach(optionItem => {
tarArr.forEach(optionItem => {
if (optionItem.id === iaItem.interactComponentId) {
optionItem.disabled = true
}
})
})
return mapOptionList
return tarArr
}
// 新增模块

View File

@@ -159,9 +159,11 @@ const dragCanvas = (e: any) => {
const canvasBox = () => {
const layoutDom = document.getElementById('go-chart-edit-layout')
if (layoutDom) {
// 此处减去滚动条的宽度和高度
const scrollW = 20
return {
height: layoutDom.clientHeight - 25,
width: layoutDom.clientWidth
height: layoutDom.clientHeight - scrollW,
width: layoutDom.clientWidth - scrollW
}
}
return {

View File

@@ -58,7 +58,7 @@ const previewHandle = () => {
// 发布
const sendHandle = () => {
goDialog({
message: '想体验发布功能,请前往 master-fetch 分支查看: https://gitee.com/MTrun/go-view/tree/master-fetch',
message: '想体验发布功能,请前往查看: https://demo.mtruning.club/#/login。源码需切换到master-fetch 分支。',
positiveText: '了然',
closeNegativeText: true,
onPositiveCallback: () => {}

View File

@@ -74,7 +74,7 @@ const themeColor = computed(() => {
// 组件渲染结束初始化数据池
clearMittDataPondMap()
onMounted(() => {
initDataPond(chartEditStore.requestGlobalConfig)
initDataPond(useChartEditStore)
})
</script>

View File

@@ -12,7 +12,44 @@ export const useScale = (localStorageInfo: ChartEditStorageType) => {
const height = ref(localStorageInfo.editCanvasConfig.height)
const scaleRef = ref({ width: 1, height: 1 })
provide(SCALE_KEY, scaleRef);
provide(SCALE_KEY, scaleRef)
// 监听鼠标滚轮 +ctrl 键
const useAddWheelHandle = (removeEvent: Function) => {
addEventListener(
'wheel',
(e: any) => {
if (window?.$KeyboardActive?.ctrl) {
e.preventDefault()
e.stopPropagation()
removeEvent()
const transform = previewRef.value?.style.transform
const regRes = transform.match(/scale\((\d+\.?\d*)*/) as RegExpMatchArray
const width = regRes[1]
const previewBoxDom = document.querySelector('.go-preview') as HTMLElement
const entityDom = document.querySelector('.go-preview-entity') as HTMLElement
if (previewBoxDom) {
previewBoxDom.style.overflow = 'unset'
previewBoxDom.style.position = 'absolute'
previewBoxDom.style.top = '10px'
previewBoxDom.style.left = '20px'
}
if (entityDom) {
entityDom.style.overflow = 'unset'
}
if (e.wheelDelta > 0) {
const resNum = parseFloat(Number(width).toFixed(2))
previewRef.value.style.transform = `scale(${resNum > 5 ? 5 : resNum + 0.1})`
} else {
const resNum = parseFloat(Number(width).toFixed(2))
previewRef.value.style.transform = `scale(${resNum < 0.2 ? 0.2 : resNum - 0.1})`
}
}
},
{ passive: false }
)
}
const updateScaleRef = (scale: { width: number; height: number }) => {
// 这里需要解构保证赋值给scaleRef的为一个新对象
@@ -23,74 +60,82 @@ export const useScale = (localStorageInfo: ChartEditStorageType) => {
// 屏幕适配
onMounted(() => {
switch (localStorageInfo.editCanvasConfig.previewScaleType) {
case PreviewScaleEnum.FIT: (() => {
const { calcRate, windowResize, unWindowResize } = usePreviewFitScale(
width.value as number,
height.value as number,
previewRef.value,
updateScaleRef
)
calcRate()
windowResize()
onUnmounted(() => {
unWindowResize()
})
})()
break;
case PreviewScaleEnum.SCROLL_Y: (() => {
const { calcRate, windowResize, unWindowResize } = usePreviewScrollYScale(
width.value as number,
height.value as number,
previewRef.value,
(scale) => {
const dom = entityRef.value
dom.style.width = `${width.value * scale.width}px`
dom.style.height = `${height.value * scale.height}px`
updateScaleRef(scale)
}
)
calcRate()
windowResize()
onUnmounted(() => {
unWindowResize()
})
})()
case PreviewScaleEnum.FIT:
;(() => {
const { calcRate, windowResize, unWindowResize } = usePreviewFitScale(
width.value as number,
height.value as number,
previewRef.value,
updateScaleRef
)
calcRate()
windowResize()
useAddWheelHandle(unWindowResize)
onUnmounted(() => {
unWindowResize()
})
})()
break
case PreviewScaleEnum.SCROLL_Y:
;(() => {
const { calcRate, windowResize, unWindowResize } = usePreviewScrollYScale(
width.value as number,
height.value as number,
previewRef.value,
scale => {
const dom = entityRef.value
dom.style.width = `${width.value * scale.width}px`
dom.style.height = `${height.value * scale.height}px`
updateScaleRef(scale)
}
)
calcRate()
windowResize()
useAddWheelHandle(unWindowResize)
onUnmounted(() => {
unWindowResize()
})
})()
break;
case PreviewScaleEnum.SCROLL_X: (() => {
const { calcRate, windowResize, unWindowResize } = usePreviewScrollXScale(
width.value as number,
height.value as number,
previewRef.value,
(scale) => {
const dom = entityRef.value
dom.style.width = `${width.value * scale.width}px`
dom.style.height = `${height.value * scale.height}px`
updateScaleRef(scale)
}
)
calcRate()
windowResize()
onUnmounted(() => {
unWindowResize()
})
})()
break
case PreviewScaleEnum.SCROLL_X:
;(() => {
const { calcRate, windowResize, unWindowResize } = usePreviewScrollXScale(
width.value as number,
height.value as number,
previewRef.value,
scale => {
const dom = entityRef.value
dom.style.width = `${width.value * scale.width}px`
dom.style.height = `${height.value * scale.height}px`
updateScaleRef(scale)
}
)
calcRate()
windowResize()
useAddWheelHandle(unWindowResize)
onUnmounted(() => {
unWindowResize()
})
})()
break;
case PreviewScaleEnum.FULL: (() => {
const { calcRate, windowResize, unWindowResize } = usePreviewFullScale(
width.value as number,
height.value as number,
previewRef.value,
updateScaleRef
)
calcRate()
windowResize()
onUnmounted(() => {
unWindowResize()
})
})()
break;
break
case PreviewScaleEnum.FULL:
;(() => {
const { calcRate, windowResize, unWindowResize } = usePreviewFullScale(
width.value as number,
height.value as number,
previewRef.value,
updateScaleRef
)
calcRate()
windowResize()
useAddWheelHandle(unWindowResize)
onUnmounted(() => {
unWindowResize()
})
})()
break
}
})

View File

@@ -1,5 +1,5 @@
<template>
<div :class="`go-preview ${chartEditStore.editCanvasConfig.previewScaleType}`">
<div :class="`go-preview ${chartEditStore.editCanvasConfig.previewScaleType}`" @mousedown="dragCanvas">
<template v-if="showEntity">
<!-- 实体区域 -->
<div ref="entityRef" class="go-preview-entity">
@@ -30,7 +30,7 @@
import { computed } from 'vue'
import { PreviewRenderList } from './components/PreviewRenderList'
import { getFilterStyle, setTitle } from '@/utils'
import { getEditCanvasConfigStyle, getSessionStorageInfo } from './utils'
import { getEditCanvasConfigStyle, getSessionStorageInfo, keyRecordHandle, dragCanvas } from './utils'
import { useComInstall } from './hooks/useComInstall.hook'
import { useScale } from './hooks/useScale.hook'
import { useStore } from './hooks/useStore.hook'
@@ -60,6 +60,9 @@ const showEntity = computed(() => {
useStore(chartEditStore)
const { entityRef, previewRef } = useScale(chartEditStore)
const { show } = useComInstall(chartEditStore)
// 开启键盘监听
keyRecordHandle()
</script>
<style lang="scss" scoped>

View File

@@ -0,0 +1,55 @@
import { listen } from 'dom-helpers'
import throttle from 'lodash/throttle'
let prevMoveXValue = [0, 0]
let prevMoveYValue = [0, 0]
// 拖拽处理
export const dragCanvas = (e: MouseEvent) => {
const previewBoxDom = document.querySelector('.go-preview') as HTMLElement
if (!previewBoxDom || previewBoxDom.style.position !== 'absolute') return
if (!window.$KeyboardActive?.space) return
e.preventDefault()
e.stopPropagation()
// @ts-ignore
document.activeElement?.blur()
const startX = e.screenX
const startY = e.screenY
const listenMousemove = listen(
window,
'mousemove',
throttle((moveEvent: MouseEvent) => {
const nx = moveEvent.screenX - startX
const ny = moveEvent.screenY - startY
const [prevMoveX1, prevMoveX2] = prevMoveXValue
const [prevMoveY1, prevMoveY2] = prevMoveYValue
prevMoveXValue = [prevMoveX2, nx]
prevMoveYValue = [prevMoveY2, ny]
// 去除小数部分
if (previewBoxDom) {
const oldLeft = previewBoxDom.style.left ? Number(previewBoxDom.style.left.split('px')[0]) : 0
const oldTop = previewBoxDom.style.top ? Number(previewBoxDom.style.top.split('px')[0]) : 0
previewBoxDom.style.left =
oldLeft +
(prevMoveX2 > prevMoveX1 ? Math.abs(prevMoveX2 - prevMoveX1) : -Math.abs(prevMoveX2 - prevMoveX1)) +
'px'
previewBoxDom.style.top =
oldTop +
(prevMoveY2 > prevMoveY1 ? Math.abs(prevMoveY2 - prevMoveY1) : -Math.abs(prevMoveY2 - prevMoveY1)) +
'px'
}
}, 20)
)
const listenMouseup = listen(window, 'mouseup', () => {
prevMoveXValue = [0, 0]
prevMoveYValue = [0, 0]
listenMousemove()
listenMouseup()
})
}

View File

@@ -1,2 +1,4 @@
export * from './style'
export * from './storage'
export * from './style'
export * from './storage'
export * from './keyboard'
export * from './drag'

View File

@@ -0,0 +1,49 @@
// 处理键盘记录
export const keyRecordHandle = () => {
// 默认赋值
window.$KeyboardActive = {
ctrl: false,
space: false
}
document.onkeydown = (e: KeyboardEvent) => {
const { keyCode } = e
if (keyCode == 32 && e.target == document.body) e.preventDefault()
if ([17, 32].includes(keyCode) && window.$KeyboardActive) {
switch (keyCode) {
case 17:
window.$KeyboardActive.ctrl = true
break
case 32:
window.$KeyboardActive.space = true
const previewBoxDom = document.querySelector('.go-preview') as HTMLElement
if (previewBoxDom && previewBoxDom.style.position === 'absolute') {
previewBoxDom.style.cursor = 'move'
}
break
}
}
}
document.onkeyup = (e: KeyboardEvent) => {
const { keyCode } = e
if (keyCode == 32 && e.target == document.body) e.preventDefault()
if ([17, 32].includes(keyCode) && window.$KeyboardActive) {
switch (keyCode) {
case 17:
window.$KeyboardActive.ctrl = false
break
case 32:
window.$KeyboardActive.space = false
break
}
}
const previewBoxDom = document.querySelector('.go-preview') as HTMLElement
if (previewBoxDom) {
previewBoxDom.style.cursor = 'default'
}
}
}

View File

@@ -5,4 +5,5 @@ declare module '*.vue' {
}
declare module 'lodash/*'
declare module 'dom-helpers'
declare module 'dom-helpers'
declare module '@iconify/vue'