mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 88eb98c0e6 | |||
| e8a18fc642 | |||
| fa0c930886 | |||
| 708aa54f3a | |||
| 57337f7980 | |||
| 89f4d122dd | |||
| b92bec3eed | |||
| 72f32e47a0 | |||
| 43908013e3 | |||
| 80bd1a3f23 | |||
| de60ea050c | |||
| 7cb3dce262 | |||
| 416c8df729 | |||
| b13a4b01df | |||
| 075c3532dc | |||
| fa40b08049 | |||
| 55c0a4e051 | |||
| 0795808075 | |||
| 0fa6316f52 | |||
| 9cd111ca58 | |||
| 2c18182dd0 | |||
| 36cad9373e | |||
| fcbed695b0 | |||
| 5a01d8587b | |||
| 4570a21a63 | |||
| bb72341519 | |||
| 78afc86411 | |||
| 91ff6a7aa2 | |||
| b3ec97ffcc | |||
| 24fe9e425c | |||
| 09d9e79f40 | |||
| 7f30a186df | |||
| 65d1e6a879 | |||
| e963603d22 | |||
| 3b68f4d4d9 | |||
| 4fd30c495f | |||
| 37158397be | |||
| b4bdb0b3f7 | |||
| cd6cbf8c26 | |||
| bb5fe95d30 | |||
| 1c63f74a6d | |||
| 0094b17ec2 | |||
| 80f377ecd6 | |||
| 55ce5ce919 | |||
| a09fa134f8 | |||
| f2854b29aa | |||
| 1ff06c2bc3 | |||
| 604ca8b312 | |||
| e6bb5eb0a1 | |||
| 109a95a96b | |||
| 96cfb8a2b2 | |||
| 32ee9f040c |
148
README.md
148
README.md
@ -7,12 +7,12 @@
|
|||||||
JEECG BOOT 低代码开发平台(前后端分离版本)
|
JEECG BOOT 低代码开发平台(前后端分离版本)
|
||||||
===============
|
===============
|
||||||
|
|
||||||
当前最新版本: 2.2.0(发布日期:2020-05-06)
|
当前最新版本: 2.3(发布日期:2020-09-14)
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||||
[](http://www.jeecg.com)
|
[](http://www.jeecg.com)
|
||||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
|
|
||||||
@ -39,12 +39,12 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
技术文档
|
技术文档
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- 在线演示 : [http://boot.jeecg.com](http://boot.jeecg.com)
|
|
||||||
|
|
||||||
- 技术官网: [http://www.jeecg.com](http://www.jeecg.com)
|
- 技术官网: [http://www.jeecg.com](http://www.jeecg.com)
|
||||||
|
|
||||||
- 开发文档: [http://doc.jeecg.com](http://doc.jeecg.com/1273753)
|
- 开发文档: [http://doc.jeecg.com](http://doc.jeecg.com/1273753)
|
||||||
|
|
||||||
|
- 在线演示 : [http://boot.jeecg.com](http://boot.jeecg.com)
|
||||||
|
|
||||||
- 视频教程 :[JeecgBoot入门视频教程](http://www.jeecg.com/doc/video)
|
- 视频教程 :[JeecgBoot入门视频教程](http://www.jeecg.com/doc/video)
|
||||||
|
|
||||||
- 常见问题: [入门常见问题大全](http://bbs.jeecg.com/forum.php?mod=viewthread&tid=7816&extra=page%3D1)
|
- 常见问题: [入门常见问题大全](http://bbs.jeecg.com/forum.php?mod=viewthread&tid=7816&extra=page%3D1)
|
||||||
@ -56,56 +56,58 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
交流互动
|
交流互动
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- QQ交流群 : ②769925425、①284271917(满)
|
- QQ交流群 : ③816531124、②769925425(满)、①284271917(满)
|
||||||
|
|
||||||
- 反馈问题: [反馈问题,请按格式发Issues](https://github.com/zhangdaiscott/jeecg-boot/issues/new)
|
- 反馈问题: [反馈问题,请按格式发Issues](https://github.com/zhangdaiscott/jeecg-boot/issues/new)
|
||||||
|
|
||||||
- 参与开源: [欢迎加入JEECG开源团队,共同进步!!](http://www.jeecg.com/doc/join)
|
- 参与开源: [欢迎加入JEECG开源团队,共同进步!!](http://www.jeecg.com/doc/join)
|
||||||
|
|
||||||
- Online一分钟: [1分钟快速学习](https://my.oschina.net/jeecg/blog/3083313)
|
- Online一分钟: [1分钟快速学习](https://jeecg.blog.csdn.net/article/details/106078912)
|
||||||
|
|
||||||
|
|
||||||
为什么选择JEECG-BOOT?
|
为什么选择JEECG-BOOT?
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
||||||
* 2.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
|
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywarking),提供切换机制支持单体和微服务自由切换
|
||||||
* 3.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
|
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
|
||||||
* 4.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大幅度提升开发效率,不再为重复工作发愁。
|
* 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
|
||||||
* 5.低代码能力:Online在线表单(无需编码,通过在线配置表单,实现表单的增删改查,支持单表、树、一对多、一对一等模型,实现人人皆可编码)
|
* 5.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大幅度提升开发效率,不再为重复工作发愁。
|
||||||
* 5-1.低代码能力:Online在线报表(无需编码,通过在线配置方式,实现数据报表,可以快速抽取数据,减轻开发压力,实现人人皆可编码)
|
* 6.低代码能力:Online在线表单(无需编码,通过在线配置表单,实现表单的增删改查,支持单表、树、一对多、一对一等模型,实现人人皆可编码)
|
||||||
* 5-2.低代码能力:Online在线图表(无需编码,通过在线配置方式,实现曲线图,柱状图,数据报表等,支持自定义排版布局,实现人人皆可编码)
|
* 7.低代码能力:Online在线报表(无需编码,通过在线配置方式,实现数据报表,可以快速抽取数据,减轻开发压力,实现人人皆可编码)
|
||||||
* 6.封装完善的用户、角色、菜单、组织机构、数据字典、在线定时任务等基础功能,支持访问授权、按钮权限、数据权限等功能
|
* 8.低代码能力:Online在线图表(无需编码,通过在线配置方式,实现曲线图,柱状图,数据报表等,支持自定义排版布局,实现人人皆可编码)
|
||||||
* 7.常用共通封装,各种工具类(定时任务,短信接口,邮件发送,Excel导入导出等),基本满足80%项目需求
|
* 9.封装完善的用户、角色、菜单、组织机构、数据字典、在线定时任务等基础功能,支持访问授权、按钮权限、数据权限等功能
|
||||||
* 8.简易Excel导入导出,支持单表导出和一对多表模式导出,生成的代码自带导入导出功能
|
* 10.常用共通封装,各种工具类(定时任务,短信接口,邮件发送,Excel导入导出等),基本满足80%项目需求
|
||||||
* 9.集成简易报表工具,图像报表和数据导出非常方便,可极其方便的生成图形报表、pdf、excel、word等报表;
|
* 11.简易Excel导入导出,支持单表导出和一对多表模式导出,生成的代码自带导入导出功能
|
||||||
* 10.采用前后分离技术,页面UI风格精美,针对常用组件做了封装:时间、行表格控件、截取显示控件、报表组件,编辑器等等
|
* 12.集成简易报表工具,图像报表和数据导出非常方便,可极其方便的生成图形报表、pdf、excel、word等报表;
|
||||||
* 11.查询过滤器:查询功能自动生成,后台动态拼SQL追加查询条件;支持多种匹配方式(全匹配/模糊查询/包含查询/不匹配查询);
|
* 13.采用前后分离技术,页面UI风格精美,针对常用组件做了封装:时间、行表格控件、截取显示控件、报表组件,编辑器等等
|
||||||
* 12.数据权限(精细化数据权限控制,控制到行级,列表级,表单字段级,实现不同人看不同数据,不同人对同一个页面操作不同字段
|
* 14.查询过滤器:查询功能自动生成,后台动态拼SQL追加查询条件;支持多种匹配方式(全匹配/模糊查询/包含查询/不匹配查询);
|
||||||
* 13.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等);
|
* 15.数据权限(精细化数据权限控制,控制到行级,列表级,表单字段级,实现不同人看不同数据,不同人对同一个页面操作不同字段
|
||||||
* 14.支持SAAS服务模式,提供SaaS多租户架构方案。
|
* 16.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等);
|
||||||
* 15.分布式文件服务,集成minio、阿里OSS等优秀的第三方,提供便捷的文件上传与管理,同时也支持本地存储。
|
* 17.支持SAAS服务模式,提供SaaS多租户架构方案。
|
||||||
* 16.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle三大主流数据库。
|
* 18.分布式文件服务,集成minio、阿里OSS等优秀的第三方,提供便捷的文件上传与管理,同时也支持本地存储。
|
||||||
* 17.集成工作流activiti,并实现了只需在页面配置流程转向,可极大的简化bpm工作流的开发;用bpm的流程设计器画出了流程走向,一个工作流基本就完成了,只需写很少量的java代码;
|
* 19.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle三大主流数据库。
|
||||||
* 18.低代码能力:在线流程设计,采用开源Activiti流程引擎,实现在线画流程,自定义表单,表单挂靠,业务流转
|
* 20.集成工作流activiti,并实现了只需在页面配置流程转向,可极大的简化bpm工作流的开发;用bpm的流程设计器画出了流程走向,一个工作流基本就完成了,只需写很少量的java代码;
|
||||||
* 19.多数据源:及其简易的使用方式,在线配置数据源配置,便捷的从其他数据抓取数据;
|
* 21.低代码能力:在线流程设计,采用开源Activiti流程引擎,实现在线画流程,自定义表单,表单挂靠,业务流转
|
||||||
* 20.提供单点登录CAS集成方案,项目中已经提供完善的对接代码
|
* 22.多数据源:及其简易的使用方式,在线配置数据源配置,便捷的从其他数据抓取数据;
|
||||||
* 21.低代码能力:表单设计器,支持用户自定义表单布局,支持单表,一对多表单、支持select、radio、checkbox、textarea、date、popup、列表、宏等控件
|
* 23.提供单点登录CAS集成方案,项目中已经提供完善的对接代码
|
||||||
* 22.专业接口对接机制,统一采用restful接口方式,集成swagger-ui在线接口文档,Jwt token安全验证,方便客户端对接
|
* 24.低代码能力:表单设计器,支持用户自定义表单布局,支持单表,一对多表单、支持select、radio、checkbox、textarea、date、popup、列表、宏等控件
|
||||||
* 23.接口安全机制,可细化控制接口授权,非常简便实现不同客户端只看自己数据等控制
|
* 25.专业接口对接机制,统一采用restful接口方式,集成swagger-ui在线接口文档,Jwt token安全验证,方便客户端对接
|
||||||
* 24.高级组合查询功能,在线配置支持主子表关联查询,可保存查询历史
|
* 26.接口安全机制,可细化控制接口授权,非常简便实现不同客户端只看自己数据等控制
|
||||||
* 25.提供各种系统监控,实时跟踪系统运行情况(监控 Redis、Tomcat、jvm、服务器信息、请求追踪、SQL监控)
|
* 27.高级组合查询功能,在线配置支持主子表关联查询,可保存查询历史
|
||||||
* 26.消息中心(支持短信、邮件、微信推送等等)
|
* 28.提供各种系统监控,实时跟踪系统运行情况(监控 Redis、Tomcat、jvm、服务器信息、请求追踪、SQL监控)
|
||||||
* 27.集成Websocket消息通知机制
|
* 29.消息中心(支持短信、邮件、微信推送等等)
|
||||||
* 28.移动自适应效果优秀,提供APP发布方案:
|
* 30.集成Websocket消息通知机制
|
||||||
* 29.支持多语言,提供国际化方案;
|
* 31.移动自适应效果优秀,提供APP发布方案:
|
||||||
* 30.数据变更记录日志,可记录数据每次变更内容,通过版本对比功能查看历史变化
|
* 32.支持多语言,提供国际化方案;
|
||||||
* 31.平台UI强大,实现了移动自适应
|
* 33.数据变更记录日志,可记录数据每次变更内容,通过版本对比功能查看历史变化
|
||||||
* 32.平台首页风格,提供多种组合模式,支持自定义风格
|
* 34.平台UI强大,实现了移动自适应
|
||||||
* 33.提供简单易用的打印插件,支持谷歌、火狐、IE11+ 等各种浏览器
|
* 35.平台首页风格,提供多种组合模式,支持自定义风格
|
||||||
* 34.示例代码丰富,提供很多学习案例参考
|
* 36.提供简单易用的打印插件,支持谷歌、火狐、IE11+ 等各种浏览器
|
||||||
* 35.采用maven分模块开发方式
|
* 37.示例代码丰富,提供很多学习案例参考
|
||||||
* 36.支持菜单动态路由
|
* 38.采用maven分模块开发方式
|
||||||
* 37.权限控制采用 RBAC(Role-Based Access Control,基于角色的访问控制)
|
* 39.支持菜单动态路由
|
||||||
|
* 40.权限控制采用 RBAC(Role-Based Access Control,基于角色的访问控制)
|
||||||
|
* 41.提供新行编辑表格JVXETable,轻松满足各种复杂ERP布局,拥有更高的性能、更灵活的扩展、更强大的功能
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -128,12 +130,14 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
|
|
||||||
|
|
||||||
#### 后端
|
#### 后端
|
||||||
- 基础框架:Spring Boot 2.1.3.RELEASE
|
- 基础框架:Spring Boot 2.1.3.RELEASE \ Spring Cloud Alibaba 2.1.0.RELEASE
|
||||||
|
|
||||||
- 持久层框架:Mybatis-plus_3.1.2
|
- 持久层框架:Mybatis-plus_3.1.2
|
||||||
|
|
||||||
- 安全框架:Apache Shiro 1.4.0,Jwt_3.7.0
|
- 安全框架:Apache Shiro 1.4.0,Jwt_3.7.0
|
||||||
|
|
||||||
|
- 微服务技术:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywarking
|
||||||
|
|
||||||
- 数据库连接池:阿里巴巴Druid 1.1.10
|
- 数据库连接池:阿里巴巴Druid 1.1.10
|
||||||
|
|
||||||
- 缓存框架:redis
|
- 缓存框架:redis
|
||||||
@ -158,6 +162,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 功能模块
|
### 功能模块
|
||||||
```
|
```
|
||||||
├─系统管理
|
├─系统管理
|
||||||
@ -167,12 +172,13 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│ ├─权限设置(支持按钮权限、数据权限)
|
│ ├─权限设置(支持按钮权限、数据权限)
|
||||||
│ ├─表单权限(控制字段禁用、隐藏)
|
│ ├─表单权限(控制字段禁用、隐藏)
|
||||||
│ ├─部门管理
|
│ ├─部门管理
|
||||||
|
│ ├─我的部门(二级管理员)
|
||||||
│ └─字典管理
|
│ └─字典管理
|
||||||
│ └─树分类字典
|
│ └─分类字典
|
||||||
│ └─系统公告
|
│ └─系统公告
|
||||||
│ └─我的组织机构
|
|
||||||
│ └─职务管理
|
│ └─职务管理
|
||||||
│ └─通讯录
|
│ └─通讯录
|
||||||
|
│ └─多租户管理
|
||||||
├─消息中心
|
├─消息中心
|
||||||
│ ├─消息管理
|
│ ├─消息管理
|
||||||
│ ├─模板管理
|
│ ├─模板管理
|
||||||
@ -185,6 +191,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│ ├─Excel导入导出工具集成(支持单表,一对多 导入导出)
|
│ ├─Excel导入导出工具集成(支持单表,一对多 导入导出)
|
||||||
│ ├─平台移动自适应支持
|
│ ├─平台移动自适应支持
|
||||||
├─系统监控
|
├─系统监控
|
||||||
|
│ ├─Gateway路由网关
|
||||||
│ ├─性能扫描监控
|
│ ├─性能扫描监控
|
||||||
│ │ ├─监控 Redis
|
│ │ ├─监控 Redis
|
||||||
│ │ ├─Tomcat
|
│ │ ├─Tomcat
|
||||||
@ -216,6 +223,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│─常用示例
|
│─常用示例
|
||||||
│ ├─自定义组件
|
│ ├─自定义组件
|
||||||
│ ├─对象存储(对接阿里云)
|
│ ├─对象存储(对接阿里云)
|
||||||
|
│ ├─JVXETable示例(各种复杂ERP布局示例)
|
||||||
│ ├─单表模型例子
|
│ ├─单表模型例子
|
||||||
│ └─一对多模型例子
|
│ └─一对多模型例子
|
||||||
│ └─打印例子
|
│ └─打印例子
|
||||||
@ -267,6 +275,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│ ├─Online在线表单 - 功能已开放
|
│ ├─Online在线表单 - 功能已开放
|
||||||
│ ├─在线代码生成器 - 功能已开放
|
│ ├─在线代码生成器 - 功能已开放
|
||||||
│ ├─Online在线报表 - 功能已开放
|
│ ├─Online在线报表 - 功能已开放
|
||||||
|
│ ├─多数据源管理
|
||||||
│ ├─Online在线图表
|
│ ├─Online在线图表
|
||||||
│ ├─Online图表模板配置
|
│ ├─Online图表模板配置
|
||||||
│ ├─高级表单设计器
|
│ ├─高级表单设计器
|
||||||
@ -288,6 +297,41 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 微服务整体解决方案(2.3+版本)
|
||||||
|
|
||||||
|
|
||||||
|
1、服务注册和发现 Nacos √
|
||||||
|
|
||||||
|
2、统一配置中心 Nacos √
|
||||||
|
|
||||||
|
3、路由网关 gateway √
|
||||||
|
|
||||||
|
4、分布式 http feign √
|
||||||
|
|
||||||
|
5、熔断和降级 Sentinel √
|
||||||
|
|
||||||
|
6、分布式文件 Minio、阿里OSS √
|
||||||
|
|
||||||
|
7、统一权限控制 JWT + Shiro √
|
||||||
|
|
||||||
|
8、服务监控 SpringBootAdmin [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1761865)
|
||||||
|
|
||||||
|
9、链路跟踪 Skywarking [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1771670)
|
||||||
|
|
||||||
|
10、消息中间件 SpringCloudStream+RabbitMQ [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1744409)
|
||||||
|
|
||||||
|
11、分布式任务 xxl-job [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1801263)
|
||||||
|
|
||||||
|
12、分布式事务 Seata
|
||||||
|
|
||||||
|
13、分布式日志 elk + kafa
|
||||||
|
|
||||||
|
14、支持 docker-compose、k8s、jenkins
|
||||||
|
|
||||||
|
15、CAS 单点登录 √
|
||||||
|
|
||||||
|
#### 微服务架构图
|
||||||
|

|
||||||
|
|
||||||
### Jeecg Boot 产品功能蓝图
|
### Jeecg Boot 产品功能蓝图
|
||||||

|

|
||||||
@ -422,15 +466,15 @@ yarn run lint
|
|||||||
|
|
||||||
附属文档
|
附属文档
|
||||||
----
|
----
|
||||||
- [Ant Design Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn)
|
- [Ant Design Vue](https://www.antdv.com/docs/vue/introduce-cn)
|
||||||
|
|
||||||
- [报表 viser-vue](https://viserjs.github.io/demo.html#/viser/bar/basic-bar)
|
- [报表 viser-vue](https://viserjs.github.io/demo.html#/viser/line/basic-line)
|
||||||
|
|
||||||
- [Vue](https://cn.vuejs.org/v2/guide)
|
- [Vue](https://cn.vuejs.org/v2/guide)
|
||||||
|
|
||||||
- [路由/菜单说明](https://github.com/zhangdaiscott/jeecg-boot/tree/master/ant-design-jeecg-vue/src/router/README.md)
|
- [路由/菜单说明](https://gitee.com/jeecg/jeecg-boot/tree/v1.1/ant-design-jeecg-vue/src/router/README.md)
|
||||||
|
|
||||||
- [ANTD 默认配置项](https://github.com/zhangdaiscott/jeecg-boot/tree/master/ant-design-jeecg-vue/src/defaultSettings.js)
|
- [ANTD 默认配置项](https://gitee.com/jeecg/jeecg-boot/blob/v1.1/ant-design-jeecg-vue/src/defaultSettings.js)
|
||||||
|
|
||||||
- 其他待补充...
|
- 其他待补充...
|
||||||
|
|
||||||
|
|||||||
23
ant-design-vue-jeecg/.dockerignore
Normal file
23
ant-design-vue-jeecg/.dockerignore
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
docs
|
||||||
|
public
|
||||||
|
src
|
||||||
|
.dockerignore
|
||||||
|
.editorconfig
|
||||||
|
.eslintignore
|
||||||
|
.gitattributes
|
||||||
|
.gitignore
|
||||||
|
.prettierrc
|
||||||
|
babel.config.js
|
||||||
|
Dockerfile
|
||||||
|
idea.config.js
|
||||||
|
LICENSE
|
||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
|
README.md
|
||||||
|
vue.config.js
|
||||||
|
yarn
|
||||||
|
yarn.lock
|
||||||
|
yarn-error.log
|
||||||
|
.idea
|
||||||
|
.svn
|
||||||
|
node_modules
|
||||||
29
ant-design-vue-jeecg/Dockerfile
Normal file
29
ant-design-vue-jeecg/Dockerfile
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
FROM nginx
|
||||||
|
MAINTAINER jeecgos@163.com
|
||||||
|
VOLUME /tmp
|
||||||
|
ENV LANG en_US.UTF-8
|
||||||
|
RUN echo "server { \
|
||||||
|
listen 80; \
|
||||||
|
location ^~ /jeecg-boot { \
|
||||||
|
proxy_pass http://jeecg-boot-system:8080/jeecg-boot/; \
|
||||||
|
proxy_set_header Host jeecg-boot-system; \
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr; \
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; \
|
||||||
|
} \
|
||||||
|
#解决Router(mode: 'history')模式下,刷新路由地址不能找到页面的问题 \
|
||||||
|
location / { \
|
||||||
|
root /var/www/html/; \
|
||||||
|
index index.html index.htm; \
|
||||||
|
if (!-e \$request_filename) { \
|
||||||
|
rewrite ^(.*)\$ /index.html?s=\$1 last; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
access_log /var/log/nginx/access.log ; \
|
||||||
|
} " > /etc/nginx/conf.d/default.conf \
|
||||||
|
&& mkdir -p /var/www \
|
||||||
|
&& mkdir -p /var/www/html
|
||||||
|
|
||||||
|
ADD dist/ /var/www/html/
|
||||||
|
EXPOSE 80
|
||||||
|
EXPOSE 443
|
||||||
@ -1,7 +1,7 @@
|
|||||||
Ant Design Jeecg Vue
|
Ant Design Jeecg Vue
|
||||||
====
|
====
|
||||||
|
|
||||||
当前最新版本: 2.2.0(发布日期:2020-05-06)
|
当前最新版本: 2.3.0(发布日期:20200914)
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
----
|
----
|
||||||
@ -104,3 +104,32 @@ yarn run lint
|
|||||||
----
|
----
|
||||||
|
|
||||||
> @vue/cli 升级后,eslint 规则更新了。由于影响到全部 .vue 文件,需要逐个验证。既暂时关闭部分原本不验证的规则,后期维护时,在逐步修正这些 rules
|
> @vue/cli 升级后,eslint 规则更新了。由于影响到全部 .vue 文件,需要逐个验证。既暂时关闭部分原本不验证的规则,后期维护时,在逐步修正这些 rules
|
||||||
|
|
||||||
|
|
||||||
|
Docker 镜像使用
|
||||||
|
----
|
||||||
|
|
||||||
|
```
|
||||||
|
# 1.修改前端项目的后台域名
|
||||||
|
public/index.html
|
||||||
|
域名改成: http://jeecg-boot-system:8080/jeecg-boot
|
||||||
|
|
||||||
|
# 2.先进入打包前端项目
|
||||||
|
yarn run build
|
||||||
|
|
||||||
|
# 3.构建镜像
|
||||||
|
docker build -t nginx:jeecgboot .
|
||||||
|
|
||||||
|
# 4.启动镜像
|
||||||
|
docker run --name jeecg-boot-nginx -p 80:80 -d nginx:jeecgboot
|
||||||
|
|
||||||
|
# 5.配置host
|
||||||
|
|
||||||
|
# jeecgboot
|
||||||
|
127.0.0.1 jeecg-boot-redis
|
||||||
|
127.0.0.1 jeecg-boot-mysql
|
||||||
|
127.0.0.1 jeecg-boot-system
|
||||||
|
|
||||||
|
# 6.访问前台项目
|
||||||
|
http://localhost:80
|
||||||
|
```
|
||||||
@ -1,6 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
['@vue/app',
|
['@vue/app',
|
||||||
{ useBuiltIns: 'entry' }]
|
{ useBuiltIns: 'entry' }]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
18182
ant-design-vue-jeecg/package-lock.json
generated
Normal file
18182
ant-design-vue-jeecg/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,22 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-antd-jeecg",
|
"name": "vue-antd-jeecg",
|
||||||
"version": "2.2.0",
|
"version": "2.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pre": "yarn --registry https://registry.npm.taobao.org || cnpm install || npm install --registry https://registry.npm.taobao.org ",
|
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "vue-cli-service build",
|
"build": "vue-cli-service build",
|
||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@antv/data-set": "^0.11.2",
|
"ant-design-vue": "^1.6.3",
|
||||||
"@jeecg/antd-online-beta220": "^1.0.1",
|
"@jeecg/antd-online-mini": "2.3.0",
|
||||||
"@tinymce/tinymce-vue": "^2.0.0",
|
"@antv/data-set": "^0.11.4",
|
||||||
"ant-design-vue": "1.5.2",
|
"viser-vue": "^2.4.8",
|
||||||
"area-data": "^5.0.6",
|
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"clipboard": "^2.0.4",
|
|
||||||
"codemirror": "^5.46.0",
|
|
||||||
"dayjs": "^1.8.0",
|
"dayjs": "^1.8.0",
|
||||||
"enquire.js": "^2.1.6",
|
"enquire.js": "^2.1.6",
|
||||||
"js-cookie": "^2.2.0",
|
"js-cookie": "^2.2.0",
|
||||||
@ -24,20 +21,29 @@
|
|||||||
"lodash.pick": "^4.4.0",
|
"lodash.pick": "^4.4.0",
|
||||||
"md5": "^2.2.1",
|
"md5": "^2.2.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"tinymce": "^5.1.4",
|
|
||||||
"viser-vue": "^2.4.4",
|
|
||||||
"vue": "^2.6.10",
|
"vue": "^2.6.10",
|
||||||
"vue-area-linkage": "^5.1.0",
|
"vue-cropper": "^0.5.4",
|
||||||
"vue-cropper": "^0.4.8",
|
|
||||||
"vue-i18n": "^8.7.0",
|
"vue-i18n": "^8.7.0",
|
||||||
"vue-loader": "^15.7.0",
|
"vue-loader": "^15.7.0",
|
||||||
"vue-ls": "^3.2.0",
|
"vue-ls": "^3.2.0",
|
||||||
"vue-photo-preview": "^1.1.3",
|
|
||||||
"vue-print-nb-jeecg": "^1.0.9",
|
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.0.1",
|
||||||
|
"vuex": "^3.1.0",
|
||||||
|
"vue-print-nb-jeecg": "^1.0.9",
|
||||||
|
"clipboard": "^2.0.4",
|
||||||
|
"vue-photo-preview": "^1.1.3",
|
||||||
"vue-splitpane": "^1.0.4",
|
"vue-splitpane": "^1.0.4",
|
||||||
"vuedraggable": "^2.20.0",
|
"vuedraggable": "^2.20.0",
|
||||||
"vuex": "^3.1.0"
|
"codemirror": "^5.46.0",
|
||||||
|
"@tinymce/tinymce-vue": "^2.1.0",
|
||||||
|
"tinymce": "^5.3.2",
|
||||||
|
"@toast-ui/editor": "^2.1.2",
|
||||||
|
"vue-area-linkage": "^5.1.0",
|
||||||
|
"area-data": "^5.0.6",
|
||||||
|
"jsoneditor": "^9.0.0",
|
||||||
|
"dom-align": "1.12.0",
|
||||||
|
"xe-utils": "2.4.8",
|
||||||
|
"vxe-table": "2.9.13",
|
||||||
|
"vxe-table-plugin-antd": "1.8.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/polyfill": "^7.2.5",
|
"@babel/polyfill": "^7.2.5",
|
||||||
@ -45,14 +51,15 @@
|
|||||||
"@vue/cli-plugin-eslint": "^3.3.0",
|
"@vue/cli-plugin-eslint": "^3.3.0",
|
||||||
"@vue/cli-service": "^3.3.0",
|
"@vue/cli-service": "^3.3.0",
|
||||||
"@vue/eslint-config-standard": "^4.0.0",
|
"@vue/eslint-config-standard": "^4.0.0",
|
||||||
"babel-eslint": "^10.0.1",
|
"babel-eslint": "7.2.3",
|
||||||
"compression-webpack-plugin": "^3.1.0",
|
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-plugin-vue": "^5.1.0",
|
"eslint-plugin-vue": "^5.1.0",
|
||||||
"html-webpack-plugin": "^4.2.0",
|
|
||||||
"less": "^3.9.0",
|
"less": "^3.9.0",
|
||||||
"less-loader": "^4.1.0",
|
"less-loader": "^4.1.0",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"vue-template-compiler": "^2.6.10",
|
||||||
|
"html-webpack-plugin": "^4.2.0",
|
||||||
|
"compression-webpack-plugin": "^3.1.0",
|
||||||
|
"babel-plugin-import": "^1.13.0"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"root": true,
|
"root": true,
|
||||||
@ -89,9 +96,10 @@
|
|||||||
"vue/no-use-v-if-with-v-for": 0,
|
"vue/no-use-v-if-with-v-for": 0,
|
||||||
"vue/html-closing-bracket-newline": 0,
|
"vue/html-closing-bracket-newline": 0,
|
||||||
"vue/no-parsing-error": 0,
|
"vue/no-parsing-error": 0,
|
||||||
"no-console": 0,
|
|
||||||
"no-tabs": 0,
|
"no-tabs": 0,
|
||||||
"indent": [1, 4]
|
"indent": ["off", 2],
|
||||||
|
"no-console": 0,
|
||||||
|
"space-before-function-paren": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
|
|||||||
20
ant-design-vue-jeecg/public/color.less
vendored
20
ant-design-vue-jeecg/public/color.less
vendored
@ -7680,6 +7680,16 @@ font.weak {
|
|||||||
color: #f5222d;
|
color: #f5222d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 侧边导航栏首页颜色跟随主题变化
|
||||||
|
.ant-menu.ant-menu-root > .ant-menu-item:first-child.ant-menu-item-selected {
|
||||||
|
& > a,
|
||||||
|
& > a:hover {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-menu-submenu-selected {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
// begin -------- JAreaLinkage 三级联动样式 --------------
|
// begin -------- JAreaLinkage 三级联动样式 --------------
|
||||||
.cascader-menu-list .cascader-menu-option.hover,
|
.cascader-menu-list .cascader-menu-option.hover,
|
||||||
@ -7699,3 +7709,13 @@ font.weak {
|
|||||||
box-shadow: 0 0 0 2px color(~`colorPalette("@{primary-color}", 1)`);
|
box-shadow: 0 0 0 2px color(~`colorPalette("@{primary-color}", 1)`);
|
||||||
}
|
}
|
||||||
// end -------- JAreaLinkage 三级联动样式 --------------
|
// end -------- JAreaLinkage 三级联动样式 --------------
|
||||||
|
|
||||||
|
// TESTA-521
|
||||||
|
.ant-menu-submenu-selected {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTA-521
|
||||||
|
.tab-layout-tabs.ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active {
|
||||||
|
border-color: @primary-color !important;
|
||||||
|
}
|
||||||
2
ant-design-vue-jeecg/public/index.html
vendored
2
ant-design-vue-jeecg/public/index.html
vendored
@ -8,6 +8,7 @@
|
|||||||
<title>Jeecg-Boot 企业级快速开发平台</title>
|
<title>Jeecg-Boot 企业级快速开发平台</title>
|
||||||
<link rel="icon" href="<%= BASE_URL %>logo.png">
|
<link rel="icon" href="<%= BASE_URL %>logo.png">
|
||||||
<script src="/cdn/babel-polyfill/polyfill_7_2_5.js"></script>
|
<script src="/cdn/babel-polyfill/polyfill_7_2_5.js"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
html,
|
html,
|
||||||
body,
|
body,
|
||||||
@ -246,6 +247,7 @@
|
|||||||
window._CONFIG['casPrefixUrl'] = 'http://cas.example.org:8443/cas';
|
window._CONFIG['casPrefixUrl'] = 'http://cas.example.org:8443/cas';
|
||||||
window._CONFIG['onlinePreviewDomainURL'] = 'http://fileview.jeecg.com/onlinePreview'
|
window._CONFIG['onlinePreviewDomainURL'] = 'http://fileview.jeecg.com/onlinePreview'
|
||||||
window._CONFIG['staticDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/static';
|
window._CONFIG['staticDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/static';
|
||||||
|
//window._CONFIG['downloadUrl'] = window._CONFIG['domianURL'] + '/sys/common/download';
|
||||||
window._CONFIG['pdfDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/pdf/pdfPreviewIframe';
|
window._CONFIG['pdfDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/pdf/pdfPreviewIframe';
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@ -2,10 +2,17 @@ import { getAction, deleteAction, putAction, postAction, httpAction } from '@/ap
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import {UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
|
import {UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
|
||||||
|
|
||||||
|
////根路径
|
||||||
|
// const doMian = "/jeecg-boot/";
|
||||||
|
////图片预览请求地址
|
||||||
|
// const imgView = "http://localhost:8080/jeecg-boot/sys/common/view/";
|
||||||
|
|
||||||
//角色管理
|
//角色管理
|
||||||
const addRole = (params)=>postAction("/sys/role/add",params);
|
const addRole = (params)=>postAction("/sys/role/add",params);
|
||||||
const editRole = (params)=>putAction("/sys/role/edit",params);
|
const editRole = (params)=>putAction("/sys/role/edit",params);
|
||||||
|
// const getRoleList = (params)=>getAction("/sys/role/list",params);
|
||||||
|
// const deleteRole = (params)=>deleteAction("/sys/role/delete",params);
|
||||||
|
// const deleteRoleList = (params)=>deleteAction("/sys/role/deleteBatch",params);
|
||||||
const checkRoleCode = (params)=>getAction("/sys/role/checkRoleCode",params);
|
const checkRoleCode = (params)=>getAction("/sys/role/checkRoleCode",params);
|
||||||
const queryall = (params)=>getAction("/sys/role/queryall",params);
|
const queryall = (params)=>getAction("/sys/role/queryall",params);
|
||||||
|
|
||||||
@ -14,6 +21,8 @@ const addUser = (params)=>postAction("/sys/user/add",params);
|
|||||||
const editUser = (params)=>putAction("/sys/user/edit",params);
|
const editUser = (params)=>putAction("/sys/user/edit",params);
|
||||||
const queryUserRole = (params)=>getAction("/sys/user/queryUserRole",params);
|
const queryUserRole = (params)=>getAction("/sys/user/queryUserRole",params);
|
||||||
const getUserList = (params)=>getAction("/sys/user/list",params);
|
const getUserList = (params)=>getAction("/sys/user/list",params);
|
||||||
|
// const deleteUser = (params)=>deleteAction("/sys/user/delete",params);
|
||||||
|
// const deleteUserList = (params)=>deleteAction("/sys/user/deleteBatch",params);
|
||||||
const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
|
const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
|
||||||
//验证用户是否存在
|
//验证用户是否存在
|
||||||
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
|
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
|
||||||
@ -24,15 +33,20 @@ const changePassword = (params)=>putAction("/sys/user/changePassword",params);
|
|||||||
const addPermission= (params)=>postAction("/sys/permission/add",params);
|
const addPermission= (params)=>postAction("/sys/permission/add",params);
|
||||||
const editPermission= (params)=>putAction("/sys/permission/edit",params);
|
const editPermission= (params)=>putAction("/sys/permission/edit",params);
|
||||||
const getPermissionList = (params)=>getAction("/sys/permission/list",params);
|
const getPermissionList = (params)=>getAction("/sys/permission/list",params);
|
||||||
|
/*update_begin author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
|
||||||
const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
|
const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
|
||||||
const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
|
const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
|
||||||
const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
|
const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
|
||||||
|
/*update_end author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
|
||||||
|
|
||||||
|
// const deletePermission = (params)=>deleteAction("/sys/permission/delete",params);
|
||||||
|
// const deletePermissionList = (params)=>deleteAction("/sys/permission/deleteBatch",params);
|
||||||
const queryTreeList = (params)=>getAction("/sys/permission/queryTreeList",params);
|
const queryTreeList = (params)=>getAction("/sys/permission/queryTreeList",params);
|
||||||
const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",params);
|
const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",params);
|
||||||
const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params);
|
const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params);
|
||||||
const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params);
|
const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params);
|
||||||
const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params);
|
const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params);
|
||||||
|
//const queryPermissionsByUser = (params)=>getAction("/sys/permission/queryByUser",params);
|
||||||
const queryPermissionsByUser = (params)=>getAction("/sys/permission/getUserPermissionByToken",params);
|
const queryPermissionsByUser = (params)=>getAction("/sys/permission/getUserPermissionByToken",params);
|
||||||
const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params);
|
const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params);
|
||||||
const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params);
|
const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params);
|
||||||
@ -54,15 +68,21 @@ const saveDeptRolePermission = (params)=>postAction("/sys/sysDepartPermission/sa
|
|||||||
const queryMyDepartTreeList = (params)=>getAction("/sys/sysDepart/queryMyDeptTreeList",params);
|
const queryMyDepartTreeList = (params)=>getAction("/sys/sysDepart/queryMyDeptTreeList",params);
|
||||||
|
|
||||||
//日志管理
|
//日志管理
|
||||||
|
//const getLogList = (params)=>getAction("/sys/log/list",params);
|
||||||
const deleteLog = (params)=>deleteAction("/sys/log/delete",params);
|
const deleteLog = (params)=>deleteAction("/sys/log/delete",params);
|
||||||
const deleteLogList = (params)=>deleteAction("/sys/log/deleteBatch",params);
|
const deleteLogList = (params)=>deleteAction("/sys/log/deleteBatch",params);
|
||||||
|
|
||||||
//数据字典
|
//数据字典
|
||||||
const addDict = (params)=>postAction("/sys/dict/add",params);
|
const addDict = (params)=>postAction("/sys/dict/add",params);
|
||||||
const editDict = (params)=>putAction("/sys/dict/edit",params);
|
const editDict = (params)=>putAction("/sys/dict/edit",params);
|
||||||
|
//const getDictList = (params)=>getAction("/sys/dict/list",params);
|
||||||
const treeList = (params)=>getAction("/sys/dict/treeList",params);
|
const treeList = (params)=>getAction("/sys/dict/treeList",params);
|
||||||
|
// const delDict = (params)=>deleteAction("/sys/dict/delete",params);
|
||||||
|
//const getDictItemList = (params)=>getAction("/sys/dictItem/list",params);
|
||||||
const addDictItem = (params)=>postAction("/sys/dictItem/add",params);
|
const addDictItem = (params)=>postAction("/sys/dictItem/add",params);
|
||||||
const editDictItem = (params)=>putAction("/sys/dictItem/edit",params);
|
const editDictItem = (params)=>putAction("/sys/dictItem/edit",params);
|
||||||
|
//const delDictItem = (params)=>deleteAction("/sys/dictItem/delete",params);
|
||||||
|
//const delDictItemList = (params)=>deleteAction("/sys/dictItem/deleteBatch",params);
|
||||||
|
|
||||||
//字典标签专用(通过code获取字典数组)
|
//字典标签专用(通过code获取字典数组)
|
||||||
export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItems/${code}`,params);
|
export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItems/${code}`,params);
|
||||||
@ -81,18 +101,33 @@ const doReovkeData = (params)=>getAction("/sys/annountCement/doReovkeData",param
|
|||||||
//获取系统访问量
|
//获取系统访问量
|
||||||
const getLoginfo = (params)=>getAction("/sys/loginfo",params);
|
const getLoginfo = (params)=>getAction("/sys/loginfo",params);
|
||||||
const getVisitInfo = (params)=>getAction("/sys/visitInfo",params);
|
const getVisitInfo = (params)=>getAction("/sys/visitInfo",params);
|
||||||
|
//数据日志访问
|
||||||
|
// const getDataLogList = (params)=>getAction("/sys/dataLog/list",params);
|
||||||
|
|
||||||
// 根据部门主键查询用户信息
|
// 根据部门主键查询用户信息
|
||||||
const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params);
|
const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params);
|
||||||
|
|
||||||
|
// 查询用户角色表里的所有信息
|
||||||
|
// const queryUserRoleMap = (params)=>getAction("/sys/user/queryUserRoleMap",params);
|
||||||
// 重复校验
|
// 重复校验
|
||||||
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
|
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
|
||||||
// 加载分类字典
|
// 加载分类字典
|
||||||
const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params);
|
const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params);
|
||||||
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
|
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
|
||||||
//我的通告
|
//加载我的通告信息
|
||||||
const getUserNoticeInfo= (params)=>getAction("/sys/sysAnnouncementSend/getMyAnnouncementSend",params);
|
const getUserNoticeInfo= (params)=>getAction("/sys/sysAnnouncementSend/getMyAnnouncementSend",params);
|
||||||
|
const getTransitURL = url => `/sys/common/transitRESTful?url=${encodeURIComponent(url)}`
|
||||||
|
// 中转HTTP请求
|
||||||
|
export const transitRESTful = {
|
||||||
|
get: (url, parameter) => getAction(getTransitURL(url), parameter),
|
||||||
|
post: (url, parameter) => postAction(getTransitURL(url), parameter),
|
||||||
|
put: (url, parameter) => putAction(getTransitURL(url), parameter),
|
||||||
|
http: (url, parameter) => httpAction(getTransitURL(url), parameter),
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
// imgView,
|
||||||
|
// doMian,
|
||||||
addRole,
|
addRole,
|
||||||
editRole,
|
editRole,
|
||||||
checkRoleCode,
|
checkRoleCode,
|
||||||
|
|||||||
@ -167,11 +167,15 @@ export function uploadAction(url,parameter){
|
|||||||
*/
|
*/
|
||||||
export function getFileAccessHttpUrl(avatar,subStr) {
|
export function getFileAccessHttpUrl(avatar,subStr) {
|
||||||
if(!subStr) subStr = 'http'
|
if(!subStr) subStr = 'http'
|
||||||
if(avatar && avatar.startsWith(subStr)){
|
try {
|
||||||
return avatar;
|
if(avatar && avatar.startsWith(subStr)){
|
||||||
}else{
|
return avatar;
|
||||||
if(avatar && avatar.length>0 && avatar.indexOf('[')==-1){
|
}else{
|
||||||
return window._CONFIG['staticDomainURL'] + "/" + avatar;
|
if(avatar && avatar.length>0 && avatar.indexOf('[')==-1){
|
||||||
|
return window._CONFIG['staticDomainURL'] + "/" + avatar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}catch(err){
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
ant-design-vue-jeecg/src/assets/less/codemirror_idea.css
Normal file
1
ant-design-vue-jeecg/src/assets/less/codemirror_idea.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
.cm-s-idea span.cm-meta{color:olive}.cm-s-idea span.cm-number{color:#00f}.cm-s-idea span.cm-keyword{line-height:1em;font-weight:700;color:navy}.cm-s-idea span.cm-atom{font-weight:700;color:navy}.cm-s-idea span.cm-def{color:#000}.cm-s-idea span.cm-variable{color:#000}.cm-s-idea span.cm-variable-2{color:#000}.cm-s-idea span.cm-type,.cm-s-idea span.cm-variable-3{color:#000}.cm-s-idea span.cm-property{color:#000}.cm-s-idea span.cm-operator{color:#000}.cm-s-idea span.cm-comment{color:grey}.cm-s-idea span.cm-string{color:green}.cm-s-idea span.cm-string-2{color:green}.cm-s-idea span.cm-qualifier{color:#555}.cm-s-idea span.cm-error{color:red}.cm-s-idea span.cm-attribute{color:#00f}.cm-s-idea span.cm-tag{color:navy}.cm-s-idea span.cm-link{color:#00f}.cm-s-idea .CodeMirror-activeline-background{background:#fffae3}.cm-s-idea span.cm-builtin{color:#30a}.cm-s-idea span.cm-bracket{color:#cc7}.cm-s-idea{font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif}.cm-s-idea .CodeMirror-matchingbracket{outline:1px solid grey;color:#000!important}.CodeMirror-hints.idea{font-family:Menlo,Monaco,Consolas,'Courier New',monospace;color:#616569;background-color:#ebf3fd!important}.CodeMirror-hints.idea .CodeMirror-hint-active{background-color:#a2b8c9!important;color:#5c6065!important}
|
||||||
@ -56,3 +56,6 @@
|
|||||||
.j-inner-table-wrapper /deep/ .ant-table-expanded-row .ant-table-wrapper .ant-table-tbody .ant-table-row {
|
.j-inner-table-wrapper /deep/ .ant-table-expanded-row .ant-table-wrapper .ant-table-tbody .ant-table-row {
|
||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**隐藏样式-modal确定按钮 */
|
||||||
|
.jee-hidden{display: none}
|
||||||
205
ant-design-vue-jeecg/src/components/JVxeCells/JVxeFileCell.vue
Normal file
205
ant-design-vue-jeecg/src/components/JVxeCells/JVxeFileCell.vue
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="hasFile" v-for="(file, fileKey) of [innerFile || {}]">
|
||||||
|
<div :key="fileKey" style="position: relative;">
|
||||||
|
<a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
|
||||||
|
<a-icon type="loading"/>
|
||||||
|
<span style="margin-left:5px">上传中…</span>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-tooltip v-else-if="file.status==='done'" :title="file.name">
|
||||||
|
<a-icon type="paper-clip"/>
|
||||||
|
<span style="margin-left:5px">{{ ellipsisFileName }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-tooltip v-else :title="file.name">
|
||||||
|
<a-icon type="paper-clip" style="color:red;"/>
|
||||||
|
<span style="color:red;margin-left:5px">{{ ellipsisFileName }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<template style="width: 30px">
|
||||||
|
<a-dropdown :trigger="['click']" placement="bottomRight" style="margin-left: 10px;">
|
||||||
|
<a-tooltip title="操作">
|
||||||
|
<a-icon
|
||||||
|
v-if="file.status!=='uploading'"
|
||||||
|
type="setting"
|
||||||
|
style="cursor: pointer;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-menu slot="overlay">
|
||||||
|
<a-menu-item v-if="originColumn.allowDownload !== false" @click="handleClickDownloadFile">
|
||||||
|
<span><a-icon type="download"/> 下载</span>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile">
|
||||||
|
<span><a-icon type="delete"/> 删除</span>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item @click="handleMoreOperation">
|
||||||
|
<span><a-icon type="bars"/> 更多</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<a-upload
|
||||||
|
v-show="!hasFile"
|
||||||
|
name="file"
|
||||||
|
:data="{'isup': 1}"
|
||||||
|
:multiple="false"
|
||||||
|
:action="uploadAction"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:showUploadList="false"
|
||||||
|
v-bind="cellProps"
|
||||||
|
@change="handleChangeUpload"
|
||||||
|
>
|
||||||
|
<a-button icon="upload">{{originColumn.btnText || '上传文件'}}</a-button>
|
||||||
|
</a-upload>
|
||||||
|
<j-file-pop ref="filePop" @ok="handleFileSuccess"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getFileAccessHttpUrl } from '@api/manage'
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
import JFilePop from '@/components/jeecg/minipop/JFilePop'
|
||||||
|
|
||||||
|
import JVxeUploadCell from '@/components/jeecg/JVxeTable/components/cells/JVxeUploadCell'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeFileCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
components: {JFilePop},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innerFile: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
/** upload headers */
|
||||||
|
uploadHeaders() {
|
||||||
|
let {originColumn: col} = this
|
||||||
|
let headers = {}
|
||||||
|
if (col.token === true) {
|
||||||
|
headers['X-Access-Token'] = this.$ls.get(ACCESS_TOKEN)
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 上传请求地址 */
|
||||||
|
uploadAction() {
|
||||||
|
if (!this.originColumn.action) {
|
||||||
|
return window._CONFIG['domianURL'] + '/sys/common/upload'
|
||||||
|
} else {
|
||||||
|
return this.originColumn.action
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hasFile() {
|
||||||
|
return this.innerFile != null
|
||||||
|
},
|
||||||
|
|
||||||
|
ellipsisFileName() {
|
||||||
|
let length = 5
|
||||||
|
let file = this.innerFile
|
||||||
|
if (!file || !file.name) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (file.name.length > length) {
|
||||||
|
return file.name.substr(0, length) + '…'
|
||||||
|
}
|
||||||
|
return file.name
|
||||||
|
},
|
||||||
|
|
||||||
|
responseName() {
|
||||||
|
if (this.originColumn.responseName) {
|
||||||
|
return this.originColumn.responseName
|
||||||
|
} else {
|
||||||
|
return 'message'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler() {
|
||||||
|
if (this.innerValue) {
|
||||||
|
this.innerFile = this.innerValue
|
||||||
|
} else {
|
||||||
|
this.innerFile = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
// 点击更多按钮
|
||||||
|
handleMoreOperation() {
|
||||||
|
let path = ''
|
||||||
|
if (this.innerFile) {
|
||||||
|
path = this.innerFile.path
|
||||||
|
}
|
||||||
|
this.$refs.filePop.show('', path)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 更多上传回调
|
||||||
|
handleFileSuccess(file) {
|
||||||
|
if (file) {
|
||||||
|
this.innerFile.path = file.path
|
||||||
|
this.handleChangeCommon(this.innerFile)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChangeUpload(info) {
|
||||||
|
let {originColumn: col} = this
|
||||||
|
let {file} = info
|
||||||
|
let value = {
|
||||||
|
name: file.name,
|
||||||
|
type: file.type,
|
||||||
|
size: file.size,
|
||||||
|
status: file.status,
|
||||||
|
percent: file.percent
|
||||||
|
}
|
||||||
|
if (file.response) {
|
||||||
|
value['responseName'] = file.response[this.responseName]
|
||||||
|
}
|
||||||
|
if (file.status === 'done') {
|
||||||
|
value['path'] = file.response[this.responseName]
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
} else if (file.status === 'error') {
|
||||||
|
value['message'] = file.response.message || '未知错误'
|
||||||
|
}
|
||||||
|
this.innerFile = value
|
||||||
|
},
|
||||||
|
|
||||||
|
handleClickDownloadFile() {
|
||||||
|
let {url, path} = this.innerFile || {}
|
||||||
|
if (!url || url.length === 0) {
|
||||||
|
if (path && path.length > 0) {
|
||||||
|
url = getFileAccessHttpUrl(path.split(',')[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (url) {
|
||||||
|
window.open(url)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleClickDeleteFile() {
|
||||||
|
this.handleChangeCommon(null)
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
switches: {visible: true},
|
||||||
|
getValue: value => JVxeUploadCell.enhanced.getValue(value),
|
||||||
|
setValue: value => JVxeUploadCell.enhanced.setValue(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
</style>
|
||||||
230
ant-design-vue-jeecg/src/components/JVxeCells/JVxeImageCell.vue
Normal file
230
ant-design-vue-jeecg/src/components/JVxeCells/JVxeImageCell.vue
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="hasFile" v-for="(file, fileKey) of [innerFile || {}]">
|
||||||
|
<div :key="fileKey" style="position: relative;">
|
||||||
|
<template v-if="!file || !(file['url'] || file['path'] || file['message'])">
|
||||||
|
<a-tooltip :title="'请稍后: ' + JSON.stringify (file) + ((file['url'] || file['path'] || file['message']))">
|
||||||
|
<a-icon type="loading"/>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="file['path']">
|
||||||
|
<img class="j-editable-image" :src="imgSrc" alt="无图片" @click="handleMoreOperation"/>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError"/>
|
||||||
|
</template>
|
||||||
|
<template slot="addonBefore" style="width: 30px">
|
||||||
|
<a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
|
||||||
|
<a-icon type="loading"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip v-else-if="file.status==='done'" title="上传完成">
|
||||||
|
<a-icon type="check-circle" style="color:#00DB00;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip v-else title="上传失败">
|
||||||
|
<a-icon type="exclamation-circle" style="color:red;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template style="width: 30px">
|
||||||
|
<a-dropdown :trigger="['click']" placement="bottomRight" style="margin-left: 10px;">
|
||||||
|
<a-tooltip title="操作">
|
||||||
|
<a-icon
|
||||||
|
v-if="file.status!=='uploading'"
|
||||||
|
type="setting"
|
||||||
|
style="cursor: pointer;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-menu slot="overlay">
|
||||||
|
<a-menu-item v-if="originColumn.allowDownload !== false" @click="handleClickDownloadFile">
|
||||||
|
<span><a-icon type="download"/> 下载</span>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile">
|
||||||
|
<span><a-icon type="delete"/> 删除</span>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item @click="handleMoreOperation">
|
||||||
|
<span><a-icon type="bars"/> 更多</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<a-upload
|
||||||
|
v-show="!hasFile"
|
||||||
|
name="file"
|
||||||
|
:data="{'isup': 1}"
|
||||||
|
:multiple="false"
|
||||||
|
:action="uploadAction"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:showUploadList="false"
|
||||||
|
v-bind="cellProps"
|
||||||
|
@change="handleChangeUpload"
|
||||||
|
>
|
||||||
|
<a-button icon="upload">{{originColumn.btnText || '上传图片'}}</a-button>
|
||||||
|
</a-upload>
|
||||||
|
<j-file-pop ref="filePop" @ok="handleFileSuccess"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getFileAccessHttpUrl } from '@api/manage'
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
import JFilePop from '@/components/jeecg/minipop/JFilePop'
|
||||||
|
|
||||||
|
import JVxeUploadCell from '@/components/jeecg/JVxeTable/components/cells/JVxeUploadCell'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeImageCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
components: {JFilePop},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innerFile: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
/** upload headers */
|
||||||
|
uploadHeaders() {
|
||||||
|
let {originColumn: col} = this
|
||||||
|
let headers = {}
|
||||||
|
if (col.token === true) {
|
||||||
|
headers['X-Access-Token'] = this.$ls.get(ACCESS_TOKEN)
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 上传请求地址 */
|
||||||
|
uploadAction() {
|
||||||
|
if (!this.originColumn.action) {
|
||||||
|
return window._CONFIG['domianURL'] + '/sys/common/upload'
|
||||||
|
} else {
|
||||||
|
return this.originColumn.action
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hasFile() {
|
||||||
|
return this.innerFile != null
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 预览图片地址 */
|
||||||
|
imgSrc() {
|
||||||
|
if (this.innerFile) {
|
||||||
|
if (this.innerFile['url']) {
|
||||||
|
return this.innerFile['url']
|
||||||
|
} else if (this.innerFile['path']) {
|
||||||
|
let path = this.innerFile['path'].split(',')[0]
|
||||||
|
return getFileAccessHttpUrl(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
|
||||||
|
responseName() {
|
||||||
|
if (this.originColumn.responseName) {
|
||||||
|
return this.originColumn.responseName
|
||||||
|
} else {
|
||||||
|
return 'message'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler() {
|
||||||
|
if (this.innerValue) {
|
||||||
|
this.innerFile = this.innerValue
|
||||||
|
} else {
|
||||||
|
this.innerFile = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
// 点击更多按钮
|
||||||
|
handleMoreOperation() {
|
||||||
|
let path = ''
|
||||||
|
if (this.innerFile) {
|
||||||
|
path = this.innerFile.path
|
||||||
|
}
|
||||||
|
this.$refs.filePop.show('', path, 'img')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 更多上传回调
|
||||||
|
handleFileSuccess(file) {
|
||||||
|
if (file) {
|
||||||
|
this.innerFile.path = file.path
|
||||||
|
this.handleChangeCommon(this.innerFile)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 弹出上传出错详细信息
|
||||||
|
handleClickShowImageError() {
|
||||||
|
let file = this.innerFile || null
|
||||||
|
if (file && file['message']) {
|
||||||
|
this.$error({title: '上传出错', content: '错误信息:' + file['message'], maskClosable: true})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChangeUpload(info) {
|
||||||
|
let {originColumn: col} = this
|
||||||
|
let {file} = info
|
||||||
|
let value = {
|
||||||
|
name: file.name,
|
||||||
|
type: file.type,
|
||||||
|
size: file.size,
|
||||||
|
status: file.status,
|
||||||
|
percent: file.percent
|
||||||
|
}
|
||||||
|
if (file.response) {
|
||||||
|
value['responseName'] = file.response[this.responseName]
|
||||||
|
}
|
||||||
|
if (file.status === 'done') {
|
||||||
|
value['path'] = file.response[this.responseName]
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
} else if (file.status === 'error') {
|
||||||
|
value['message'] = file.response.message || '未知错误'
|
||||||
|
}
|
||||||
|
this.innerFile = value
|
||||||
|
},
|
||||||
|
|
||||||
|
handleClickDownloadFile() {
|
||||||
|
if (this.imgSrc) {
|
||||||
|
window.open(this.imgSrc)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleClickDeleteFile() {
|
||||||
|
this.handleChangeCommon(null)
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
switches: {visible: true},
|
||||||
|
getValue: value => JVxeUploadCell.enhanced.getValue(value),
|
||||||
|
setValue: value => JVxeUploadCell.enhanced.setValue(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.j-editable-image {
|
||||||
|
height: 32px;
|
||||||
|
max-width: 100px !important;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<j-popup
|
||||||
|
v-bind="popupProps"
|
||||||
|
@input="handlePopupInput"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins, { vModel, dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxePopupCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
computed: {
|
||||||
|
popupProps() {
|
||||||
|
const {innerValue, originColumn: col, caseId, cellProps} = this
|
||||||
|
return {
|
||||||
|
...cellProps,
|
||||||
|
value: innerValue,
|
||||||
|
field: col.field || col.key,
|
||||||
|
code: col.popupCode,
|
||||||
|
orgFields: col.orgFields,
|
||||||
|
destFields: col.destFields,
|
||||||
|
groupId: caseId,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** popup回调 */
|
||||||
|
handlePopupInput(value, others) {
|
||||||
|
const {row, originColumn: col} = this
|
||||||
|
// 存储输入的值
|
||||||
|
let popupValue = value
|
||||||
|
if (others && Object.keys(others).length > 0) {
|
||||||
|
Object.keys(others).forEach(key => {
|
||||||
|
let currentValue = others[key]
|
||||||
|
// 当前列直接赋值,其他列通过vModel赋值
|
||||||
|
if (key === col.key) {
|
||||||
|
popupValue = currentValue
|
||||||
|
} else {
|
||||||
|
vModel.call(this, currentValue, row, key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.handleChangeCommon(popupValue)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
aopEvents: {
|
||||||
|
editActived: event => dispatchEvent(event, 'ant-input'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<a-radio-group
|
||||||
|
:class="clazz"
|
||||||
|
:value="innerValue"
|
||||||
|
v-bind="cellProps"
|
||||||
|
@change="(e)=>handleChangeCommon(e.target.value)"
|
||||||
|
>
|
||||||
|
<a-radio
|
||||||
|
v-for="item of originColumn.options"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
@click="$event=>handleRadioClick(item,$event)"
|
||||||
|
>{{ item.text }}
|
||||||
|
</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeRadioCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
computed: {
|
||||||
|
scrolling() {
|
||||||
|
return !!this.renderOptions.scrolling
|
||||||
|
},
|
||||||
|
clazz() {
|
||||||
|
return {
|
||||||
|
'j-vxe-radio': true,
|
||||||
|
'no-animation': this.scrolling
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleRadioClick(item) {
|
||||||
|
if (this.originColumn.allowClear === true) {
|
||||||
|
// 取消选择
|
||||||
|
if (item.value === this.innerValue) {
|
||||||
|
this.handleChangeCommon(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
switches: {visible: true},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
// 关闭动画,防止滚动时动态赋值出现问题
|
||||||
|
.j-vxe-radio.no-animation {
|
||||||
|
.ant-radio-inner,
|
||||||
|
.ant-radio-inner::after {
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,260 @@
|
|||||||
|
import debounce from 'lodash/debounce'
|
||||||
|
import { getAction } from '@/api/manage'
|
||||||
|
import { cloneObject } from '@/utils/util'
|
||||||
|
import { filterDictText } from '@/components/dict/JDictSelectUtil'
|
||||||
|
import { ajaxGetDictItems, getDictItemsFromCache } from '@/api/api'
|
||||||
|
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
/** 公共资源 */
|
||||||
|
const common = {
|
||||||
|
/** value - label map,防止重复查询(刷新清空缓存) */
|
||||||
|
labelMap: new Map(),
|
||||||
|
|
||||||
|
/** 公共data */
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
innerSelectValue: null,
|
||||||
|
innerOptions: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 公共计算属性 */
|
||||||
|
computed: {
|
||||||
|
dict() {
|
||||||
|
return this.originColumn.dict
|
||||||
|
},
|
||||||
|
options() {
|
||||||
|
if (this.isAsync) {
|
||||||
|
return this.innerOptions
|
||||||
|
} else {
|
||||||
|
return this.originColumn.options || []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 是否是异步模式
|
||||||
|
isAsync() {
|
||||||
|
let isAsync = this.originColumn.async
|
||||||
|
return (isAsync != null && isAsync !== '') ? !!isAsync : true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/** 公共属性监听 */
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler(value) {
|
||||||
|
if (value == null || value === '') {
|
||||||
|
this.innerSelectValue = null
|
||||||
|
} else {
|
||||||
|
this.loadDataByValue(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dict() {
|
||||||
|
this.loadDataByDict()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 公共方法 */
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
// 根据 value 查询数据,用于回显
|
||||||
|
async loadDataByValue(value) {
|
||||||
|
if (this.isAsync) {
|
||||||
|
if (this.innerSelectValue !== value) {
|
||||||
|
if (common.labelMap.has(value)) {
|
||||||
|
this.innerOptions = cloneObject(common.labelMap.get(value))
|
||||||
|
} else {
|
||||||
|
let {success, result} = await getAction(`/sys/dict/loadDictItem/${this.dict}`, {key: value})
|
||||||
|
if (success && result && result.length > 0) {
|
||||||
|
this.innerOptions = [{value: value, text: result[0]}]
|
||||||
|
common.labelMap.set(value, cloneObject(this.innerOptions))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.innerSelectValue = (value || '').toString()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 初始化字典
|
||||||
|
async loadDataByDict() {
|
||||||
|
if (!this.isAsync) {
|
||||||
|
// 如果字典项集合有数据
|
||||||
|
if (!this.originColumn.options || this.originColumn.options.length === 0) {
|
||||||
|
// 根据字典Code, 初始化字典数组
|
||||||
|
let dictStr = ''
|
||||||
|
if (this.dict) {
|
||||||
|
let arr = this.dict.split(',')
|
||||||
|
if (arr[0].indexOf('where') > 0) {
|
||||||
|
let tbInfo = arr[0].split('where')
|
||||||
|
dictStr = tbInfo[0].trim() + ',' + arr[1] + ',' + arr[2] + ',' + encodeURIComponent(tbInfo[1])
|
||||||
|
} else {
|
||||||
|
dictStr = this.dict
|
||||||
|
}
|
||||||
|
if (this.dict.indexOf(',') === -1) {
|
||||||
|
//优先从缓存中读取字典配置
|
||||||
|
let cache = getDictItemsFromCache(this.dict)
|
||||||
|
if (cache) {
|
||||||
|
this.innerOptions = cache
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let {success, result} = await ajaxGetDictItems(dictStr, null)
|
||||||
|
if (success) {
|
||||||
|
this.innerOptions = result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示组件,自带翻译
|
||||||
|
export const DictSearchSpanCell = {
|
||||||
|
name: 'JVxeSelectSearchSpanCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
...common.data.apply(this),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...common.computed,
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
...common.watch,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...common.methods,
|
||||||
|
},
|
||||||
|
render(h) {
|
||||||
|
return h('span', {}, [
|
||||||
|
filterDictText(this.innerOptions, this.innerSelectValue || this.innerValue)
|
||||||
|
])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求id
|
||||||
|
let requestId = 0
|
||||||
|
|
||||||
|
// 输入选择组件
|
||||||
|
export const DictSearchInputCell = {
|
||||||
|
name: 'JVxeSelectSearchInputCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
...common.data.apply(this),
|
||||||
|
|
||||||
|
hasRequest: false,
|
||||||
|
scopedSlots: {
|
||||||
|
notFoundContent: () => {
|
||||||
|
if (this.loading) {
|
||||||
|
return <a-spin size="small"/>
|
||||||
|
} else if (this.hasRequest) {
|
||||||
|
return <div>没有查询到任何数据</div>
|
||||||
|
} else {
|
||||||
|
return <div>{this.tipsContent}</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...common.computed,
|
||||||
|
tipsContent() {
|
||||||
|
return this.originColumn.tipsContent || '请输入搜索内容'
|
||||||
|
},
|
||||||
|
filterOption() {
|
||||||
|
if (this.isAsync) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return (input, option) => option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
...common.watch,
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadData = debounce(this.loadData, 300)//消抖
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...common.methods,
|
||||||
|
|
||||||
|
loadData(value) {
|
||||||
|
const currentRequestId = ++requestId
|
||||||
|
this.loading = true
|
||||||
|
this.innerOptions = []
|
||||||
|
if (value == null || value.trim() === '') {
|
||||||
|
this.loading = false
|
||||||
|
this.hasRequest = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 字典code格式:table,text,code
|
||||||
|
this.hasRequest = true
|
||||||
|
getAction(`/sys/dict/loadDict/${this.dict}`, {keyword: value}).then(res => {
|
||||||
|
if (currentRequestId !== requestId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let {success, result, message} = res
|
||||||
|
if (success) {
|
||||||
|
this.innerOptions = result
|
||||||
|
result.forEach((item) => {
|
||||||
|
common.labelMap.set(item.value, [item])
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$message.warning(message)
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChange(selectedValue) {
|
||||||
|
this.innerSelectValue = selectedValue
|
||||||
|
this.handleChangeCommon(this.innerSelectValue)
|
||||||
|
},
|
||||||
|
handleSearch(value) {
|
||||||
|
if (this.isAsync) {
|
||||||
|
// 在输入时也应该开启加载,因为loadData加了消抖,所以会有800ms的用户主观上认为的卡顿时间
|
||||||
|
this.loading = true
|
||||||
|
if (this.innerOptions.length > 0) {
|
||||||
|
this.innerOptions = []
|
||||||
|
}
|
||||||
|
this.loadData(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
renderOptionItem() {
|
||||||
|
let options = []
|
||||||
|
this.options.forEach(({value, text, label, title, disabled}) => {
|
||||||
|
options.push(
|
||||||
|
<a-select-option key={value} value={value} disabled={disabled}>{text || label || title}</a-select-option>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return options
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<a-select
|
||||||
|
showSearch
|
||||||
|
allowClear
|
||||||
|
value={this.innerSelectValue}
|
||||||
|
filterOption={this.filterOption}
|
||||||
|
style="width: 100%"
|
||||||
|
{...this.cellProps}
|
||||||
|
onSearch={this.handleSearch}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
scopedSlots={this.scopedSlots}
|
||||||
|
>
|
||||||
|
{this.renderOptionItem()}
|
||||||
|
</a-select>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
aopEvents: {
|
||||||
|
editActived: event => dispatchEvent(event, 'ant-select'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
36
ant-design-vue-jeecg/src/components/JVxeCells/install.js
Normal file
36
ant-design-vue-jeecg/src/components/JVxeCells/install.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { installCell, JVXETypes } from '@/components/jeecg/JVxeTable'
|
||||||
|
import JVxePopupCell from './JVxePopupCell'
|
||||||
|
import { DictSearchInputCell, DictSearchSpanCell } from './JVxeSelectDictSearchCell'
|
||||||
|
import JVxeFileCell from './JVxeFileCell'
|
||||||
|
import JVxeImageCell from './JVxeImageCell'
|
||||||
|
import JVxeRadioCell from './JVxeRadioCell'
|
||||||
|
import JVxeSelectCell from '@comp/jeecg/JVxeTable/components/cells/JVxeSelectCell'
|
||||||
|
import JVxeTextareaCell from '@comp/jeecg/JVxeTable/components/cells/JVxeTextareaCell'
|
||||||
|
|
||||||
|
// 注册online组件
|
||||||
|
JVXETypes.input_pop = 'input_pop'
|
||||||
|
JVXETypes.list_multi = 'list_multi'
|
||||||
|
JVXETypes.sel_search = 'sel_search'
|
||||||
|
installCell(JVXETypes.input_pop, JVxeTextareaCell)
|
||||||
|
installCell(JVXETypes.list_multi, JVxeSelectCell)
|
||||||
|
installCell(JVXETypes.sel_search, JVxeSelectCell)
|
||||||
|
|
||||||
|
// 注册【popup】组件(普通封装方式)
|
||||||
|
JVXETypes.popup = 'popup'
|
||||||
|
installCell(JVXETypes.popup, JVxePopupCell)
|
||||||
|
|
||||||
|
// 注册【字典搜索下拉】组件(高级封装方式)
|
||||||
|
JVXETypes.selectDictSearch = 'select-dict-search'
|
||||||
|
installCell(JVXETypes.selectDictSearch, DictSearchInputCell, DictSearchSpanCell)
|
||||||
|
|
||||||
|
// 注册【文件上传】组件
|
||||||
|
JVXETypes.file = 'file'
|
||||||
|
installCell(JVXETypes.file, JVxeFileCell)
|
||||||
|
|
||||||
|
// 注册【图片上传】组件
|
||||||
|
JVXETypes.image = 'image'
|
||||||
|
installCell(JVXETypes.image, JVxeImageCell)
|
||||||
|
|
||||||
|
// 注册【单选框】组件
|
||||||
|
JVXETypes.radio = 'radio'
|
||||||
|
installCell(JVXETypes.radio, JVxeRadioCell)
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{ padding: '0 0 32px 32px' }">
|
<div :style="{ padding: '0 0 32px 32px' }">
|
||||||
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
|
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
|
||||||
<v-chart :data="data" :height="height" :force-fit="true" :onClick="handleClick">
|
<v-chart :data="data" :height="height" :force-fit="true" :scale="scale" :onClick="handleClick">
|
||||||
<v-tooltip/>
|
<v-tooltip/>
|
||||||
<v-axis/>
|
<v-axis/>
|
||||||
<v-legend/>
|
<v-legend/>
|
||||||
@ -78,6 +78,14 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
return rows
|
return rows
|
||||||
|
},
|
||||||
|
scale() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'cat',
|
||||||
|
dataKey: 'x'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,6 +57,7 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
scale: [{
|
scale: [{
|
||||||
|
type: 'cat',
|
||||||
dataKey: 'x',
|
dataKey: 'x',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 1
|
max: 1
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<a-radio-button v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio-button>
|
<a-radio-button v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio-button>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
|
|
||||||
<a-select v-else-if="tagType=='select'" :getPopupContainer = "(target) => target.parentNode" :placeholder="placeholder" :disabled="disabled" :value="getValueSting" @change="handleInput">
|
<a-select v-else-if="tagType=='select'" :getPopupContainer = "getPopupContainer" :placeholder="placeholder" :disabled="disabled" :value="getValueSting" @change="handleInput">
|
||||||
<a-select-option :value="undefined">请选择</a-select-option>
|
<a-select-option :value="undefined">请选择</a-select-option>
|
||||||
<a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">
|
<a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">
|
||||||
<span style="display: inline-block;width: 100%" :title=" item.text || item.label ">
|
<span style="display: inline-block;width: 100%" :title=" item.text || item.label ">
|
||||||
@ -28,7 +28,11 @@
|
|||||||
triggerChange: Boolean,
|
triggerChange: Boolean,
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
value: [String, Number],
|
value: [String, Number],
|
||||||
type: String
|
type: String,
|
||||||
|
getPopupContainer:{
|
||||||
|
type: Function,
|
||||||
|
default: (node) => node.parentNode
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -56,7 +60,10 @@
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getValueSting(){
|
getValueSting(){
|
||||||
return this.value != null ? this.value.toString() : null;
|
// update-begin author:wangshuai date:20200601 for: 不显示placeholder的文字 ------
|
||||||
|
// 当有null或“” placeholder不显示
|
||||||
|
return this.value != null ? this.value.toString() : undefined;
|
||||||
|
// update-end author:wangshuai date:20200601 for: 不显示placeholder的文字 ------
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@ -36,15 +36,20 @@ export async function initDictOptions(dictCode) {
|
|||||||
*/
|
*/
|
||||||
export function filterDictText(dictOptions, text) {
|
export function filterDictText(dictOptions, text) {
|
||||||
// --update-begin----author:sunjianlei---date:20200323------for: 字典翻译 text 允许逗号分隔 ---
|
// --update-begin----author:sunjianlei---date:20200323------for: 字典翻译 text 允许逗号分隔 ---
|
||||||
if (text != null && dictOptions instanceof Array) {
|
if (text != null && Array.isArray(dictOptions)) {
|
||||||
let result = []
|
let result = []
|
||||||
// 允许多个逗号分隔
|
// 允许多个逗号分隔,允许传数组对象
|
||||||
let splitText = text.toString().trim().split(',')
|
let splitText
|
||||||
|
if (Array.isArray(text)) {
|
||||||
|
splitText = text
|
||||||
|
} else {
|
||||||
|
splitText = text.toString().trim().split(',')
|
||||||
|
}
|
||||||
for (let txt of splitText) {
|
for (let txt of splitText) {
|
||||||
let dictText = txt
|
let dictText = txt
|
||||||
for (let dictItem of dictOptions) {
|
for (let dictItem of dictOptions) {
|
||||||
if (txt === dictItem.value.toString()) {
|
if (txt.toString() === dictItem.value.toString()) {
|
||||||
dictText = dictItem.text
|
dictText = (dictItem.text || dictItem.title || dictItem.label)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,6 +90,14 @@
|
|||||||
handler(){
|
handler(){
|
||||||
this.initDictData()
|
this.initDictData()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'dictOptions':{
|
||||||
|
deep: true,
|
||||||
|
handler(val){
|
||||||
|
if(val && val.length>0){
|
||||||
|
this.options = [...val]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="!reloading" class="j-area-linkage">
|
<div class="j-area-linkage">
|
||||||
|
<div v-if="reloading">
|
||||||
|
<span> Reloading... </span>
|
||||||
|
</div>
|
||||||
<area-cascader
|
<area-cascader
|
||||||
v-if="_type === enums.type[0]"
|
v-else-if="_type === enums.type[0]"
|
||||||
:value="innerValue"
|
:value="innerValue"
|
||||||
:data="pcaa"
|
:data="pcaa"
|
||||||
:level="1"
|
:level="1"
|
||||||
@ -90,19 +93,23 @@
|
|||||||
this.initAreaData();
|
this.initAreaData();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
/** 重新加载组件 */
|
||||||
|
reload() {
|
||||||
|
this.reloading = true
|
||||||
|
this.$nextTick(() => this.reloading = false)
|
||||||
|
},
|
||||||
|
|
||||||
/** 通过 value 反推 options */
|
/** 通过 value 反推 options */
|
||||||
loadDataByValue(value) {
|
loadDataByValue(value) {
|
||||||
if(!value || value.length==0){
|
if (!value || value.length === 0) {
|
||||||
this.innerValue = []
|
this.innerValue = []
|
||||||
this.reloading = true;
|
} else {
|
||||||
setTimeout(()=>{
|
this.initAreaData()
|
||||||
this.reloading = false
|
let arr = this.areaData.getRealCode(value)
|
||||||
},100)
|
|
||||||
}else{
|
|
||||||
this.initAreaData();
|
|
||||||
let arr = this.areaData.getRealCode(value);
|
|
||||||
this.innerValue = arr
|
this.innerValue = arr
|
||||||
}
|
}
|
||||||
|
this.reload()
|
||||||
},
|
},
|
||||||
/** 通过地区code获取子级 */
|
/** 通过地区code获取子级 */
|
||||||
loadDataByCode(value) {
|
loadDataByCode(value) {
|
||||||
|
|||||||
@ -196,9 +196,14 @@
|
|||||||
if(!value){
|
if(!value){
|
||||||
this.$emit('change', '');
|
this.$emit('change', '');
|
||||||
this.treeValue = ''
|
this.treeValue = ''
|
||||||
} else if (value instanceof Array) {
|
} else if (Array.isArray(value)) {
|
||||||
//this.$emit('change', value.map(item => item.value).join(','))
|
let labels = []
|
||||||
//this.treeValue = value
|
let values = value.map(item => {
|
||||||
|
labels.push(item.label)
|
||||||
|
return item.value
|
||||||
|
})
|
||||||
|
this.backValue(values.join(','), labels.join(','))
|
||||||
|
this.treeValue = value
|
||||||
} else {
|
} else {
|
||||||
this.backValue(value.value,value.label)
|
this.backValue(value.value,value.label)
|
||||||
this.treeValue = value
|
this.treeValue = value
|
||||||
|
|||||||
@ -46,6 +46,8 @@
|
|||||||
import 'codemirror/mode/swift/swift.js'
|
import 'codemirror/mode/swift/swift.js'
|
||||||
import 'codemirror/mode/vue/vue.js'
|
import 'codemirror/mode/vue/vue.js'
|
||||||
|
|
||||||
|
import { isIE11, isIE } from '@/utils/browser'
|
||||||
|
|
||||||
// 尝试获取全局实例
|
// 尝试获取全局实例
|
||||||
const CodeMirror = window.CodeMirror || _CodeMirror
|
const CodeMirror = window.CodeMirror || _CodeMirror
|
||||||
|
|
||||||
@ -85,7 +87,21 @@
|
|||||||
zIndex: {
|
zIndex: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: 999
|
default: 999
|
||||||
}
|
},
|
||||||
|
// 是否自适应高度,可以传String或Boolean
|
||||||
|
// 传 String 类型只能写"!ie" ,
|
||||||
|
// 填写这个字符串,代表其他浏览器自适应高度
|
||||||
|
// 唯独IE下不自适应高度,因为IE下不支持min、max-height样式
|
||||||
|
// 如果填写的不是"!ie"就视为true
|
||||||
|
autoHeight: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 不自适应高度的情况下生效的固定高度
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '240px'
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@ -217,14 +233,30 @@
|
|||||||
hintOptions: this.options.hintOptions
|
hintOptions: this.options.hintOptions
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fullScreenParentProps(){
|
isAutoHeight() {
|
||||||
|
let {autoHeight} = this
|
||||||
|
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
||||||
|
autoHeight = !(isIE() || isIE11())
|
||||||
|
} else {
|
||||||
|
autoHeight = true
|
||||||
|
}
|
||||||
|
return autoHeight
|
||||||
|
},
|
||||||
|
fullScreenParentProps() {
|
||||||
let props = {
|
let props = {
|
||||||
class: ['full-screen-parent', this.fullCoder ? 'full-screen' : ''],
|
class: {
|
||||||
|
'full-screen-parent': true,
|
||||||
|
'full-screen': this.fullCoder,
|
||||||
|
'auto-height': this.isAutoHeight
|
||||||
|
},
|
||||||
style: {}
|
style: {}
|
||||||
}
|
}
|
||||||
if (this.fullCoder) {
|
if (this.fullCoder) {
|
||||||
props.style['z-index'] = this.zIndex
|
props.style['z-index'] = this.zIndex
|
||||||
}
|
}
|
||||||
|
if (!this.isAutoHeight) {
|
||||||
|
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
||||||
|
}
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -240,7 +272,8 @@
|
|||||||
// 编辑器赋值
|
// 编辑器赋值
|
||||||
if(this.value||this.code){
|
if(this.value||this.code){
|
||||||
this.hasCode=true
|
this.hasCode=true
|
||||||
this.coder.setValue(this.value || this.code)
|
//this.coder.setValue(this.value || this.code)
|
||||||
|
this.setCodeContent(this.value || this.code)
|
||||||
}else{
|
}else{
|
||||||
this.coder.setValue('')
|
this.coder.setValue('')
|
||||||
this.hasCode=false
|
this.hasCode=false
|
||||||
@ -408,6 +441,7 @@
|
|||||||
top: 12px;
|
top: 12px;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-screen-child {
|
.full-screen-child {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
@ -416,9 +450,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.full-screen-child {
|
.full-screen-child {
|
||||||
min-height: 120px;
|
height: 100%;
|
||||||
max-height: 320px;
|
}
|
||||||
overflow:hidden;
|
|
||||||
|
&.auto-height {
|
||||||
|
.full-screen-child {
|
||||||
|
min-height: 120px;
|
||||||
|
max-height: 320px;
|
||||||
|
height: unset;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.full-screen .full-screen-child {
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
282
ant-design-vue-jeecg/src/components/jeecg/JCodeEditor2.vue
Normal file
282
ant-design-vue-jeecg/src/components/jeecg/JCodeEditor2.vue
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
<template>
|
||||||
|
<div v-bind="fullScreenParentProps">
|
||||||
|
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
||||||
|
|
||||||
|
<div class="code-editor-cust full-screen-child">
|
||||||
|
<a-textarea auto-size v-model="textareaValue" :placeholder="placeholderShow" @change="handleChange" :style="{'max-height': maxHeight+'px','min-height': minHeight+'px'}"></a-textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script type="text/ecmascript-6">
|
||||||
|
export default {
|
||||||
|
name: 'JCodeEditor',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
// 是否显示全屏按钮
|
||||||
|
fullScreen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 全屏以后的z-index
|
||||||
|
zIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 999
|
||||||
|
},
|
||||||
|
// 是否自适应高度,可以传String或Boolean
|
||||||
|
// 传 String 类型只能写"!ie" ,
|
||||||
|
// 填写这个字符串,代表其他浏览器自适应高度
|
||||||
|
// 唯独IE下不自适应高度,因为IE下不支持min、max-height样式
|
||||||
|
// 如果填写的不是"!ie"就视为true
|
||||||
|
autoHeight: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 不自适应高度的情况下生效的固定高度
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '240px'
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
minHeight:{
|
||||||
|
type:Number,
|
||||||
|
default: 100,
|
||||||
|
required:false
|
||||||
|
},
|
||||||
|
maxHeight:{
|
||||||
|
type:Number,
|
||||||
|
default: 320,
|
||||||
|
required:false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
textareaValue: '',
|
||||||
|
// 内部真实的内容
|
||||||
|
code: '',
|
||||||
|
iconType: 'fullscreen',
|
||||||
|
hasCode:false,
|
||||||
|
// 默认的语法类型
|
||||||
|
mode: 'javascript',
|
||||||
|
// 编辑器实例
|
||||||
|
coder: null,
|
||||||
|
// 默认配置
|
||||||
|
options: {
|
||||||
|
// 缩进格式
|
||||||
|
tabSize: 2,
|
||||||
|
// 主题,对应主题库 JS 需要提前引入
|
||||||
|
theme: 'panda-syntax',
|
||||||
|
line: true,
|
||||||
|
// extraKeys: {'Ctrl': 'autocomplete'},//自定义快捷键
|
||||||
|
hintOptions: {
|
||||||
|
tables: {
|
||||||
|
users: ['name', 'score', 'birthDate'],
|
||||||
|
countries: ['name', 'population', 'size']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// code 编辑器 是否全屏
|
||||||
|
fullCoder: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
fullCoder:{
|
||||||
|
handler(value) {
|
||||||
|
if(value){
|
||||||
|
this.iconType="fullscreen-exit"
|
||||||
|
}else{
|
||||||
|
this.iconType="fullscreen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
placeholderShow() {
|
||||||
|
if (this.placeholder == null) {
|
||||||
|
return `请在此输入代码`
|
||||||
|
} else {
|
||||||
|
return this.placeholder
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isAutoHeight() {
|
||||||
|
let {autoHeight} = this
|
||||||
|
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
||||||
|
autoHeight = !(isIE() || isIE11())
|
||||||
|
} else {
|
||||||
|
autoHeight = true
|
||||||
|
}
|
||||||
|
return autoHeight
|
||||||
|
},
|
||||||
|
fullScreenParentProps() {
|
||||||
|
let props = {
|
||||||
|
class: {
|
||||||
|
'full-screen-parent': true,
|
||||||
|
'full-screen': this.fullCoder,
|
||||||
|
'auto-height': this.isAutoHeight
|
||||||
|
},
|
||||||
|
style: {}
|
||||||
|
}
|
||||||
|
if (this.fullCoder) {
|
||||||
|
props.style['z-index'] = this.zIndex
|
||||||
|
}
|
||||||
|
if (!this.isAutoHeight) {
|
||||||
|
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
||||||
|
}
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
// 初始化
|
||||||
|
this._initialize()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 初始化
|
||||||
|
_initialize () {
|
||||||
|
this.setCodeContent(this.value)
|
||||||
|
},
|
||||||
|
handleChange(e){
|
||||||
|
this.$emit('input', e.target.value)
|
||||||
|
},
|
||||||
|
getCodeContent(){
|
||||||
|
return this.value
|
||||||
|
},
|
||||||
|
setCodeContent(val){
|
||||||
|
setTimeout(()=>{
|
||||||
|
if(!val){
|
||||||
|
this.textareaValue = ''
|
||||||
|
}else{
|
||||||
|
this.textareaValue = val
|
||||||
|
}
|
||||||
|
},300)
|
||||||
|
},
|
||||||
|
nullTipClick(){
|
||||||
|
this.coder.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.code-editor-cust{
|
||||||
|
flex-grow:1;
|
||||||
|
display:flex;
|
||||||
|
position:relative;
|
||||||
|
height:100%;
|
||||||
|
.CodeMirror{
|
||||||
|
flex-grow:1;
|
||||||
|
z-index:1;
|
||||||
|
.CodeMirror-code{
|
||||||
|
line-height:19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.code-mode-select{
|
||||||
|
position:absolute;
|
||||||
|
z-index:2;
|
||||||
|
right:10px;
|
||||||
|
top:10px;
|
||||||
|
max-width:130px;
|
||||||
|
}
|
||||||
|
.CodeMirror{
|
||||||
|
height: auto;
|
||||||
|
min-height:100%;
|
||||||
|
}
|
||||||
|
.null-tip{
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
left: 36px;
|
||||||
|
z-index: 10;
|
||||||
|
color: #ffffffc9;
|
||||||
|
line-height: initial;
|
||||||
|
}
|
||||||
|
.null-tip-hidden{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全屏样式 */
|
||||||
|
.full-screen-parent {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.full-screen-icon {
|
||||||
|
opacity: 0;
|
||||||
|
color: black;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 24px;
|
||||||
|
background-color: white;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 2px;
|
||||||
|
z-index: 9;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.full-screen-icon {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.88);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.full-screen {
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
width: calc(100% - 20px);
|
||||||
|
height: calc(100% - 20px);
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
|
||||||
|
.full-screen-icon {
|
||||||
|
top: 12px;
|
||||||
|
right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-screen-child {
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-screen-child {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.auto-height {
|
||||||
|
.full-screen-child {
|
||||||
|
min-height: 120px;
|
||||||
|
max-height: 320px;
|
||||||
|
height: unset;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.full-screen .full-screen-child {
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-cursor{
|
||||||
|
height:18.4px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-date-picker
|
<a-date-picker
|
||||||
|
dropdownClassName="j-date-picker"
|
||||||
:disabled="disabled || readOnly"
|
:disabled="disabled || readOnly"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@change="handleDateChange"
|
@change="handleDateChange"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tinymce-editor">
|
<div class="tinymce-editor">
|
||||||
<editor
|
<editor
|
||||||
|
v-if="!reloading"
|
||||||
v-model="myValue"
|
v-model="myValue"
|
||||||
:init="init"
|
:init="init"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@ -23,7 +24,9 @@
|
|||||||
import 'tinymce/plugins/colorpicker'
|
import 'tinymce/plugins/colorpicker'
|
||||||
import 'tinymce/plugins/textcolor'
|
import 'tinymce/plugins/textcolor'
|
||||||
import 'tinymce/plugins/fullscreen'
|
import 'tinymce/plugins/fullscreen'
|
||||||
|
import 'tinymce/icons/default'
|
||||||
import { uploadAction,getFileAccessHttpUrl } from '@/api/manage'
|
import { uploadAction,getFileAccessHttpUrl } from '@/api/manage'
|
||||||
|
import { getVmParentByName } from '@/utils/util'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Editor
|
Editor
|
||||||
@ -83,21 +86,58 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
myValue: this.value
|
myValue: this.value,
|
||||||
|
reloading: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
tinymce.init({})
|
this.initATabsChangeAutoReload()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
reload() {
|
||||||
|
this.reloading = true
|
||||||
|
this.$nextTick(() => this.reloading = false)
|
||||||
|
},
|
||||||
|
|
||||||
onClick(e) {
|
onClick(e) {
|
||||||
this.$emit('onClick', e, tinymce)
|
this.$emit('onClick', e, tinymce)
|
||||||
},
|
},
|
||||||
//可以添加一些自己的自定义事件,如清空内容
|
//可以添加一些自己的自定义事件,如清空内容
|
||||||
clear() {
|
clear() {
|
||||||
this.myValue = ''
|
this.myValue = ''
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动判断父级是否是 <a-tabs/> 组件,然后添加事件监听,自动触发reload()
|
||||||
|
*
|
||||||
|
* 由于 tabs 组件切换会导致 tinymce 无法输入,
|
||||||
|
* 只有重新加载才能使用(无论是vue版的还是jQuery版tinymce都有这个通病)
|
||||||
|
*/
|
||||||
|
initATabsChangeAutoReload() {
|
||||||
|
// 获取父级
|
||||||
|
let tabs = getVmParentByName(this, 'ATabs')
|
||||||
|
let tabPane = getVmParentByName(this, 'ATabPane')
|
||||||
|
if (tabs && tabPane) {
|
||||||
|
// 用户自定义的 key
|
||||||
|
let currentKey = tabPane.$vnode.key
|
||||||
|
// 添加事件监听
|
||||||
|
tabs.$on('change', (key) => {
|
||||||
|
// 切换到自己时执行reload
|
||||||
|
if (currentKey === key) {
|
||||||
|
this.reload()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
//update--begin--autor:wangshuai-----date:20200724------for:富文本编辑器切换tab无法修改------
|
||||||
|
let tabLayout = getVmParentByName(this, 'TabLayout')
|
||||||
|
tabLayout.excuteCallback(()=>{
|
||||||
|
this.reload()
|
||||||
|
})
|
||||||
|
//update--begin--autor:wangshuai-----date:20200724------for:文本编辑器切换tab无法修改------
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value(newValue) {
|
value(newValue) {
|
||||||
|
|||||||
@ -1,27 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-upload
|
<div class="img">
|
||||||
name="file"
|
<a-upload
|
||||||
listType="picture-card"
|
name="file"
|
||||||
:multiple="isMultiple"
|
listType="picture-card"
|
||||||
:action="uploadAction"
|
:multiple="isMultiple"
|
||||||
:headers="headers"
|
:action="uploadAction"
|
||||||
:data="{biz:bizPath}"
|
:headers="headers"
|
||||||
:fileList="fileList"
|
:data="{biz:bizPath}"
|
||||||
:beforeUpload="beforeUpload"
|
:fileList="fileList"
|
||||||
:disabled="disabled"
|
:beforeUpload="beforeUpload"
|
||||||
:isMultiple="isMultiple"
|
:disabled="disabled"
|
||||||
:showUploadList="isMultiple"
|
:isMultiple="isMultiple"
|
||||||
@change="handleChange"
|
:showUploadList="isMultiple"
|
||||||
@preview="handlePreview">
|
@change="handleChange"
|
||||||
<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="height:104px;max-width:300px"/>
|
@preview="handlePreview"
|
||||||
<div v-else >
|
:class="!isMultiple?'imgupload':''">
|
||||||
<a-icon :type="uploadLoading ? 'loading' : 'plus'" />
|
<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="height:104px;max-width:300px"/>
|
||||||
<div class="ant-upload-text">{{ text }}</div>
|
<div v-else class="iconp">
|
||||||
</div>
|
<a-icon :type="uploadLoading ? 'loading' : 'plus'" />
|
||||||
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
|
<div class="ant-upload-text">{{ text }}</div>
|
||||||
<img alt="example" style="width: 100%" :src="previewImage"/>
|
</div>
|
||||||
</a-modal>
|
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
|
||||||
</a-upload>
|
<img alt="example" style="width: 100%" :src="previewImage"/>
|
||||||
|
</a-modal>
|
||||||
|
</a-upload>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -86,6 +89,9 @@
|
|||||||
} else {
|
} else {
|
||||||
this.initFileList(val)
|
this.initFileList(val)
|
||||||
}
|
}
|
||||||
|
if(!val || val.length==0){
|
||||||
|
this.picUrl = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
@ -168,8 +174,14 @@
|
|||||||
if(!this.isMultiple){
|
if(!this.isMultiple){
|
||||||
arr.push(uploadFiles[uploadFiles.length-1].response.message)
|
arr.push(uploadFiles[uploadFiles.length-1].response.message)
|
||||||
}else{
|
}else{
|
||||||
for(var a=0;a<uploadFiles.length;a++){
|
for(let a=0;a<uploadFiles.length;a++){
|
||||||
arr.push(uploadFiles[a].response.message)
|
// update-begin-author:taoyan date:20200819 for:【开源问题z】上传图片组件 LOWCOD-783
|
||||||
|
if(uploadFiles[a].status === 'done' ) {
|
||||||
|
arr.push(uploadFiles[a].response.message)
|
||||||
|
}else{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// update-end-author:taoyan date:20200819 for:【开源问题z】上传图片组件 LOWCOD-783
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(arr.length>0){
|
if(arr.length>0){
|
||||||
@ -197,5 +209,12 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* update--begin--autor:lvdandan-----date:20201016------for:j-image-upload图片组件单张图片详情回显空白
|
||||||
|
* https://github.com/zhangdaiscott/jeecg-boot/issues/1810
|
||||||
|
* https://github.com/zhangdaiscott/jeecg-boot/issues/1779
|
||||||
|
*/
|
||||||
|
/deep/ .imgupload .ant-upload-select{display:block}
|
||||||
|
/deep/ .imgupload .ant-upload.ant-upload-select-picture-card{ width:120px;height: 120px;}
|
||||||
|
/deep/ .imgupload .iconp{padding:32px;}
|
||||||
|
/* update--end--autor:lvdandan-----date:20201016------for:j-image-upload图片组件单张图片详情回显空白*/
|
||||||
</style>
|
</style>
|
||||||
@ -24,6 +24,11 @@
|
|||||||
type:String,
|
type:String,
|
||||||
required:false,
|
required:false,
|
||||||
default:''
|
default:''
|
||||||
|
},
|
||||||
|
trim:{
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default:false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
@ -56,7 +61,10 @@
|
|||||||
let text = this.value
|
let text = this.value
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case JINPUT_QUERY_LIKE:
|
case JINPUT_QUERY_LIKE:
|
||||||
text = text.substring(1,text.length-1);
|
//修复路由传参的值传送到jinput框被前后各截取了一位 #1336
|
||||||
|
if(text.indexOf("*") != -1){
|
||||||
|
text = text.substring(1,text.length-1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case JINPUT_QUERY_NE:
|
case JINPUT_QUERY_NE:
|
||||||
text = text.substring(1);
|
text = text.substring(1);
|
||||||
@ -74,6 +82,9 @@
|
|||||||
},
|
},
|
||||||
backValue(e){
|
backValue(e){
|
||||||
let text = e.target.value
|
let text = e.target.value
|
||||||
|
if(text && this.trim===true){
|
||||||
|
text = text.trim()
|
||||||
|
}
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case JINPUT_QUERY_LIKE:
|
case JINPUT_QUERY_LIKE:
|
||||||
text = "*"+text+"*";
|
text = "*"+text+"*";
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
export default {
|
||||||
|
minHeight: '200px',
|
||||||
|
previewStyle: 'vertical',
|
||||||
|
useCommandShortcut: true,
|
||||||
|
useDefaultHTMLSanitizer: true,
|
||||||
|
usageStatistics: false,
|
||||||
|
hideModeSwitch: false,
|
||||||
|
toolbarItems: [
|
||||||
|
'heading',
|
||||||
|
'bold',
|
||||||
|
'italic',
|
||||||
|
'strike',
|
||||||
|
'divider',
|
||||||
|
'hr',
|
||||||
|
'quote',
|
||||||
|
'divider',
|
||||||
|
'ul',
|
||||||
|
'ol',
|
||||||
|
'task',
|
||||||
|
'indent',
|
||||||
|
'outdent',
|
||||||
|
'divider',
|
||||||
|
'table',
|
||||||
|
'image',
|
||||||
|
'link',
|
||||||
|
'divider',
|
||||||
|
'code',
|
||||||
|
'codeblock'
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<div class="j-markdown-editor" :id="id"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import 'codemirror/lib/codemirror.css'
|
||||||
|
import '@toast-ui/editor/dist/toastui-editor.css';
|
||||||
|
import '@toast-ui/editor/dist/i18n/zh-cn';
|
||||||
|
|
||||||
|
import Editor from '@toast-ui/editor';
|
||||||
|
import defaultOptions from './default-options'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JMarkdownEditor',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default() {
|
||||||
|
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return defaultOptions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'markdown'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: '300px'
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'zh-CN'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
editorOptions() {
|
||||||
|
const options = Object.assign({}, defaultOptions, this.options)
|
||||||
|
options.initialEditType = this.mode
|
||||||
|
options.height = this.height
|
||||||
|
options.language = this.language
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(newValue, preValue) {
|
||||||
|
if (newValue !== preValue && newValue !== this.editor.getMarkdown()) {
|
||||||
|
this.editor.setMarkdown(newValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
language(val) {
|
||||||
|
this.destroyEditor()
|
||||||
|
this.initEditor()
|
||||||
|
},
|
||||||
|
height(newValue) {
|
||||||
|
this.editor.height(newValue)
|
||||||
|
},
|
||||||
|
mode(newValue) {
|
||||||
|
this.editor.changeMode(newValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initEditor()
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.destroyEditor()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initEditor() {
|
||||||
|
this.editor = new Editor({
|
||||||
|
el: document.getElementById(this.id),
|
||||||
|
...this.editorOptions
|
||||||
|
})
|
||||||
|
if (this.value) {
|
||||||
|
this.editor.setMarkdown(this.value)
|
||||||
|
}
|
||||||
|
this.editor.on('change', () => {
|
||||||
|
this.$emit('change', this.editor.getMarkdown())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
destroyEditor() {
|
||||||
|
if (!this.editor) return
|
||||||
|
this.editor.off('change')
|
||||||
|
this.editor.remove()
|
||||||
|
},
|
||||||
|
setMarkdown(value) {
|
||||||
|
this.editor.setMarkdown(value)
|
||||||
|
},
|
||||||
|
getMarkdown() {
|
||||||
|
return this.editor.getMarkdown()
|
||||||
|
},
|
||||||
|
setHtml(value) {
|
||||||
|
this.editor.setHtml(value)
|
||||||
|
},
|
||||||
|
getHtml() {
|
||||||
|
return this.editor.getHtml()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
prop: 'value',
|
||||||
|
event: 'change'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
|
||||||
|
.j-markdown-editor {
|
||||||
|
/deep/ .tui-editor-defaultUI {
|
||||||
|
.te-mode-switch,
|
||||||
|
.tui-scrollsync
|
||||||
|
{
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -39,6 +39,7 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { getClass, getStyle } from '@/utils/props-util'
|
import { getClass, getStyle } from '@/utils/props-util'
|
||||||
|
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JModal',
|
name: 'JModal',
|
||||||
@ -109,7 +110,7 @@
|
|||||||
return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
|
return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
|
||||||
},
|
},
|
||||||
allSlotsKeys() {
|
allSlotsKeys() {
|
||||||
return this.slotsKeys.concat(this.scopedSlotsKeys)
|
return Object.keys(this.$slots).concat(Object.keys(this.$scopedSlots))
|
||||||
},
|
},
|
||||||
// 切换全屏的按钮图标
|
// 切换全屏的按钮图标
|
||||||
fullscreenButtonIcon() {
|
fullscreenButtonIcon() {
|
||||||
@ -151,6 +152,7 @@
|
|||||||
/** 切换全屏 */
|
/** 切换全屏 */
|
||||||
toggleFullscreen() {
|
toggleFullscreen() {
|
||||||
this.innerFullscreen = !this.innerFullscreen
|
this.innerFullscreen = !this.innerFullscreen
|
||||||
|
triggerWindowResizeEvent()
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -165,7 +167,12 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
height: 100vh;
|
// 兼容1.6.2版本的antdv
|
||||||
|
& .ant-modal {
|
||||||
|
top: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
& .ant-modal-content {
|
& .ant-modal-content {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
@ -189,7 +196,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.j-modal-title-row {
|
.j-modal-title-row {
|
||||||
@ -208,12 +214,9 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
color: rgba(0, 0, 0, 0.75);
|
color: rgba(0, 0, 0, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
|
|||||||
205
ant-design-vue-jeecg/src/components/jeecg/JPopup.vue
Normal file
205
ant-design-vue-jeecg/src/components/jeecg/JPopup.vue
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<template>
|
||||||
|
<div class="components-input-demo-presuffix" v-if="avalid">
|
||||||
|
<!---->
|
||||||
|
<a-input @click="openModal" :placeholder="placeholder" v-model="showText" readOnly :disabled="disabled">
|
||||||
|
<a-icon slot="prefix" type="cluster" :title="title"/>
|
||||||
|
<a-icon v-if="showText" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
|
||||||
|
</a-input>
|
||||||
|
|
||||||
|
<j-popup-onl-report
|
||||||
|
ref="jPopupOnlReport"
|
||||||
|
:code="code"
|
||||||
|
:multi="multi"
|
||||||
|
:groupId="uniqGroupId"
|
||||||
|
@ok="callBack"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JPopupOnlReport from './modal/JPopupOnlReport'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JPopup',
|
||||||
|
components: {
|
||||||
|
JPopupOnlReport
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
code: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
orgFields: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
destFields: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 1200,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
triggerChange: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
multi: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
/** 分组ID,用于将多个popup的请求合并到一起,不传不分组 */
|
||||||
|
groupId: String
|
||||||
|
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showText: '',
|
||||||
|
title: '',
|
||||||
|
avalid: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
uniqGroupId() {
|
||||||
|
if (this.groupId) {
|
||||||
|
let { groupId, code, field, orgFields, destFields } = this
|
||||||
|
return `${groupId}_${code}_${field}_${orgFields}_${destFields}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
immediate: true,
|
||||||
|
handler: function(val) {
|
||||||
|
if (!val) {
|
||||||
|
this.showText = ''
|
||||||
|
} else {
|
||||||
|
this.showText = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (!this.orgFields || !this.destFields || !this.code) {
|
||||||
|
this.$message.error('popup参数未正确配置!')
|
||||||
|
this.avalid = false
|
||||||
|
}
|
||||||
|
if (this.destFields.split(',').length != this.orgFields.split(',').length) {
|
||||||
|
this.$message.error('popup参数未正确配置,原始值和目标值数量不一致!')
|
||||||
|
this.avalid = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openModal() {
|
||||||
|
if (this.disabled === false) {
|
||||||
|
this.$refs.jPopupOnlReport.show()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleEmpty() {
|
||||||
|
this.showText = ''
|
||||||
|
let destFieldsArr = this.destFields.split(',')
|
||||||
|
if (destFieldsArr.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let res = {}
|
||||||
|
for (let i = 0; i < destFieldsArr.length; i++) {
|
||||||
|
res[destFieldsArr[i]] = ''
|
||||||
|
}
|
||||||
|
if (this.triggerChange) {
|
||||||
|
this.$emit('callback', res)
|
||||||
|
} else {
|
||||||
|
this.$emit('input', '', res)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callBack(rows) {
|
||||||
|
// update--begin--autor:lvdandan-----date:20200630------for:多选时未带回多个值------
|
||||||
|
let orgFieldsArr = this.orgFields.split(',')
|
||||||
|
let destFieldsArr = this.destFields.split(',')
|
||||||
|
let resetText = false
|
||||||
|
if (this.field && this.field.length > 0) {
|
||||||
|
this.showText = ''
|
||||||
|
resetText = true
|
||||||
|
}
|
||||||
|
let res = {}
|
||||||
|
if (orgFieldsArr.length > 0) {
|
||||||
|
for (let i = 0; i < orgFieldsArr.length; i++) {
|
||||||
|
let tempDestArr = []
|
||||||
|
for(let rw of rows){
|
||||||
|
let val = rw[orgFieldsArr[i]]
|
||||||
|
if(!val){
|
||||||
|
val = ""
|
||||||
|
}
|
||||||
|
tempDestArr.push(val)
|
||||||
|
}
|
||||||
|
res[destFieldsArr[i]] = tempDestArr.join(",")
|
||||||
|
}
|
||||||
|
if (resetText === true) {
|
||||||
|
let tempText = []
|
||||||
|
for(let rw of rows){
|
||||||
|
let val = rw[orgFieldsArr[destFieldsArr.indexOf(this.field)]]
|
||||||
|
if(!val){
|
||||||
|
val = ""
|
||||||
|
}
|
||||||
|
tempText.push(val)
|
||||||
|
}
|
||||||
|
this.showText = tempText.join(",")
|
||||||
|
}
|
||||||
|
// update--end--autor:lvdandan-----date:20200630------for:多选时未带回多个值------
|
||||||
|
}
|
||||||
|
if (this.triggerChange) {
|
||||||
|
//v-dec时即triggerChange为true时 将整个对象给form页面 让他自己setFieldsValue
|
||||||
|
this.$emit('callback', res)
|
||||||
|
} else {
|
||||||
|
//v-model时 需要传一个参数field 表示当前这个字段 从而根据这个字段的顺序找到原始值
|
||||||
|
// this.$emit("input",row[orgFieldsArr[destFieldsArr.indexOf(this.field)]])
|
||||||
|
this.$emit('input', this.showText, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.components-input-demo-presuffix .anticon-close-circle {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #ccc;
|
||||||
|
transition: color 0.3s;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-input-demo-presuffix .anticon-close-circle:hover {
|
||||||
|
color: #f5222d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-input-demo-presuffix .anticon-close-circle:active {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -145,6 +145,10 @@
|
|||||||
<j-date v-else-if=" item.type=='datetime' " v-model="item.val" placeholder="请选择时间" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"></j-date>
|
<j-date v-else-if=" item.type=='datetime' " v-model="item.val" placeholder="请选择时间" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"></j-date>
|
||||||
<a-time-picker v-else-if="item.type==='time'" :value="item.val ? moment(item.val,'HH:mm:ss') : null" format="HH:mm:ss" style="width: 100%" @change="(time,value)=>item.val=value"/>
|
<a-time-picker v-else-if="item.type==='time'" :value="item.val ? moment(item.val,'HH:mm:ss') : null" format="HH:mm:ss" style="width: 100%" @change="(time,value)=>item.val=value"/>
|
||||||
<a-input-number v-else-if=" item.type=='int'||item.type=='number' " style="width: 100%" placeholder="请输入数值" v-model="item.val"/>
|
<a-input-number v-else-if=" item.type=='int'||item.type=='number' " style="width: 100%" placeholder="请输入数值" v-model="item.val"/>
|
||||||
|
<a-select v-else-if="item.type=='switch'" placeholder="请选择" v-model="item.val">
|
||||||
|
<a-select-option value="Y">是</a-select-option>
|
||||||
|
<a-select-option value="N">否</a-select-option>
|
||||||
|
</a-select>
|
||||||
<a-input v-else v-model="item.val" placeholder="请输入值"/>
|
<a-input v-else v-model="item.val" placeholder="请输入值"/>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
@ -494,10 +498,9 @@
|
|||||||
} else {
|
} else {
|
||||||
if (Array.isArray(item.options)) {
|
if (Array.isArray(item.options)) {
|
||||||
// 如果有字典属性,就不需要保存 options 了
|
// 如果有字典属性,就不需要保存 options 了
|
||||||
if (item.dictCode) {
|
//update-begin-author:taoyan date:20200819 for:【开源问题】 高级查询 下拉框作为并且选项很多多多 LOWCOD-779
|
||||||
// 去掉特殊属性
|
delete item.options
|
||||||
delete item.options
|
//update-end-author:taoyan date:20200819 for:【开源问题】 高级查询 下拉框作为并且选项很多多多 LOWCOD-779
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,8 +511,17 @@
|
|||||||
renderSaveTreeData(item) {
|
renderSaveTreeData(item) {
|
||||||
item.icon = this.treeIcon
|
item.icon = this.treeIcon
|
||||||
item.originTitle = item['title']
|
item.originTitle = item['title']
|
||||||
item.title = (fn, vNode) => {
|
item.title = (arg1, arg2) => {
|
||||||
let { originTitle } = vNode.dataRef
|
let vNode
|
||||||
|
// 兼容旧版的Antdv
|
||||||
|
if (arg1.dataRef) {
|
||||||
|
vNode = arg1
|
||||||
|
} else if (arg2.dataRef) {
|
||||||
|
vNode = arg2
|
||||||
|
} else {
|
||||||
|
return <span style="color:red;">Antdv版本不支持</span>
|
||||||
|
}
|
||||||
|
let {originTitle} = vNode.dataRef
|
||||||
return (
|
return (
|
||||||
<div class="j-history-tree-title">
|
<div class="j-history-tree-title">
|
||||||
<span>{originTitle}</span>
|
<span>{originTitle}</span>
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-switch v-model="checkStatus" :disabled="disabled" @change="handleChange"/>
|
<div>
|
||||||
|
<a-select v-if="query" style="width: 100%" @change="handleSelectChange">
|
||||||
|
<a-select-option v-for="(item, index) in queryOption" :key="index" :value="item.value">
|
||||||
|
{{ item.text }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-switch v-else v-model="checkStatus" :disabled="disabled" @change="handleChange"/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
@ -7,7 +14,7 @@
|
|||||||
name: 'JSwitch',
|
name: 'JSwitch',
|
||||||
props: {
|
props: {
|
||||||
value:{
|
value:{
|
||||||
type: String,
|
type: String | Number,
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
disabled:{
|
disabled:{
|
||||||
@ -19,6 +26,11 @@
|
|||||||
type:Array,
|
type:Array,
|
||||||
required:false,
|
required:false,
|
||||||
default:()=>['Y','N']
|
default:()=>['Y','N']
|
||||||
|
},
|
||||||
|
query:{
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
@ -30,23 +42,37 @@
|
|||||||
value:{
|
value:{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(val){
|
handler(val){
|
||||||
if(!val){
|
if(!this.query){
|
||||||
this.checkStatus = false
|
if(!val){
|
||||||
this.$emit('change', this.options[1]);
|
|
||||||
}else{
|
|
||||||
if(this.options[0]==val){
|
|
||||||
this.checkStatus = true
|
|
||||||
}else{
|
|
||||||
this.checkStatus = false
|
this.checkStatus = false
|
||||||
|
this.$emit('change', this.options[1]);
|
||||||
|
}else{
|
||||||
|
if(this.options[0]==val){
|
||||||
|
this.checkStatus = true
|
||||||
|
}else{
|
||||||
|
this.checkStatus = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed:{
|
||||||
|
queryOption(){
|
||||||
|
let arr = []
|
||||||
|
arr.push({value:this.options[0],text:'是'})
|
||||||
|
arr.push({value:this.options[1],text:'否'})
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleChange(checked){
|
handleChange(checked){
|
||||||
let flag = checked===false?this.options[1]:this.options[0];
|
let flag = checked===false?this.options[1]:this.options[0];
|
||||||
this.$emit('change', flag);
|
this.$emit('change', flag);
|
||||||
|
},
|
||||||
|
handleSelectChange(value){
|
||||||
|
this.$emit('change', value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
|
|||||||
77
ant-design-vue-jeecg/src/components/jeecg/JTime.vue
Normal file
77
ant-design-vue-jeecg/src/components/jeecg/JTime.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<a-time-picker
|
||||||
|
:disabled="disabled || readOnly"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:value="momVal"
|
||||||
|
:format="dateFormat"
|
||||||
|
:getCalendarContainer="getCalendarContainer"
|
||||||
|
@change="handleTimeChange"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import moment from 'moment'
|
||||||
|
export default {
|
||||||
|
name: 'JTime',
|
||||||
|
props: {
|
||||||
|
placeholder:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
value:{
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
dateFormat:{
|
||||||
|
type: String,
|
||||||
|
default: 'HH:mm:ss',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
readOnly:{
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
disabled:{
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
getCalendarContainer: {
|
||||||
|
type: Function,
|
||||||
|
default: (node) => node.parentNode
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
let timeStr = this.value;
|
||||||
|
return {
|
||||||
|
decorator:"",
|
||||||
|
momVal:!timeStr?null:moment(timeStr,this.dateFormat)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value (val) {
|
||||||
|
if(!val){
|
||||||
|
this.momVal = null
|
||||||
|
}else{
|
||||||
|
this.momVal = moment(val,this.dateFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
moment,
|
||||||
|
handleTimeChange(mom,timeStr){
|
||||||
|
this.$emit('change', timeStr);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//2.2新增 在组件内定义 指定父组件调用时候的传值属性和事件类型 这个牛逼
|
||||||
|
model: {
|
||||||
|
prop: 'value',
|
||||||
|
event: 'change'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -121,7 +121,6 @@
|
|||||||
getAction(this.url_root,param).then(res=>{
|
getAction(this.url_root,param).then(res=>{
|
||||||
if(res.success){
|
if(res.success){
|
||||||
this.handleTreeNodeValue(res.result)
|
this.handleTreeNodeValue(res.result)
|
||||||
console.log("aaaa",res.result)
|
|
||||||
this.treeData = [...res.result]
|
this.treeData = [...res.result]
|
||||||
}else{
|
}else{
|
||||||
this.$message.error(res.message)
|
this.$message.error(res.message)
|
||||||
|
|||||||
@ -236,7 +236,6 @@
|
|||||||
}else{
|
}else{
|
||||||
try {
|
try {
|
||||||
let test=JSON.parse(mycondition);
|
let test=JSON.parse(mycondition);
|
||||||
console.log("aaaaasdsdd",typeof test)
|
|
||||||
if(typeof test == 'object' && test){
|
if(typeof test == 'object' && test){
|
||||||
resolve()
|
resolve()
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@ -225,7 +225,13 @@
|
|||||||
let arr = [];
|
let arr = [];
|
||||||
|
|
||||||
for(var a=0;a<uploadFiles.length;a++){
|
for(var a=0;a<uploadFiles.length;a++){
|
||||||
arr.push(uploadFiles[a].response.message)
|
// update-begin-author:lvdandan date:20200603 for:【TESTA-514】【开源issue】多个文件同时上传时,控制台报错
|
||||||
|
if(uploadFiles[a].status === 'done' ) {
|
||||||
|
arr.push(uploadFiles[a].response.message)
|
||||||
|
}else{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// update-end-author:lvdandan date:20200603 for:【TESTA-514】【开源issue】多个文件同时上传时,控制台报错
|
||||||
}
|
}
|
||||||
if(arr.length>0){
|
if(arr.length>0){
|
||||||
path = arr.join(",")
|
path = arr.join(",")
|
||||||
@ -279,12 +285,18 @@
|
|||||||
//returnUrl为false时返回文件名称、文件路径及文件大小
|
//returnUrl为false时返回文件名称、文件路径及文件大小
|
||||||
this.newFileList = [];
|
this.newFileList = [];
|
||||||
for(var a=0;a<fileList.length;a++){
|
for(var a=0;a<fileList.length;a++){
|
||||||
var fileJson = {
|
// update-begin-author:lvdandan date:20200603 for:【TESTA-514】【开源issue】多个文件同时上传时,控制台报错
|
||||||
fileName:fileList[a].name,
|
if(fileList[a].status === 'done' ) {
|
||||||
filePath:fileList[a].response.message,
|
var fileJson = {
|
||||||
fileSize:fileList[a].size
|
fileName:fileList[a].name,
|
||||||
};
|
filePath:fileList[a].response.message,
|
||||||
this.newFileList.push(fileJson);
|
fileSize:fileList[a].size
|
||||||
|
};
|
||||||
|
this.newFileList.push(fileJson);
|
||||||
|
}else{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// update-end-author:lvdandan date:20200603 for:【TESTA-514】【开源issue】多个文件同时上传时,控制台报错
|
||||||
}
|
}
|
||||||
this.$emit('change', this.newFileList);
|
this.$emit('change', this.newFileList);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<j-modal
|
||||||
|
title="详细信息"
|
||||||
|
:width="1200"
|
||||||
|
:visible="visible"
|
||||||
|
@ok="handleOk"
|
||||||
|
@cancel="close"
|
||||||
|
switch-fullscreen
|
||||||
|
:fullscreen.sync="fullscreen"
|
||||||
|
>
|
||||||
|
|
||||||
|
<transition name="fade">
|
||||||
|
<div v-if="visible">
|
||||||
|
<slot name="mainForm" :row="row" :column="column"/>
|
||||||
|
<slot name="subForm" :row="row" :column="column"/>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
</j-modal>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { cloneObject } from '@/utils/util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeDetailsModal',
|
||||||
|
inject: ['superTrigger'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
fullscreen: false,
|
||||||
|
row: null,
|
||||||
|
column: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
open(event) {
|
||||||
|
let {row, column} = event
|
||||||
|
this.row = cloneObject(row)
|
||||||
|
this.column = column
|
||||||
|
this.visible = true
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.visible = false
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOk() {
|
||||||
|
this.superTrigger('detailsConfirm', {
|
||||||
|
row: this.row,
|
||||||
|
column: this.column,
|
||||||
|
callback: (success) => {
|
||||||
|
this.visible = !success
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less">
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="boxClass">
|
||||||
|
<a-pagination
|
||||||
|
:disabled="disabled"
|
||||||
|
v-bind="bindProps"
|
||||||
|
@change="handleChange"
|
||||||
|
@showSizeChange="handleShowSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxePagination',
|
||||||
|
props: {
|
||||||
|
size: String,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
pagination: PropTypes.object.def({}),
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
defaultPagination: {
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
pageSizeOptions: ['10', '20', '30'],
|
||||||
|
showTotal: (total, range) => {
|
||||||
|
return range[0] + '-' + range[1] + ' 共 ' + total + ' 条'
|
||||||
|
},
|
||||||
|
showQuickJumper: true,
|
||||||
|
showSizeChanger: true,
|
||||||
|
total: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
bindProps() {
|
||||||
|
return {
|
||||||
|
...this.defaultPagination,
|
||||||
|
...this.pagination,
|
||||||
|
size: this.size === 'tiny' ? 'small' : ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
boxClass() {
|
||||||
|
return {
|
||||||
|
'j-vxe-pagination': true,
|
||||||
|
'show-quick-jumper': !!this.bindProps.showQuickJumper
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleChange(current, pageSize) {
|
||||||
|
this.$set(this.pagination, 'current', current)
|
||||||
|
this.$emit('change', {current, pageSize})
|
||||||
|
},
|
||||||
|
handleShowSizeChange(current, pageSize) {
|
||||||
|
this.$set(this.pagination, 'pageSize', pageSize)
|
||||||
|
this.$emit('change', {current, pageSize})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,164 @@
|
|||||||
|
<template>
|
||||||
|
<a-popover :visible="visible" placement="bottom" overlayClassName="j-vxe-popover-overlay" :overlayStyle="overlayStyle">
|
||||||
|
<div class="j-vxe-popover-title" slot="title">
|
||||||
|
<div>子表</div>
|
||||||
|
<div class="j-vxe-popover-title-close" @click="close">
|
||||||
|
<a-icon type="close"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template slot="content">
|
||||||
|
<transition name="fade">
|
||||||
|
<slot v-if="visible" name="subForm" :row="row" :column="column"/>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div ref="div" class="j-vxe-popover-div"></div>
|
||||||
|
|
||||||
|
</a-popover>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import domAlign from 'dom-align'
|
||||||
|
import { getParentNodeByTagName } from '../utils/vxeUtils'
|
||||||
|
import { cloneObject, triggerWindowResizeEvent } from '@/utils/util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeSubPopover',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
// 当前行
|
||||||
|
row: null,
|
||||||
|
column: null,
|
||||||
|
|
||||||
|
overlayStyle: {
|
||||||
|
width: null,
|
||||||
|
zIndex: 100
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
toggle(event) {
|
||||||
|
if (this.row == null) {
|
||||||
|
this.open(event)
|
||||||
|
} else {
|
||||||
|
this.row.id === event.row.id ? this.close() : this.reopen(event)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
open(event, level = 0) {
|
||||||
|
if (level > 3) {
|
||||||
|
this.$message.error('打开子表失败')
|
||||||
|
console.warn('【JVxeSubPopover】打开子表失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let {row, column, $table, $event: {target}} = event
|
||||||
|
this.row = cloneObject(row)
|
||||||
|
this.column = column
|
||||||
|
|
||||||
|
let className = target.className || ''
|
||||||
|
className = typeof className === 'string' ? className : className.toString()
|
||||||
|
|
||||||
|
// 点击的是expand,不做处理
|
||||||
|
if (className.includes('vxe-table--expand-btn')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 点击的是checkbox,不做处理
|
||||||
|
if (className.includes('vxe-checkbox--icon') || className.includes('vxe-cell--checkbox')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 点击的是radio,不做处理
|
||||||
|
if (className.includes('vxe-radio--icon') || className.includes('vxe-cell--radio')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let table = $table.$el
|
||||||
|
let tr = getParentNodeByTagName(target, 'tr')
|
||||||
|
if (table && tr) {
|
||||||
|
let clientWidth = table.clientWidth
|
||||||
|
let clientHeight = tr.clientHeight
|
||||||
|
this.$refs.div.style.width = clientWidth + 'px'
|
||||||
|
this.$refs.div.style.height = clientHeight + 'px'
|
||||||
|
this.overlayStyle.width = Number.parseInt((clientWidth - clientWidth * 0.04)) + 'px'
|
||||||
|
this.overlayStyle.maxWidth = this.overlayStyle.width
|
||||||
|
domAlign(this.$refs.div, tr, {
|
||||||
|
points: ['tl', 'tl'],
|
||||||
|
offset: [0, 0],
|
||||||
|
overflow: {
|
||||||
|
alwaysByViewport: true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.visible = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
triggerWindowResizeEvent()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let num = ++level
|
||||||
|
console.warn('【JVxeSubPopover】table or tr 获取失败,正在进行第 ' + num + '次重试', {event, table, tr})
|
||||||
|
window.setTimeout(() => this.open(event, num), 100)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
if (this.visible) {
|
||||||
|
this.row = null
|
||||||
|
this.visible = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reopen(event) {
|
||||||
|
this.close()
|
||||||
|
this.open(event)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.j-vxe-popover-title {
|
||||||
|
.j-vxe-popover-title-close {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 31px;
|
||||||
|
height: 31px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 31px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 300ms;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.j-vxe-popover-div {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 31px;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="less">
|
||||||
|
.j-vxe-popover-overlay.ant-popover {
|
||||||
|
.ant-popover-title {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="boxClass">
|
||||||
|
<!-- 工具按钮 -->
|
||||||
|
<div class="j-vxe-tool-button div" :size="btnSize">
|
||||||
|
<slot v-if="showPrefix" name="toolbarPrefix" :size="btnSize"/>
|
||||||
|
|
||||||
|
<a-button v-if="showAdd" icon="plus" @click="trigger('add')" :disabled="disabled" type="primary">新增</a-button>
|
||||||
|
<a-button v-if="showSave" icon="save" @click="trigger('save')" :disabled="disabled">保存</a-button>
|
||||||
|
<template v-if="selectedRowIds.length > 0">
|
||||||
|
<a-popconfirm
|
||||||
|
v-if="showRemove"
|
||||||
|
:title="`确定要删除这 ${selectedRowIds.length} 项吗?`"
|
||||||
|
@confirm="trigger('remove')"
|
||||||
|
>
|
||||||
|
<a-button icon="minus" :disabled="disabled">删除</a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
<template v-if="showClearSelection">
|
||||||
|
<a-button icon="delete" @click="trigger('clearSelection')">清空选择</a-button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<slot v-if="showSuffix" name="toolbarSuffix" :size="btnSize"/>
|
||||||
|
<a v-if="showCollapse" @click="toggleCollapse" style="margin-left: 4px">
|
||||||
|
<span>{{ collapsed ? '展开' : '收起' }}</span>
|
||||||
|
<a-icon :type="collapsed ? 'down' : 'up'"/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'JVxeToolbar',
|
||||||
|
props: {
|
||||||
|
toolbarConfig: Object,
|
||||||
|
excludeCode: Array,
|
||||||
|
size: String,
|
||||||
|
disabled: Boolean,
|
||||||
|
disabledRows: Object,
|
||||||
|
selectedRowIds: Array,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 是否收起
|
||||||
|
collapsed: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
boxClass() {
|
||||||
|
return {
|
||||||
|
'j-vxe-toolbar': true,
|
||||||
|
'j-vxe-toolbar-collapsed': this.collapsed,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
btns() {
|
||||||
|
let arr = this.toolbarConfig.btn || ['add', 'remove', 'clearSelection']
|
||||||
|
let exclude = [...this.excludeCode]
|
||||||
|
// TODO 需要将remove替换batch_delete
|
||||||
|
// 系统默认的批量删除编码配置为 batch_delete 此处需要转化一下
|
||||||
|
if(exclude.indexOf('batch_delete')>=0){
|
||||||
|
exclude.add('remove')
|
||||||
|
}
|
||||||
|
// 按钮权限 需要去掉不被授权的按钮
|
||||||
|
return arr.filter(item=>{
|
||||||
|
return exclude.indexOf(item)<0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
slots() {
|
||||||
|
return this.toolbarConfig.slot || ['prefix', 'suffix']
|
||||||
|
},
|
||||||
|
showPrefix() {
|
||||||
|
return this.slots.includes('prefix')
|
||||||
|
},
|
||||||
|
showSuffix() {
|
||||||
|
return this.slots.includes('suffix')
|
||||||
|
},
|
||||||
|
showAdd() {
|
||||||
|
return this.btns.includes('add')
|
||||||
|
},
|
||||||
|
showSave() {
|
||||||
|
return this.btns.includes('save')
|
||||||
|
},
|
||||||
|
showRemove() {
|
||||||
|
return this.btns.includes('remove')
|
||||||
|
},
|
||||||
|
showClearSelection() {
|
||||||
|
if (this.btns.includes('clearSelection')) {
|
||||||
|
// 有禁用行时才显示清空选择按钮
|
||||||
|
// 因为禁用行会阻止选择行,导致无法取消全选
|
||||||
|
let length = Object.keys(this.disabledRows).length
|
||||||
|
return length > 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
showCollapse() {
|
||||||
|
return this.btns.includes('collapse')
|
||||||
|
},
|
||||||
|
|
||||||
|
btnSize() {
|
||||||
|
return this.size === 'tiny' ? 'small' : null
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 触发事件 */
|
||||||
|
trigger(name) {
|
||||||
|
this.$emit(name)
|
||||||
|
},
|
||||||
|
// 切换展开收起
|
||||||
|
toggleCollapse() {
|
||||||
|
this.collapsed = !this.collapsed
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.j-vxe-toolbar-collapsed {
|
||||||
|
[data-collapse] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.j-vxe-tool-button.div .ant-btn {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="clazz" :style="boxStyle">
|
||||||
|
<a-checkbox
|
||||||
|
ref="checkbox"
|
||||||
|
:checked="innerValue"
|
||||||
|
v-bind="cellProps"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { neverNull } from '@/utils/util'
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeCheckboxCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
props: {},
|
||||||
|
computed: {
|
||||||
|
bordered() {
|
||||||
|
return !!this.renderOptions.bordered
|
||||||
|
},
|
||||||
|
scrolling() {
|
||||||
|
return !!this.renderOptions.scrolling
|
||||||
|
},
|
||||||
|
clazz() {
|
||||||
|
return {
|
||||||
|
'j-vxe-checkbox': true,
|
||||||
|
'no-animation': this.scrolling
|
||||||
|
}
|
||||||
|
},
|
||||||
|
boxStyle() {
|
||||||
|
const style = {}
|
||||||
|
// 如果有边框且未设置align属性,就强制居中
|
||||||
|
if (this.bordered && !this.originColumn.align) {
|
||||||
|
style['text-align'] = 'center'
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleChange(event) {
|
||||||
|
this.handleChangeCommon(event.target.checked)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
switches: {
|
||||||
|
visible: true,
|
||||||
|
},
|
||||||
|
getValue(value) {
|
||||||
|
let {own: col} = this.column
|
||||||
|
// 处理 customValue
|
||||||
|
if (Array.isArray(col.customValue)) {
|
||||||
|
let customValue = getCustomValue(col)
|
||||||
|
if (typeof value === 'boolean') {
|
||||||
|
return value ? customValue[0] : customValue[1]
|
||||||
|
} else {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setValue(value) {
|
||||||
|
let {own: col} = this.column
|
||||||
|
// 判断是否设定了customValue(自定义值)
|
||||||
|
if (Array.isArray(col.customValue)) {
|
||||||
|
let customValue = getCustomValue(col)
|
||||||
|
return neverNull(value).toString() === customValue[0].toString()
|
||||||
|
} else {
|
||||||
|
return !!value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createValue({column}) {
|
||||||
|
let {own: col} = column
|
||||||
|
if (Array.isArray(col.customValue)) {
|
||||||
|
let customValue = getCustomValue(col)
|
||||||
|
return col.defaultChecked ? customValue[0] : customValue[1]
|
||||||
|
} else {
|
||||||
|
return !!col.defaultChecked
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCustomValue(col) {
|
||||||
|
let customTrue = neverNull(col.customValue[0], true)
|
||||||
|
let customFalse = neverNull(col.customValue[1], false)
|
||||||
|
return [customTrue, customFalse]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
// 关闭动画,防止滚动时动态赋值出现问题
|
||||||
|
.j-vxe-checkbox.no-animation {
|
||||||
|
.ant-checkbox-inner,
|
||||||
|
.ant-checkbox-inner::after {
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<a-date-picker
|
||||||
|
ref="datePicker"
|
||||||
|
:value="innerDateValue"
|
||||||
|
allowClear
|
||||||
|
:format="dateFormat"
|
||||||
|
:showTime="isDatetime"
|
||||||
|
dropdownClassName="j-vxe-date-picker"
|
||||||
|
style="min-width: 0;"
|
||||||
|
v-bind="cellProps"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import moment from 'moment'
|
||||||
|
import { JVXETypes } from '@/components/jeecg/JVxeTable/index'
|
||||||
|
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeDateCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innerDateValue: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isDatetime() {
|
||||||
|
return this.$type === JVXETypes.datetime
|
||||||
|
},
|
||||||
|
dateFormat() {
|
||||||
|
let format = this.originColumn.format
|
||||||
|
return format ? format : (this.isDatetime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val == null || val === '') {
|
||||||
|
this.innerDateValue = null
|
||||||
|
} else {
|
||||||
|
this.innerDateValue = moment(val, this.dateFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleChange(mom, dateStr) {
|
||||||
|
this.handleChangeCommon(dateStr)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
aopEvents: {
|
||||||
|
editActived: event => dispatchEvent(event, 'ant-calendar-picker', el => el.children[0].dispatchEvent(event.$event)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
<template>
|
||||||
|
<a-dropdown :trigger="['click']">
|
||||||
|
<div class="j-vxe-ds-icons">
|
||||||
|
<a-icon type="align-left"/>
|
||||||
|
<a-icon type="align-right"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="j-vxe-ds-btns">-->
|
||||||
|
<!-- <a-button icon="caret-up" size="small" :disabled="disabledMoveUp" @click="handleRowMoveUp"/>-->
|
||||||
|
<!-- <a-button icon="caret-down" size="small" :disabled="disabledMoveDown" @click="handleRowMoveDown"/>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<a-menu slot="overlay">
|
||||||
|
<a-menu-item key="0" :disabled="disabledMoveUp" @click="handleRowMoveUp">向上移</a-menu-item>
|
||||||
|
<a-menu-item key="1" :disabled="disabledMoveDown" @click="handleRowMoveDown">向下移</a-menu-item>
|
||||||
|
<a-menu-divider/>
|
||||||
|
<a-menu-item key="3" @click="handleRowInsertDown">插入一行</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeDragSortCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
computed: {
|
||||||
|
// 排序结果保存字段
|
||||||
|
dragSortKey() {
|
||||||
|
return this.renderOptions.dragSortKey || 'orderNum'
|
||||||
|
},
|
||||||
|
disabledMoveUp() {
|
||||||
|
return this.rowIndex === 0
|
||||||
|
},
|
||||||
|
disabledMoveDown() {
|
||||||
|
return this.rowIndex === (this.rows.length - 1)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 向上移 */
|
||||||
|
handleRowMoveUp(event) {
|
||||||
|
// event.target.blur()
|
||||||
|
if (!this.disabledMoveUp) {
|
||||||
|
this.trigger('rowMoveUp', this.rowIndex)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 向下移 */
|
||||||
|
handleRowMoveDown(event) {
|
||||||
|
// event.target.blur()
|
||||||
|
if (!this.disabledMoveDown) {
|
||||||
|
this.trigger('rowMoveDown', this.rowIndex)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 插入一行 */
|
||||||
|
handleRowInsertDown() {
|
||||||
|
this.trigger('rowInsertDown', this.rowIndex)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
// 【功能开关】
|
||||||
|
switches: {
|
||||||
|
editRender: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.j-vxe-ds-icons {
|
||||||
|
position: relative;
|
||||||
|
/*cursor: move;*/
|
||||||
|
cursor: pointer;
|
||||||
|
width: 14px;
|
||||||
|
height: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
.anticon-align-left,
|
||||||
|
.anticon-align-right {
|
||||||
|
position: absolute;
|
||||||
|
top: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anticon-align-left {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anticon-align-right {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.j-vxe-ds-btns {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 24px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
align-content: center;
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
z-index: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
/*height: 30%;*/
|
||||||
|
height: 40%;
|
||||||
|
display: block;
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
z-index: 1;
|
||||||
|
/* height: 40%;*/
|
||||||
|
|
||||||
|
/* & .anticon-caret-up,*/
|
||||||
|
/* & .anticon-caret-down {*/
|
||||||
|
/* top: 2px;*/
|
||||||
|
/* }*/
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .anticon-caret-up,
|
||||||
|
& .anticon-caret-down {
|
||||||
|
vertical-align: top;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
transition: top 0.3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<a-input
|
||||||
|
ref="input"
|
||||||
|
:value="innerValue"
|
||||||
|
v-bind="cellProps"
|
||||||
|
@blur="handleBlur"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { JVXETypes } from '@/components/jeecg/JVxeTable'
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
const NumberRegExp = /^-?\d+\.?\d*$/
|
||||||
|
export default {
|
||||||
|
name: 'JVxeInputCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
/** 处理change事件 */
|
||||||
|
handleChange(event) {
|
||||||
|
let {$type} = this
|
||||||
|
let {target} = event
|
||||||
|
let {value, selectionStart} = target
|
||||||
|
let change = true
|
||||||
|
if ($type === JVXETypes.inputNumber) {
|
||||||
|
// 判断输入的值是否匹配数字正则表达式,不匹配就还原
|
||||||
|
if (!NumberRegExp.test(value) && (value !== '' && value !== '-')) {
|
||||||
|
change = false
|
||||||
|
value = this.innerValue
|
||||||
|
target.value = value || ''
|
||||||
|
if (typeof selectionStart === 'number') {
|
||||||
|
target.selectionStart = selectionStart - 1
|
||||||
|
target.selectionEnd = selectionStart - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 触发事件,存储输入的值
|
||||||
|
if (change) {
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type === JVXETypes.inputNumber) {
|
||||||
|
// this.recalcOneStatisticsColumn(col.key)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 处理blur失去焦点事件 */
|
||||||
|
handleBlur(event) {
|
||||||
|
let {$type} = this
|
||||||
|
let {target} = event
|
||||||
|
// 判断输入的值是否匹配数字正则表达式,不匹配就置空
|
||||||
|
if ($type === JVXETypes.inputNumber) {
|
||||||
|
if (!NumberRegExp.test(target.value)) {
|
||||||
|
target.value = ''
|
||||||
|
} else {
|
||||||
|
target.value = Number.parseFloat(target.value)
|
||||||
|
}
|
||||||
|
this.handleChangeCommon(target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleBlurCommon(target.value)
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
installOptions: {
|
||||||
|
// 自动聚焦的 class 类名
|
||||||
|
autofocus: '.ant-input',
|
||||||
|
},
|
||||||
|
getValue(value) {
|
||||||
|
if (this.$type === JVXETypes.inputNumber && typeof value === 'string') {
|
||||||
|
if (NumberRegExp.test(value)) {
|
||||||
|
return Number.parseFloat(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<reload-effect
|
||||||
|
:vNode="innerValue"
|
||||||
|
:effect="reloadEffect"
|
||||||
|
@effect-end="handleEffectEnd"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ReloadEffect from './ReloadEffect'
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeNormalCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
components: {ReloadEffect},
|
||||||
|
computed: {
|
||||||
|
reloadEffectRowKeysMap() {
|
||||||
|
return this.renderOptions.reloadEffectRowKeysMap
|
||||||
|
},
|
||||||
|
reloadEffect() {
|
||||||
|
return (this.renderOptions.reloadEffect && this.reloadEffectRowKeysMap[this.row.id]) === true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 特效结束
|
||||||
|
handleEffectEnd() {
|
||||||
|
this.$delete(this.reloadEffectRowKeysMap, this.row.id)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
switches: {
|
||||||
|
editRender: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<a-progress
|
||||||
|
:class="clazz"
|
||||||
|
:percent="innerValue"
|
||||||
|
size="small"
|
||||||
|
v-bind="cellProps"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
// JVxe 进度条组件
|
||||||
|
export default {
|
||||||
|
name: 'JVxeProgressCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
clazz() {
|
||||||
|
return {
|
||||||
|
'j-vxe-progress': true,
|
||||||
|
'no-animation': this.scrolling
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrolling() {
|
||||||
|
return !!this.renderOptions.scrolling
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
switches: {
|
||||||
|
editRender: false,
|
||||||
|
},
|
||||||
|
setValue(value) {
|
||||||
|
try {
|
||||||
|
if (typeof value !== 'number') {
|
||||||
|
return Number.parseFloat(value)
|
||||||
|
} else {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
// 关闭进度条的动画,防止滚动时动态赋值出现问题
|
||||||
|
.j-vxe-progress.no-animation {
|
||||||
|
/deep/ .ant-progress-success-bg,
|
||||||
|
/deep/ .ant-progress-bg {
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,150 @@
|
|||||||
|
<template>
|
||||||
|
<a-select
|
||||||
|
ref="select"
|
||||||
|
:value="innerValue"
|
||||||
|
allowClear
|
||||||
|
:filterOption="handleSelectFilterOption"
|
||||||
|
v-bind="selectProps"
|
||||||
|
style="width: 100%;"
|
||||||
|
@blur="handleBlur"
|
||||||
|
@change="handleChangeCommon"
|
||||||
|
@search="handleSearchSelect"
|
||||||
|
>
|
||||||
|
|
||||||
|
<template v-for="option of originColumn.options">
|
||||||
|
<a-select-option :key="option.value" :value="option.value" :disabled="option.disabled">
|
||||||
|
<span>{{option.text || option.label || option.title|| option.value}}</span>
|
||||||
|
</a-select-option>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
import { JVXETypes } from '@comp/jeecg/JVxeTable/index'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeSelectCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
computed: {
|
||||||
|
selectProps() {
|
||||||
|
let props = {...this.cellProps}
|
||||||
|
// 判断select是否允许输入
|
||||||
|
let {allowSearch, allowInput} = this.originColumn
|
||||||
|
if (allowInput === true || allowSearch === true) {
|
||||||
|
props['showSearch'] = true
|
||||||
|
}
|
||||||
|
return props
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
let multiple = [JVXETypes.selectMultiple, JVXETypes.list_multi]
|
||||||
|
let search = [JVXETypes.selectSearch, JVXETypes.sel_search]
|
||||||
|
if (multiple.includes(this.$type)) {
|
||||||
|
// 处理多选
|
||||||
|
let props = this.originColumn.props || {}
|
||||||
|
props['mode'] = 'multiple'
|
||||||
|
props['maxTagCount'] = 1
|
||||||
|
this.$set(this.originColumn, 'props', props)
|
||||||
|
} else if (search.includes(this.$type)) {
|
||||||
|
// 处理搜索
|
||||||
|
this.$set(this.originColumn, 'allowSearch', true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
/** 处理blur失去焦点事件 */
|
||||||
|
handleBlur(value) {
|
||||||
|
let {allowInput, options} = this.originColumn
|
||||||
|
|
||||||
|
if (allowInput === true) {
|
||||||
|
// 删除无用的因搜索(用户输入)而创建的项
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
let indexes = []
|
||||||
|
options.forEach((option, index) => {
|
||||||
|
if (option.value.toLocaleString() === value.toLocaleString()) {
|
||||||
|
delete option.searchAdd
|
||||||
|
} else if (option.searchAdd === true) {
|
||||||
|
indexes.push(index)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 翻转删除数组中的项
|
||||||
|
for (let index of indexes.reverse()) {
|
||||||
|
options.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleBlurCommon(value)
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 用于搜索下拉框中的内容 */
|
||||||
|
handleSelectFilterOption(input, option) {
|
||||||
|
let {allowSearch, allowInput} = this.originColumn
|
||||||
|
if (allowSearch === true || allowInput === true) {
|
||||||
|
//update-begin-author:taoyan date:20200820 for:【专项任务】大连项目反馈行编辑问题处理 下拉框搜索
|
||||||
|
return option.componentOptions.children[0].children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
//update-end-author:taoyan date:20200820 for:【专项任务】大连项目反馈行编辑问题处理 下拉框搜索
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
|
||||||
|
/** select 搜索时的事件,用于动态添加options */
|
||||||
|
handleSearchSelect(value) {
|
||||||
|
let {allowSearch, allowInput, options} = this.originColumn
|
||||||
|
|
||||||
|
if (allowSearch !== true && allowInput === true) {
|
||||||
|
// 是否找到了对应的项,找不到则添加这一项
|
||||||
|
let flag = false
|
||||||
|
for (let option of options) {
|
||||||
|
if (option.value.toLocaleString() === value.toLocaleString()) {
|
||||||
|
flag = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// !!value :不添加空值
|
||||||
|
if (!flag && !!value) {
|
||||||
|
// searchAdd 是否是通过搜索添加的
|
||||||
|
options.push({title: value, value: value, searchAdd: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
aopEvents: {
|
||||||
|
editActived: event => dispatchEvent(event, 'ant-select'),
|
||||||
|
},
|
||||||
|
translate: {enabled: true},
|
||||||
|
getValue(value) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.join(',')
|
||||||
|
} else {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setValue(value) {
|
||||||
|
let {column: {own: col}, params: {$table}} = this
|
||||||
|
// 判断是否是多选
|
||||||
|
if ((col.props || {})['mode'] === 'multiple') {
|
||||||
|
$table.$set(col.props, 'maxTagCount', 1)
|
||||||
|
}
|
||||||
|
if (value != null && value !== '') {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value === '' ? [] : value.split(',')
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
// 插槽
|
||||||
|
export default {
|
||||||
|
name: 'JVxeSlotCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
computed: {
|
||||||
|
slotProps() {
|
||||||
|
return {
|
||||||
|
value: this.innerValue,
|
||||||
|
row: this.row,
|
||||||
|
column: this.originColumn,
|
||||||
|
|
||||||
|
params: this.params,
|
||||||
|
$table: this.params.$table,
|
||||||
|
rowId: this.params.rowid,
|
||||||
|
index: this.params.rowIndex,
|
||||||
|
rowIndex: this.params.rowIndex,
|
||||||
|
columnIndex: this.params.columnIndex,
|
||||||
|
|
||||||
|
target: this.renderOptions.target,
|
||||||
|
caseId: this.renderOptions.target.caseId,
|
||||||
|
scrolling: this.renderOptions.scrolling,
|
||||||
|
reloadEffect: this.renderOptions.reloadEffect,
|
||||||
|
|
||||||
|
triggerChange: (v) => this.handleChangeCommon(v),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render(h) {
|
||||||
|
let {slot} = this.renderOptions
|
||||||
|
if (slot) {
|
||||||
|
return h('div', {}, slot(this.slotProps))
|
||||||
|
} else {
|
||||||
|
return h('div')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
switches: {
|
||||||
|
editRender: false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// :isNotPass="notPassedIds.includes(col.key+row.id)"
|
||||||
@ -0,0 +1,145 @@
|
|||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
// tags 组件的显示组件
|
||||||
|
export const TagsSpanCell = {
|
||||||
|
name: 'JVxeTagsCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innerTags: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler(value) {
|
||||||
|
if (value !== this.innerTags.join(';')) {
|
||||||
|
let rv = replaceValue(value)
|
||||||
|
this.innerTags = rv.split(';')
|
||||||
|
this.handleChangeCommon(rv)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
renderTags(h) {
|
||||||
|
let tags = []
|
||||||
|
for (let tag of this.innerTags) {
|
||||||
|
if (tag) {
|
||||||
|
let tagProps = {}
|
||||||
|
let tagStyle = {}
|
||||||
|
let setTagColor = this.originColumn.setTagColor
|
||||||
|
if (typeof setTagColor === 'function') {
|
||||||
|
/**
|
||||||
|
* 设置 tag 颜色
|
||||||
|
*
|
||||||
|
* @param event 包含的字段:
|
||||||
|
* event.tagValue 当前tag的值
|
||||||
|
* event.value 当前原始值
|
||||||
|
* event.row 当前行的所有值
|
||||||
|
* event.column 当前列的配置
|
||||||
|
* event.column.own 当前列的原始配置
|
||||||
|
* @return Array | String 可以返回一个数组,数据第一项是tag背景颜色,第二项是字体颜色。也可以返回一个字符串,即tag背景颜色
|
||||||
|
*/
|
||||||
|
let color = setTagColor({
|
||||||
|
tagValue: tag,
|
||||||
|
value: this.innerValue,
|
||||||
|
row: this.row,
|
||||||
|
column: this.column,
|
||||||
|
})
|
||||||
|
if (Array.isArray(color)) {
|
||||||
|
tagProps.color = color[0]
|
||||||
|
tagStyle.color = color[1]
|
||||||
|
} else if (color && typeof color === 'string') {
|
||||||
|
tagProps.color = color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tags.push(h('a-tag', {
|
||||||
|
props: tagProps,
|
||||||
|
style: tagStyle,
|
||||||
|
}, [tag]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tags
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render(h) {
|
||||||
|
return h('div', {}, [
|
||||||
|
this.renderTags(h)
|
||||||
|
])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// tags 组件的输入框
|
||||||
|
export const TagsInputCell = {
|
||||||
|
name: 'JVxeTagsInputCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innerTagValue: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler(value) {
|
||||||
|
if (value !== this.innerTagValue) {
|
||||||
|
this.handleInputChange(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
handleInputChange(value, event) {
|
||||||
|
this.innerTagValue = replaceValue(value, event)
|
||||||
|
this.handleChangeCommon(this.innerTagValue)
|
||||||
|
return this.innerTagValue
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
render(h) {
|
||||||
|
return h('a-input', {
|
||||||
|
props: {
|
||||||
|
value: this.innerValue,
|
||||||
|
...this.cellProps
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
change: (event) => {
|
||||||
|
let {target, target: {value}} = event
|
||||||
|
let newValue = this.handleInputChange(value, event)
|
||||||
|
if (newValue !== value) {
|
||||||
|
target.value = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将值每隔两位加上一个分号
|
||||||
|
function replaceValue(value, event) {
|
||||||
|
if (value) {
|
||||||
|
// 首先去掉现有的分号
|
||||||
|
value = value.replace(/;/g, '')
|
||||||
|
// 然后再遍历添加分号
|
||||||
|
let rv = ''
|
||||||
|
let splitArr = value.split('')
|
||||||
|
let count = 0
|
||||||
|
splitArr.forEach((val, index) => {
|
||||||
|
rv += val
|
||||||
|
let position = index + 1
|
||||||
|
if (position % 2 === 0 && position < splitArr.length) {
|
||||||
|
count++
|
||||||
|
rv += ';'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (event && count > 0) {
|
||||||
|
let {target, target: {selectionStart}} = event
|
||||||
|
target.selectionStart = selectionStart + count
|
||||||
|
target.selectionEnd = selectionStart + count
|
||||||
|
}
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<j-input-pop
|
||||||
|
:value="innerValue"
|
||||||
|
:width="300"
|
||||||
|
:height="210"
|
||||||
|
v-bind="cellProps"
|
||||||
|
style="width: 100%;"
|
||||||
|
@change="handleChangeCommon"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JInputPop from '@/components/jeecg/minipop/JInputPop'
|
||||||
|
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeTextareaCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
components: {JInputPop},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
installOptions: {
|
||||||
|
autofocus: '.ant-input',
|
||||||
|
},
|
||||||
|
aopEvents: {
|
||||||
|
editActived: event => dispatchEvent(event, 'anticon-fullscreen'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-if="hasFile" v-for="(file, fileKey) of [innerFile || {}]">
|
||||||
|
<a-input
|
||||||
|
:key="fileKey"
|
||||||
|
:readOnly="true"
|
||||||
|
:value="file.name"
|
||||||
|
>
|
||||||
|
|
||||||
|
<template slot="addonBefore" style="width: 30px">
|
||||||
|
<a-tooltip v-if="file.status === 'uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
|
||||||
|
<a-icon type="loading"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip v-else-if="file.status === 'done'" title="上传完成">
|
||||||
|
<a-icon type="check-circle" style="color:#00DB00;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip v-else title="上传失败">
|
||||||
|
<a-icon type="exclamation-circle" style="color:red;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<span v-if="file.status === 'uploading'" slot="addonAfter">{{ Math.floor(file.percent) }}%</span>
|
||||||
|
<template v-else-if="originColumn.allowDownload !== false || originColumn.allowRemove !== false" slot="addonAfter">
|
||||||
|
<a-dropdown :trigger="['click']" placement="bottomRight">
|
||||||
|
<a-tooltip title="操作">
|
||||||
|
<a-icon
|
||||||
|
type="setting"
|
||||||
|
style="cursor: pointer;"/>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-menu slot="overlay">
|
||||||
|
<!-- <a-menu-item @click="handleClickPreviewFile">-->
|
||||||
|
<!-- <span><a-icon type="eye"/> 预览</span>-->
|
||||||
|
<!-- </a-menu-item>-->
|
||||||
|
<a-menu-item v-if="originColumn.allowDownload !== false" @click="handleClickDownloadFile">
|
||||||
|
<span><a-icon type="download"/> 下载</span>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile">
|
||||||
|
<span><a-icon type="delete"/> 删除</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</a-input>
|
||||||
|
</template>
|
||||||
|
<a-upload
|
||||||
|
v-show="!hasFile"
|
||||||
|
name="file"
|
||||||
|
:data="{'isup': 1}"
|
||||||
|
:multiple="false"
|
||||||
|
:action="originColumn.action"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:showUploadList="false"
|
||||||
|
v-bind="cellProps"
|
||||||
|
@change="handleChangeUpload"
|
||||||
|
>
|
||||||
|
<a-button icon="upload">{{originColumn.btnText || '点击上传'}}</a-button>
|
||||||
|
</a-upload>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
import { getFileAccessHttpUrl } from '@api/manage'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeUploadCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innerFile: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
/** upload headers */
|
||||||
|
uploadHeaders() {
|
||||||
|
let {originColumn: col} = this
|
||||||
|
let headers = {}
|
||||||
|
if (col.token === true) {
|
||||||
|
headers['X-Access-Token'] = this.$ls.get(ACCESS_TOKEN)
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
},
|
||||||
|
|
||||||
|
hasFile() {
|
||||||
|
return this.innerFile != null
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler() {
|
||||||
|
if (this.innerValue) {
|
||||||
|
this.innerFile = this.innerValue
|
||||||
|
} else {
|
||||||
|
this.innerFile = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
handleChangeUpload(info) {
|
||||||
|
let {row, originColumn: col} = this
|
||||||
|
let {file} = info
|
||||||
|
let value = {
|
||||||
|
name: file.name,
|
||||||
|
type: file.type,
|
||||||
|
size: file.size,
|
||||||
|
status: file.status,
|
||||||
|
percent: file.percent
|
||||||
|
}
|
||||||
|
if (col.responseName && file.response) {
|
||||||
|
value['responseName'] = file.response[col.responseName]
|
||||||
|
}
|
||||||
|
if (file.status === 'done') {
|
||||||
|
value['path'] = file.response[col.responseName]
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
} else if (file.status === 'error') {
|
||||||
|
value['message'] = file.response.message || '未知错误'
|
||||||
|
}
|
||||||
|
this.innerFile = value
|
||||||
|
},
|
||||||
|
|
||||||
|
// handleClickPreviewFile(id) {
|
||||||
|
// this.$message.info('尚未实现')
|
||||||
|
// },
|
||||||
|
|
||||||
|
handleClickDownloadFile(id) {
|
||||||
|
let {path} = this.value || {}
|
||||||
|
if (path) {
|
||||||
|
let url = getFileAccessHttpUrl(path)
|
||||||
|
window.open(url)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleClickDeleteFile() {
|
||||||
|
this.handleChangeCommon(null)
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
|
enhanced: {
|
||||||
|
switches: {visible: true},
|
||||||
|
getValue: value => fileGetValue(value),
|
||||||
|
setValue: value => fileSetValue(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileGetValue(value) {
|
||||||
|
if (value && value.path) {
|
||||||
|
return value.path
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileSetValue(value) {
|
||||||
|
if (value) {
|
||||||
|
let first = value.split(',')[0]
|
||||||
|
let name = first.substring(first.lastIndexOf('/') + 1)
|
||||||
|
return {
|
||||||
|
name: name,
|
||||||
|
path: value,
|
||||||
|
status: 'done',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
import '../../less/reload-effect.less'
|
||||||
|
import { randomString } from '@/utils/util'
|
||||||
|
|
||||||
|
// 修改数据特效
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
vNode: null,
|
||||||
|
// 是否启用特效
|
||||||
|
effect: Boolean,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// vNode: null,
|
||||||
|
innerEffect: false,
|
||||||
|
// 应付同时多个特效
|
||||||
|
effectIdx: 0,
|
||||||
|
effectList: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
vNode: {
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
handler(vNode, old) {
|
||||||
|
this.innerEffect = this.effect
|
||||||
|
if (this.innerEffect && old != null) {
|
||||||
|
let topLayer = this.renderSpan(old, 'top')
|
||||||
|
this.effectList.push(topLayer)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
// 条件渲染内容 span
|
||||||
|
renderVNode() {
|
||||||
|
if (this.vNode == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let bottom = this.renderSpan(this.vNode, 'bottom')
|
||||||
|
// 启用了特效,并且有旧数据,就渲染特效顶层
|
||||||
|
if (this.innerEffect && this.effectList.length > 0) {
|
||||||
|
this.$emit('effect-begin')
|
||||||
|
// 1.4s 以后关闭特效
|
||||||
|
window.setTimeout(() => {
|
||||||
|
let item = this.effectList[this.effectIdx]
|
||||||
|
if (item && item.elm) {
|
||||||
|
// 特效结束后,展示先把 display 设为 none,而不是直接删掉该元素,
|
||||||
|
// 目的是为了防止页面重新渲染,导致动画重置
|
||||||
|
item.elm.style.display = 'none'
|
||||||
|
}
|
||||||
|
// 当所有的层级动画都结束时,再删掉所有元素
|
||||||
|
if (++this.effectIdx === this.effectList.length) {
|
||||||
|
this.innerEffect = false
|
||||||
|
this.effectIdx = 0
|
||||||
|
this.effectList = []
|
||||||
|
this.$emit('effect-end')
|
||||||
|
}
|
||||||
|
}, 1400)
|
||||||
|
return [this.effectList, bottom]
|
||||||
|
} else {
|
||||||
|
return bottom
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 渲染内容 span
|
||||||
|
renderSpan(vNode, layer) {
|
||||||
|
let options = {
|
||||||
|
key: layer + this.effectIdx + randomString(6),
|
||||||
|
class: ['j-vxe-reload-effect-span', `layer-${layer}`],
|
||||||
|
style: {},
|
||||||
|
}
|
||||||
|
if (layer === 'top') {
|
||||||
|
// 最新渲染的在下面
|
||||||
|
options.style['z-index'] = (9999 - this.effectIdx)
|
||||||
|
}
|
||||||
|
return this.$createElement('span', options, [vNode])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render(h) {
|
||||||
|
return h('div', {
|
||||||
|
class: ['j-vxe-reload-effect-box'],
|
||||||
|
}, [this.renderVNode()])
|
||||||
|
},
|
||||||
|
}
|
||||||
81
ant-design-vue-jeecg/src/components/jeecg/JVxeTable/index.js
Normal file
81
ant-design-vue-jeecg/src/components/jeecg/JVxeTable/index.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { installCell, mapCell } from './install'
|
||||||
|
import JVxeTable from './components/JVxeTable'
|
||||||
|
|
||||||
|
import JVxeSlotCell from './components/cells/JVxeSlotCell'
|
||||||
|
import JVxeNormalCell from './components/cells/JVxeNormalCell'
|
||||||
|
import JVxeInputCell from './components/cells/JVxeInputCell'
|
||||||
|
import JVxeDateCell from './components/cells/JVxeDateCell'
|
||||||
|
import JVxeSelectCell from './components/cells/JVxeSelectCell'
|
||||||
|
import JVxeCheckboxCell from './components/cells/JVxeCheckboxCell'
|
||||||
|
import JVxeUploadCell from './components/cells/JVxeUploadCell'
|
||||||
|
import { TagsInputCell, TagsSpanCell } from './components/cells/JVxeTagsCell'
|
||||||
|
import JVxeProgressCell from './components/cells/JVxeProgressCell'
|
||||||
|
import JVxeTextareaCell from './components/cells/JVxeTextareaCell'
|
||||||
|
import JVxeDragSortCell from './components/cells/JVxeDragSortCell'
|
||||||
|
|
||||||
|
// 组件类型
|
||||||
|
export const JVXETypes = {
|
||||||
|
// 为了防止和 vxe 内置的类型冲突,所以加上一个前缀
|
||||||
|
// 前缀是自动加的,代码中直接用就行(JVXETypes.input)
|
||||||
|
_prefix: 'j-',
|
||||||
|
|
||||||
|
// 行号列
|
||||||
|
rowNumber: 'row-number',
|
||||||
|
// 选择列
|
||||||
|
rowCheckbox: 'row-checkbox',
|
||||||
|
// 单选列
|
||||||
|
rowRadio: 'row-radio',
|
||||||
|
// 展开列
|
||||||
|
rowExpand: 'row-expand',
|
||||||
|
// 上下排序
|
||||||
|
rowDragSort: 'row-drag-sort',
|
||||||
|
|
||||||
|
input: 'input',
|
||||||
|
inputNumber: 'inputNumber',
|
||||||
|
textarea: 'textarea',
|
||||||
|
select: 'select',
|
||||||
|
date: 'date',
|
||||||
|
datetime: 'datetime',
|
||||||
|
checkbox: 'checkbox',
|
||||||
|
upload: 'upload',
|
||||||
|
// 下拉搜索
|
||||||
|
selectSearch: 'select-search',
|
||||||
|
// 下拉多选
|
||||||
|
selectMultiple: 'select-multiple',
|
||||||
|
// 进度条
|
||||||
|
progress: 'progress',
|
||||||
|
|
||||||
|
// 拖轮Tags(暂无用)
|
||||||
|
tags: 'tags',
|
||||||
|
|
||||||
|
slot: 'slot',
|
||||||
|
normal: 'normal',
|
||||||
|
hidden: 'hidden',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册自定义组件
|
||||||
|
export const AllCells = {
|
||||||
|
...mapCell(JVXETypes.normal, JVxeNormalCell),
|
||||||
|
...mapCell(JVXETypes.input, JVxeInputCell),
|
||||||
|
...mapCell(JVXETypes.inputNumber, JVxeInputCell),
|
||||||
|
...mapCell(JVXETypes.checkbox, JVxeCheckboxCell),
|
||||||
|
...mapCell(JVXETypes.select, JVxeSelectCell),
|
||||||
|
...mapCell(JVXETypes.selectSearch, JVxeSelectCell), // 下拉搜索
|
||||||
|
...mapCell(JVXETypes.selectMultiple, JVxeSelectCell), // 下拉多选
|
||||||
|
...mapCell(JVXETypes.date, JVxeDateCell),
|
||||||
|
...mapCell(JVXETypes.datetime, JVxeDateCell),
|
||||||
|
...mapCell(JVXETypes.upload, JVxeUploadCell),
|
||||||
|
...mapCell(JVXETypes.textarea, JVxeTextareaCell),
|
||||||
|
|
||||||
|
...mapCell(JVXETypes.tags, TagsInputCell, TagsSpanCell),
|
||||||
|
...mapCell(JVXETypes.progress, JVxeProgressCell),
|
||||||
|
|
||||||
|
...mapCell(JVXETypes.rowDragSort, JVxeDragSortCell),
|
||||||
|
...mapCell(JVXETypes.slot, JVxeSlotCell),
|
||||||
|
|
||||||
|
/* hidden 是特殊的组件,不在这里注册 */
|
||||||
|
}
|
||||||
|
|
||||||
|
export { installCell, mapCell }
|
||||||
|
|
||||||
|
export default JVxeTable
|
||||||
105
ant-design-vue-jeecg/src/components/jeecg/JVxeTable/install.js
Normal file
105
ant-design-vue-jeecg/src/components/jeecg/JVxeTable/install.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import { getEventPath } from '@/utils/util'
|
||||||
|
import JVxeTable, { AllCells, JVXETypes } from './index'
|
||||||
|
import './less/j-vxe-table.less'
|
||||||
|
// 引入 vxe-table
|
||||||
|
import 'xe-utils'
|
||||||
|
import VXETable, { Grid } from 'vxe-table'
|
||||||
|
import VXETablePluginAntd from 'vxe-table-plugin-antd'
|
||||||
|
import 'vxe-table/lib/index.css'
|
||||||
|
import 'vxe-table-plugin-antd/dist/style.css'
|
||||||
|
import { getEnhancedMixins, installAllCell, installOneCell } from '@/components/jeecg/JVxeTable/utils/cellUtils'
|
||||||
|
|
||||||
|
// VxeGrid所有的方法映射
|
||||||
|
const VxeGridMethodsMap = {}
|
||||||
|
Object.keys(Grid.methods).forEach(key => {
|
||||||
|
// 使用eval可以避免闭包(但是要注意不要写es6的代码)
|
||||||
|
VxeGridMethodsMap[key] = eval(`(function(){return this.$refs.vxe.${key}.apply(this.$refs.vxe,arguments)})`)
|
||||||
|
})
|
||||||
|
// 将Grid所有的方法都映射(继承)到JVxeTable上
|
||||||
|
JVxeTable.methods = Object.assign({}, VxeGridMethodsMap, JVxeTable.methods)
|
||||||
|
|
||||||
|
// VXETable 全局配置
|
||||||
|
const VXETableSettings = {
|
||||||
|
// z-index 起始值
|
||||||
|
zIndex: 1000,
|
||||||
|
table: {
|
||||||
|
validConfig: {
|
||||||
|
// 校验提示方式:强制使用tooltip
|
||||||
|
message: 'tooltip'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行注册方法
|
||||||
|
Vue.use(VXETable, VXETableSettings)
|
||||||
|
VXETable.use(VXETablePluginAntd)
|
||||||
|
Vue.component(JVxeTable.name, JVxeTable)
|
||||||
|
|
||||||
|
// 注册自定义组件
|
||||||
|
installAllCell(VXETable)
|
||||||
|
|
||||||
|
// 添加事件拦截器 event.clearActived
|
||||||
|
// 比如点击了某个组件的弹出层面板之后,此时被激活单元格不应该被自动关闭,通过返回 false 可以阻止默认的行为。
|
||||||
|
VXETable.interceptor.add('event.clearActived', function (params, event, target) {
|
||||||
|
// 获取组件增强
|
||||||
|
let col = params.column.own
|
||||||
|
const interceptor = getEnhancedMixins(col.$type, 'interceptor')
|
||||||
|
// 执行增强
|
||||||
|
let flag = interceptor['event.clearActived'].apply(this, arguments)
|
||||||
|
if (flag === false) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = getEventPath(event)
|
||||||
|
for (let p of path) {
|
||||||
|
let className = p.className || ''
|
||||||
|
className = typeof className === 'string' ? className : className.toString()
|
||||||
|
|
||||||
|
/* --- 特殊处理以下组件,点击以下标签时不清空编辑状态 --- */
|
||||||
|
|
||||||
|
// 点击的标签是JInputPop
|
||||||
|
if (className.includes('j-input-pop')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 点击的标签是JPopup的弹出层
|
||||||
|
if (className.includes('j-popup-modal')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 执行增强
|
||||||
|
let flag = interceptor['event.clearActived.className'].apply(this, [className, ...arguments])
|
||||||
|
if (flag === false) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册map
|
||||||
|
* @param type 类型
|
||||||
|
* @param cell 输入组件
|
||||||
|
* @param span 显示组件,可空,默认为 JVxeNormalCell 组件
|
||||||
|
*/
|
||||||
|
export function mapCell(type, cell, span) {
|
||||||
|
let cells = {[type]: cell}
|
||||||
|
if (span) {
|
||||||
|
cells[type + ':span'] = span
|
||||||
|
}
|
||||||
|
return cells
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册自定义组件
|
||||||
|
*
|
||||||
|
* @param type 类型
|
||||||
|
* @param cell 输入组件
|
||||||
|
* @param span 显示组件,可空,默认为 JVxeNormalCell 组件
|
||||||
|
*/
|
||||||
|
export function installCell(type, cell, span) {
|
||||||
|
let exclude = [JVXETypes.rowNumber, JVXETypes.rowCheckbox, JVXETypes.rowRadio, JVXETypes.rowExpand, JVXETypes.rowDragSort]
|
||||||
|
if (exclude.includes(type)) {
|
||||||
|
throw new Error(`【installCell】不能使用"${type}"作为组件的type,因为这是关键字。`)
|
||||||
|
}
|
||||||
|
Object.assign(AllCells, mapCell(type, cell, span))
|
||||||
|
installOneCell(VXETable, type)
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
@import "size/tiny";
|
||||||
|
|
||||||
|
.j-vxe-table-box {
|
||||||
|
|
||||||
|
// 工具栏
|
||||||
|
.j-vxe-toolbar {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页器
|
||||||
|
.j-vxe-pagination {
|
||||||
|
margin-top: 8px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
.ant-pagination-options-size-changer.ant-select {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.show-quick-jumper {
|
||||||
|
.ant-pagination-options-size-changer.ant-select {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更改 header 底色
|
||||||
|
.vxe-table.border--default .vxe-table--header-wrapper,
|
||||||
|
.vxe-table.border--full .vxe-table--header-wrapper,
|
||||||
|
.vxe-table.border--outer .vxe-table--header-wrapper {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更改 tooltip 校验失败的颜色
|
||||||
|
.vxe-table--tooltip-wrapper.vxe-table--valid-error {
|
||||||
|
background-color: #f5222d !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更改 输入框 校验失败的颜色
|
||||||
|
.col--valid-error > .vxe-cell > .ant-input,
|
||||||
|
.col--valid-error > .vxe-cell > .ant-select .ant-input,
|
||||||
|
.col--valid-error > .vxe-cell > .ant-select .ant-select-selection,
|
||||||
|
.col--valid-error > .vxe-cell > .ant-input-number,
|
||||||
|
.col--valid-error > .vxe-cell > .ant-cascader-picker .ant-cascader-input,
|
||||||
|
.col--valid-error > .vxe-cell > .ant-calendar-picker .ant-calendar-picker-input,
|
||||||
|
.col--valid-error > .vxe-tree-cell > .ant-input,
|
||||||
|
.col--valid-error > .vxe-tree-cell > .ant-select .ant-input,
|
||||||
|
.col--valid-error > .vxe-tree-cell > .ant-select .ant-select-selection,
|
||||||
|
.col--valid-error > .vxe-tree-cell > .ant-input-number,
|
||||||
|
.col--valid-error > .vxe-tree-cell > .ant-cascader-picker .ant-cascader-input,
|
||||||
|
.col--valid-error > .vxe-tree-cell > .ant-calendar-picker .ant-calendar-picker-input {
|
||||||
|
border-color: #f5222d !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽排序列样式
|
||||||
|
.vxe-table .col--row-drag-sort .vxe-cell {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
.j-vxe-reload-effect-box {
|
||||||
|
|
||||||
|
&,
|
||||||
|
.j-vxe-reload-effect-span {
|
||||||
|
display: inline;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.j-vxe-reload-effect-span {
|
||||||
|
|
||||||
|
&.layer-top {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
transform-origin: 0 0;
|
||||||
|
animation: reload-effect 1.5s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.layer-bottom {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义动画
|
||||||
|
@keyframes reload-effect {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotateX(0);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: rotateX(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,332 @@
|
|||||||
|
.j-vxe-table-box {
|
||||||
|
|
||||||
|
@height: 24px;
|
||||||
|
@lineHeight: 1.5;
|
||||||
|
@spacing: 4px;
|
||||||
|
@fontSize: 14px;
|
||||||
|
@borderRadius: 2px;
|
||||||
|
|
||||||
|
&.size--tiny {
|
||||||
|
|
||||||
|
.vxe-table--header .vxe-cell--checkbox {
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table--body .vxe-cell--checkbox {
|
||||||
|
line-height: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-cell {
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: @fontSize;
|
||||||
|
line-height: @lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table .vxe-header--column .vxe-cell {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-body--column.col--actived {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.vxe-cell {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ant输入框
|
||||||
|
.ant-input,
|
||||||
|
// ant下拉框
|
||||||
|
.ant-select-selection {
|
||||||
|
padding: 2px @spacing;
|
||||||
|
height: @height;
|
||||||
|
font-size: @fontSize;
|
||||||
|
border-radius: @borderRadius;
|
||||||
|
line-height: @lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入框图标对齐
|
||||||
|
.ant-input-affix-wrapper {
|
||||||
|
& .ant-input-prefix {
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ant-input:not(:first-child) {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按钮 addon
|
||||||
|
.ant-input-group-addon {
|
||||||
|
border-color: transparent;
|
||||||
|
border-radius: @borderRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ant下拉多选框
|
||||||
|
.ant-select-selection--multiple {
|
||||||
|
min-height: @height;
|
||||||
|
|
||||||
|
& .ant-select-selection__rendered > ul > li {
|
||||||
|
height: calc(@height - 6px);
|
||||||
|
font-size: calc(@fontSize - 2px);
|
||||||
|
margin-top: 0;
|
||||||
|
line-height: @lineHeight;
|
||||||
|
padding: 0 18px 0 4px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ant-select-selection__clear,
|
||||||
|
& .ant-select-arrow {
|
||||||
|
top: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ant按钮
|
||||||
|
.ant-upload {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: @height;
|
||||||
|
padding: 0 8px;
|
||||||
|
font-size: @fontSize;
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: @borderRadius;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-selection__rendered {
|
||||||
|
line-height: @lineHeight;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 工具栏
|
||||||
|
.j-vxe-toolbar {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
|
||||||
|
.ant-form-item-label,
|
||||||
|
.ant-form-item-control {
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-inline .ant-form-item {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 内置属性 */
|
||||||
|
|
||||||
|
.vxe-table.size--tiny {
|
||||||
|
& .vxe-table--expanded {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .vxe-body--expanded-cell {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.size--tiny .vxe-loading .vxe-loading--spinner {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table.size--tiny .vxe-body--column.col--ellipsis,
|
||||||
|
.vxe-table.size--tiny .vxe-footer--column.col--ellipsis,
|
||||||
|
.vxe-table.size--tiny .vxe-header--column.col--ellipsis,
|
||||||
|
.vxe-table.vxe-editable.size--tiny .vxe-body--column {
|
||||||
|
height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table.size--tiny .vxe-table--empty-block,
|
||||||
|
.vxe-table.size--tiny .vxe-table--empty-placeholder {
|
||||||
|
min-height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table.size--tiny .vxe-body--column:not(.col--ellipsis),
|
||||||
|
.vxe-table.size--tiny .vxe-footer--column:not(.col--ellipsis),
|
||||||
|
.vxe-table.size--tiny .vxe-header--column:not(.col--ellipsis) {
|
||||||
|
padding: 4px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table.size--tiny .vxe-cell .vxe-default-input,
|
||||||
|
.vxe-table.size--tiny .vxe-cell .vxe-default-select,
|
||||||
|
.vxe-table.size--tiny .vxe-cell .vxe-default-textarea {
|
||||||
|
height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table.size--tiny .vxe-cell .vxe-default-input[type=date]::-webkit-inner-spin-button {
|
||||||
|
margin-top: 1px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table.size--tiny.virtual--x .col--ellipsis .vxe-cell,
|
||||||
|
.vxe-table.size--tiny.virtual--y .col--ellipsis .vxe-cell,
|
||||||
|
.vxe-table.size--tiny .vxe-body--column.col--ellipsis .vxe-cell,
|
||||||
|
.vxe-table.size--tiny .vxe-footer--column.col--ellipsis .vxe-cell,
|
||||||
|
.vxe-table.size--tiny .vxe-header--column.col--ellipsis .vxe-cell {
|
||||||
|
max-height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table.size--tiny .vxe-cell--checkbox .vxe-checkbox--icon,
|
||||||
|
.vxe-table.size--tiny .vxe-cell--radio .vxe-radio--icon {
|
||||||
|
font-size: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.vxe-table.size--tiny .vxe-table--filter-option > .vxe-checkbox--icon,
|
||||||
|
.vxe-table.size--small .vxe-table--filter-option > .vxe-checkbox--icon {
|
||||||
|
font-size: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-modal--wrapper.size--tiny .vxe-export--panel-column-option > .vxe-checkbox--icon,
|
||||||
|
.vxe-modal--wrapper.size--small .vxe-export--panel-column-option > .vxe-checkbox--icon {
|
||||||
|
font-size: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-grid.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-toolbar.size--tiny {
|
||||||
|
font-size: 12px;
|
||||||
|
height: 46px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-toolbar.size--tiny .vxe-custom--option > .vxe-checkbox--icon {
|
||||||
|
font-size: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-pager.size--tiny {
|
||||||
|
font-size: 12px;
|
||||||
|
height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-checkbox.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-checkbox.size--tiny .vxe-checkbox--icon {
|
||||||
|
font-size: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-radio-button.size--tiny .vxe-radio--label {
|
||||||
|
line-height: 26px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-radio.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-radio.size--tiny .vxe-radio--icon {
|
||||||
|
font-size: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-input.size--tiny {
|
||||||
|
font-size: 12px;
|
||||||
|
height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-input.size--tiny .vxe-input--inner[type=date]::-webkit-inner-spin-button,
|
||||||
|
.vxe-input.size--tiny .vxe-input--inner[type=month]::-webkit-inner-spin-button,
|
||||||
|
.vxe-input.size--tiny .vxe-input--inner[type=week]::-webkit-inner-spin-button {
|
||||||
|
margin-top: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-dropdown--panel.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-textarea--autosize.size--tiny,
|
||||||
|
.vxe-textarea.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-textarea.size--tiny:not(.is--autosize) {
|
||||||
|
min-height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-button.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-button.size--tiny.type--button {
|
||||||
|
height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-button.size--tiny.type--button.is--circle {
|
||||||
|
min-width: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-button.size--tiny.type--button.is--round {
|
||||||
|
border-radius: 14px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-button.size--tiny .vxe-button--icon,
|
||||||
|
.vxe-button.size--tiny .vxe-button--loading-icon {
|
||||||
|
min-width: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-modal--wrapper.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-form.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-form.size--tiny .vxe-form--item-inner {
|
||||||
|
min-height: 30px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-form.size--tiny .vxe-default-input[type=reset],
|
||||||
|
.vxe-form.size--tiny .vxe-default-input[type=submit] {
|
||||||
|
line-height: 26px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-form.size--tiny .vxe-default-input,
|
||||||
|
.vxe-form.size--tiny .vxe-default-select {
|
||||||
|
height: @height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-select--panel.size--tiny,
|
||||||
|
.vxe-select.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-select--panel.size--tiny .vxe-optgroup--title,
|
||||||
|
.vxe-select--panel.size--tiny .vxe-select-option {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-switch.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.vxe-pulldown--panel.size--tiny,
|
||||||
|
.vxe-pulldown.size--tiny {
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,303 @@
|
|||||||
|
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||||
|
import { filterDictText } from '@/components/dict/JDictSelectUtil'
|
||||||
|
import { getEnhancedMixins, JVXERenderType, replaceProps } from '@/components/jeecg/JVxeTable/utils/cellUtils'
|
||||||
|
|
||||||
|
// noinspection JSUnusedLocalSymbols
|
||||||
|
export default {
|
||||||
|
inject: {
|
||||||
|
getParentContainer: {default: () => ((node) => node.parentNode)},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
value: PropTypes.any,
|
||||||
|
row: PropTypes.object,
|
||||||
|
column: PropTypes.object,
|
||||||
|
// 组件参数
|
||||||
|
params: PropTypes.object,
|
||||||
|
// 渲染选项
|
||||||
|
renderOptions: PropTypes.object,
|
||||||
|
// 渲染类型
|
||||||
|
renderType: PropTypes.string.def('default'),
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innerValue: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
caseId() {
|
||||||
|
return this.renderOptions.caseId
|
||||||
|
},
|
||||||
|
originColumn() {
|
||||||
|
return this.column.own
|
||||||
|
},
|
||||||
|
$type() {
|
||||||
|
return this.originColumn.$type
|
||||||
|
},
|
||||||
|
rows() {
|
||||||
|
return this.params.data
|
||||||
|
},
|
||||||
|
rowIndex() {
|
||||||
|
return this.params.rowIndex
|
||||||
|
},
|
||||||
|
columnIndex() {
|
||||||
|
return this.params.columnIndex
|
||||||
|
},
|
||||||
|
cellProps() {
|
||||||
|
let {originColumn: col, renderOptions} = this
|
||||||
|
|
||||||
|
let props = {}
|
||||||
|
|
||||||
|
// 输入占位符
|
||||||
|
props['placeholder'] = replaceProps(col, col.placeholder)
|
||||||
|
|
||||||
|
// 解析props
|
||||||
|
if (typeof col.props === 'object') {
|
||||||
|
Object.keys(col.props).forEach(key => {
|
||||||
|
props[key] = replaceProps(col, col.props[key])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是禁用的列
|
||||||
|
props['disabled'] = (typeof col['disabled'] === 'boolean' ? col['disabled'] : props['disabled'])
|
||||||
|
|
||||||
|
// TODO 判断是否是禁用的行
|
||||||
|
// if (props['disabled'] !== true) {
|
||||||
|
// props['disabled'] = ((this.disabledRowIds || []).indexOf(row.id) !== -1)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 判断是否禁用所有组件
|
||||||
|
if (renderOptions.disabled === true) {
|
||||||
|
props['disabled'] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return props
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$type: {
|
||||||
|
immediate: true,
|
||||||
|
handler($type) {
|
||||||
|
this.enhanced = getEnhancedMixins($type)
|
||||||
|
this.listeners = getListeners.call(this)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
let value = val
|
||||||
|
|
||||||
|
// 验证值格式
|
||||||
|
let originValue = this.row[this.column.property]
|
||||||
|
let getValue = this.enhanced.getValue.call(this, originValue)
|
||||||
|
if (originValue !== getValue) {
|
||||||
|
// 值格式不正确,重新赋值
|
||||||
|
value = getValue
|
||||||
|
vModel.call(this, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.innerValue = this.enhanced.setValue.call(this, value)
|
||||||
|
|
||||||
|
// 判断是否启用翻译
|
||||||
|
if (this.renderType === JVXERenderType.spaner && this.enhanced.translate.enabled) {
|
||||||
|
this.innerValue = this.enhanced.translate.handler.call(this, value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
/** 通用处理change事件 */
|
||||||
|
handleChangeCommon(value) {
|
||||||
|
let handle = this.enhanced.getValue.call(this, value)
|
||||||
|
this.trigger('change', {value: handle})
|
||||||
|
// 触发valueChange事件
|
||||||
|
this.parentTrigger('valueChange', {
|
||||||
|
type: this.$type,
|
||||||
|
value: handle,
|
||||||
|
oldValue: this.value,
|
||||||
|
col: this.originColumn,
|
||||||
|
rowIndex: this.params.rowIndex,
|
||||||
|
columnIndex: this.params.columnIndex,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 通用处理blur事件 */
|
||||||
|
handleBlurCommon(value) {
|
||||||
|
this.trigger('blur', {value})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果事件存在的话,就触发
|
||||||
|
* @param name 事件名
|
||||||
|
* @param event 事件参数
|
||||||
|
* @param args 其他附带参数
|
||||||
|
*/
|
||||||
|
trigger(name, event, args = []) {
|
||||||
|
let listener = this.listeners[name]
|
||||||
|
if (typeof listener === 'function') {
|
||||||
|
if (typeof event === 'object') {
|
||||||
|
event = this.packageEvent(name, event)
|
||||||
|
}
|
||||||
|
listener(event, ...args)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parentTrigger(name, event, args = []) {
|
||||||
|
args.unshift(this.packageEvent(name, event))
|
||||||
|
this.trigger('trigger', name, args)
|
||||||
|
},
|
||||||
|
packageEvent(name, event = {}) {
|
||||||
|
event.row = this.row
|
||||||
|
event.column = this.column
|
||||||
|
event.cellTarget = this
|
||||||
|
if (!event.type) {
|
||||||
|
event.type = name
|
||||||
|
}
|
||||||
|
if (!event.cellType) {
|
||||||
|
event.cellType = this.$type
|
||||||
|
}
|
||||||
|
// 是否校验表单,默认为true
|
||||||
|
if (typeof event.validate !== 'boolean') {
|
||||||
|
event.validate = true
|
||||||
|
}
|
||||||
|
return event
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
prop: 'value',
|
||||||
|
event: 'change'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 【自定义增强】用于实现一些增强事件
|
||||||
|
* 【注】这里只是定义接口,具体功能需要到各个组件内实现(也有部分功能实现)
|
||||||
|
* 【注】该属性不是Vue官方属性,是JVxeTable组件自定义的
|
||||||
|
* 所以方法内的 this 指向并不是当前组件,而是方法自身,
|
||||||
|
* 也就是说并不能 this 打点调实例里的任何方法
|
||||||
|
*/
|
||||||
|
enhanced: {
|
||||||
|
// 注册参数(详见:https://xuliangzhan_admin.gitee.io/vxe-table/#/table/renderer/edit)
|
||||||
|
installOptions: {
|
||||||
|
// 自动聚焦的 class 类名
|
||||||
|
autofocus: '',
|
||||||
|
},
|
||||||
|
// 事件拦截器(用于兼容)
|
||||||
|
interceptor: {
|
||||||
|
// 已实现:event.clearActived
|
||||||
|
// 说明:比如点击了某个组件的弹出层面板之后,此时被激活单元格不应该被自动关闭,通过返回 false 可以阻止默认的行为。
|
||||||
|
['event.clearActived'](params, event, target) {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
// 自定义:event.clearActived.className
|
||||||
|
// 说明:比原生的多了一个参数:className,用于判断点击的元素的样式名(递归到顶层)
|
||||||
|
['event.clearActived.className'](params, event, target) {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 【功能开关】
|
||||||
|
switches: {
|
||||||
|
// 是否使用 editRender 模式(仅当前组件,并非全局)
|
||||||
|
// 如果设为true,则表头上方会出现一个可编辑的图标
|
||||||
|
editRender: true,
|
||||||
|
// false = 组件触发后可视);true = 组件一直可视
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
|
// 【切面增强】切面事件处理,一般在某些方法执行后同步执行
|
||||||
|
aopEvents: {
|
||||||
|
// 单元格被激活编辑时会触发该事件
|
||||||
|
editActived() {
|
||||||
|
},
|
||||||
|
// 单元格编辑状态下被关闭时会触发该事件
|
||||||
|
editClosed() {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 【翻译增强】可以实现例如select组件保存的value,但是span模式下需要显示成text
|
||||||
|
translate: {
|
||||||
|
// 是否启用翻译
|
||||||
|
enabled: false,
|
||||||
|
/**
|
||||||
|
* 【翻译处理方法】如果handler留空,则使用默认的翻译方法
|
||||||
|
* (this指向当前组件)
|
||||||
|
*
|
||||||
|
* @param value 需要翻译的值
|
||||||
|
* @returns{*} 返回翻译后的数据
|
||||||
|
*/
|
||||||
|
handler(value,) {
|
||||||
|
// 默认翻译方法
|
||||||
|
return filterDictText(this.column.own.options, value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 【获取值增强】组件抛出的值
|
||||||
|
* (this指向当前组件)
|
||||||
|
*
|
||||||
|
* @param value 保存到数据库里的值
|
||||||
|
* @returns{*} 返回处理后的值
|
||||||
|
*/
|
||||||
|
getValue(value) {
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 【设置值增强】设置给组件的值
|
||||||
|
* (this指向当前组件)
|
||||||
|
*
|
||||||
|
* @param value 组件触发的值
|
||||||
|
* @returns{*} 返回处理后的值
|
||||||
|
*/
|
||||||
|
setValue(value) {
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 【新增行增强】在用户点击新增时触发的事件,返回新行的默认值
|
||||||
|
*
|
||||||
|
* @param row 行数据
|
||||||
|
* @param column 列配置,.own 是用户配置的参数
|
||||||
|
* @param $table vxe 实例
|
||||||
|
* @param renderOptions 渲染选项
|
||||||
|
* @param params 可以在这里获取 $table
|
||||||
|
*
|
||||||
|
* @returns 返回新值
|
||||||
|
*/
|
||||||
|
createValue({row, column, $table, renderOptions, params}) {
|
||||||
|
return column.own.defaultValue
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getListeners() {
|
||||||
|
let listeners = Object.assign({}, (this.renderOptions.listeners || {}))
|
||||||
|
if (!listeners.change) {
|
||||||
|
listeners.change = async (event) => {
|
||||||
|
vModel.call(this, event.value)
|
||||||
|
await this.$nextTick()
|
||||||
|
// 处理 change 事件相关逻辑(例如校验)
|
||||||
|
this.params.$table.updateStatus(this.params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners
|
||||||
|
}
|
||||||
|
|
||||||
|
export function vModel(value, row, property) {
|
||||||
|
if (!row) {
|
||||||
|
row = this.row
|
||||||
|
}
|
||||||
|
if (!property) {
|
||||||
|
property = this.column.property
|
||||||
|
}
|
||||||
|
this.$set(row, property, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 模拟触发事件 */
|
||||||
|
export function dispatchEvent({cell, $event}, className, handler) {
|
||||||
|
window.setTimeout(() => {
|
||||||
|
let element = cell.getElementsByClassName(className)
|
||||||
|
if (element && element.length > 0) {
|
||||||
|
if (typeof handler === 'function') {
|
||||||
|
handler(element[0])
|
||||||
|
} else {
|
||||||
|
// 模拟触发点击事件
|
||||||
|
element[0].dispatchEvent($event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
@ -0,0 +1,264 @@
|
|||||||
|
import store from '@/store/'
|
||||||
|
import { randomUUID } from '@/utils/util'
|
||||||
|
// vxe socket
|
||||||
|
const vs = {
|
||||||
|
// 页面唯一 id,用于标识同一用户,不同页面的websocket
|
||||||
|
pageId: randomUUID(),
|
||||||
|
// webSocket 对象
|
||||||
|
ws: null,
|
||||||
|
// 一些常量
|
||||||
|
constants: {
|
||||||
|
// 消息类型
|
||||||
|
TYPE: 'type',
|
||||||
|
// 消息数据
|
||||||
|
DATA: 'data',
|
||||||
|
// 消息类型:心跳检测
|
||||||
|
TYPE_HB: 'heart_beat',
|
||||||
|
// 消息类型:通用数据传递
|
||||||
|
TYPE_CSD: 'common_send_date',
|
||||||
|
// 消息类型:更新vxe table数据
|
||||||
|
TYPE_UVT: 'update_vxe_table',
|
||||||
|
},
|
||||||
|
// 心跳检测
|
||||||
|
heartCheck: {
|
||||||
|
// 间隔时间,间隔多久发送一次心跳消息
|
||||||
|
interval: 10000,
|
||||||
|
// 心跳消息超时时间,心跳消息多久没有回复后重连
|
||||||
|
timeout: 6000,
|
||||||
|
timeoutTimer: null,
|
||||||
|
clear() {
|
||||||
|
clearTimeout(this.timeoutTimer)
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
start() {
|
||||||
|
vs.sendMessage(vs.constants.TYPE_HB, '')
|
||||||
|
// 如果超过一定时间还没重置,说明后端主动断开了
|
||||||
|
this.timeoutTimer = window.setTimeout(() => {
|
||||||
|
vs.reconnect()
|
||||||
|
}, this.timeout)
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
// 心跳消息返回
|
||||||
|
back() {
|
||||||
|
this.clear()
|
||||||
|
window.setTimeout(() => this.start(), this.interval)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 初始化 WebSocket */
|
||||||
|
initialWebSocket() {
|
||||||
|
if (this.ws === null) {
|
||||||
|
const userId = store.getters.userInfo.id
|
||||||
|
const domain = window._CONFIG['domianURL'].replace('https://', 'wss://').replace('http://', 'ws://')
|
||||||
|
const url = `${domain}/vxeSocket/${userId}/${this.pageId}`
|
||||||
|
|
||||||
|
this.ws = new WebSocket(url)
|
||||||
|
this.ws.onopen = this.on.open.bind(this)
|
||||||
|
this.ws.onerror = this.on.error.bind(this)
|
||||||
|
this.ws.onmessage = this.on.message.bind(this)
|
||||||
|
this.ws.onclose = this.on.close.bind(this)
|
||||||
|
|
||||||
|
console.log('this.ws: ', this.ws)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
sendMessage(type, message) {
|
||||||
|
try {
|
||||||
|
let ws = this.ws
|
||||||
|
if (ws != null && ws.readyState === ws.OPEN) {
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: type,
|
||||||
|
data: message
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('【VXEWebSocket】发送消息失败:(' + err.code + ')')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 绑定全局VXE表格 */
|
||||||
|
tableMap: new Map(),
|
||||||
|
CSDMap: new Map(),
|
||||||
|
/** 添加绑定 */
|
||||||
|
addBind(map, key, value) {
|
||||||
|
let binds = map.get(key)
|
||||||
|
if (Array.isArray(binds)) {
|
||||||
|
binds.push(value)
|
||||||
|
} else {
|
||||||
|
map.set(key, [value])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 移除绑定 */
|
||||||
|
removeBind(map, key, value) {
|
||||||
|
let binds = map.get(key)
|
||||||
|
if (Array.isArray(binds)) {
|
||||||
|
for (let i = 0; i < binds.length; i++) {
|
||||||
|
let bind = binds[i]
|
||||||
|
if (bind === value) {
|
||||||
|
binds.splice(i, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (binds.length === 0) {
|
||||||
|
map.delete(key)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
map.delete(key)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 呼叫绑定的表单
|
||||||
|
callBind(map, key, callback) {
|
||||||
|
let binds = map.get(key)
|
||||||
|
if (Array.isArray(binds)) {
|
||||||
|
binds.forEach(callback)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
lockReconnect: false,
|
||||||
|
/** 尝试重连 */
|
||||||
|
reconnect() {
|
||||||
|
if (this.lockReconnect) return
|
||||||
|
this.lockReconnect = true
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.ws && this.ws.close) {
|
||||||
|
this.ws.close()
|
||||||
|
}
|
||||||
|
this.ws = null
|
||||||
|
console.info('【VXEWebSocket】尝试重连...')
|
||||||
|
this.initialWebSocket()
|
||||||
|
this.lockReconnect = false
|
||||||
|
}, 5000)
|
||||||
|
},
|
||||||
|
|
||||||
|
on: {
|
||||||
|
open() {
|
||||||
|
console.log('【VXEWebSocket】连接成功')
|
||||||
|
this.heartCheck.start()
|
||||||
|
},
|
||||||
|
error(e) {
|
||||||
|
console.warn('【VXEWebSocket】连接发生错误:', e)
|
||||||
|
this.reconnect()
|
||||||
|
},
|
||||||
|
message(e) {
|
||||||
|
// 解析消息
|
||||||
|
let json
|
||||||
|
try {
|
||||||
|
json = JSON.parse(e.data)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('【VXEWebSocket】收到无法解析的消息:', e.data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let type = json[this.constants.TYPE]
|
||||||
|
let data = json[this.constants.DATA]
|
||||||
|
switch (type) {
|
||||||
|
// 心跳检测
|
||||||
|
case this.constants.TYPE_HB:
|
||||||
|
this.heartCheck.back()
|
||||||
|
break
|
||||||
|
// 通用数据传递
|
||||||
|
case this.constants.TYPE_CSD:
|
||||||
|
this.callBind(this.CSDMap, data.key, (fn) => fn.apply(this, data.args))
|
||||||
|
break
|
||||||
|
// 更新form数据
|
||||||
|
case this.constants.TYPE_UVT:
|
||||||
|
this.callBind(this.tableMap, data.socketKey, (vm) => this.onVM['onUpdateTable'].apply(vm, data.args))
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.warn('【VXEWebSocket】收到不识别的消息类型:' + type)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close(e) {
|
||||||
|
console.log('【VXEWebSocket】连接被关闭:', e)
|
||||||
|
this.reconnect()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
onVM: {
|
||||||
|
/** 收到更新表格的消息 */
|
||||||
|
onUpdateTable(row, caseId) {
|
||||||
|
// 判断是不是自己发的消息
|
||||||
|
if (this.caseId !== caseId) {
|
||||||
|
const tableRow = this.getIfRowById(row.id).row
|
||||||
|
// 局部保更新数据
|
||||||
|
if (tableRow) {
|
||||||
|
// 特殊处理拖轮状态
|
||||||
|
if (row['tug_status'] && tableRow['tug_status']) {
|
||||||
|
row['tug_status'] = Object.assign({}, tableRow['tug_status'], row['tug_status'])
|
||||||
|
}
|
||||||
|
// 判断是否启用重载特效
|
||||||
|
if (this.reloadEffect) {
|
||||||
|
this.$set(this.reloadEffectRowKeysMap, row.id, true)
|
||||||
|
}
|
||||||
|
Object.keys(row).forEach(key => {
|
||||||
|
if (key !== 'id') {
|
||||||
|
this.$set(tableRow, key, row[key])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$refs.vxe.reloadRow(tableRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 是否开启使用 webSocket 无痕刷新
|
||||||
|
socketReload: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
socketKey: {
|
||||||
|
type: String,
|
||||||
|
default: 'vxe-default'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.socketReload) {
|
||||||
|
vs.initialWebSocket()
|
||||||
|
vs.addBind(vs.tableMap, this.socketKey, this)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
/** 发送socket消息更新行 */
|
||||||
|
socketSendUpdateRow(row) {
|
||||||
|
vs.sendMessage(vs.constants.TYPE_UVT, {
|
||||||
|
socketKey: this.socketKey,
|
||||||
|
args: [row, this.caseId],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
vs.removeBind(vs.tableMap, this.socketKey, this)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加WebSocket通用数据传递绑定,相同的key可以添加多个方法绑定
|
||||||
|
* @param key 唯一key
|
||||||
|
* @param fn 当消息来的时候触发的回调方法
|
||||||
|
*/
|
||||||
|
export function addBindSocketCSD(key, fn) {
|
||||||
|
if (typeof fn === 'function') {
|
||||||
|
vs.addBind(vs.CSDMap, key, fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除WebSocket通用数据传递绑定
|
||||||
|
* @param key 唯一key
|
||||||
|
* @param fn 要移除的方法,必须和添加时的方法内存层面上保持一致才可以正确移除
|
||||||
|
*/
|
||||||
|
export function removeBindSocketCSD(key, fn) {
|
||||||
|
if (typeof fn === 'function') {
|
||||||
|
vs.removeBind(vs.CSDMap, key, fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
import { AllCells, JVXETypes } from '@/components/jeecg/JVxeTable'
|
||||||
|
import JVxeCellMixins from '../mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export const JVXERenderType = {
|
||||||
|
editer: 'editer',
|
||||||
|
spaner: 'spaner',
|
||||||
|
default: 'default',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 安装所有vxe组件 */
|
||||||
|
export function installAllCell(VXETable) {
|
||||||
|
// 遍历所有组件批量注册
|
||||||
|
Object.keys(AllCells).forEach(type => installOneCell(VXETable, type))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 安装单个vxe组件 */
|
||||||
|
export function installOneCell(VXETable, type) {
|
||||||
|
const switches = getEnhancedMixins(type, 'switches')
|
||||||
|
if (switches.editRender === false) {
|
||||||
|
installCellRender(VXETable, type, AllCells[type])
|
||||||
|
} else {
|
||||||
|
installEditRender(VXETable, type, AllCells[type])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 注册可编辑组件 */
|
||||||
|
export function installEditRender(VXETable, type, comp, spanComp) {
|
||||||
|
// 获取当前组件的增强
|
||||||
|
const enhanced = getEnhancedMixins(type)
|
||||||
|
// span 组件
|
||||||
|
if (!spanComp && AllCells[type + ':span']) {
|
||||||
|
spanComp = AllCells[type + ':span']
|
||||||
|
} else {
|
||||||
|
spanComp = AllCells[JVXETypes.normal]
|
||||||
|
}
|
||||||
|
// 添加渲染
|
||||||
|
VXETable.renderer.add(JVXETypes._prefix + type, {
|
||||||
|
// 可编辑模板
|
||||||
|
renderEdit: createRender(comp, enhanced, JVXERenderType.editer),
|
||||||
|
// 显示模板
|
||||||
|
renderCell: createRender(spanComp, enhanced, JVXERenderType.spaner),
|
||||||
|
// 增强注册
|
||||||
|
...enhanced.installOptions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 注册普通组件 */
|
||||||
|
export function installCellRender(VXETable, type, comp = AllCells[JVXETypes.normal]) {
|
||||||
|
// 获取当前组件的增强
|
||||||
|
const enhanced = getEnhancedMixins(type)
|
||||||
|
VXETable.renderer.add(JVXETypes._prefix + type, {
|
||||||
|
// 默认显示模板
|
||||||
|
renderDefault: createRender(comp, enhanced, JVXERenderType.default),
|
||||||
|
// 增强注册
|
||||||
|
...enhanced.installOptions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRender(comp, enhanced, renderType) {
|
||||||
|
return function (h, renderOptions, params) {
|
||||||
|
return [h(comp, {
|
||||||
|
props: {
|
||||||
|
value: params.row[params.column.property],
|
||||||
|
row: params.row,
|
||||||
|
column: params.column,
|
||||||
|
params: params,
|
||||||
|
renderOptions: renderOptions,
|
||||||
|
renderType: renderType,
|
||||||
|
}
|
||||||
|
})]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已混入的组件增强
|
||||||
|
const AllCellsMixins = new Map()
|
||||||
|
|
||||||
|
/** 获取某个组件的增强 */
|
||||||
|
export function getEnhanced(type) {
|
||||||
|
let cell = AllCells[type]
|
||||||
|
if (cell && cell.enhanced) {
|
||||||
|
return cell.enhanced
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取某个组件的增强(混入默认值)
|
||||||
|
*
|
||||||
|
* @param type JVXETypes
|
||||||
|
* @param name 可空,增强名称,留空返回所有增强
|
||||||
|
*/
|
||||||
|
export function getEnhancedMixins(type, name) {
|
||||||
|
const getByName = (e) => name ? e[name] : e
|
||||||
|
if (AllCellsMixins.has(type)) {
|
||||||
|
return getByName(AllCellsMixins.get(type))
|
||||||
|
}
|
||||||
|
let defEnhanced = JVxeCellMixins.enhanced
|
||||||
|
let enhanced = getEnhanced(type)
|
||||||
|
if (enhanced) {
|
||||||
|
Object.keys(defEnhanced).forEach(key => {
|
||||||
|
let def = defEnhanced[key]
|
||||||
|
if (enhanced.hasOwnProperty(key)) {
|
||||||
|
// 方法如果存在就不覆盖
|
||||||
|
if (typeof def !== 'function' && typeof def !== 'string') {
|
||||||
|
enhanced[key] = Object.assign({}, def, enhanced[key])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enhanced[key] = def
|
||||||
|
}
|
||||||
|
})
|
||||||
|
AllCellsMixins.set(type, enhanced)
|
||||||
|
return getByName(enhanced)
|
||||||
|
}
|
||||||
|
AllCellsMixins.set(type, defEnhanced)
|
||||||
|
return getByName(defEnhanced)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 辅助方法:替换${...}变量 */
|
||||||
|
export function replaceProps(col, value) {
|
||||||
|
if (value && typeof value === 'string') {
|
||||||
|
let text = value
|
||||||
|
text = text.replace(/\${title}/g, col.title)
|
||||||
|
text = text.replace(/\${key}/g, col.key)
|
||||||
|
text = text.replace(/\${defaultValue}/g, col.defaultValue)
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
@ -0,0 +1,190 @@
|
|||||||
|
import { getVmParentByName } from '@/utils/util'
|
||||||
|
import { JVXETypes } from '@comp/jeecg/JVxeTable/index'
|
||||||
|
|
||||||
|
export const VALIDATE_FAILED = Symbol()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定的 $refs 对象
|
||||||
|
* 有时候可能会遇到组件未挂载到页面中的情况,导致无法获取 $refs 中的某个对象
|
||||||
|
* 这个方法可以等待挂载完成之后再返回 $refs 的对象,避免报错
|
||||||
|
* @author sunjianlei
|
||||||
|
**/
|
||||||
|
export function getRefPromise(vm, name) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
(function next() {
|
||||||
|
let ref = vm.$refs[name]
|
||||||
|
if (ref) {
|
||||||
|
resolve(ref)
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
next()
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取某一数字输入框列中的最大的值 */
|
||||||
|
export function getInputNumberMaxValue(col, rowsValues) {
|
||||||
|
let maxNum = 0
|
||||||
|
Object.values(rowsValues).forEach((rowValue, index) => {
|
||||||
|
let val = rowValue[col.key], num
|
||||||
|
try {
|
||||||
|
num = Number.parseFloat(val)
|
||||||
|
} catch {
|
||||||
|
num = 0
|
||||||
|
}
|
||||||
|
// 把首次循环的结果当成最大值
|
||||||
|
if (index === 0) {
|
||||||
|
maxNum = num
|
||||||
|
} else {
|
||||||
|
maxNum = (num > maxNum) ? num : maxNum
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return maxNum
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 根据 tagName 获取父级节点
|
||||||
|
*
|
||||||
|
* @param dom 一级dom节点
|
||||||
|
* @param tagName 标签名,不区分大小写
|
||||||
|
* @return {HTMLElement | NULL}
|
||||||
|
*/
|
||||||
|
export function getParentNodeByTagName(dom, tagName = 'body') {
|
||||||
|
if (tagName === 'body') {
|
||||||
|
return document.body
|
||||||
|
}
|
||||||
|
if (dom.parentNode) {
|
||||||
|
if (dom.parentNode.tagName.toLowerCase() === tagName.trim().toLowerCase()) {
|
||||||
|
return dom.parentNode
|
||||||
|
} else {
|
||||||
|
return getParentNodeByTagName(dom.parentNode, tagName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vxe columns 封装成高级查询可识别的选项
|
||||||
|
* @param columns
|
||||||
|
* @param handler 单独处理方法
|
||||||
|
*/
|
||||||
|
export function vxePackageToSuperQuery(columns, handler) {
|
||||||
|
if (Array.isArray(columns)) {
|
||||||
|
// 高级查询所需要的参数
|
||||||
|
let fieldList = []
|
||||||
|
// 遍历列
|
||||||
|
for (let i = 0; i < columns.length; i++) {
|
||||||
|
let col = columns[i]
|
||||||
|
if (col.type === JVXETypes.rowCheckbox ||
|
||||||
|
col.type === JVXETypes.rowRadio ||
|
||||||
|
col.type === JVXETypes.rowExpand ||
|
||||||
|
col.type === JVXETypes.rowNumber
|
||||||
|
) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let field = {
|
||||||
|
type: 'string',
|
||||||
|
value: col.key,
|
||||||
|
text: col.title,
|
||||||
|
dictCode: col.dictCode || col.dict,
|
||||||
|
}
|
||||||
|
if (col.type === JVXETypes.date || col.type === JVXETypes.datetime) {
|
||||||
|
field.type = col.type
|
||||||
|
field.format = col.format
|
||||||
|
}
|
||||||
|
if (col.type === JVXETypes.inputNumber) {
|
||||||
|
field.type = 'int'
|
||||||
|
}
|
||||||
|
if (Array.isArray(col.options)) {
|
||||||
|
field.options = col.options
|
||||||
|
}
|
||||||
|
if (typeof handler === 'function') {
|
||||||
|
Object.assign(field, handler(col, idx))
|
||||||
|
}
|
||||||
|
fieldList.push(field)
|
||||||
|
}
|
||||||
|
return fieldList
|
||||||
|
} else {
|
||||||
|
console.error('columns必须是一个数组')
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一次性验证主表单和所有的次表单
|
||||||
|
* @param form 主表单 form 对象
|
||||||
|
* @param cases 接收一个数组,每项都是一个JVxeTable实例
|
||||||
|
* @param autoJumpTab
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @author sunjianlei
|
||||||
|
*/
|
||||||
|
export async function validateFormAndTables(form, cases, autoJumpTab) {
|
||||||
|
if (!(form && typeof form.validateFields === 'function')) {
|
||||||
|
throw `form 参数需要的是一个form对象,而传入的却是${typeof form}`
|
||||||
|
}
|
||||||
|
let dataMap = {}
|
||||||
|
let values = await new Promise((resolve, reject) => {
|
||||||
|
// 验证主表表单
|
||||||
|
form.validateFields((err, values) => {
|
||||||
|
err ? reject({error: VALIDATE_FAILED, originError: err}) : resolve(values)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Object.assign(dataMap, {formValue: values})
|
||||||
|
// 验证所有子表的表单
|
||||||
|
let subData = await validateTables(cases, autoJumpTab)
|
||||||
|
// 合并最终数据
|
||||||
|
dataMap = Object.assign(dataMap, {tablesValue: subData})
|
||||||
|
return dataMap
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证并获取一个或多个表格的所有值
|
||||||
|
*
|
||||||
|
* @param cases 接收一个数组,每项都是一个JVxeTable实例
|
||||||
|
* @param autoJumpTab 校验失败后,是否自动跳转tab选项
|
||||||
|
*/
|
||||||
|
export function validateTables(cases, autoJumpTab = true) {
|
||||||
|
if (!Array.isArray(cases)) {
|
||||||
|
throw `'validateTables'函数的'cases'参数需要的是一个数组,而传入的却是${typeof cases}`
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let tablesData = []
|
||||||
|
let index = 0
|
||||||
|
if (!cases || cases.length === 0) {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
(function next() {
|
||||||
|
let vm = cases[index]
|
||||||
|
vm.validateTable().then(errMap => {
|
||||||
|
// 校验通过
|
||||||
|
if (!errMap) {
|
||||||
|
tablesData[index] = vm.getAll()
|
||||||
|
// 判断校验是否全部完成,完成返回成功,否则继续进行下一步校验
|
||||||
|
if (++index === cases.length) {
|
||||||
|
resolve(tablesData)
|
||||||
|
} else (
|
||||||
|
next()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// 尝试获取tabKey,如果在ATab组件内即可获取
|
||||||
|
let paneKey
|
||||||
|
let tabPane = getVmParentByName(vm, 'ATabPane')
|
||||||
|
if (tabPane) {
|
||||||
|
paneKey = tabPane.$vnode.key
|
||||||
|
// 自动跳转到该表格
|
||||||
|
if (autoJumpTab) {
|
||||||
|
let tabs = getVmParentByName(tabPane, 'Tabs')
|
||||||
|
tabs && tabs.setActiveKey && tabs.setActiveKey(paneKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 出现未验证通过的表单,不再进行下一步校验,直接返回失败
|
||||||
|
reject({error: VALIDATE_FAILED, index, paneKey, errMap})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})()
|
||||||
|
})
|
||||||
|
}
|
||||||
65
ant-design-vue-jeecg/src/components/jeecg/README_JPopup.md
Normal file
65
ant-design-vue-jeecg/src/components/jeecg/README_JPopup.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# JPopup 弹窗选择组件
|
||||||
|
|
||||||
|
## 参数配置
|
||||||
|
| 参数 | 类型 | 必填 |说明|
|
||||||
|
|--------------|---------|----|---------|
|
||||||
|
| placeholder |string | | placeholder |
|
||||||
|
| code |string | | online报表编码 |
|
||||||
|
| orgFields |string | | online报表中显示的列,多个以逗号隔开 |
|
||||||
|
| destFields |string | | 回调对象的属性,多个以逗号隔开,其顺序和orgFields一一对应 |
|
||||||
|
| field |string | | v-model模式专用,表示从destFields中选择一个属性的值返回给当前组件 |
|
||||||
|
| triggerChange |Boolean | | v-decorator模式下需设置成true |
|
||||||
|
| callback(事件) |function | | 回调事件,v-decorator模式下用到,用于设置form控件的值 |
|
||||||
|
|
||||||
|
使用示例
|
||||||
|
----
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<a-form :form="form">
|
||||||
|
<a-form-item label="v-model模式指定一个值返回至当前组件" style="width: 300px">
|
||||||
|
<j-popup
|
||||||
|
v-model="selectValue"
|
||||||
|
code="user_msg"
|
||||||
|
org-fields="username,realname"
|
||||||
|
dest-fields="popup,other"
|
||||||
|
field="popup"/>
|
||||||
|
{{ selectValue }}
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="v-decorator模式支持回调多个值至当前表单" style="width: 300px">
|
||||||
|
<j-popup
|
||||||
|
v-decorator="['one']"
|
||||||
|
:trigger-change="true"
|
||||||
|
code="user_msg"
|
||||||
|
org-fields="username,realname"
|
||||||
|
dest-fields="one,two"
|
||||||
|
@callback="popupCallback"/>
|
||||||
|
{{ getFormFieldValue('one') }}
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="v-decorator模式被回调的值" style="width: 300px">
|
||||||
|
<a-input v-decorator="['two']"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
|
||||||
|
</a-form >
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: this.$form.createForm(this),
|
||||||
|
selectValue:"",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
getFormFieldValue(field){
|
||||||
|
return this.form.getFieldValue(field)
|
||||||
|
},
|
||||||
|
popupCallback(row){
|
||||||
|
this.form.setFieldsValue(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
246
ant-design-vue-jeecg/src/components/jeecg/dynamic/JEditorDyn.vue
Normal file
246
ant-design-vue-jeecg/src/components/jeecg/dynamic/JEditorDyn.vue
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tinymce-containerty" :style="{width:containerWidth}">
|
||||||
|
<textarea :id="tinymceId" class="tinymce-textarea" @change="ada"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* docs:
|
||||||
|
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
|
||||||
|
*/
|
||||||
|
import load from './load'
|
||||||
|
//const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
|
||||||
|
//const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
|
||||||
|
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
|
||||||
|
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JEditorDyn',
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: function() {
|
||||||
|
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
type: [String, Array],
|
||||||
|
required: false,
|
||||||
|
default: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists link unlink image media table | removeformat | fullscreen',
|
||||||
|
},
|
||||||
|
menubar: {
|
||||||
|
type: String,
|
||||||
|
default: 'file edit insert view format table'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: [Number, String],
|
||||||
|
required: false,
|
||||||
|
default: 360
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: [Number, String],
|
||||||
|
required: false,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
type: [String, Array],
|
||||||
|
default: 'lists image link media table textcolor wordcount contextmenu fullscreen'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
hasChange: false,
|
||||||
|
hasInit: false,
|
||||||
|
tinymceId: this.id,
|
||||||
|
fullscreen: false,
|
||||||
|
languageTypeList: {
|
||||||
|
'en': 'en',
|
||||||
|
'zh': 'zh_CN',
|
||||||
|
'es': 'es_MX',
|
||||||
|
'ja': 'ja'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
containerWidth() {
|
||||||
|
const width = this.width
|
||||||
|
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
|
||||||
|
return `${width}px`
|
||||||
|
}
|
||||||
|
return width
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(val) {
|
||||||
|
if (!this.hasChange && this.hasInit) {
|
||||||
|
this.$nextTick(() =>
|
||||||
|
window.tinymce.get(this.tinymceId).setContent(val || ''))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
if (window.tinymce) {
|
||||||
|
this.initTinymce()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deactivated() {
|
||||||
|
this.destroyTinymce()
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.destroyTinymce()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
ada() {
|
||||||
|
console.log('change')
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
// dynamic load tinymce from cdn
|
||||||
|
load(tinymceCDN, (err) => {
|
||||||
|
if (err) {
|
||||||
|
this.$message.error(err.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.initTinymce()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initTinymce() {
|
||||||
|
const _this = this
|
||||||
|
window.tinymce.init({
|
||||||
|
selector: `#${this.tinymceId}`,
|
||||||
|
language: this.languageTypeList['zh'],
|
||||||
|
height: this.height,
|
||||||
|
body_class: 'panel-body ',
|
||||||
|
object_resizing: false,
|
||||||
|
toolbar: this.toolbar,
|
||||||
|
menubar: false,
|
||||||
|
plugins: this.plugins,
|
||||||
|
end_container_on_empty_block: true,
|
||||||
|
powerpaste_word_import: 'clean',
|
||||||
|
code_dialog_height: 450,
|
||||||
|
code_dialog_width: 1000,
|
||||||
|
advlist_bullet_styles: 'square',
|
||||||
|
advlist_number_styles: 'default',
|
||||||
|
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
|
||||||
|
default_link_target: '_blank',
|
||||||
|
link_title: false,
|
||||||
|
nonbreaking_force_tab: true, // inserting nonbreaking space need Nonbreaking Space Plugin
|
||||||
|
init_instance_callback: editor => {
|
||||||
|
if (_this.value) {
|
||||||
|
editor.setContent(_this.value)
|
||||||
|
}
|
||||||
|
_this.hasInit = true
|
||||||
|
editor.on('NodeChange Change KeyUp SetContent', () => {
|
||||||
|
this.hasChange = true
|
||||||
|
this.$emit('input', editor.getContent())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setup(editor) {
|
||||||
|
editor.on('FullscreenStateChanged', (e) => {
|
||||||
|
_this.fullscreen = e.state
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// it will try to keep these URLs intact
|
||||||
|
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
|
||||||
|
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
|
||||||
|
convert_urls: false
|
||||||
|
// 整合七牛上传
|
||||||
|
// images_dataimg_filter(img) {
|
||||||
|
// setTimeout(() => {
|
||||||
|
// const $image = $(img);
|
||||||
|
// $image.removeAttr('width');
|
||||||
|
// $image.removeAttr('height');
|
||||||
|
// if ($image[0].height && $image[0].width) {
|
||||||
|
// $image.attr('data-wscntype', 'image');
|
||||||
|
// $image.attr('data-wscnh', $image[0].height);
|
||||||
|
// $image.attr('data-wscnw', $image[0].width);
|
||||||
|
// $image.addClass('wscnph');
|
||||||
|
// }
|
||||||
|
// }, 0);
|
||||||
|
// return img
|
||||||
|
// },
|
||||||
|
// images_upload_handler(blobInfo, success, failure, progress) {
|
||||||
|
// progress(0);
|
||||||
|
// const token = _this.$store.getters.token;
|
||||||
|
// getToken(token).then(response => {
|
||||||
|
// const url = response.data.qiniu_url;
|
||||||
|
// const formData = new FormData();
|
||||||
|
// formData.append('token', response.data.qiniu_token);
|
||||||
|
// formData.append('key', response.data.qiniu_key);
|
||||||
|
// formData.append('file', blobInfo.blob(), url);
|
||||||
|
// upload(formData).then(() => {
|
||||||
|
// success(url);
|
||||||
|
// progress(100);
|
||||||
|
// })
|
||||||
|
// }).catch(err => {
|
||||||
|
// failure('err')
|
||||||
|
// console.log(err);
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
})
|
||||||
|
},
|
||||||
|
destroyTinymce() {
|
||||||
|
const tinymce = window.tinymce.get(this.tinymceId)
|
||||||
|
if (this.fullscreen) {
|
||||||
|
tinymce.execCommand('mceFullScreen')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tinymce) {
|
||||||
|
tinymce.destroy()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setContent(value) {
|
||||||
|
window.tinymce.get(this.tinymceId).setContent(value)
|
||||||
|
},
|
||||||
|
getContent() {
|
||||||
|
window.tinymce.get(this.tinymceId).getContent()
|
||||||
|
},
|
||||||
|
imageSuccessCBK(arr) {
|
||||||
|
arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.tinymce-containerty {
|
||||||
|
position: relative;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tinymce-containerty {
|
||||||
|
::v-deep {
|
||||||
|
.mce-fullscreen {
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tinymce-textarea {
|
||||||
|
visibility: hidden;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-custom-btn-container {
|
||||||
|
position: absolute;
|
||||||
|
right: 4px;
|
||||||
|
top: 4px;
|
||||||
|
/*z-index: 2005;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullscreen .editor-custom-btn-container {
|
||||||
|
z-index: 10000;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-upload-btn {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<div class="j-markdown-editor" :id="dynamicId"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import load from './load'
|
||||||
|
import { md_js, md_zh_cn_js } from './Resource'
|
||||||
|
import defaultOptions from '@/components/jeecg/JMarkdownEditor/default-options.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JMdEditorDyn',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default() {
|
||||||
|
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return defaultOptions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'markdown'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: '300px'
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'zh-CN'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null,
|
||||||
|
dynamicId: this.id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
editorOptions() {
|
||||||
|
const options = Object.assign({}, defaultOptions, this.options)
|
||||||
|
options.initialEditType = this.mode
|
||||||
|
options.height = this.height
|
||||||
|
options.language = this.language
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(newValue, preValue) {
|
||||||
|
if (newValue !== preValue && newValue !== this.editor.getMarkdown()) {
|
||||||
|
this.editor.setMarkdown(newValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
language(val) {
|
||||||
|
this.destroyEditor()
|
||||||
|
this.initEditor()
|
||||||
|
},
|
||||||
|
height(newValue) {
|
||||||
|
this.editor.height(newValue)
|
||||||
|
},
|
||||||
|
mode(newValue) {
|
||||||
|
this.editor.changeMode(newValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.destroyEditor()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init(){
|
||||||
|
|
||||||
|
this.initEditor()
|
||||||
|
/* load(md_js,'',()=>{
|
||||||
|
load(md_zh_cn_js,'',()=>{
|
||||||
|
|
||||||
|
})
|
||||||
|
})*/
|
||||||
|
},
|
||||||
|
initEditor() {
|
||||||
|
const Editor = toastui.Editor
|
||||||
|
this.editor = new Editor({
|
||||||
|
el: document.getElementById(this.dynamicId),
|
||||||
|
...this.editorOptions
|
||||||
|
})
|
||||||
|
if (this.value) {
|
||||||
|
this.editor.setMarkdown(this.value)
|
||||||
|
}
|
||||||
|
this.editor.on('change', () => {
|
||||||
|
this.$emit('change', this.editor.getMarkdown())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
destroyEditor() {
|
||||||
|
if (!this.editor) return
|
||||||
|
this.editor.off('change')
|
||||||
|
this.editor.remove()
|
||||||
|
},
|
||||||
|
setMarkdown(value) {
|
||||||
|
this.editor.setMarkdown(value)
|
||||||
|
},
|
||||||
|
getMarkdown() {
|
||||||
|
return this.editor.getMarkdown()
|
||||||
|
},
|
||||||
|
setHtml(value) {
|
||||||
|
this.editor.setHtml(value)
|
||||||
|
},
|
||||||
|
getHtml() {
|
||||||
|
return this.editor.getHtml()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
prop: 'value',
|
||||||
|
event: 'change'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
|
||||||
|
.j-markdown-editor {
|
||||||
|
/deep/ .tui-editor-defaultUI {
|
||||||
|
.te-mode-switch,
|
||||||
|
.tui-scrollsync
|
||||||
|
{
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,325 @@
|
|||||||
|
<template>
|
||||||
|
<div class="jeecg-editor-ty" :class="fullCoder?'jeecg-editor-max':'jeecg-editor-min'">
|
||||||
|
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
||||||
|
<textarea :id="dynamicId" />
|
||||||
|
<span @click="nullTipClick" class="null-tip" :class="{'null-tip-hidden': hasCode}" :style="nullTipStyle">{{ placeholderShow }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import load from './load'
|
||||||
|
import '@/assets/less/codemirror_idea.css'
|
||||||
|
import './cm_sql_hint.js'
|
||||||
|
import { sql_keyword } from './Resource'
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JSqlCodeEditorDyn',
|
||||||
|
props:{
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: function() {
|
||||||
|
return 'vue-editor-' + new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 显示行号
|
||||||
|
lineNumbers: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
zIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 999
|
||||||
|
},
|
||||||
|
autoHeight: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 不自适应高度的情况下生效的固定高度
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '240px'
|
||||||
|
},
|
||||||
|
autoHeight: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示全屏按钮
|
||||||
|
fullScreen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
autoHint:{
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
dynamicId: this.id,
|
||||||
|
coder: '',
|
||||||
|
hasCode: false,
|
||||||
|
code: '',
|
||||||
|
// code 编辑器 是否全屏
|
||||||
|
fullCoder: false,
|
||||||
|
iconType: 'fullscreen',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
placeholderShow() {
|
||||||
|
if (this.placeholder == null) {
|
||||||
|
return `请在此输入javascript代码`
|
||||||
|
} else {
|
||||||
|
return this.placeholder
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nullTipStyle(){
|
||||||
|
if (this.lineNumbers) {
|
||||||
|
return { left: '36px' }
|
||||||
|
} else {
|
||||||
|
return { left: '12px' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isAutoHeight() {
|
||||||
|
let {autoHeight} = this
|
||||||
|
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
||||||
|
autoHeight = !(isIE() || isIE11())
|
||||||
|
} else {
|
||||||
|
autoHeight = true
|
||||||
|
}
|
||||||
|
return autoHeight
|
||||||
|
},
|
||||||
|
fullScreenParentProps() {
|
||||||
|
let props = {
|
||||||
|
class: {
|
||||||
|
'full-screen-parent': true,
|
||||||
|
'full-screen': this.fullCoder,
|
||||||
|
'auto-height': this.isAutoHeight
|
||||||
|
},
|
||||||
|
style: {}
|
||||||
|
}
|
||||||
|
if (this.fullCoder) {
|
||||||
|
props.style['z-index'] = this.zIndex
|
||||||
|
}
|
||||||
|
if (!this.isAutoHeight) {
|
||||||
|
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
||||||
|
}
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
fullCoder:{
|
||||||
|
handler(value) {
|
||||||
|
if(value){
|
||||||
|
this.iconType="fullscreen-exit"
|
||||||
|
}else{
|
||||||
|
this.iconType="fullscreen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
init(){
|
||||||
|
this.main();
|
||||||
|
},
|
||||||
|
main(){
|
||||||
|
let obj = document.getElementById(this.dynamicId);
|
||||||
|
const that = this;
|
||||||
|
let editor = CodeMirror.fromTextArea(obj,{
|
||||||
|
theme:'idea',
|
||||||
|
lineNumbers: this.lineNumbers,
|
||||||
|
lineWrapping: true,
|
||||||
|
mode: "sql",
|
||||||
|
indentUnit: 1,
|
||||||
|
indentWithTabs: true,
|
||||||
|
styleActiveLine: true,
|
||||||
|
/* styleSelectedText: false, */
|
||||||
|
extraKeys: {
|
||||||
|
"F11": function(cm) {
|
||||||
|
that.fullCoder = !that.fullCoder
|
||||||
|
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
|
||||||
|
},
|
||||||
|
"Esc": function(cm) {
|
||||||
|
that.fullCoder = false
|
||||||
|
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
||||||
|
},
|
||||||
|
"Alt-/": function(cm) {
|
||||||
|
cm.showHint();
|
||||||
|
},
|
||||||
|
"Tab": (cm) => {
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
cm.indentSelection('add');
|
||||||
|
} else {
|
||||||
|
//cm.indentLine(cm.getCursor().line, "add");
|
||||||
|
//走两格 第三格输入
|
||||||
|
cm.replaceSelection(Array(3).join(" "), "end", "+input");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Shift-Tab": (cm) => {
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
cm.indentSelection('subtract');
|
||||||
|
} else {
|
||||||
|
// cm.indentLine(cm.getCursor().line, "subtract");
|
||||||
|
const cursor = cm.getCursor();
|
||||||
|
// 光标回退 indexUnit 字符
|
||||||
|
cm.setCursor({line: cursor.line, ch: cursor.ch - 4});
|
||||||
|
}
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.coder = editor
|
||||||
|
this.addEvent();
|
||||||
|
this.setCoderValue();
|
||||||
|
this.addSystemHint();
|
||||||
|
},
|
||||||
|
setCoderValue(){
|
||||||
|
if(this.value||this.code){
|
||||||
|
this.hasCode=true
|
||||||
|
this.setCodeContent(this.value || this.code)
|
||||||
|
}else{
|
||||||
|
this.coder.setValue('')
|
||||||
|
this.hasCode=false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getCodeContent(){
|
||||||
|
return this.code
|
||||||
|
},
|
||||||
|
setCodeContent(val){
|
||||||
|
setTimeout(()=>{
|
||||||
|
if(!val){
|
||||||
|
this.coder.setValue('')
|
||||||
|
}else{
|
||||||
|
this.coder.setValue(val)
|
||||||
|
}
|
||||||
|
},300)
|
||||||
|
},
|
||||||
|
addSystemHint(){
|
||||||
|
this.coder.setOption('hintOptions', {
|
||||||
|
completeSingle: false,
|
||||||
|
tables: sql_keyword
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addEvent(){
|
||||||
|
if(this.autoHint){
|
||||||
|
this.coder.on('cursorActivity', ()=>{
|
||||||
|
this.coder.showHint();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.coder.on('change', (coder) => {
|
||||||
|
this.code = coder.getValue()
|
||||||
|
if(this.code){
|
||||||
|
this.hasCode=true
|
||||||
|
}else{
|
||||||
|
this.hasCode=false
|
||||||
|
}
|
||||||
|
if (this.$emit) {
|
||||||
|
this.$emit('input', this.code)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.coder.on('focus', () => {
|
||||||
|
this.hasCode=true
|
||||||
|
});
|
||||||
|
this.coder.on('blur', () => {
|
||||||
|
if(this.code){
|
||||||
|
this.hasCode=true
|
||||||
|
}else{
|
||||||
|
this.hasCode=false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadResource(src,type){
|
||||||
|
return new Promise((resolve,reject)=>{
|
||||||
|
load(src,type,(msg)=>{
|
||||||
|
if(!msg){
|
||||||
|
resolve();
|
||||||
|
}else{
|
||||||
|
reject(msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
nullTipClick(){
|
||||||
|
this.coder.focus()
|
||||||
|
},
|
||||||
|
fullToggle(){
|
||||||
|
this.fullCoder = !this.fullCoder
|
||||||
|
this.coder.setOption("fullScreen", this.fullCoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" >
|
||||||
|
.jeecg-editor-ty{
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.full-screen-icon {
|
||||||
|
opacity: 0;
|
||||||
|
color: black;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 24px;
|
||||||
|
background-color: white;
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 2px;
|
||||||
|
z-index: 9;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
.full-screen-icon {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.88);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.null-tip{
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
left: 36px;
|
||||||
|
z-index: 10;
|
||||||
|
font-size:16px;
|
||||||
|
color: #acaaaac9;
|
||||||
|
line-height: initial;
|
||||||
|
}
|
||||||
|
.null-tip-hidden{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.jeecg-editor-max{
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 999;
|
||||||
|
height: 100%;
|
||||||
|
width: 100% !important;
|
||||||
|
|
||||||
|
.CodeMirror{
|
||||||
|
position: inherit !important;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.full-screen-icon{
|
||||||
|
z-index:9999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,319 @@
|
|||||||
|
<template>
|
||||||
|
<div class="jeecg-editor-ty" :class="fullCoder?'jeecg-editor-max':'jeecg-editor-min'">
|
||||||
|
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
||||||
|
<textarea :id="dynamicId" />
|
||||||
|
<span @click="nullTipClick" class="null-tip" :class="{'null-tip-hidden': hasCode}" :style="nullTipStyle">{{ placeholderShow }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import '@/assets/less/codemirror_idea.css'
|
||||||
|
import './cm_hint.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JsCodeEditorDyn',
|
||||||
|
props:{
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: function() {
|
||||||
|
return 'vue-editor-' + new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 显示行号
|
||||||
|
lineNumbers: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
zIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 999
|
||||||
|
},
|
||||||
|
autoHeight: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 不自适应高度的情况下生效的固定高度
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '240px'
|
||||||
|
},
|
||||||
|
autoHeight: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示全屏按钮
|
||||||
|
fullScreen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
dynamicId: this.id,
|
||||||
|
coder: '',
|
||||||
|
hasCode: false,
|
||||||
|
code: '',
|
||||||
|
// code 编辑器 是否全屏
|
||||||
|
fullCoder: false,
|
||||||
|
iconType: 'fullscreen',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
placeholderShow() {
|
||||||
|
if (this.placeholder == null) {
|
||||||
|
return `请在此输入javascript代码`
|
||||||
|
} else {
|
||||||
|
return this.placeholder
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nullTipStyle(){
|
||||||
|
if (this.lineNumbers) {
|
||||||
|
return { left: '36px' }
|
||||||
|
} else {
|
||||||
|
return { left: '12px' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isAutoHeight() {
|
||||||
|
let {autoHeight} = this
|
||||||
|
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
||||||
|
autoHeight = !(isIE() || isIE11())
|
||||||
|
} else {
|
||||||
|
autoHeight = true
|
||||||
|
}
|
||||||
|
return autoHeight
|
||||||
|
},
|
||||||
|
fullScreenParentProps() {
|
||||||
|
let props = {
|
||||||
|
class: {
|
||||||
|
'full-screen-parent': true,
|
||||||
|
'full-screen': this.fullCoder,
|
||||||
|
'auto-height': this.isAutoHeight
|
||||||
|
},
|
||||||
|
style: {}
|
||||||
|
}
|
||||||
|
if (this.fullCoder) {
|
||||||
|
props.style['z-index'] = this.zIndex
|
||||||
|
}
|
||||||
|
if (!this.isAutoHeight) {
|
||||||
|
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
||||||
|
}
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
fullCoder:{
|
||||||
|
handler(value) {
|
||||||
|
if(value){
|
||||||
|
this.iconType="fullscreen-exit"
|
||||||
|
}else{
|
||||||
|
this.iconType="fullscreen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
init(){
|
||||||
|
this.main();
|
||||||
|
},
|
||||||
|
main(){
|
||||||
|
let obj = document.getElementById(this.dynamicId);
|
||||||
|
const that = this;
|
||||||
|
let editor = CodeMirror.fromTextArea(obj,{
|
||||||
|
theme:'idea',
|
||||||
|
lineNumbers: this.lineNumbers,
|
||||||
|
lineWrapping: true,
|
||||||
|
mode: "javascript",
|
||||||
|
indentUnit: 1,
|
||||||
|
indentWithTabs: true,
|
||||||
|
styleActiveLine: true,
|
||||||
|
/* styleSelectedText: false, */
|
||||||
|
extraKeys: {
|
||||||
|
"F11": function(cm) {
|
||||||
|
that.fullCoder = !that.fullCoder
|
||||||
|
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
|
||||||
|
},
|
||||||
|
"Esc": function(cm) {
|
||||||
|
that.fullCoder = false
|
||||||
|
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
||||||
|
},
|
||||||
|
"Alt-/": function(cm) {
|
||||||
|
let a = cm.getValue()+""
|
||||||
|
console.log('a',a)
|
||||||
|
cm.showHint();
|
||||||
|
},
|
||||||
|
"Tab": (cm) => {
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
cm.indentSelection('add');
|
||||||
|
} else {
|
||||||
|
//cm.indentLine(cm.getCursor().line, "add");
|
||||||
|
//走两格 第三格输入
|
||||||
|
cm.replaceSelection(Array(3).join(" "), "end", "+input");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Shift-Tab": (cm) => {
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
cm.indentSelection('subtract');
|
||||||
|
} else {
|
||||||
|
// cm.indentLine(cm.getCursor().line, "subtract");
|
||||||
|
const cursor = cm.getCursor();
|
||||||
|
// 光标回退 indexUnit 字符
|
||||||
|
cm.setCursor({line: cursor.line, ch: cursor.ch - 4});
|
||||||
|
}
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.coder = editor
|
||||||
|
this.addEvent();
|
||||||
|
this.setCoderValue();
|
||||||
|
},
|
||||||
|
setCoderValue(){
|
||||||
|
if(this.value||this.code){
|
||||||
|
this.hasCode=true
|
||||||
|
this.setCodeContent(this.value || this.code)
|
||||||
|
}else{
|
||||||
|
this.coder.setValue('')
|
||||||
|
this.hasCode=false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getCodeContent(){
|
||||||
|
return this.code
|
||||||
|
},
|
||||||
|
setCodeContent(val){
|
||||||
|
setTimeout(()=>{
|
||||||
|
if(!val){
|
||||||
|
this.coder.setValue('')
|
||||||
|
}else{
|
||||||
|
this.coder.setValue(val)
|
||||||
|
}
|
||||||
|
},300)
|
||||||
|
},
|
||||||
|
addEvent(){
|
||||||
|
const that = this;
|
||||||
|
this.coder.on('cursorActivity',function(wl) {
|
||||||
|
let arr = wl.state.activeLines
|
||||||
|
if(arr && arr.length>0){
|
||||||
|
let text = arr[0].text
|
||||||
|
if(text.lastIndexOf('that.')>=0){
|
||||||
|
that.coder.showHint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.coder.on('change', (coder) => {
|
||||||
|
this.code = coder.getValue()
|
||||||
|
if(this.code){
|
||||||
|
this.hasCode=true
|
||||||
|
}else{
|
||||||
|
this.hasCode=false
|
||||||
|
}
|
||||||
|
if (this.$emit) {
|
||||||
|
this.$emit('input', this.code)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.coder.on('focus', () => {
|
||||||
|
this.hasCode=true
|
||||||
|
});
|
||||||
|
this.coder.on('blur', () => {
|
||||||
|
if(this.code){
|
||||||
|
this.hasCode=true
|
||||||
|
}else{
|
||||||
|
this.hasCode=false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadResource(src,type){
|
||||||
|
return new Promise((resolve,reject)=>{
|
||||||
|
load(src,type,(msg)=>{
|
||||||
|
if(!msg){
|
||||||
|
resolve();
|
||||||
|
}else{
|
||||||
|
reject(msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
nullTipClick(){
|
||||||
|
this.coder.focus()
|
||||||
|
},
|
||||||
|
fullToggle(){
|
||||||
|
this.fullCoder = !this.fullCoder
|
||||||
|
this.coder.setOption("fullScreen", this.fullCoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less" >
|
||||||
|
.jeecg-editor-ty{
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.full-screen-icon {
|
||||||
|
opacity: 0;
|
||||||
|
color: black;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 24px;
|
||||||
|
background-color: white;
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 2px;
|
||||||
|
z-index: 9;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
.full-screen-icon {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.88);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.null-tip{
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
left: 36px;
|
||||||
|
z-index: 10;
|
||||||
|
font-size:16px;
|
||||||
|
color: #acaaaac9;
|
||||||
|
line-height: initial;
|
||||||
|
}
|
||||||
|
.null-tip-hidden{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.jeecg-editor-max{
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 999;
|
||||||
|
height: 100%;
|
||||||
|
width: 100% !important;
|
||||||
|
|
||||||
|
.CodeMirror{
|
||||||
|
position: inherit !important;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.full-screen-icon{
|
||||||
|
z-index:9999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
/**js编辑器关键词用于提示*/
|
||||||
|
const js_keyword = [
|
||||||
|
'that',
|
||||||
|
'getAction','postAction','deleteAction',
|
||||||
|
'beforeAdd','beforeEdit','beforeDelete','mounted','created','show'
|
||||||
|
]
|
||||||
|
|
||||||
|
/**js编辑器 方法名用于提示*/
|
||||||
|
const js_method = [
|
||||||
|
'.getSelectOptions','.changeOptions','.triggleChangeValues','.immediateEnhance ','.simpleDateFormat','.lodash'
|
||||||
|
]
|
||||||
|
|
||||||
|
/**sql编辑器 表名字段名用于提示*/
|
||||||
|
const sql_keyword = {
|
||||||
|
sys_user: ['USERNAME', 'REALNAME', 'ID','BIRTHDAY','AGE'],
|
||||||
|
demo: ['name', 'age', 'id', 'sex']
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
js_keyword,
|
||||||
|
js_method,
|
||||||
|
sql_keyword
|
||||||
|
}
|
||||||
177
ant-design-vue-jeecg/src/components/jeecg/dynamic/cm_hint.js
Normal file
177
ant-design-vue-jeecg/src/components/jeecg/dynamic/cm_hint.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||||
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||||
|
import { js_keyword, js_method } from './Resource'
|
||||||
|
(function(mod) {
|
||||||
|
mod(CodeMirror);
|
||||||
|
/*if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||||
|
mod(require("../../lib/codemirror"));
|
||||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||||
|
define(["../../lib/codemirror"], mod);
|
||||||
|
else // Plain browser env*/
|
||||||
|
|
||||||
|
})(function(CodeMirror) {
|
||||||
|
var Pos = CodeMirror.Pos;
|
||||||
|
|
||||||
|
function forEach(arr, f) {
|
||||||
|
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrayContains(arr, item) {
|
||||||
|
if (!Array.prototype.indexOf) {
|
||||||
|
var i = arr.length;
|
||||||
|
while (i--) {
|
||||||
|
if (arr[i] === item) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return arr.indexOf(item) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scriptHint(editor, keywords, getToken, options) {
|
||||||
|
// Find the token at the cursor
|
||||||
|
var cur = editor.getCursor(), token = getToken(editor, cur);
|
||||||
|
if (/\b(?:string|comment)\b/.test(token.type)) return;
|
||||||
|
var innerMode = CodeMirror.innerMode(editor.getMode(), token.state);
|
||||||
|
if (innerMode.mode.helperType === "json") return;
|
||||||
|
token.state = innerMode.state;
|
||||||
|
if('.' === token.string){
|
||||||
|
let arr = []
|
||||||
|
for(let k of js_method){
|
||||||
|
arr.push(k)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
list: arr,
|
||||||
|
from: Pos(cur.line, token.start),
|
||||||
|
to: Pos(cur.line, token.end)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// If it's not a 'word-style' token, ignore the token.
|
||||||
|
if (!/^[\w$_]*$/.test(token.string)) {
|
||||||
|
token = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||||
|
type: token.string == "." ? "property" : null};
|
||||||
|
} else if (token.end > cur.ch) {
|
||||||
|
token.end = cur.ch;
|
||||||
|
token.string = token.string.slice(0, cur.ch - token.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tprop = token;
|
||||||
|
// If it is a property, find out what it is a property of.
|
||||||
|
while (tprop.type == "property") {
|
||||||
|
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||||
|
if (tprop.string != ".") return;
|
||||||
|
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||||
|
if (!context) var context = [];
|
||||||
|
context.push(tprop);
|
||||||
|
}
|
||||||
|
return {list: getCompletions(token, context, keywords, options),
|
||||||
|
from: Pos(cur.line, token.start),
|
||||||
|
to: Pos(cur.line, token.end)};
|
||||||
|
}
|
||||||
|
|
||||||
|
function javascriptHint(editor, options) {
|
||||||
|
return scriptHint(editor, javascriptKeywords,
|
||||||
|
function (e, cur) {return e.getTokenAt(cur);},
|
||||||
|
options);
|
||||||
|
};
|
||||||
|
CodeMirror.registerHelper("hint", "javascript", javascriptHint);
|
||||||
|
|
||||||
|
function getCoffeeScriptToken(editor, cur) {
|
||||||
|
// This getToken, it is for coffeescript, imitates the behavior of
|
||||||
|
// getTokenAt method in javascript.js, that is, returning "property"
|
||||||
|
// type and treat "." as indepenent token.
|
||||||
|
var token = editor.getTokenAt(cur);
|
||||||
|
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
|
||||||
|
token.end = token.start;
|
||||||
|
token.string = '.';
|
||||||
|
token.type = "property";
|
||||||
|
}
|
||||||
|
else if (/^\.[\w$_]*$/.test(token.string)) {
|
||||||
|
token.type = "property";
|
||||||
|
token.start++;
|
||||||
|
token.string = token.string.replace(/\./, '');
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
function coffeescriptHint(editor, options) {
|
||||||
|
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
|
||||||
|
}
|
||||||
|
CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint);
|
||||||
|
|
||||||
|
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
|
||||||
|
"toUpperCase toLowerCase split concat match replace search").split(" ");
|
||||||
|
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
|
||||||
|
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
|
||||||
|
var funcProps = "prototype apply call bind".split(" ");
|
||||||
|
|
||||||
|
var javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends false finally for function " +
|
||||||
|
"if in import instanceof new null return super switch this throw true try typeof var void while with yield that").split(" ");
|
||||||
|
for(let jk of js_keyword){
|
||||||
|
javascriptKeywords.push(jk)
|
||||||
|
}
|
||||||
|
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
|
||||||
|
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
|
||||||
|
|
||||||
|
function forAllProps(obj, callback) {
|
||||||
|
if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) {
|
||||||
|
for (var name in obj) callback(name)
|
||||||
|
} else {
|
||||||
|
for (var o = obj; o; o = Object.getPrototypeOf(o))
|
||||||
|
Object.getOwnPropertyNames(o).forEach(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCompletions(token, context, keywords, options) {
|
||||||
|
var found = [], start = token.string, global = options && options.globalScope || window;
|
||||||
|
function maybeAdd(str) {
|
||||||
|
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
|
||||||
|
}
|
||||||
|
function gatherCompletions(obj) {
|
||||||
|
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||||
|
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
||||||
|
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
||||||
|
forAllProps(obj, maybeAdd)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context && context.length) {
|
||||||
|
// If this is a property, see if it belongs to some object we can
|
||||||
|
// find in the current environment.
|
||||||
|
var obj = context.pop(), base;
|
||||||
|
if (obj.type && obj.type.indexOf("variable") === 0) {
|
||||||
|
if (options && options.additionalContext)
|
||||||
|
base = options.additionalContext[obj.string];
|
||||||
|
if (!options || options.useGlobalScope !== false)
|
||||||
|
base = base || global[obj.string];
|
||||||
|
} else if (obj.type == "string") {
|
||||||
|
base = "";
|
||||||
|
} else if (obj.type == "atom") {
|
||||||
|
base = 1;
|
||||||
|
} else if (obj.type == "function") {
|
||||||
|
if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
|
||||||
|
(typeof global.jQuery == 'function'))
|
||||||
|
base = global.jQuery();
|
||||||
|
else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function'))
|
||||||
|
base = global._();
|
||||||
|
}
|
||||||
|
while (base != null && context.length)
|
||||||
|
base = base[context.pop().string];
|
||||||
|
if (base != null) gatherCompletions(base);
|
||||||
|
} else {
|
||||||
|
// If not, just look in the global object, any local scope, and optional additional-context
|
||||||
|
// (reading into JS mode internals to get at the local and global variables)
|
||||||
|
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
|
||||||
|
for (var c = token.state.context; c; c = c.prev)
|
||||||
|
for (var v = c.vars; v; v = v.next) maybeAdd(v.name)
|
||||||
|
for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
|
||||||
|
if (options && options.additionalContext != null)
|
||||||
|
for (var key in options.additionalContext)
|
||||||
|
maybeAdd(key);
|
||||||
|
if (!options || options.useGlobalScope !== false)
|
||||||
|
gatherCompletions(global);
|
||||||
|
forEach(keywords, maybeAdd);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
});
|
||||||
305
ant-design-vue-jeecg/src/components/jeecg/dynamic/cm_sql_hint.js
Normal file
305
ant-design-vue-jeecg/src/components/jeecg/dynamic/cm_sql_hint.js
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||||
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||||
|
|
||||||
|
(function(mod) {
|
||||||
|
/*if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||||
|
mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
|
||||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||||
|
define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
|
||||||
|
else */
|
||||||
|
// Plain browser env
|
||||||
|
mod(CodeMirror);
|
||||||
|
})(function(CodeMirror) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var tables;
|
||||||
|
var defaultTable;
|
||||||
|
var keywords;
|
||||||
|
var identifierQuote;
|
||||||
|
var CONS = {
|
||||||
|
QUERY_DIV: ";",
|
||||||
|
ALIAS_KEYWORD: "AS"
|
||||||
|
};
|
||||||
|
var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;
|
||||||
|
|
||||||
|
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
|
||||||
|
|
||||||
|
function getKeywords(editor) {
|
||||||
|
var mode = editor.doc.modeOption;
|
||||||
|
if (mode === "sql") mode = "text/x-sql";
|
||||||
|
return CodeMirror.resolveMode(mode).keywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIdentifierQuote(editor) {
|
||||||
|
var mode = editor.doc.modeOption;
|
||||||
|
if (mode === "sql") mode = "text/x-sql";
|
||||||
|
return CodeMirror.resolveMode(mode).identifierQuote || "`";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getText(item) {
|
||||||
|
return typeof item == "string" ? item : item.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapTable(name, value) {
|
||||||
|
if (isArray(value)) value = {columns: value}
|
||||||
|
if (!value.text) value.text = name
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTables(input) {
|
||||||
|
var result = {}
|
||||||
|
if (isArray(input)) {
|
||||||
|
for (var i = input.length - 1; i >= 0; i--) {
|
||||||
|
var item = input[i]
|
||||||
|
result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
|
||||||
|
}
|
||||||
|
} else if (input) {
|
||||||
|
for (var name in input)
|
||||||
|
result[name.toUpperCase()] = wrapTable(name, input[name])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTable(name) {
|
||||||
|
return tables[name.toUpperCase()]
|
||||||
|
}
|
||||||
|
|
||||||
|
function shallowClone(object) {
|
||||||
|
var result = {};
|
||||||
|
for (var key in object) if (object.hasOwnProperty(key))
|
||||||
|
result[key] = object[key];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function match(string, word) {
|
||||||
|
var len = string.length;
|
||||||
|
var sub = getText(word).substr(0, len);
|
||||||
|
return string.toUpperCase() === sub.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMatches(result, search, wordlist, formatter) {
|
||||||
|
if (isArray(wordlist)) {
|
||||||
|
for (var i = 0; i < wordlist.length; i++)
|
||||||
|
if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
|
||||||
|
} else {
|
||||||
|
for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
|
||||||
|
var val = wordlist[word]
|
||||||
|
if (!val || val === true)
|
||||||
|
val = word
|
||||||
|
else
|
||||||
|
val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
|
||||||
|
if (match(search, val)) result.push(formatter(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanName(name) {
|
||||||
|
// Get rid name from identifierQuote and preceding dot(.)
|
||||||
|
if (name.charAt(0) == ".") {
|
||||||
|
name = name.substr(1);
|
||||||
|
}
|
||||||
|
// replace doublicated identifierQuotes with single identifierQuotes
|
||||||
|
// and remove single identifierQuotes
|
||||||
|
var nameParts = name.split(identifierQuote+identifierQuote);
|
||||||
|
for (var i = 0; i < nameParts.length; i++)
|
||||||
|
nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), "");
|
||||||
|
return nameParts.join(identifierQuote);
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertIdentifierQuotes(name) {
|
||||||
|
var nameParts = getText(name).split(".");
|
||||||
|
for (var i = 0; i < nameParts.length; i++)
|
||||||
|
nameParts[i] = identifierQuote +
|
||||||
|
// doublicate identifierQuotes
|
||||||
|
nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) +
|
||||||
|
identifierQuote;
|
||||||
|
var escaped = nameParts.join(".");
|
||||||
|
if (typeof name == "string") return escaped;
|
||||||
|
name = shallowClone(name);
|
||||||
|
name.text = escaped;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nameCompletion(cur, token, result, editor) {
|
||||||
|
// Try to complete table, column names and return start position of completion
|
||||||
|
var useIdentifierQuotes = false;
|
||||||
|
var nameParts = [];
|
||||||
|
var start = token.start;
|
||||||
|
var cont = true;
|
||||||
|
while (cont) {
|
||||||
|
cont = (token.string.charAt(0) == ".");
|
||||||
|
useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote);
|
||||||
|
|
||||||
|
start = token.start;
|
||||||
|
nameParts.unshift(cleanName(token.string));
|
||||||
|
|
||||||
|
token = editor.getTokenAt(Pos(cur.line, token.start));
|
||||||
|
if (token.string == ".") {
|
||||||
|
cont = true;
|
||||||
|
token = editor.getTokenAt(Pos(cur.line, token.start));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to complete table names
|
||||||
|
var string = nameParts.join(".");
|
||||||
|
addMatches(result, string, tables, function(w) {
|
||||||
|
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Try to complete columns from defaultTable
|
||||||
|
addMatches(result, string, defaultTable, function(w) {
|
||||||
|
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Try to complete columns
|
||||||
|
string = nameParts.pop();
|
||||||
|
var table = nameParts.join(".");
|
||||||
|
|
||||||
|
var alias = false;
|
||||||
|
var aliasTable = table;
|
||||||
|
// Check if table is available. If not, find table by Alias
|
||||||
|
if (!getTable(table)) {
|
||||||
|
var oldTable = table;
|
||||||
|
table = findTableByAlias(table, editor);
|
||||||
|
if (table !== oldTable) alias = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var columns = getTable(table);
|
||||||
|
if (columns && columns.columns)
|
||||||
|
columns = columns.columns;
|
||||||
|
|
||||||
|
if (columns) {
|
||||||
|
addMatches(result, string, columns, function(w) {
|
||||||
|
var tableInsert = table;
|
||||||
|
if (alias == true) tableInsert = aliasTable;
|
||||||
|
if (typeof w == "string") {
|
||||||
|
w = tableInsert + "." + w;
|
||||||
|
} else {
|
||||||
|
w = shallowClone(w);
|
||||||
|
w.text = tableInsert + "." + w.text;
|
||||||
|
}
|
||||||
|
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
function eachWord(lineText, f) {
|
||||||
|
var words = lineText.split(/\s+/)
|
||||||
|
for (var i = 0; i < words.length; i++)
|
||||||
|
if (words[i]) f(words[i].replace(/[,;]/g, ''))
|
||||||
|
}
|
||||||
|
|
||||||
|
function findTableByAlias(alias, editor) {
|
||||||
|
var doc = editor.doc;
|
||||||
|
var fullQuery = doc.getValue();
|
||||||
|
var aliasUpperCase = alias.toUpperCase();
|
||||||
|
var previousWord = "";
|
||||||
|
var table = "";
|
||||||
|
var separator = [];
|
||||||
|
var validRange = {
|
||||||
|
start: Pos(0, 0),
|
||||||
|
end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
|
||||||
|
};
|
||||||
|
|
||||||
|
//add separator
|
||||||
|
var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
|
||||||
|
while(indexOfSeparator != -1) {
|
||||||
|
separator.push(doc.posFromIndex(indexOfSeparator));
|
||||||
|
indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
|
||||||
|
}
|
||||||
|
separator.unshift(Pos(0, 0));
|
||||||
|
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
|
||||||
|
|
||||||
|
//find valid range
|
||||||
|
var prevItem = null;
|
||||||
|
var current = editor.getCursor()
|
||||||
|
for (var i = 0; i < separator.length; i++) {
|
||||||
|
if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
|
||||||
|
validRange = {start: prevItem, end: separator[i]};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevItem = separator[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validRange.start) {
|
||||||
|
var query = doc.getRange(validRange.start, validRange.end, false);
|
||||||
|
|
||||||
|
for (var i = 0; i < query.length; i++) {
|
||||||
|
var lineText = query[i];
|
||||||
|
eachWord(lineText, function(word) {
|
||||||
|
var wordUpperCase = word.toUpperCase();
|
||||||
|
if (wordUpperCase === aliasUpperCase && getTable(previousWord))
|
||||||
|
table = previousWord;
|
||||||
|
if (wordUpperCase !== CONS.ALIAS_KEYWORD)
|
||||||
|
previousWord = word;
|
||||||
|
});
|
||||||
|
if (table) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
|
||||||
|
tables = parseTables(options && options.tables)
|
||||||
|
var defaultTableName = options && options.defaultTable;
|
||||||
|
var disableKeywords = options && options.disableKeywords;
|
||||||
|
defaultTable = defaultTableName && getTable(defaultTableName);
|
||||||
|
keywords = getKeywords(editor);
|
||||||
|
identifierQuote = getIdentifierQuote(editor);
|
||||||
|
|
||||||
|
if (defaultTableName && !defaultTable)
|
||||||
|
defaultTable = findTableByAlias(defaultTableName, editor);
|
||||||
|
|
||||||
|
defaultTable = defaultTable || [];
|
||||||
|
|
||||||
|
if (defaultTable.columns)
|
||||||
|
defaultTable = defaultTable.columns;
|
||||||
|
|
||||||
|
var cur = editor.getCursor();
|
||||||
|
var result = [];
|
||||||
|
var token = editor.getTokenAt(cur), start, end, search;
|
||||||
|
if (token.end > cur.ch) {
|
||||||
|
token.end = cur.ch;
|
||||||
|
token.string = token.string.slice(0, cur.ch - token.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.string.match(/^[.`"'\w@][\w$#]*$/g)) {
|
||||||
|
search = token.string;
|
||||||
|
start = token.start;
|
||||||
|
end = token.end;
|
||||||
|
} else {
|
||||||
|
start = end = cur.ch;
|
||||||
|
search = "";
|
||||||
|
}
|
||||||
|
if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) {
|
||||||
|
start = nameCompletion(cur, token, result, editor);
|
||||||
|
} else {
|
||||||
|
var objectOrClass = function(w, className) {
|
||||||
|
if (typeof w === "object") {
|
||||||
|
w.className = className;
|
||||||
|
} else {
|
||||||
|
w = { text: w, className: className };
|
||||||
|
}
|
||||||
|
return w;
|
||||||
|
};
|
||||||
|
addMatches(result, search, defaultTable, function(w) {
|
||||||
|
return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table");
|
||||||
|
});
|
||||||
|
addMatches(
|
||||||
|
result,
|
||||||
|
search,
|
||||||
|
tables, function(w) {
|
||||||
|
return objectOrClass(w, "CodeMirror-hint-table");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!disableKeywords)
|
||||||
|
addMatches(result, search, keywords, function(w) {
|
||||||
|
return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
|
||||||
|
});
|
||||||
|
});
|
||||||
92
ant-design-vue-jeecg/src/components/jeecg/dynamic/load.js
Normal file
92
ant-design-vue-jeecg/src/components/jeecg/dynamic/load.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
let callbacks = []
|
||||||
|
|
||||||
|
function loadSuccess(key) {
|
||||||
|
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144
|
||||||
|
// check is successfully downloaded script
|
||||||
|
return window[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
const load = (src, type, callback) => {
|
||||||
|
if(type=='link'){
|
||||||
|
|
||||||
|
loadStyle(src, callback)
|
||||||
|
}else{
|
||||||
|
let loadKey = ''
|
||||||
|
if(src.indexOf('tinymce')>=0){
|
||||||
|
loadKey = 'tinymce'
|
||||||
|
}else if(src.indexOf('codemirror')>=0){
|
||||||
|
loadKey = 'CodeMirror'
|
||||||
|
}
|
||||||
|
const scriptTag = document.getElementById(src)
|
||||||
|
//const cb = callback || function() {}
|
||||||
|
if (!scriptTag) {
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src = src // src url for the third-party library being loaded.
|
||||||
|
script.id = src
|
||||||
|
script.onload=()=>callback()
|
||||||
|
script.onerror=()=>callback('加载失败:'+src)
|
||||||
|
document.body.appendChild(script)
|
||||||
|
//callbacks.push(cb)
|
||||||
|
// const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
|
||||||
|
// onEnd(script)
|
||||||
|
}else{
|
||||||
|
if (loadSuccess(loadKey)) {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scriptTag) {
|
||||||
|
/* else {
|
||||||
|
callbacks.push(cb)
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stdOnEnd(script) {
|
||||||
|
script['onload'] = function() {
|
||||||
|
// this.onload = null here is necessary
|
||||||
|
// because even IE9 works not like others
|
||||||
|
this.onerror = this.onload = null
|
||||||
|
for (const cb of callbacks) {
|
||||||
|
cb(null, script)
|
||||||
|
}
|
||||||
|
callbacks = null
|
||||||
|
}
|
||||||
|
script['onerror'] = function() {
|
||||||
|
this.onerror = this.onload = null
|
||||||
|
cb(new Error('Failed to load ' + src), script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ieOnEnd(script) {
|
||||||
|
script.onreadystatechange = function() {
|
||||||
|
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
|
||||||
|
this.onreadystatechange = null
|
||||||
|
for (const cb of callbacks) {
|
||||||
|
cb(null, script) // there is no way to catch loading errors in IE8
|
||||||
|
}
|
||||||
|
callbacks = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadStyle(src, callback) {
|
||||||
|
const link = document.getElementById(src)
|
||||||
|
if (!link) {
|
||||||
|
const link = document.createElement('link')
|
||||||
|
link.setAttribute("rel", "stylesheet");
|
||||||
|
link.setAttribute("type", "text/css");
|
||||||
|
link.setAttribute("href", src);
|
||||||
|
link.id = src
|
||||||
|
let heads = document.getElementsByTagName("head")
|
||||||
|
if(heads.length){
|
||||||
|
heads[0].appendChild(link)
|
||||||
|
}else{
|
||||||
|
document.documentElement.appendChild(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default load
|
||||||
@ -1,9 +1,11 @@
|
|||||||
import JModal from './JModal'
|
import JModal from './JModal'
|
||||||
import JFormContainer from './JFormContainer.vue'
|
import JFormContainer from './JFormContainer.vue'
|
||||||
|
import JPopup from './JPopup.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(Vue) {
|
install(Vue) {
|
||||||
Vue.component('JFormContainer', JFormContainer)
|
Vue.component('JFormContainer', JFormContainer)
|
||||||
|
Vue.component('JPopup', JPopup)
|
||||||
Vue.component(JModal.name, JModal)
|
Vue.component(JModal.name, JModal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<a-modal
|
<a-modal
|
||||||
title="文件上传"
|
:title="fileType === 'image' ? '图片上传' : '文件上传'"
|
||||||
:width="width"
|
:width="width"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
@ok="ok"
|
@ok="ok"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-popover trigger="contextmenu" v-model="visible" :placement="position">
|
<a-popover trigger="contextmenu" v-model="visible" :placement="position" overlayClassName="j-input-pop">
|
||||||
<!--"(node) => node.parentNode.parentNode"-->
|
<!--"(node) => node.parentNode.parentNode"-->
|
||||||
<div slot="title">
|
<div slot="title">
|
||||||
<span>{{ title }}</span>
|
<span>{{ title }}</span>
|
||||||
@ -7,11 +7,11 @@
|
|||||||
<a-icon type="close" @click="visible=false"/>
|
<a-icon type="close" @click="visible=false"/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<a-input :value="inputContent" @change="handleInputChange">
|
<a-input :value="inputContent" :disabled="disabled" @change="handleInputChange">
|
||||||
<a-icon slot="suffix" type="fullscreen" @click.stop="pop" />
|
<a-icon slot="suffix" type="fullscreen" @click.stop="pop" />
|
||||||
</a-input>
|
</a-input>
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
<textarea :value="inputContent" @input="handleInputChange" :style="{ height: height + 'px', width: width + 'px' }"></textarea>
|
<a-textarea ref="textarea" :value="inputContent" :disabled="disabled" @input="handleInputChange" :style="{ height: height + 'px', width: width + 'px' }"/>
|
||||||
</div>
|
</div>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
@ -48,7 +48,11 @@
|
|||||||
type:String,
|
type:String,
|
||||||
default:'',
|
default:'',
|
||||||
required:false
|
required:false
|
||||||
}
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
@ -80,6 +84,9 @@
|
|||||||
},
|
},
|
||||||
pop(){
|
pop(){
|
||||||
this.visible=true
|
this.visible=true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.textarea.focus()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
getPopupContainer(node){
|
getPopupContainer(node){
|
||||||
if(!this.popContainer){
|
if(!this.popContainer){
|
||||||
|
|||||||
@ -0,0 +1,349 @@
|
|||||||
|
<template>
|
||||||
|
<j-modal
|
||||||
|
:title="title"
|
||||||
|
:width="modalWidth"
|
||||||
|
:visible="visible"
|
||||||
|
:confirmLoading="confirmLoading"
|
||||||
|
switchFullscreen
|
||||||
|
wrapClassName="j-popup-modal"
|
||||||
|
@ok="handleSubmit"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
cancelText="关闭">
|
||||||
|
|
||||||
|
<div class="table-page-search-wrapper">
|
||||||
|
<a-form layout="inline" @keyup.enter.native="searchByquery">
|
||||||
|
<a-row :gutter="24" v-if="showSearchFlag">
|
||||||
|
<template v-for="(item,index) in queryInfo">
|
||||||
|
<template v-if=" item.hidden==='1' ">
|
||||||
|
<a-col :md="8" :sm="24" :key=" 'query'+index " v-show="toggleSearchStatus">
|
||||||
|
<online-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></online-query-form-item>
|
||||||
|
</a-col>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-col :md="8" :sm="24" :key=" 'query'+index ">
|
||||||
|
<online-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></online-query-form-item>
|
||||||
|
</a-col>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<a-col :md="8" :sm="8">
|
||||||
|
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
|
||||||
|
<a-button type="primary" @click="searchByquery" icon="search">查询</a-button>
|
||||||
|
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
|
||||||
|
<a @click="handleToggleSearch" style="margin-left: 8px">
|
||||||
|
{{ toggleSearchStatus ? '收起' : '展开' }}
|
||||||
|
<a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
|
||||||
|
<i class="anticon anticon-info-circle ant-alert-icon"></i>
|
||||||
|
已选择 <a style="font-weight: 600">{{ table.selectedRowKeys.length }}</a>项
|
||||||
|
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
|
||||||
|
|
||||||
|
<a v-if="!showSearchFlag" style="margin-left: 24px" @click="onlyReload">刷新</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-table
|
||||||
|
ref="table"
|
||||||
|
size="middle"
|
||||||
|
bordered
|
||||||
|
:rowKey="combineRowKey"
|
||||||
|
:columns="table.columns"
|
||||||
|
:dataSource="table.dataSource"
|
||||||
|
:pagination="table.pagination"
|
||||||
|
:loading="table.loading"
|
||||||
|
:rowSelection="{fixed:true,selectedRowKeys: table.selectedRowKeys, onChange: handleChangeInTableSelect}"
|
||||||
|
@change="handleChangeInTable"
|
||||||
|
style="min-height: 300px"
|
||||||
|
:scroll="tableScroll"
|
||||||
|
:customRow="clickThenCheck">
|
||||||
|
</a-table>
|
||||||
|
|
||||||
|
|
||||||
|
</j-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getAction } from '@/api/manage'
|
||||||
|
import {filterObj} from '@/utils/util'
|
||||||
|
import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
|
||||||
|
import { httpGroupRequest } from '@/api/GroupRequest.js'
|
||||||
|
|
||||||
|
const MODAL_WIDTH = 1200;
|
||||||
|
export default {
|
||||||
|
name: 'JPopupOnlReport',
|
||||||
|
props: ['multi', 'code', 'groupId'],
|
||||||
|
components:{
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
visible:false,
|
||||||
|
title:"",
|
||||||
|
confirmLoading:false,
|
||||||
|
queryInfo:[],
|
||||||
|
toggleSearchStatus:false,
|
||||||
|
queryParam:{
|
||||||
|
|
||||||
|
},
|
||||||
|
dictOptions: {},
|
||||||
|
url: {
|
||||||
|
getColumns: '/online/cgreport/api/getRpColumns/',
|
||||||
|
getData: '/online/cgreport/api/getData/',
|
||||||
|
getQueryInfo: '/online/cgreport/api/getQueryInfo/'
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
loading: true,
|
||||||
|
// 表头
|
||||||
|
columns: [],
|
||||||
|
//数据集
|
||||||
|
dataSource: [],
|
||||||
|
// 选择器
|
||||||
|
selectedRowKeys: [],
|
||||||
|
selectionRows: [],
|
||||||
|
// 分页参数
|
||||||
|
pagination: {
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
pageSizeOptions: ['10', '20', '30'],
|
||||||
|
showTotal: (total, range) => {
|
||||||
|
return range[0] + '-' + range[1] + ' 共' + total + '条'
|
||||||
|
},
|
||||||
|
showQuickJumper: true,
|
||||||
|
showSizeChanger: true,
|
||||||
|
total: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cgRpConfigId:"",
|
||||||
|
modalWidth:MODAL_WIDTH,
|
||||||
|
tableScroll:{x:MODAL_WIDTH-100}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.loadColumnsInfo()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
code() {
|
||||||
|
this.loadColumnsInfo()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
showSearchFlag(){
|
||||||
|
return this.queryInfo && this.queryInfo.length>0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
loadColumnsInfo(){
|
||||||
|
let url = `${this.url.getColumns}${this.code}`
|
||||||
|
//缓存key
|
||||||
|
let groupIdKey
|
||||||
|
if (this.groupId) {
|
||||||
|
groupIdKey = this.groupId + url
|
||||||
|
}
|
||||||
|
httpGroupRequest(() => getAction(url), groupIdKey).then(res => {
|
||||||
|
if(res.success){
|
||||||
|
this.initDictOptionData(res.result.dictOptions);
|
||||||
|
this.cgRpConfigId = res.result.cgRpConfigId
|
||||||
|
this.title = res.result.cgRpConfigName
|
||||||
|
let currColumns = res.result.columns
|
||||||
|
for(let a=0;a<currColumns.length;a++){
|
||||||
|
if(currColumns[a].customRender){
|
||||||
|
let dictCode = currColumns[a].customRender;
|
||||||
|
currColumns[a].customRender=(text)=>{
|
||||||
|
return filterMultiDictText(this.dictOptions[dictCode], text+"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.table.columns = [...currColumns]
|
||||||
|
this.initQueryInfo()
|
||||||
|
this.loadData(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initQueryInfo() {
|
||||||
|
let url = `${this.url.getQueryInfo}${this.cgRpConfigId}`
|
||||||
|
//缓存key
|
||||||
|
let groupIdKey
|
||||||
|
if (this.groupId) {
|
||||||
|
groupIdKey = this.groupId + url
|
||||||
|
}
|
||||||
|
httpGroupRequest(() => getAction(url), groupIdKey).then((res) => {
|
||||||
|
// console.log("获取查询条件", res);
|
||||||
|
if (res.success) {
|
||||||
|
this.queryInfo = res.result
|
||||||
|
} else {
|
||||||
|
this.$message.warning(res.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadData(arg) {
|
||||||
|
if (arg == 1) {
|
||||||
|
this.table.pagination.current = 1
|
||||||
|
}
|
||||||
|
let params = this.getQueryParams();//查询条件
|
||||||
|
this.table.loading = true
|
||||||
|
let url = `${this.url.getData}${this.cgRpConfigId}`
|
||||||
|
//缓存key
|
||||||
|
let groupIdKey
|
||||||
|
if (this.groupId) {
|
||||||
|
groupIdKey = this.groupId + url + JSON.stringify(params)
|
||||||
|
}
|
||||||
|
httpGroupRequest(() => getAction(url, params), groupIdKey).then(res => {
|
||||||
|
this.table.loading = false
|
||||||
|
// console.log("daa",res)
|
||||||
|
let data = res.result
|
||||||
|
if (data) {
|
||||||
|
this.table.pagination.total = Number(data.total)
|
||||||
|
this.table.dataSource = data.records
|
||||||
|
} else {
|
||||||
|
this.table.pagination.total = 0
|
||||||
|
this.table.dataSource = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getQueryParams() {
|
||||||
|
let param = Object.assign({}, this.queryParam, this.sorter);
|
||||||
|
param.pageNo = this.table.pagination.current;
|
||||||
|
param.pageSize = this.table.pagination.pageSize;
|
||||||
|
return filterObj(param);
|
||||||
|
},
|
||||||
|
handleChangeInTableSelect(selectedRowKeys, selectionRows) {
|
||||||
|
//update-begin-author:taoyan date:2020902 for:【issue】开源online的几个问题 LOWCOD-844
|
||||||
|
if(!selectedRowKeys || selectedRowKeys.length==0){
|
||||||
|
this.table.selectionRows = []
|
||||||
|
}else if(selectedRowKeys.length == selectionRows.length){
|
||||||
|
this.table.selectionRows = selectionRows
|
||||||
|
}else{
|
||||||
|
//当两者长度不一的时候 需要判断
|
||||||
|
let keys = this.table.selectedRowKeys
|
||||||
|
let rows = this.table.selectionRows;
|
||||||
|
//这个循环 添加新的记录
|
||||||
|
for(let i=0;i<selectionRows.length;i++){
|
||||||
|
let combineKey = this.combineRowKey(selectionRows[i])
|
||||||
|
if(keys.indexOf(combineKey)<0){
|
||||||
|
//如果 原来的key 不包含当前记录 push
|
||||||
|
rows.push(selectionRows[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//这个循环 移除取消选中的数据
|
||||||
|
this.table.selectionRows = rows.filter(item=>{
|
||||||
|
let combineKey = this.combineRowKey(item)
|
||||||
|
return selectedRowKeys.indexOf(combineKey)>=0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:2020902 for:【issue】开源online的几个问题 LOWCOD-844
|
||||||
|
this.table.selectedRowKeys = selectedRowKeys
|
||||||
|
},
|
||||||
|
handleChangeInTable(pagination, filters, sorter) {
|
||||||
|
//分页、排序、筛选变化时触发
|
||||||
|
if (Object.keys(sorter).length > 0) {
|
||||||
|
this.sorter.column = sorter.field
|
||||||
|
this.sorter.order = 'ascend' == sorter.order ? 'asc' : 'desc'
|
||||||
|
}
|
||||||
|
this.table.pagination = pagination
|
||||||
|
this.loadData()
|
||||||
|
},
|
||||||
|
handleCancel() {
|
||||||
|
this.close()
|
||||||
|
},
|
||||||
|
handleSubmit() {
|
||||||
|
if(!this.multi){
|
||||||
|
if(this.table.selectionRows && this.table.selectionRows.length>1){
|
||||||
|
this.$message.warning("请选择一条记录")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!this.table.selectionRows || this.table.selectionRows.length==0){
|
||||||
|
this.$message.warning("请选择一条记录")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
this.$emit('ok', this.table.selectionRows);
|
||||||
|
this.close()
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.$emit('close');
|
||||||
|
this.visible = false;
|
||||||
|
this.onClearSelected()
|
||||||
|
},
|
||||||
|
show(){
|
||||||
|
this.visible = true;
|
||||||
|
},
|
||||||
|
handleToggleSearch(){
|
||||||
|
this.toggleSearchStatus = !this.toggleSearchStatus;
|
||||||
|
},
|
||||||
|
searchByquery(){
|
||||||
|
this.loadData(1);
|
||||||
|
},
|
||||||
|
onlyReload(){
|
||||||
|
this.loadData();
|
||||||
|
},
|
||||||
|
searchReset(){
|
||||||
|
Object.keys(this.queryParam).forEach(key=>{
|
||||||
|
this.queryParam[key]=""
|
||||||
|
})
|
||||||
|
this.loadData(1);
|
||||||
|
},
|
||||||
|
onClearSelected(){
|
||||||
|
this.table.selectedRowKeys = []
|
||||||
|
this.table.selectionRows = []
|
||||||
|
},
|
||||||
|
combineRowKey(record){
|
||||||
|
let res = ''
|
||||||
|
Object.keys(record).forEach(key=>{
|
||||||
|
res+=record[key]
|
||||||
|
})
|
||||||
|
if(res.length>50){
|
||||||
|
res = res.substring(0,50)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
|
||||||
|
clickThenCheck(record){
|
||||||
|
return {
|
||||||
|
on: {
|
||||||
|
click: () => {
|
||||||
|
let rowKey = this.combineRowKey(record)
|
||||||
|
if(!this.table.selectedRowKeys || this.table.selectedRowKeys.length==0){
|
||||||
|
let arr1=[],arr2=[]
|
||||||
|
arr1.push(record)
|
||||||
|
arr2.push(rowKey)
|
||||||
|
this.table.selectedRowKeys=arr2
|
||||||
|
this.table.selectionRows=arr1
|
||||||
|
}else{
|
||||||
|
if(this.table.selectedRowKeys.indexOf(rowKey)<0){
|
||||||
|
this.table.selectedRowKeys.push(rowKey)
|
||||||
|
this.table.selectionRows.push(record)
|
||||||
|
}else{
|
||||||
|
let rowKey_index = this.table.selectedRowKeys.indexOf(rowKey)
|
||||||
|
this.table.selectedRowKeys.splice(rowKey_index,1);
|
||||||
|
this.table.selectionRows.splice(rowKey_index,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//防止字典中有垃圾数据
|
||||||
|
initDictOptionData(dictOptions){
|
||||||
|
let obj = { }
|
||||||
|
Object.keys(dictOptions).map(k=>{
|
||||||
|
obj[k] = dictOptions[k].filter(item=>{
|
||||||
|
return item!=null
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.dictOptions = obj
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -1,9 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<j-modal
|
||||||
centered
|
centered
|
||||||
:title="name + '选择'"
|
:title="name + '选择'"
|
||||||
:width="width"
|
:width="width"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
|
switchFullscreen
|
||||||
@ok="handleOk"
|
@ok="handleOk"
|
||||||
@cancel="close"
|
@cancel="close"
|
||||||
cancelText="关闭">
|
cancelText="关闭">
|
||||||
@ -11,28 +12,24 @@
|
|||||||
<a-row :gutter="18">
|
<a-row :gutter="18">
|
||||||
<a-col :span="16">
|
<a-col :span="16">
|
||||||
<!-- 查询区域 -->
|
<!-- 查询区域 -->
|
||||||
<div class="table-page-search-wrapper">
|
<a-form layout="inline" class="j-inline-form">
|
||||||
<a-form layout="inline">
|
<!-- 固定条件 -->
|
||||||
<a-row :gutter="24">
|
<a-form-item :label="(queryParamText||name)">
|
||||||
|
<a-input v-model="queryParam[queryParamCode||valueKey]" :placeholder="'请输入' + (queryParamText||name)" @pressEnter="searchQuery"/>
|
||||||
<a-col :span="14">
|
</a-form-item>
|
||||||
<a-form-item :label="(queryParamText||name)">
|
<!-- 动态生成的查询条件 -->
|
||||||
<a-input v-model="queryParam[queryParamCode||valueKey]" :placeholder="'请输入' + (queryParamText||name)" @pressEnter="searchQuery"/>
|
<j-select-biz-query-item v-if="queryConfig.length>0" v-show="showMoreQueryItems" :queryParam="queryParam" :queryConfig="queryConfig" @pressEnter="searchQuery"/>
|
||||||
</a-form-item>
|
<!-- 按钮 -->
|
||||||
</a-col>
|
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
|
||||||
<a-col :span="8">
|
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
|
||||||
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
|
<a v-if="queryConfig.length>0" @click="showMoreQueryItems=!showMoreQueryItems" style="margin-left: 8px">
|
||||||
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
|
{{ showMoreQueryItems ? '收起' : '展开' }}
|
||||||
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
|
<a-icon :type="showMoreQueryItems ? 'up' : 'down'"/>
|
||||||
</span>
|
</a>
|
||||||
</a-col>
|
</a-form>
|
||||||
|
|
||||||
</a-row>
|
|
||||||
</a-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-table
|
<a-table
|
||||||
size="small"
|
size="middle"
|
||||||
bordered
|
bordered
|
||||||
:rowKey="rowKey"
|
:rowKey="rowKey"
|
||||||
:columns="innerColumns"
|
:columns="innerColumns"
|
||||||
@ -49,7 +46,7 @@
|
|||||||
<a-col :span="8">
|
<a-col :span="8">
|
||||||
<a-card :title="'已选' + name" :bordered="false" :head-style="{padding:0}" :body-style="{padding:0}">
|
<a-card :title="'已选' + name" :bordered="false" :head-style="{padding:0}" :body-style="{padding:0}">
|
||||||
|
|
||||||
<a-table size="small" :rowKey="rowKey" bordered v-bind="selectedTable">
|
<a-table size="middle" :rowKey="rowKey" bordered v-bind="selectedTable">
|
||||||
<span slot="action" slot-scope="text, record, index">
|
<span slot="action" slot-scope="text, record, index">
|
||||||
<a @click="handleDeleteSelected(record, index)">删除</a>
|
<a @click="handleDeleteSelected(record, index)">删除</a>
|
||||||
</span>
|
</span>
|
||||||
@ -58,7 +55,7 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-modal>
|
</j-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -66,11 +63,12 @@
|
|||||||
import Ellipsis from '@/components/Ellipsis'
|
import Ellipsis from '@/components/Ellipsis'
|
||||||
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
|
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
|
||||||
import { cloneObject, pushIfNotExist } from '@/utils/util'
|
import { cloneObject, pushIfNotExist } from '@/utils/util'
|
||||||
|
import JSelectBizQueryItem from './JSelectBizQueryItem'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectBizComponentModal',
|
name: 'JSelectBizComponentModal',
|
||||||
mixins: [JeecgListMixin],
|
mixins: [JeecgListMixin],
|
||||||
components: { Ellipsis },
|
components: {Ellipsis, JSelectBizQueryItem},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@ -126,6 +124,11 @@
|
|||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
// 查询配置
|
||||||
|
queryConfig: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
rowKey: {
|
rowKey: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'id'
|
default: 'id'
|
||||||
@ -168,6 +171,7 @@
|
|||||||
},
|
},
|
||||||
options: [],
|
options: [],
|
||||||
dataSourceMap: {},
|
dataSourceMap: {},
|
||||||
|
showMoreQueryItems: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -205,6 +209,11 @@
|
|||||||
immediate: true,
|
immediate: true,
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(val) {
|
handler(val) {
|
||||||
|
//update--begin--autor:scott-----date:20200927------for:选取职务名称出现全选 #1753-----
|
||||||
|
if(this.innerValue){
|
||||||
|
this.innerValue.length=0;
|
||||||
|
}
|
||||||
|
//update--end--autor:scott-----date:20200927------for:选取职务名称出现全选 #1753-----
|
||||||
this.selectedTable.dataSource = val.map(key => {
|
this.selectedTable.dataSource = val.map(key => {
|
||||||
for (let data of this.dataSource) {
|
for (let data of this.dataSource) {
|
||||||
if (data[this.rowKey] === key) {
|
if (data[this.rowKey] === key) {
|
||||||
@ -298,11 +307,15 @@
|
|||||||
this.$emit('input', value)
|
this.$emit('input', value)
|
||||||
this.close()
|
this.close()
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 删除已选择的 */
|
/** 删除已选择的 */
|
||||||
handleDeleteSelected(record, index) {
|
handleDeleteSelected(record, index) {
|
||||||
this.selectedRowKeys.splice(this.selectedRowKeys.indexOf(record[this.rowKey]), 1)
|
this.selectedRowKeys.splice(this.selectedRowKeys.indexOf(record[this.rowKey]), 1)
|
||||||
this.selectedTable.dataSource.splice(index, 1)
|
//update--begin--autor:wangshuai-----date:20200722------for:JSelectBizComponent组件切换页数值问题------
|
||||||
|
this.selectedTable.dataSource.splice(this.selectedTable.dataSource.indexOf(record), 1)
|
||||||
|
this.innerValue.splice(this.innerValue.indexOf(record[this.valueKey]), 1)
|
||||||
|
console.log("this.selectedRowKeys:",this.selectedRowKeys)
|
||||||
|
console.log("this.selectedTable.dataSource:",this.selectedTable.dataSource)
|
||||||
|
//update--begin--autor:wangshuai-----date:20200722------for:JSelectBizComponent组件切换页数值问题------
|
||||||
},
|
},
|
||||||
|
|
||||||
customRowFn(record) {
|
customRowFn(record) {
|
||||||
@ -331,4 +344,29 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.full-form-item {
|
||||||
|
display: flex;
|
||||||
|
margin-right: 0;
|
||||||
|
|
||||||
|
/deep/ .ant-form-item-control-wrapper {
|
||||||
|
flex: 1 1;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.j-inline-form {
|
||||||
|
/deep/ .ant-form-item {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .ant-form-item-label {
|
||||||
|
line-height: 32px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .ant-form-item-control {
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
export default {
|
||||||
|
name: 'JSelectBizQueryItem',
|
||||||
|
props: {
|
||||||
|
queryParam: Object,
|
||||||
|
queryConfig: Array,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
renderQueryItem() {
|
||||||
|
return this.queryConfig.map(queryItem => {
|
||||||
|
const {key, label, placeholder, dictCode, props, customRender} = queryItem
|
||||||
|
const options = {
|
||||||
|
props: {},
|
||||||
|
on: {
|
||||||
|
pressEnter: () => this.$emit('pressEnter'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (props != null) {
|
||||||
|
Object.assign(options.props, props)
|
||||||
|
}
|
||||||
|
if (placeholder === undefined) {
|
||||||
|
if (dictCode) {
|
||||||
|
options.props['placeholder'] = `请选择${label}`
|
||||||
|
} else {
|
||||||
|
options.props['placeholder'] = `请输入${label}`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
options.props['placeholder'] = placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
let input
|
||||||
|
if (typeof customRender === 'function') {
|
||||||
|
input = customRender.call(this, {key, options, queryParam: this.queryParam})
|
||||||
|
} else if (dictCode) {
|
||||||
|
input = <j-dict-select-tag {...options} vModel={this.queryParam[key]} dictCode={dictCode} style="width:180px;"/>
|
||||||
|
} else {
|
||||||
|
input = <a-input {...options} vModel={this.queryParam[key]}/>
|
||||||
|
}
|
||||||
|
return <a-form-item key={key} label={label}>{input}</a-form-item>
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
return <span>{this.renderQueryItem()}</span>
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -118,10 +118,12 @@
|
|||||||
deep: true,
|
deep: true,
|
||||||
handler(val) {
|
handler(val) {
|
||||||
let rows = val.map(key => this.dataSourceMap[key])
|
let rows = val.map(key => this.dataSourceMap[key])
|
||||||
this.$emit('select', rows)
|
|
||||||
let data = val.join(',')
|
let data = val.join(',')
|
||||||
this.$emit('input', data)
|
if (data !== this.value) {
|
||||||
this.$emit('change', data)
|
this.$emit('select', rows)
|
||||||
|
this.$emit('input', data)
|
||||||
|
this.$emit('change', data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -76,6 +76,18 @@
|
|||||||
methods:{
|
methods:{
|
||||||
initComp(departNames){
|
initComp(departNames){
|
||||||
this.departNames = departNames
|
this.departNames = departNames
|
||||||
|
//update-begin-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
|
||||||
|
//TODO 当返回字段为部门名称时会有问题,因为部门名称不唯一
|
||||||
|
//返回字段不为id时,根据返回字段获取id
|
||||||
|
if(this.customReturnField !== 'id' && this.value){
|
||||||
|
const dataList = this.$refs.innerDepartSelectModal.dataList;
|
||||||
|
console.log('this.value',this.value)
|
||||||
|
this.departIds = this.value.split(',').map(item => {
|
||||||
|
const data = dataList.filter(d=>d[this.customReturnField] === item)
|
||||||
|
return data.length > 0 ? data[0].id : ''
|
||||||
|
}).join(',')
|
||||||
|
}
|
||||||
|
//update-end-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
|
||||||
},
|
},
|
||||||
openModal(){
|
openModal(){
|
||||||
this.$refs.innerDepartSelectModal.show()
|
this.$refs.innerDepartSelectModal.show()
|
||||||
|
|||||||
@ -11,12 +11,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import JDate from '@comp/jeecg/JDate'
|
||||||
import JSelectBizComponent from './JSelectBizComponent'
|
import JSelectBizComponent from './JSelectBizComponent'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectMultiUser',
|
name: 'JSelectMultiUser',
|
||||||
components: { JSelectBizComponent },
|
components: {JDate, JSelectBizComponent},
|
||||||
props: ['value'],
|
props: {
|
||||||
|
value: null, // any type
|
||||||
|
queryConfig: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
url: { list: '/sys/user/list' },
|
url: { list: '/sys/user/list' },
|
||||||
@ -33,12 +40,32 @@
|
|||||||
displayKey: 'realname',
|
displayKey: 'realname',
|
||||||
returnKeys: ['id', 'username'],
|
returnKeys: ['id', 'username'],
|
||||||
queryParamText: '账号',
|
queryParamText: '账号',
|
||||||
}
|
},
|
||||||
|
// 多条件查询配置
|
||||||
|
queryConfigDefault: [
|
||||||
|
{
|
||||||
|
key: 'sex',
|
||||||
|
label: '性别',
|
||||||
|
// 如果包含 dictCode,那么就会显示成下拉框
|
||||||
|
dictCode: 'sex',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'birthday',
|
||||||
|
label: '生日',
|
||||||
|
placeholder: '请选择出生日期',
|
||||||
|
// 如果想要使用局部注册的组件,就必须要使用箭头函数
|
||||||
|
customRender: ({key, queryParam, options}) => {
|
||||||
|
return <j-date {...options} vModel={queryParam[key]} style="width:180px;"/>
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
attrs() {
|
attrs() {
|
||||||
return Object.assign(this.default, this.$attrs)
|
return Object.assign(this.default, this.$attrs, {
|
||||||
|
queryConfig: this.queryConfigDefault.concat(this.queryConfig)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
import JSelectBizComponent from './JSelectBizComponent'
|
import JSelectBizComponent from './JSelectBizComponent'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectMultiUser',
|
name: 'JSelectRole',
|
||||||
components: { JSelectBizComponent },
|
components: { JSelectBizComponent },
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<j-modal
|
||||||
title="选择部门"
|
title="选择部门"
|
||||||
:width="modalWidth"
|
:width="modalWidth"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
:confirmLoading="confirmLoading"
|
:confirmLoading="confirmLoading"
|
||||||
@ok="handleSubmit"
|
@ok="handleSubmit"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
|
switchFullscreen
|
||||||
cancelText="关闭">
|
cancelText="关闭">
|
||||||
<a-spin tip="Loading..." :spinning="false">
|
<a-spin tip="Loading..." :spinning="false">
|
||||||
<a-input-search style="margin-bottom: 1px" placeholder="请输入部门名称按回车进行搜索" @search="onSearch" />
|
<a-input-search style="margin-bottom: 1px" placeholder="请输入部门名称按回车进行搜索" @search="onSearch" />
|
||||||
<a-tree
|
<a-tree
|
||||||
checkable
|
checkable
|
||||||
|
class="my-dept-select-tree"
|
||||||
:treeData="treeData"
|
:treeData="treeData"
|
||||||
:checkStrictly="true"
|
:checkStrictly="true"
|
||||||
@check="onCheck"
|
@check="onCheck"
|
||||||
@ -31,7 +33,7 @@
|
|||||||
</a-tree>
|
</a-tree>
|
||||||
|
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</a-modal>
|
</j-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -236,6 +238,11 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="less" scoped>
|
||||||
|
// 限制部门选择树高度,避免部门太多时点击确定不便
|
||||||
|
.my-dept-select-tree{
|
||||||
|
height: 350px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<j-modal
|
||||||
:width="modalWidth"
|
:width="modalWidth"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
:title="title"
|
:title="title"
|
||||||
|
switchFullscreen
|
||||||
@ok="handleSubmit"
|
@ok="handleSubmit"
|
||||||
@cancel="close"
|
@cancel="close"
|
||||||
|
style="top:50px"
|
||||||
cancelText="关闭"
|
cancelText="关闭"
|
||||||
style="margin-top: -70px"
|
|
||||||
wrapClassName="ant-modal-cust-warp"
|
|
||||||
>
|
>
|
||||||
<a-row :gutter="10" style="background-color: #ececec; padding: 10px; margin: -10px">
|
<a-row :gutter="10" style="background-color: #ececec; padding: 10px; margin: -10px">
|
||||||
<a-col :md="6" :sm="24">
|
<a-col :md="6" :sm="24">
|
||||||
@ -51,7 +51,7 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-modal>
|
</j-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -82,16 +82,19 @@
|
|||||||
if (this.$route.path != indexKey) {
|
if (this.$route.path != indexKey) {
|
||||||
this.addIndexToFirst()
|
this.addIndexToFirst()
|
||||||
}
|
}
|
||||||
|
// 复制一个route对象出来,不能影响原route
|
||||||
|
let currentRoute = Object.assign({}, this.$route)
|
||||||
|
currentRoute.meta = Object.assign({}, currentRoute.meta)
|
||||||
// update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
// update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
||||||
let storeKey = 'route:title:' + this.$route.fullPath
|
let storeKey = 'route:title:' + currentRoute.fullPath
|
||||||
let routeTitle = this.$ls.get(storeKey)
|
let routeTitle = this.$ls.get(storeKey)
|
||||||
if (routeTitle) {
|
if (routeTitle) {
|
||||||
this.$route.meta.title = routeTitle
|
currentRoute.meta.title = routeTitle
|
||||||
}
|
}
|
||||||
// update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
// update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
||||||
this.pageList.push(this.$route)
|
this.pageList.push(currentRoute)
|
||||||
this.linkList.push(this.$route.fullPath)
|
this.linkList.push(currentRoute.fullPath)
|
||||||
this.activePage = this.$route.fullPath
|
this.activePage = currentRoute.fullPath
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
},
|
},
|
||||||
@ -112,11 +115,11 @@
|
|||||||
}else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
|
}else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
|
||||||
this.linkList.push(newRoute.fullPath)
|
this.linkList.push(newRoute.fullPath)
|
||||||
this.pageList.push(Object.assign({},newRoute))
|
this.pageList.push(Object.assign({},newRoute))
|
||||||
// update-begin-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍
|
// update-begin-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍 #842
|
||||||
if (newRoute.meta.keepAlive) {
|
// if (newRoute.meta.keepAlive) {
|
||||||
this.routeReload()
|
// this.routeReload()
|
||||||
}
|
// }
|
||||||
// update-end-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍
|
// update-end-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍 #842
|
||||||
} else if (this.linkList.indexOf(newRoute.fullPath) >= 0) {
|
} else if (this.linkList.indexOf(newRoute.fullPath) >= 0) {
|
||||||
let oldIndex = this.linkList.indexOf(newRoute.fullPath)
|
let oldIndex = this.linkList.indexOf(newRoute.fullPath)
|
||||||
let oldPositionRoute = this.pageList[oldIndex]
|
let oldPositionRoute = this.pageList[oldIndex]
|
||||||
@ -126,8 +129,11 @@
|
|||||||
'activePage': function(key) {
|
'activePage': function(key) {
|
||||||
let index = this.linkList.lastIndexOf(key)
|
let index = this.linkList.lastIndexOf(key)
|
||||||
let waitRouter = this.pageList[index]
|
let waitRouter = this.pageList[index]
|
||||||
this.$router.push(Object.assign({},waitRouter));
|
// 【TESTA-523】修复:不允许重复跳转路由异常
|
||||||
this.changeTitle(waitRouter.meta.title)
|
if (waitRouter.fullPath !== this.$route.fullPath) {
|
||||||
|
this.$router.push(Object.assign({}, waitRouter))
|
||||||
|
this.changeTitle(waitRouter.meta.title)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'multipage': function(newVal) {
|
'multipage': function(newVal) {
|
||||||
if(this.reloadFlag){
|
if(this.reloadFlag){
|
||||||
@ -302,8 +308,12 @@
|
|||||||
this.$store.dispatch(ToggleMultipage,true)
|
this.$store.dispatch(ToggleMultipage,true)
|
||||||
this.reloadFlag = true
|
this.reloadFlag = true
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
//update-end-author:taoyan date:20191008 for:路由刷新
|
//update-end-author:taoyan date:20191008 for:路由刷新
|
||||||
|
//新增一个返回方法
|
||||||
|
excuteCallback(callback){
|
||||||
|
callback()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -352,7 +362,7 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-tabs {
|
.tab-layout-tabs.ant-tabs {
|
||||||
|
|
||||||
&.ant-tabs-card .ant-tabs-tab {
|
&.ant-tabs-card .ant-tabs-tab {
|
||||||
|
|
||||||
@ -380,7 +390,7 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-tabs.ant-tabs-card > .ant-tabs-bar {
|
.tab-layout-tabs.ant-tabs.ant-tabs-card > .ant-tabs-bar {
|
||||||
.ant-tabs-tab {
|
.ant-tabs-tab {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
border-bottom: 1px solid transparent !important;
|
border-bottom: 1px solid transparent !important;
|
||||||
|
|||||||
111
ant-design-vue-jeecg/src/components/lazy_antd.js
Normal file
111
ant-design-vue-jeecg/src/components/lazy_antd.js
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
// base library
|
||||||
|
import {
|
||||||
|
ConfigProvider,
|
||||||
|
Layout,
|
||||||
|
Input,
|
||||||
|
InputNumber,
|
||||||
|
Button,
|
||||||
|
Switch,
|
||||||
|
Radio,
|
||||||
|
Checkbox,
|
||||||
|
Select,
|
||||||
|
Card,
|
||||||
|
Form,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Modal,
|
||||||
|
Table,
|
||||||
|
Tabs,
|
||||||
|
Icon,
|
||||||
|
Badge,
|
||||||
|
Popover,
|
||||||
|
Dropdown,
|
||||||
|
List,
|
||||||
|
Avatar,
|
||||||
|
Breadcrumb,
|
||||||
|
Steps,
|
||||||
|
Spin,
|
||||||
|
Menu,
|
||||||
|
Drawer,
|
||||||
|
Tooltip,
|
||||||
|
Alert,
|
||||||
|
Tag,
|
||||||
|
Divider,
|
||||||
|
DatePicker,
|
||||||
|
TimePicker,
|
||||||
|
Upload,
|
||||||
|
Progress,
|
||||||
|
Skeleton,
|
||||||
|
Popconfirm,
|
||||||
|
PageHeader,
|
||||||
|
Result,
|
||||||
|
Statistic,
|
||||||
|
Descriptions,
|
||||||
|
message,
|
||||||
|
notification,
|
||||||
|
Empty,
|
||||||
|
Tree,
|
||||||
|
TreeSelect,
|
||||||
|
Carousel,
|
||||||
|
Pagination,
|
||||||
|
} from 'ant-design-vue'
|
||||||
|
import Viser from 'viser-vue'
|
||||||
|
|
||||||
|
Vue.use(ConfigProvider)
|
||||||
|
Vue.use(Layout)
|
||||||
|
Vue.use(Input)
|
||||||
|
Vue.use(InputNumber)
|
||||||
|
Vue.use(Button)
|
||||||
|
Vue.use(Switch)
|
||||||
|
Vue.use(Radio)
|
||||||
|
Vue.use(Checkbox)
|
||||||
|
Vue.use(Select)
|
||||||
|
Vue.use(Card)
|
||||||
|
Vue.use(Form)
|
||||||
|
Vue.use(Row)
|
||||||
|
Vue.use(Col)
|
||||||
|
Vue.use(Modal)
|
||||||
|
Vue.use(Table)
|
||||||
|
Vue.use(Tabs)
|
||||||
|
Vue.use(Icon)
|
||||||
|
Vue.use(Badge)
|
||||||
|
Vue.use(Popover)
|
||||||
|
Vue.use(Dropdown)
|
||||||
|
Vue.use(List)
|
||||||
|
Vue.use(Avatar)
|
||||||
|
Vue.use(Breadcrumb)
|
||||||
|
Vue.use(Steps)
|
||||||
|
Vue.use(Spin)
|
||||||
|
Vue.use(Menu)
|
||||||
|
Vue.use(Drawer)
|
||||||
|
Vue.use(Tooltip)
|
||||||
|
Vue.use(Alert)
|
||||||
|
Vue.use(Tag)
|
||||||
|
Vue.use(Divider)
|
||||||
|
Vue.use(DatePicker)
|
||||||
|
Vue.use(TimePicker)
|
||||||
|
Vue.use(Upload)
|
||||||
|
Vue.use(Progress)
|
||||||
|
Vue.use(Skeleton)
|
||||||
|
Vue.use(Popconfirm)
|
||||||
|
Vue.use(PageHeader)
|
||||||
|
Vue.use(Result)
|
||||||
|
Vue.use(Statistic)
|
||||||
|
Vue.use(Descriptions)
|
||||||
|
Vue.use(Empty)
|
||||||
|
Vue.use(Tree)
|
||||||
|
Vue.use(TreeSelect)
|
||||||
|
Vue.use(Carousel)
|
||||||
|
Vue.use(Pagination)
|
||||||
|
|
||||||
|
Vue.prototype.$confirm = Modal.confirm
|
||||||
|
Vue.prototype.$message = message
|
||||||
|
Vue.prototype.$notification = notification
|
||||||
|
Vue.prototype.$info = Modal.info
|
||||||
|
Vue.prototype.$success = Modal.success
|
||||||
|
Vue.prototype.$error = Modal.error
|
||||||
|
Vue.prototype.$warning = Modal.warning
|
||||||
|
|
||||||
|
process.env.NODE_ENV !== 'production' && console.warn('[jeecg-boot-vue] NOTICE: Antd use lazy-load.')
|
||||||
@ -58,7 +58,7 @@
|
|||||||
components: {
|
components: {
|
||||||
UserMenu,
|
UserMenu,
|
||||||
SMenu,
|
SMenu,
|
||||||
Logo
|
Logo,
|
||||||
},
|
},
|
||||||
mixins: [mixin],
|
mixins: [mixin],
|
||||||
props: {
|
props: {
|
||||||
@ -96,7 +96,8 @@
|
|||||||
topNavHeader: {},
|
topNavHeader: {},
|
||||||
headerIndexRight: {},
|
headerIndexRight: {},
|
||||||
topSmenuStyle: {}
|
topSmenuStyle: {}
|
||||||
}
|
},
|
||||||
|
chatStatus: '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
>
|
>
|
||||||
<side-menu
|
<side-menu
|
||||||
mode="inline"
|
mode="inline"
|
||||||
|
v-if="device === 'mobile'"
|
||||||
:menus="menus"
|
:menus="menus"
|
||||||
@menuSelect="menuSelect"
|
@menuSelect="menuSelect"
|
||||||
:theme="navTheme"
|
:theme="navTheme"
|
||||||
@ -21,7 +22,7 @@
|
|||||||
</a-drawer>
|
</a-drawer>
|
||||||
|
|
||||||
<side-menu
|
<side-menu
|
||||||
v-else
|
v-show="device === 'desktop'"
|
||||||
mode="inline"
|
mode="inline"
|
||||||
:menus="menus"
|
:menus="menus"
|
||||||
@menuSelect="myMenuSelect"
|
@menuSelect="myMenuSelect"
|
||||||
@ -131,10 +132,10 @@
|
|||||||
//this.menus = this.mainRouters.find((item) => item.path === '/').children;
|
//this.menus = this.mainRouters.find((item) => item.path === '/').children;
|
||||||
this.menus = this.permissionMenuList
|
this.menus = this.permissionMenuList
|
||||||
// 根据后台配置菜单,重新排序加载路由信息
|
// 根据后台配置菜单,重新排序加载路由信息
|
||||||
console.log('----加载菜单逻辑----')
|
//console.log('----加载菜单逻辑----')
|
||||||
console.log(this.mainRouters)
|
//console.log(this.mainRouters)
|
||||||
console.log(this.permissionMenuList)
|
//console.log(this.permissionMenuList)
|
||||||
console.log('----navTheme------'+this.navTheme)
|
//console.log('----navTheme------'+this.navTheme)
|
||||||
//--update-end----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
|
//--update-end----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -343,7 +344,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
color: white;
|
color: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,7 +360,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
color: black;
|
color: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,8 +112,9 @@ export default {
|
|||||||
pageSize: (pagination && pagination.pageSize) ||
|
pageSize: (pagination && pagination.pageSize) ||
|
||||||
this.localPagination.pageSize
|
this.localPagination.pageSize
|
||||||
});
|
});
|
||||||
|
//update--begin--autor:wangshuai-----date:20200724------for:判断showPagination是否为false------
|
||||||
!r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
|
(!this.showPagination || !r.totalCount && this.showPagination === 'auto') && (this.localPagination = false)
|
||||||
|
//update--end--autor:wangshuai-----date:20200724------for:判断showPagination是否为false-----
|
||||||
this.localDataSource = r.data; // 返回结果中的数组数据
|
this.localDataSource = r.data; // 返回结果中的数组数据
|
||||||
this.localLoading = false
|
this.localLoading = false
|
||||||
});
|
});
|
||||||
|
|||||||
@ -124,7 +124,7 @@
|
|||||||
// this.heartCheckFun();
|
// this.heartCheckFun();
|
||||||
},
|
},
|
||||||
destroyed: function () { // 离开页面生命周期函数
|
destroyed: function () { // 离开页面生命周期函数
|
||||||
this.websocketclose();
|
this.websocketOnclose();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
timerFun() {
|
timerFun() {
|
||||||
@ -186,10 +186,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
toMyAnnouncement(){
|
toMyAnnouncement(){
|
||||||
|
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: '/isps/userAnnouncement',
|
path: '/isps/userAnnouncement'
|
||||||
name: 'isps-userAnnouncement'
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
modalFormOk(){
|
modalFormOk(){
|
||||||
@ -202,7 +200,7 @@
|
|||||||
// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
|
// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
|
||||||
var userId = store.getters.userInfo.id;
|
var userId = store.getters.userInfo.id;
|
||||||
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://")+"/websocket/"+userId;
|
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://")+"/websocket/"+userId;
|
||||||
console.log(url);
|
//console.log(url);
|
||||||
this.websock = new WebSocket(url);
|
this.websock = new WebSocket(url);
|
||||||
this.websock.onopen = this.websocketOnopen;
|
this.websock.onopen = this.websocketOnopen;
|
||||||
this.websock.onerror = this.websocketOnerror;
|
this.websock.onerror = this.websocketOnerror;
|
||||||
@ -232,7 +230,10 @@
|
|||||||
//this.heartCheck.reset().start();
|
//this.heartCheck.reset().start();
|
||||||
},
|
},
|
||||||
websocketOnclose: function (e) {
|
websocketOnclose: function (e) {
|
||||||
console.log("connection closed (" + e.code + ")");
|
console.log("connection closed (" + e + ")");
|
||||||
|
if(e){
|
||||||
|
console.log("connection closed (" + e.code + ")");
|
||||||
|
}
|
||||||
this.reconnect();
|
this.reconnect();
|
||||||
},
|
},
|
||||||
websocketSend(text) { // 数据发送
|
websocketSend(text) { // 数据发送
|
||||||
|
|||||||
@ -62,6 +62,10 @@
|
|||||||
<a-icon type="cluster"/>
|
<a-icon type="cluster"/>
|
||||||
<span>切换部门</span>
|
<span>切换部门</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
<a-menu-item key="6" @click="clearCache">
|
||||||
|
<a-icon type="sync"/>
|
||||||
|
<span>清理缓存</span>
|
||||||
|
</a-menu-item>
|
||||||
<!-- <a-menu-item key="2" disabled>
|
<!-- <a-menu-item key="2" disabled>
|
||||||
<a-icon type="setting"/>
|
<a-icon type="setting"/>
|
||||||
<span>测试</span>
|
<span>测试</span>
|
||||||
@ -94,7 +98,9 @@
|
|||||||
import DepartSelect from './DepartSelect'
|
import DepartSelect from './DepartSelect'
|
||||||
import { mapActions, mapGetters,mapState } from 'vuex'
|
import { mapActions, mapGetters,mapState } from 'vuex'
|
||||||
import { mixinDevice } from '@/utils/mixin.js'
|
import { mixinDevice } from '@/utils/mixin.js'
|
||||||
import { getFileAccessHttpUrl } from "@/api/manage"
|
import { getFileAccessHttpUrl,getAction } from "@/api/manage"
|
||||||
|
import Vue from 'vue'
|
||||||
|
import { UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "UserMenu",
|
name: "UserMenu",
|
||||||
@ -168,7 +174,9 @@
|
|||||||
content: '真的要注销登录吗 ?',
|
content: '真的要注销登录吗 ?',
|
||||||
onOk() {
|
onOk() {
|
||||||
return that.Logout({}).then(() => {
|
return that.Logout({}).then(() => {
|
||||||
window.location.href="/";
|
// update-begin author:wangshuai date:20200601 for: 退出登录跳转登录页面
|
||||||
|
that.$router.push({ path: '/user/login' });
|
||||||
|
// update-end author:wangshuai date:20200601 for: 退出登录跳转登录页面
|
||||||
//window.location.reload()
|
//window.location.reload()
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
that.$message.error({
|
that.$message.error({
|
||||||
@ -214,9 +222,28 @@
|
|||||||
this.$router.push({ path: route.path })
|
this.$router.push({ path: route.path })
|
||||||
}
|
}
|
||||||
this.searchMenuVisible = false
|
this.searchMenuVisible = false
|
||||||
}
|
},
|
||||||
// update_end author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
|
// update_end author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
|
||||||
/*update_end author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
|
/*update_end author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
|
||||||
|
/*update_begin author:liushaoqian date:20200507 for: 刷新缓存*/
|
||||||
|
clearCache(){
|
||||||
|
getAction("sys/dict/refleshCache").then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
//重新加载缓存
|
||||||
|
getAction("sys/dict/queryAllDictItems").then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
Vue.ls.remove(UI_CACHE_DB_DICT_DATA)
|
||||||
|
Vue.ls.set(UI_CACHE_DB_DICT_DATA, res.result, 7 * 24 * 60 * 60 * 1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$message.success("刷新缓存完成!");
|
||||||
|
}
|
||||||
|
}).catch(e=>{
|
||||||
|
this.$message.warn("刷新缓存失败!");
|
||||||
|
console.log("刷新失败",e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/*update_end author:liushaoqian date:20200507 for: 刷新缓存*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -88,7 +88,7 @@
|
|||||||
methods: {
|
methods: {
|
||||||
show(uname){
|
show(uname){
|
||||||
if(!uname){
|
if(!uname){
|
||||||
this.$message.warning("当前系统无登陆用户!");
|
this.$message.warning("当前系统无登录用户!");
|
||||||
return
|
return
|
||||||
}else{
|
}else{
|
||||||
this.username = uname
|
this.username = uname
|
||||||
|
|||||||
@ -64,7 +64,7 @@ const updateTheme = primaryColor => {
|
|||||||
const lessConfigNode = document.createElement('script');
|
const lessConfigNode = document.createElement('script');
|
||||||
const lessScriptNode = document.createElement('script');
|
const lessScriptNode = document.createElement('script');
|
||||||
lessStyleNode.setAttribute('rel', 'stylesheet/less');
|
lessStyleNode.setAttribute('rel', 'stylesheet/less');
|
||||||
lessStyleNode.setAttribute('href', '/color.less');
|
lessStyleNode.setAttribute('href', __webpack_public_path__ + 'color.less')
|
||||||
lessConfigNode.innerHTML = `
|
lessConfigNode.innerHTML = `
|
||||||
window.less = {
|
window.less = {
|
||||||
async: true,
|
async: true,
|
||||||
|
|||||||
15
ant-design-vue-jeecg/src/icons.js
Normal file
15
ant-design-vue-jeecg/src/icons.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// src/icons.js
|
||||||
|
|
||||||
|
// export what you need
|
||||||
|
export {
|
||||||
|
default as SmileOutline
|
||||||
|
} from '@ant-design/icons/lib/outline/SmileOutline';
|
||||||
|
export {
|
||||||
|
default as MehOutline
|
||||||
|
} from '@ant-design/icons/lib/outline/MehOutline';
|
||||||
|
|
||||||
|
// export what antd other components need
|
||||||
|
export {
|
||||||
|
default as CloseOutline
|
||||||
|
} from '@ant-design/icons/lib/outline/CloseOutline';
|
||||||
|
// and other icons...
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user