mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
208 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b3d83ae0b | |||
| 081c2615be | |||
| f97c675771 | |||
| 1beddbf8e8 | |||
| 8921e84303 | |||
| 43329545d8 | |||
| 50333488a5 | |||
| 624444e3b9 | |||
| 1cd0f2627d | |||
| 18007b0524 | |||
| d92861ad77 | |||
| 8a6181b108 | |||
| 6840772959 | |||
| 1bc7ee3345 | |||
| 5f25f726c2 | |||
| 9b14d2d6a5 | |||
| 130f2bc4be | |||
| 832bc376be | |||
| 432385fc14 | |||
| 4d5ac2b518 | |||
| b83c26b8fd | |||
| b59fc67696 | |||
| af3afc7263 | |||
| 63c3dd26f5 | |||
| 892196fe9a | |||
| bbda918cde | |||
| 003ec82f48 | |||
| 4992faf66c | |||
| 34c612d9e4 | |||
| 844f1e228c | |||
| cf5fde80d4 | |||
| 49ea36c50f | |||
| f6e2b67c61 | |||
| 69a4a7df6d | |||
| 649f99664e | |||
| ef762ff21f | |||
| 02abd5c803 | |||
| 5e7342b27d | |||
| ca95d7090c | |||
| cdec71999a | |||
| 7990eff7a4 | |||
| 280f8c26ac | |||
| 4e05eaa4c5 | |||
| c6645ed800 | |||
| a674340c5e | |||
| cbd8890cb3 | |||
| b25fb55d10 | |||
| 88646bea1b | |||
| 9915b84808 | |||
| 35c1214de3 | |||
| 434b1a7e63 | |||
| 5c7d84117c | |||
| 4b9890205e | |||
| d5898139b5 | |||
| bf438069e2 | |||
| c5965b10d8 | |||
| da5ace3397 | |||
| 4674097078 | |||
| fea1607f1b | |||
| d2336bc5e1 | |||
| cf0d29557a | |||
| bb4c3c86b0 | |||
| 84a6e28677 | |||
| 5b70c1d8b8 | |||
| f942abe09b | |||
| ad4eb300f0 | |||
| 064a5c4a0e | |||
| 6d688a157b | |||
| d612af5e3b | |||
| e1c0b0fa38 | |||
| ac0979c824 | |||
| 78ba7ccba8 | |||
| b8ff5ebd43 | |||
| 5eb2541834 | |||
| 462b0d17b1 | |||
| 7cc54084dc | |||
| 32297110d9 | |||
| b7717d0461 | |||
| 97c078c46a | |||
| 17019e6261 | |||
| 4a49479985 | |||
| e49d76bc80 | |||
| d6cf2b502b | |||
| c741d779f2 | |||
| 7f847c9721 | |||
| fa2c5ecb73 | |||
| eb1578ada3 | |||
| 90758f3b2a | |||
| 766c48bdbf | |||
| d16520cc59 | |||
| 0252213b6e | |||
| ce44147e6e | |||
| 0ea4ac910a | |||
| 4f61f0ad48 | |||
| 4a5ff61ef7 | |||
| 88a0bb2d2d | |||
| b153669b69 | |||
| 449a7759be | |||
| 337920964d | |||
| 2a7946ae42 | |||
| c233f95f5f | |||
| f87cc2d97f | |||
| 02bb521b8f | |||
| 53e84ae34b | |||
| d6feeef7b5 | |||
| 18fc7b146a | |||
| 3792f46388 | |||
| f35236609c | |||
| e46b653bc4 | |||
| 4437c749ca | |||
| 74ebac4967 | |||
| a9f21795cb | |||
| a5ca8183cd | |||
| e7970e52bc | |||
| 74a9e10ce6 | |||
| df5c106d94 | |||
| ae0f9edb27 | |||
| 3d4bb704f1 | |||
| 85efec3730 | |||
| 8b0ee2d0a2 | |||
| 41c1572ad8 | |||
| 5d555158fe | |||
| 1fd0b5d4db | |||
| 693d86cf00 | |||
| 9a3f872d63 | |||
| 5b82a1aa06 | |||
| 3cb88452dc | |||
| 2fa1c7c17b | |||
| b6a3085083 | |||
| 8a7fc033cd | |||
| e0cf946d18 | |||
| c5b33b6bd1 | |||
| aec00d9ba2 | |||
| 341830c5a0 | |||
| ff45fe4858 | |||
| c13ed675a7 | |||
| 6917e91398 | |||
| 18a5c247d8 | |||
| 51bf9a7c14 | |||
| 8278041aeb | |||
| 39bb7a46fd | |||
| 1c234fbaff | |||
| ca1f5872be | |||
| 2ae3844d5e | |||
| c2db7691d1 | |||
| 543a49fcb6 | |||
| df6cf7137c | |||
| d7450cab04 | |||
| 496d85265b | |||
| b4b1162ea0 | |||
| 33e39941fb | |||
| 1b5ba9f56b | |||
| 0aadc70e74 | |||
| 94aed3ade4 | |||
| 9657eac673 | |||
| 680a8b3c42 | |||
| 6e6f88620a | |||
| 14f4f92d84 | |||
| 2c4597c0a9 | |||
| 757f1cd5a8 | |||
| 3c62a58d64 | |||
| bec39867a9 | |||
| dca8713a2e | |||
| a004acee4b | |||
| 35ef0eff90 | |||
| c70fd3383e | |||
| 3e2f640b68 | |||
| bf6c5f4623 | |||
| df259385ec | |||
| c5f51a17da | |||
| 94c0610496 | |||
| ccf4946b70 | |||
| 3b4a65ba04 | |||
| 3a8ae4c089 | |||
| 88eb98c0e6 | |||
| 63048d8c64 | |||
| e8a18fc642 | |||
| fa0c930886 | |||
| 708aa54f3a | |||
| 57337f7980 | |||
| 89f4d122dd | |||
| b92bec3eed | |||
| 72f32e47a0 | |||
| 43908013e3 | |||
| 80bd1a3f23 | |||
| de60ea050c | |||
| 7cb3dce262 | |||
| 416c8df729 | |||
| b13a4b01df | |||
| 075c3532dc | |||
| fa40b08049 | |||
| 55c0a4e051 | |||
| 0795808075 | |||
| 0fa6316f52 | |||
| 9cd111ca58 | |||
| 2c18182dd0 | |||
| 36cad9373e | |||
| fcbed695b0 | |||
| 5a01d8587b | |||
| 4570a21a63 | |||
| 8775472470 | |||
| bb72341519 | |||
| 78afc86411 | |||
| 91ff6a7aa2 | |||
| b3ec97ffcc | |||
| 24fe9e425c | |||
| 09d9e79f40 | |||
| 7f30a186df |
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -2,3 +2,4 @@
|
|||||||
*.css linguist-language=Java
|
*.css linguist-language=Java
|
||||||
*.html linguist-language=Java
|
*.html linguist-language=Java
|
||||||
*.vue linguist-language=Java
|
*.vue linguist-language=Java
|
||||||
|
*.sql linguist-language=Java
|
||||||
|
|||||||
187
README.md
187
README.md
@ -7,12 +7,12 @@
|
|||||||
JEECG BOOT 低代码开发平台(前后端分离版本)
|
JEECG BOOT 低代码开发平台(前后端分离版本)
|
||||||
===============
|
===============
|
||||||
|
|
||||||
当前最新版本: 2.2.1(发布日期:2020-07-13)
|
当前最新版本: 2.4.5(发布日期:2021-06-07)
|
||||||
|
|
||||||
|
|
||||||
[](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)
|
||||||
|
|
||||||
@ -23,11 +23,14 @@ JEECG BOOT 低代码开发平台(前后端分离版本)
|
|||||||
|
|
||||||
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||||
|
|
||||||
JeecgBoot 是一款基于代码生成器的`低代码`开发平台,零代码开发!采用前后端分离架构:SpringBoot2.x,Ant Design&Vue,Mybatis-plus,Shiro,JWT。强大的代码生成器让前后端代码一键生成,无需写任何代码! JeecgBoot引领新的开发模式(Online Coding模式-> 代码生成器模式-> 手工MERGE智能开发), 帮助解决Java项目70%的重复工作,让开发更多关注业务逻辑。既能快速提高开发效率,帮助公司节省成本,同时又不失灵活性!JeecgBoot还独创在线开发模式(No代码概念):在线表单配置(表单设计器)、移动配置能力、工作流配置(在线设计流程)、报表配置能力、在线图表配置、插件能力(可插拔)等等!
|
JeecgBoot 是一款基于代码生成器的`低代码平台`!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||||
|
|
||||||
|
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)等等!
|
||||||
|
|
||||||
|
|
||||||
`JEECG宗旨是:` 简单功能由Online Coding配置实现既`零代码开发`(在线配置表单、在线配置报表、在线图表设计、在线设计流程、在线设计表单),复杂功能由代码生成器生成进行手工Merge,既保证了`智能`又兼顾了`灵活`;
|
`JEECG宗旨是:` 简单功能由OnlineCoding配置实现,做到`零代码开发`;复杂功能由代码生成器生成进行手工Merge 实现`低代码开发`,既保证了`智能`又兼顾`灵活`;实现了低代码开发的同时又支持灵活编码,解决了当前低代码产品普遍不灵活的弊端!
|
||||||
业务流程采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
|
||||||
|
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
||||||
|
|
||||||
|
|
||||||
适用项目
|
适用项目
|
||||||
@ -39,15 +42,17 @@ 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)
|
||||||
|
|
||||||
- 视频教程 :[JeecgBoot入门视频教程](http://www.jeecg.com/doc/video)
|
- 微服务启动: [单体升级为微服务启动文档2.4+](http://doc.jeecg.com/2043906)
|
||||||
|
|
||||||
- 常见问题: [入门常见问题大全](http://bbs.jeecg.com/forum.php?mod=viewthread&tid=7816&extra=page%3D1)
|
- 在线演示 : [http://boot.jeecg.com](http://boot.jeecg.com)
|
||||||
|
|
||||||
|
- 视频教程 :[JeecgBoot入门视频](http://www.jeecg.com/doc/video)
|
||||||
|
|
||||||
|
- 常见问题: [入门常见问题Q&A](http://jeecg.com/doc/qa)
|
||||||
|
|
||||||
- 更新日志: [版本日志](http://www.jeecg.com/doc/log)
|
- 更新日志: [版本日志](http://www.jeecg.com/doc/log)
|
||||||
|
|
||||||
@ -56,56 +61,58 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
交流互动
|
交流互动
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- QQ交流群 : ②769925425、①284271917(满)
|
- QQ交流群 : ④774126647、③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、Skywalking),提供切换机制支持单体和微服务自由切换
|
||||||
* 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、Sqlserver、MariaDB、达梦等主流数据库。
|
||||||
* 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,13 +135,17 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
|
|
||||||
|
|
||||||
#### 后端
|
#### 后端
|
||||||
- 基础框架:Spring Boot 2.1.3.RELEASE
|
- 基础框架:Spring Boot 2.3.5.RELEASE
|
||||||
|
|
||||||
- 持久层框架:Mybatis-plus_3.1.2
|
- 微服务框架: Spring Cloud Alibaba 2.2.3.RELEASE
|
||||||
|
|
||||||
- 安全框架:Apache Shiro 1.4.0,Jwt_3.7.0
|
- 持久层框架:Mybatis-plus 3.4.1
|
||||||
|
|
||||||
- 数据库连接池:阿里巴巴Druid 1.1.10
|
- 安全框架:Apache Shiro 1.7.0,Jwt 3.11.0
|
||||||
|
|
||||||
|
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
||||||
|
|
||||||
|
- 数据库连接池:阿里巴巴Druid 1.1.22
|
||||||
|
|
||||||
- 缓存框架:redis
|
- 缓存框架:redis
|
||||||
|
|
||||||
@ -158,6 +169,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 功能模块
|
### 功能模块
|
||||||
```
|
```
|
||||||
├─系统管理
|
├─系统管理
|
||||||
@ -167,16 +179,17 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│ ├─权限设置(支持按钮权限、数据权限)
|
│ ├─权限设置(支持按钮权限、数据权限)
|
||||||
│ ├─表单权限(控制字段禁用、隐藏)
|
│ ├─表单权限(控制字段禁用、隐藏)
|
||||||
│ ├─部门管理
|
│ ├─部门管理
|
||||||
|
│ ├─我的部门(二级管理员)
|
||||||
│ └─字典管理
|
│ └─字典管理
|
||||||
│ └─树分类字典
|
│ └─分类字典
|
||||||
│ └─系统公告
|
│ └─系统公告
|
||||||
│ └─我的组织机构
|
|
||||||
│ └─职务管理
|
│ └─职务管理
|
||||||
│ └─通讯录
|
│ └─通讯录
|
||||||
|
│ └─多租户管理
|
||||||
├─消息中心
|
├─消息中心
|
||||||
│ ├─消息管理
|
│ ├─消息管理
|
||||||
│ ├─模板管理
|
│ ├─模板管理
|
||||||
├─智能化功能
|
├─代码生成器(低代码)
|
||||||
│ ├─代码生成器功能(一键生成前后端代码,生成后无需修改直接用,绝对是后端开发福音)
|
│ ├─代码生成器功能(一键生成前后端代码,生成后无需修改直接用,绝对是后端开发福音)
|
||||||
│ ├─代码生成器模板(提供4套模板,分别支持单表和一对多模型,不同风格选择)
|
│ ├─代码生成器模板(提供4套模板,分别支持单表和一对多模型,不同风格选择)
|
||||||
│ ├─代码生成器模板(生成代码,自带excel导入导出)
|
│ ├─代码生成器模板(生成代码,自带excel导入导出)
|
||||||
@ -185,6 +198,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│ ├─Excel导入导出工具集成(支持单表,一对多 导入导出)
|
│ ├─Excel导入导出工具集成(支持单表,一对多 导入导出)
|
||||||
│ ├─平台移动自适应支持
|
│ ├─平台移动自适应支持
|
||||||
├─系统监控
|
├─系统监控
|
||||||
|
│ ├─Gateway路由网关
|
||||||
│ ├─性能扫描监控
|
│ ├─性能扫描监控
|
||||||
│ │ ├─监控 Redis
|
│ │ ├─监控 Redis
|
||||||
│ │ ├─Tomcat
|
│ │ ├─Tomcat
|
||||||
@ -216,6 +230,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│─常用示例
|
│─常用示例
|
||||||
│ ├─自定义组件
|
│ ├─自定义组件
|
||||||
│ ├─对象存储(对接阿里云)
|
│ ├─对象存储(对接阿里云)
|
||||||
|
│ ├─JVXETable示例(各种复杂ERP布局示例)
|
||||||
│ ├─单表模型例子
|
│ ├─单表模型例子
|
||||||
│ └─一对多模型例子
|
│ └─一对多模型例子
|
||||||
│ └─打印例子
|
│ └─打印例子
|
||||||
@ -263,13 +278,19 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│ ├─提供单点登录CAS集成方案
|
│ ├─提供单点登录CAS集成方案
|
||||||
│ ├─提供APP发布方案
|
│ ├─提供APP发布方案
|
||||||
│ ├─集成Websocket消息通知机制
|
│ ├─集成Websocket消息通知机制
|
||||||
├─Online在线低代码开发(暂未开源)
|
├─Online在线开发(低代码)
|
||||||
│ ├─Online在线表单 - 功能已开放
|
│ ├─Online在线表单 - 功能已开放
|
||||||
│ ├─在线代码生成器 - 功能已开放
|
│ ├─Online代码生成器 - 功能已开放
|
||||||
│ ├─Online在线报表 - 功能已开放
|
│ ├─Online在线报表 - 功能已开放
|
||||||
│ ├─Online在线图表
|
│ ├─Online在线图表(暂不开源)
|
||||||
│ ├─Online图表模板配置
|
│ ├─Online图表模板配置(暂不开源)
|
||||||
│ ├─高级表单设计器
|
│ ├─Online布局设计(暂不开源)
|
||||||
|
│ ├─多数据源管理 - 功能已开放
|
||||||
|
├─积木报表设计器(低代码)
|
||||||
|
│ ├─打印设计器
|
||||||
|
│ ├─数据报表设计
|
||||||
|
│ ├─图形报表设计(支持echart)
|
||||||
|
│ ├─大屏设计器(暂不开源)
|
||||||
│─流程模块功能 (暂不开源)
|
│─流程模块功能 (暂不开源)
|
||||||
│ ├─流程设计器
|
│ ├─流程设计器
|
||||||
│ ├─在线表单设计
|
│ ├─在线表单设计
|
||||||
@ -288,9 +309,47 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 微服务整体解决方案(2.4+版本)
|
||||||
|
|
||||||
|
|
||||||
|
1、服务注册和发现 Nacos √
|
||||||
|
|
||||||
|
2、统一配置中心 Nacos √
|
||||||
|
|
||||||
|
3、路由网关 gateway(三种加载方式) √
|
||||||
|
|
||||||
|
4、分布式 http feign √
|
||||||
|
|
||||||
|
5、熔断和降级 Sentinel √
|
||||||
|
|
||||||
|
6、分布式文件 Minio、阿里OSS √
|
||||||
|
|
||||||
|
7、统一权限控制 JWT + Shiro √
|
||||||
|
|
||||||
|
8、服务监控 SpringBootAdmin√
|
||||||
|
|
||||||
|
9、链路跟踪 Skywalking [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1771670)
|
||||||
|
|
||||||
|
10、消息中间件 RabbitMQ √
|
||||||
|
|
||||||
|
11、分布式任务 xxl-job √
|
||||||
|
|
||||||
|
12、分布式事务 Seata
|
||||||
|
|
||||||
|
13、分布式日志 elk + kafka
|
||||||
|
|
||||||
|
14、支持 docker-compose、k8s、jenkins
|
||||||
|
|
||||||
|
15、CAS 单点登录 √
|
||||||
|
|
||||||
|
16、路由限流 √
|
||||||
|
|
||||||
|
|
||||||
|
#### 微服务架构图
|
||||||
|

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

|

|
||||||
|
|
||||||
|
|
||||||
后台开发环境和依赖
|
后台开发环境和依赖
|
||||||
@ -300,7 +359,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
- jdk8
|
- jdk8
|
||||||
- mysql
|
- mysql
|
||||||
- redis
|
- redis
|
||||||
- 数据库脚本:jeecg-boot\docs\jeecg-boot-mysql.sql
|
- 数据库脚本:jeecg-boot/db/jeecgboot-mysql-5.7.sql
|
||||||
- 默认登录账号: admin/123456
|
- 默认登录账号: admin/123456
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3
ant-design-vue-jeecg/.env
Normal file
3
ant-design-vue-jeecg/.env
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
NODE_ENV=production
|
||||||
|
VUE_APP_PLATFORM_NAME=JeecgBoot 企业级低代码平台
|
||||||
|
VUE_APP_SSO=false
|
||||||
4
ant-design-vue-jeecg/.env.development
Normal file
4
ant-design-vue-jeecg/.env.development
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
NODE_ENV=development
|
||||||
|
VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot
|
||||||
|
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
|
||||||
|
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
|
||||||
4
ant-design-vue-jeecg/.env.production
Normal file
4
ant-design-vue-jeecg/.env.production
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
NODE_ENV=production
|
||||||
|
VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot
|
||||||
|
VUE_APP_CAS_BASE_URL=http://localhost:8888/cas
|
||||||
|
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
|
||||||
4
ant-design-vue-jeecg/.env.test
Normal file
4
ant-design-vue-jeecg/.env.test
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
NODE_ENV=production
|
||||||
|
VUE_APP_API_BASE_URL=http://boot.jeecg.com:8080/jeecg-boot
|
||||||
|
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
|
||||||
|
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
|
||||||
@ -1,13 +1,13 @@
|
|||||||
Ant Design Jeecg Vue
|
Ant Design Jeecg Vue
|
||||||
====
|
====
|
||||||
|
|
||||||
当前最新版本: 2.2.1(发布日期:20200713)
|
当前最新版本: 2.4.5(发布日期:20210607)
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
----
|
----
|
||||||
|
|
||||||
基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Ant Design Pro Vue 版
|
基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Ant Design Pro Vue 版
|
||||||
Jeecg-boot 的前段UI框架,采用前后端分离方案,提供强大代码生成器的快速开发平台。
|
Jeecg-boot 的前端UI框架,采用前后端分离方案,提供强大代码生成器的低代码平台。
|
||||||
前端页面代码和后端功能代码一键生成,不需要写任何代码,保持jeecg一贯的强大!!
|
前端页面代码和后端功能代码一键生成,不需要写任何代码,保持jeecg一贯的强大!!
|
||||||
|
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ Docker 镜像使用
|
|||||||
|
|
||||||
```
|
```
|
||||||
# 1.修改前端项目的后台域名
|
# 1.修改前端项目的后台域名
|
||||||
public/index.html
|
.env.development
|
||||||
域名改成: http://jeecg-boot-system:8080/jeecg-boot
|
域名改成: http://jeecg-boot-system:8080/jeecg-boot
|
||||||
|
|
||||||
# 2.先进入打包前端项目
|
# 2.先进入打包前端项目
|
||||||
|
|||||||
@ -1,17 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-antd-jeecg",
|
"name": "vue-antd-jeecg",
|
||||||
"version": "2.2.1",
|
"version": "2.4.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || 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:test": "vue-cli-service build --mode test",
|
||||||
"build": "vue-cli-service build",
|
"build": "vue-cli-service build",
|
||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ant-design-vue": "^1.6.3",
|
"ant-design-vue": "^1.7.2",
|
||||||
|
"@jeecg/antd-online-mini": "2.4.5-RC",
|
||||||
"@antv/data-set": "^0.11.4",
|
"@antv/data-set": "^0.11.4",
|
||||||
"@jeecg/antd-online-mini": "2.2.12",
|
|
||||||
"viser-vue": "^2.4.8",
|
"viser-vue": "^2.4.8",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"dayjs": "^1.8.0",
|
"dayjs": "^1.8.0",
|
||||||
@ -39,7 +40,11 @@
|
|||||||
"@toast-ui/editor": "^2.1.2",
|
"@toast-ui/editor": "^2.1.2",
|
||||||
"vue-area-linkage": "^5.1.0",
|
"vue-area-linkage": "^5.1.0",
|
||||||
"area-data": "^5.0.6",
|
"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",
|
||||||
|
"cron-parser": "^2.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/polyfill": "^7.2.5",
|
"@babel/polyfill": "^7.2.5",
|
||||||
@ -48,13 +53,13 @@
|
|||||||
"@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": "7.2.3",
|
"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"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"root": true,
|
"root": true,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
4
ant-design-vue-jeecg/public/color.less
vendored
4
ant-design-vue-jeecg/public/color.less
vendored
@ -2421,7 +2421,9 @@ a.listItemMetaTitle {
|
|||||||
color: rgba(0, 0, 0, 0.85);
|
color: rgba(0, 0, 0, 0.85);
|
||||||
}
|
}
|
||||||
.main {
|
.main {
|
||||||
background-color: #fff;
|
//update-begin---author:liusq Date:20210108 for:[JT-409]编译主题色,然后退出登录后的首页是这样子------------
|
||||||
|
//background-color: #fff;
|
||||||
|
//update-end---author:liusq Date:20210108 for:[JT-409]编译主题色,然后退出登录后的首页是这样子------------
|
||||||
}
|
}
|
||||||
.main .leftmenu {
|
.main .leftmenu {
|
||||||
border-right: 1px solid #e8e8e8;
|
border-right: 1px solid #e8e8e8;
|
||||||
|
|||||||
13
ant-design-vue-jeecg/public/index.html
vendored
13
ant-design-vue-jeecg/public/index.html
vendored
@ -5,9 +5,9 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<title>Jeecg-Boot 企业级快速开发平台</title>
|
<title>JeecgBoot 企业级低代码平台</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="<%= BASE_URL %>cdn/babel-polyfill/polyfill_7_2_5.js"></script>
|
||||||
<style>
|
<style>
|
||||||
html,
|
html,
|
||||||
body,
|
body,
|
||||||
@ -242,23 +242,16 @@
|
|||||||
<!-- 全局配置 -->
|
<!-- 全局配置 -->
|
||||||
<script>
|
<script>
|
||||||
window._CONFIG = {};
|
window._CONFIG = {};
|
||||||
window._CONFIG['domianURL'] = 'http://127.0.0.1:8080/jeecg-boot';
|
|
||||||
window._CONFIG['casPrefixUrl'] = 'http://cas.example.org:8443/cas';
|
|
||||||
window._CONFIG['onlinePreviewDomainURL'] = 'http://fileview.jeecg.com/onlinePreview'
|
|
||||||
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';
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- built files will be auto injected -->
|
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<div id="loader-wrapper">
|
<div id="loader-wrapper">
|
||||||
<div id="loader"></div>
|
<div id="loader"></div>
|
||||||
<div class="loader-section section-left"></div>
|
<div class="loader-section section-left"></div>
|
||||||
<div class="loader-section section-right"></div>
|
<div class="loader-section section-right"></div>
|
||||||
<div class="load_title">正在加载 Jeecg-Boot 快速开发平台,请耐心等待
|
<div class="load_title">正在加载 JeecgBoot 低代码平台,请耐心等待
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -23,23 +23,22 @@ 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)
|
||||||
|
|
||||||
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/getUserPermissionByToken",params);
|
const queryPermissionsByUser = ()=>getAction("/sys/permission/getUserPermissionByToken");
|
||||||
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);
|
||||||
const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params);
|
const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params);
|
||||||
|
|
||||||
// 部门管理
|
// 部门管理
|
||||||
const queryDepartTreeList = (params)=>getAction("/sys/sysDepart/queryTreeList",params);
|
const queryDepartTreeList = (params)=>getAction("/sys/sysDepart/queryTreeList",params);
|
||||||
|
const queryDepartTreeSync = (params)=>getAction("/sys/sysDepart/queryDepartTreeSync",params);
|
||||||
const queryIdTree = (params)=>getAction("/sys/sysDepart/queryIdTree",params);
|
const queryIdTree = (params)=>getAction("/sys/sysDepart/queryIdTree",params);
|
||||||
const queryParentName = (params)=>getAction("/sys/sysDepart/queryParentName",params);
|
const queryParentName = (params)=>getAction("/sys/sysDepart/queryParentName",params);
|
||||||
const searchByKeywords = (params)=>getAction("/sys/sysDepart/searchBy",params);
|
const searchByKeywords = (params)=>getAction("/sys/sysDepart/searchBy",params);
|
||||||
@ -54,7 +53,6 @@ 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);
|
||||||
|
|
||||||
@ -71,7 +69,7 @@ export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItem
|
|||||||
function getDictItemsFromCache(dictCode) {
|
function getDictItemsFromCache(dictCode) {
|
||||||
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]) {
|
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]) {
|
||||||
let dictItems = Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode];
|
let dictItems = Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode];
|
||||||
console.log("-----------getDictItemsFromCache----------dictCode="+dictCode+"---- dictItems=",dictItems)
|
//console.log("-----------getDictItemsFromCache----------dictCode="+dictCode+"---- dictItems=",dictItems)
|
||||||
return dictItems;
|
return dictItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,6 +101,8 @@ export const transitRESTful = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
// imgView,
|
||||||
|
// doMian,
|
||||||
addRole,
|
addRole,
|
||||||
editRole,
|
editRole,
|
||||||
checkRoleCode,
|
checkRoleCode,
|
||||||
@ -126,6 +126,7 @@ export {
|
|||||||
getPermissionRuleList,
|
getPermissionRuleList,
|
||||||
queryPermissionRule,
|
queryPermissionRule,
|
||||||
queryDepartTreeList,
|
queryDepartTreeList,
|
||||||
|
queryDepartTreeSync,
|
||||||
queryIdTree,
|
queryIdTree,
|
||||||
queryParentName,
|
queryParentName,
|
||||||
searchByKeywords,
|
searchByKeywords,
|
||||||
|
|||||||
@ -36,15 +36,15 @@ export function getSmsCaptcha(parameter) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInfo() {
|
// export function getInfo() {
|
||||||
return axios({
|
// return axios({
|
||||||
url: '/api/user/info',
|
// url: '/api/user/info',
|
||||||
method: 'get',
|
// method: 'get',
|
||||||
headers: {
|
// headers: {
|
||||||
'Content-Type': 'application/json;charset=UTF-8'
|
// 'Content-Type': 'application/json;charset=UTF-8'
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function logout(logoutToken) {
|
export function logout(logoutToken) {
|
||||||
return axios({
|
return axios({
|
||||||
@ -60,14 +60,28 @@ export function logout(logoutToken) {
|
|||||||
/**
|
/**
|
||||||
* 第三方登录
|
* 第三方登录
|
||||||
* @param token
|
* @param token
|
||||||
|
* @param thirdType
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export function thirdLogin(token) {
|
export function thirdLogin(token,thirdType) {
|
||||||
return axios({
|
return axios({
|
||||||
url: `/thirdLogin/getLoginUser/${token}`,
|
url: `/sys/thirdLogin/getLoginUser/${token}/${thirdType}`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json;charset=UTF-8'
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强退其他账号
|
||||||
|
* @param token
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export function forceLogout(parameter) {
|
||||||
|
return axios({
|
||||||
|
url: '/sys/online/forceLogout',
|
||||||
|
method: 'post',
|
||||||
|
data: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,31 +1,42 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { axios } from '@/utils/request'
|
import { axios } from '@/utils/request'
|
||||||
|
import signMd5Utils from '@/utils/encryption/signMd5Utils'
|
||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
user: '/api/user',
|
user: '/mock/api/user',
|
||||||
role: '/api/role',
|
role: '/mock/api/role',
|
||||||
service: '/api/service',
|
service: '/mock/api/service',
|
||||||
permission: '/api/permission',
|
permission: '/mock/api/permission',
|
||||||
permissionNoPager: '/api/permission/no-pager'
|
permissionNoPager: '/mock/api/permission/no-pager'
|
||||||
}
|
}
|
||||||
|
|
||||||
export default api
|
export default api
|
||||||
|
|
||||||
//post
|
//post
|
||||||
export function postAction(url,parameter) {
|
export function postAction(url,parameter) {
|
||||||
|
let sign = signMd5Utils.getSign(url, parameter);
|
||||||
|
//将签名和时间戳,添加在请求接口 Header
|
||||||
|
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
||||||
|
|
||||||
return axios({
|
return axios({
|
||||||
url: url,
|
url: url,
|
||||||
method:'post' ,
|
method:'post' ,
|
||||||
data: parameter
|
data: parameter,
|
||||||
|
headers: signHeader
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//post method= {post | put}
|
//post method= {post | put}
|
||||||
export function httpAction(url,parameter,method) {
|
export function httpAction(url,parameter,method) {
|
||||||
|
let sign = signMd5Utils.getSign(url, parameter);
|
||||||
|
//将签名和时间戳,添加在请求接口 Header
|
||||||
|
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
||||||
|
|
||||||
return axios({
|
return axios({
|
||||||
url: url,
|
url: url,
|
||||||
method:method ,
|
method:method ,
|
||||||
data: parameter
|
data: parameter,
|
||||||
|
headers: signHeader
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +51,15 @@ export function putAction(url,parameter) {
|
|||||||
|
|
||||||
//get
|
//get
|
||||||
export function getAction(url,parameter) {
|
export function getAction(url,parameter) {
|
||||||
|
let sign = signMd5Utils.getSign(url, parameter);
|
||||||
|
//将签名和时间戳,添加在请求接口 Header
|
||||||
|
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
||||||
|
|
||||||
return axios({
|
return axios({
|
||||||
url: url,
|
url: url,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: parameter
|
params: parameter,
|
||||||
|
headers: signHeader
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +183,7 @@ export function uploadAction(url,parameter){
|
|||||||
*/
|
*/
|
||||||
export function getFileAccessHttpUrl(avatar,subStr) {
|
export function getFileAccessHttpUrl(avatar,subStr) {
|
||||||
if(!subStr) subStr = 'http'
|
if(!subStr) subStr = 'http'
|
||||||
|
try {
|
||||||
if(avatar && avatar.startsWith(subStr)){
|
if(avatar && avatar.startsWith(subStr)){
|
||||||
return avatar;
|
return avatar;
|
||||||
}else{
|
}else{
|
||||||
@ -174,4 +191,7 @@ export function getFileAccessHttpUrl(avatar,subStr) {
|
|||||||
return window._CONFIG['staticDomainURL'] + "/" + avatar;
|
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}
|
||||||
@ -5,21 +5,25 @@ import store from '@/store'
|
|||||||
* 单点登录
|
* 单点登录
|
||||||
*/
|
*/
|
||||||
const init = (callback) => {
|
const init = (callback) => {
|
||||||
|
if (process.env.VUE_APP_SSO == 'true') {
|
||||||
console.log("-------单点登录开始-------");
|
console.log("-------单点登录开始-------");
|
||||||
let token = Vue.ls.get(ACCESS_TOKEN);
|
let token = Vue.ls.get(ACCESS_TOKEN);
|
||||||
let st = getUrlParam("ticket");
|
let st = getUrlParam("ticket");
|
||||||
let sevice = "http://"+window.location.host+"/";
|
let sevice = "http://" + window.location.host + "/";
|
||||||
if(token){
|
if (token) {
|
||||||
loginSuccess(callback);
|
loginSuccess(callback);
|
||||||
}else{
|
} else {
|
||||||
if(st){
|
if (st) {
|
||||||
validateSt(st,sevice,callback);
|
validateSt(st, sevice, callback);
|
||||||
}else{
|
} else {
|
||||||
let serviceUrl = encodeURIComponent(sevice);
|
let serviceUrl = encodeURIComponent(sevice);
|
||||||
window.location.href = window._CONFIG['casPrefixUrl']+"/login?service="+serviceUrl;
|
window.location.href = window._CONFIG['casPrefixUrl'] + "/login?service=" + serviceUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("-------单点登录结束-------");
|
console.log("-------单点登录结束-------");
|
||||||
|
}else{
|
||||||
|
callback && callback()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const SSO = {
|
const SSO = {
|
||||||
init: init
|
init: init
|
||||||
|
|||||||
217
ant-design-vue-jeecg/src/components/JVxeCells/JVxeFileCell.vue
Normal file
217
ant-design-vue-jeecg/src/components/JVxeCells/JVxeFileCell.vue
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
<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(originColumn)">
|
||||||
|
<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" :number="number"/>
|
||||||
|
</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,
|
||||||
|
number:0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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(originColumn) {
|
||||||
|
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number,用于控制上传文件
|
||||||
|
if (originColumn.number) {
|
||||||
|
this.number = originColumn.number
|
||||||
|
} else {
|
||||||
|
this.number = 0
|
||||||
|
}
|
||||||
|
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number,用于控制上传文件
|
||||||
|
if(originColumn && originColumn.fieldExtendJson){
|
||||||
|
let json = JSON.parse(originColumn.fieldExtendJson);
|
||||||
|
this.number = json.uploadnum?json.uploadnum:0;
|
||||||
|
}
|
||||||
|
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>
|
||||||
242
ant-design-vue-jeecg/src/components/JVxeCells/JVxeImageCell.vue
Normal file
242
ant-design-vue-jeecg/src/components/JVxeCells/JVxeImageCell.vue
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
<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(originColumn)">
|
||||||
|
<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" :number="number"/>
|
||||||
|
</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,
|
||||||
|
number:0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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(originColumn) {
|
||||||
|
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number,用于控制上传文件
|
||||||
|
if (originColumn.number) {
|
||||||
|
this.number = originColumn.number
|
||||||
|
} else {
|
||||||
|
this.number = 0
|
||||||
|
}
|
||||||
|
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number,用于控制上传文件
|
||||||
|
if(originColumn && originColumn.fieldExtendJson){
|
||||||
|
let json = JSON.parse(originColumn.fieldExtendJson);
|
||||||
|
this.number = json.uploadnum?json.uploadnum:0;
|
||||||
|
}
|
||||||
|
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,63 @@
|
|||||||
|
<template>
|
||||||
|
<j-popup
|
||||||
|
v-bind="popupProps"
|
||||||
|
@input="handlePopupInput"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins, { dispatchEvent, vModel } 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,
|
||||||
|
param: col.param,
|
||||||
|
sorter: col.sorter,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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.call(this, 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,262 @@
|
|||||||
|
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.call(this, 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)
|
||||||
@ -39,5 +39,5 @@ UserMenu.vue:首页右上侧的内容
|
|||||||

|

|
||||||
####16.trend包 趋势显示组件(如下图)
|
####16.trend包 趋势显示组件(如下图)
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
@ -12,13 +12,13 @@ export default class Area {
|
|||||||
let arr = []
|
let arr = []
|
||||||
const province = pcaa['86']
|
const province = pcaa['86']
|
||||||
Object.keys(province).map(key=>{
|
Object.keys(province).map(key=>{
|
||||||
arr.push({id:key, text:province[key], pid:'86'});
|
arr.push({id:key, text:province[key], pid:'86', index:1});
|
||||||
const city = pcaa[key];
|
const city = pcaa[key];
|
||||||
Object.keys(city).map(key2=>{
|
Object.keys(city).map(key2=>{
|
||||||
arr.push({id:key2, text:city[key2], pid:key});
|
arr.push({id:key2, text:city[key2], pid:key, index:2});
|
||||||
const qu = pcaa[key2];
|
const qu = pcaa[key2];
|
||||||
Object.keys(qu).map(key3=>{
|
Object.keys(qu).map(key3=>{
|
||||||
arr.push({id:key3, text:qu[key3], pid:key2});
|
arr.push({id:key3, text:qu[key3], pid:key2, index:3});
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -45,33 +45,35 @@ export default class Area {
|
|||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
let arr = []
|
let arr = []
|
||||||
this.getAreaBycode(code,arr);
|
this.getAreaBycode(code, arr, 3);
|
||||||
return arr.join('/')
|
return arr.join('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
getRealCode(code){
|
getRealCode(code){
|
||||||
let arr = []
|
let arr = []
|
||||||
this.getPcode(code, arr)
|
this.getPcode(code, arr, 3)
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPcode(id, arr){
|
getPcode(id, arr, index){
|
||||||
for(let item of this.all){
|
for(let item of this.all){
|
||||||
if(item.id === id){
|
if(item.id === id && item.index == index){
|
||||||
arr.unshift(id)
|
arr.unshift(id)
|
||||||
if(item.pid != '86'){
|
if(item.pid != '86'){
|
||||||
this.getPcode(item.pid,arr)
|
this.getPcode(item.pid, arr, --index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getAreaBycode(code,arr){
|
getAreaBycode(code, arr, index){
|
||||||
//console.log("this.all.length",this.all)
|
|
||||||
for(let item of this.all){
|
for(let item of this.all){
|
||||||
if(item.id === code){
|
if(item.id === code && item.index == index){
|
||||||
arr.unshift(item.text);
|
arr.unshift(item.text);
|
||||||
this.getAreaBycode(item.pid,arr)
|
if(item.pid != '86'){
|
||||||
|
this.getAreaBycode(item.pid, arr, --index)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
props: {
|
props: {
|
||||||
dictCode: String,
|
dictCode: String,
|
||||||
placeholder: String,
|
placeholder: String,
|
||||||
triggerChange: Boolean,
|
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
value: [String, Number],
|
value: [String, Number],
|
||||||
type: String,
|
type: String,
|
||||||
@ -82,19 +81,15 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
handleInput(e) {
|
handleInput(e='') {
|
||||||
let val;
|
let val;
|
||||||
if(this.tagType=="radio"){
|
if(Object.keys(e).includes('target')){
|
||||||
val = e.target.value
|
val = e.target.value
|
||||||
}else{
|
}else{
|
||||||
val = e
|
val = e
|
||||||
}
|
}
|
||||||
console.log(val);
|
console.log(val);
|
||||||
if(this.triggerChange){
|
|
||||||
this.$emit('change', val);
|
this.$emit('change', val);
|
||||||
}else{
|
|
||||||
this.$emit('input', val);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
setCurrentDictOptions(dictOptions){
|
setCurrentDictOptions(dictOptions){
|
||||||
this.dictOptions = dictOptions
|
this.dictOptions = dictOptions
|
||||||
@ -102,6 +97,10 @@
|
|||||||
getCurrentDictOptions(){
|
getCurrentDictOptions(){
|
||||||
return this.dictOptions
|
return this.dictOptions
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
model:{
|
||||||
|
prop: 'value',
|
||||||
|
event: 'change'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -10,7 +10,9 @@
|
|||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:getPopupContainer="(node) => node.parentNode"
|
:getPopupContainer="getParentContainer"
|
||||||
|
optionFilterProp="children"
|
||||||
|
:filterOption="filterOption"
|
||||||
allowClear>
|
allowClear>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="(item,index) in dictOptions"
|
v-for="(item,index) in dictOptions"
|
||||||
@ -34,13 +36,23 @@
|
|||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
value: String,
|
value: String,
|
||||||
type: String,
|
type: String,
|
||||||
options:Array
|
options:Array,
|
||||||
|
spliter:{
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ','
|
||||||
|
},
|
||||||
|
popContainer:{
|
||||||
|
type:String,
|
||||||
|
default:'',
|
||||||
|
required:false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dictOptions: [],
|
dictOptions: [],
|
||||||
tagType:"",
|
tagType:"",
|
||||||
arrayValue:!this.value?[]:this.value.split(",")
|
arrayValue:!this.value?[]:this.value.split(this.spliter)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -66,7 +78,7 @@
|
|||||||
if(!val){
|
if(!val){
|
||||||
this.arrayValue = []
|
this.arrayValue = []
|
||||||
}else{
|
}else{
|
||||||
this.arrayValue = this.value.split(",")
|
this.arrayValue = this.value.split(this.spliter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -76,8 +88,9 @@
|
|||||||
this.dictOptions = [...this.options]
|
this.dictOptions = [...this.options]
|
||||||
}else{
|
}else{
|
||||||
//优先从缓存中读取字典配置
|
//优先从缓存中读取字典配置
|
||||||
if(getDictItemsFromCache(this.dictCode)){
|
let cacheOption = getDictItemsFromCache(this.dictCode)
|
||||||
this.dictOptions = getDictItemsFromCache(this.dictCode);
|
if(cacheOption && cacheOption.length>0){
|
||||||
|
this.dictOptions = cacheOption
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//根据字典Code, 初始化字典数组
|
//根据字典Code, 初始化字典数组
|
||||||
@ -90,15 +103,27 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
onChange (selectedValue) {
|
onChange (selectedValue) {
|
||||||
this.$emit('change', selectedValue.join(","));
|
this.$emit('change', selectedValue.join(this.spliter));
|
||||||
},
|
},
|
||||||
setCurrentDictOptions(dictOptions){
|
setCurrentDictOptions(dictOptions){
|
||||||
this.dictOptions = dictOptions
|
this.dictOptions = dictOptions
|
||||||
},
|
},
|
||||||
getCurrentDictOptions(){
|
getCurrentDictOptions(){
|
||||||
return this.dictOptions
|
return this.dictOptions
|
||||||
|
},
|
||||||
|
getParentContainer(node){
|
||||||
|
if(!this.popContainer){
|
||||||
|
return node.parentNode
|
||||||
|
}else{
|
||||||
|
return document.querySelector(this.popContainer)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// update--begin--autor:lvdandan-----date:20201120------for:LOWCOD-1086 下拉多选框,搜索时只字典code进行搜索不能通过字典text搜索
|
||||||
|
filterOption(input, option) {
|
||||||
|
return option.componentOptions.children[0].children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
}
|
||||||
|
// update--end--autor:lvdandan-----date:20201120------for:LOWCOD-1086 下拉多选框,搜索时只字典code进行搜索不能通过字典text搜索
|
||||||
|
},
|
||||||
model: {
|
model: {
|
||||||
prop: 'value',
|
prop: 'value',
|
||||||
event: 'change'
|
event: 'change'
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
showSearch
|
showSearch
|
||||||
labelInValue
|
labelInValue
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:getPopupContainer="(node) => node.parentNode"
|
:getPopupContainer="getParentContainer"
|
||||||
@search="loadData"
|
@search="loadData"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
v-model="selectedAsyncValue"
|
v-model="selectedAsyncValue"
|
||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<a-select
|
<a-select
|
||||||
v-else
|
v-else
|
||||||
:getPopupContainer="(node) => node.parentNode"
|
:getPopupContainer="getParentContainer"
|
||||||
showSearch
|
showSearch
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@ -55,7 +55,21 @@
|
|||||||
type:String,
|
type:String,
|
||||||
default:"请选择",
|
default:"请选择",
|
||||||
required:false
|
required:false
|
||||||
}
|
},
|
||||||
|
popContainer:{
|
||||||
|
type:String,
|
||||||
|
default:'',
|
||||||
|
required:false
|
||||||
|
},
|
||||||
|
pageSize:{
|
||||||
|
type: Number,
|
||||||
|
default: 10,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
getPopupContainer: {
|
||||||
|
type:Function,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
this.loadData = debounce(this.loadData, 800);//消抖
|
this.loadData = debounce(this.loadData, 800);//消抖
|
||||||
@ -90,6 +104,14 @@
|
|||||||
handler(){
|
handler(){
|
||||||
this.initDictData()
|
this.initDictData()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'dictOptions':{
|
||||||
|
deep: true,
|
||||||
|
handler(val){
|
||||||
|
if(val && val.length>0){
|
||||||
|
this.options = [...val]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
@ -118,7 +140,7 @@
|
|||||||
this.options = []
|
this.options = []
|
||||||
this.loading=true
|
this.loading=true
|
||||||
// 字典code格式:table,text,code
|
// 字典code格式:table,text,code
|
||||||
getAction(`/sys/dict/loadDict/${this.dict}`,{keyword:value}).then(res=>{
|
getAction(`/sys/dict/loadDict/${this.dict}`,{keyword:value, pageSize: this.pageSize}).then(res=>{
|
||||||
this.loading=false
|
this.loading=false
|
||||||
if(res.success){
|
if(res.success){
|
||||||
if(currentLoad!=this.lastLoad){
|
if(currentLoad!=this.lastLoad){
|
||||||
@ -163,6 +185,17 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
//异步一开始也加载一点数据
|
||||||
|
this.loading=true
|
||||||
|
getAction(`/sys/dict/loadDict/${this.dict}`,{pageSize: this.pageSize, keyword:''}).then(res=>{
|
||||||
|
this.loading=false
|
||||||
|
if(res.success){
|
||||||
|
this.options = res.result
|
||||||
|
}else{
|
||||||
|
this.$message.warning(res.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
filterOption(input, option) {
|
filterOption(input, option) {
|
||||||
@ -174,9 +207,18 @@
|
|||||||
this.callback()
|
this.callback()
|
||||||
},
|
},
|
||||||
handleAsyncChange(selectedObj){
|
handleAsyncChange(selectedObj){
|
||||||
|
//update-begin-author:scott date:20201222 for:【搜索】搜索查询组件,删除条件,默认下拉还是上次的缓存数据,不好 JT-191
|
||||||
|
if(selectedObj){
|
||||||
this.selectedAsyncValue = selectedObj
|
this.selectedAsyncValue = selectedObj
|
||||||
this.selectedValue = selectedObj.key
|
this.selectedValue = selectedObj.key
|
||||||
|
}else{
|
||||||
|
this.selectedAsyncValue = null
|
||||||
|
this.selectedValue = null
|
||||||
|
this.options = null
|
||||||
|
this.loadData("")
|
||||||
|
}
|
||||||
this.callback()
|
this.callback()
|
||||||
|
//update-end-author:scott date:20201222 for:【搜索】搜索查询组件,删除条件,默认下拉还是上次的缓存数据,不好 JT-191
|
||||||
},
|
},
|
||||||
callback(){
|
callback(){
|
||||||
this.$emit('change', this.selectedValue);
|
this.$emit('change', this.selectedValue);
|
||||||
@ -186,7 +228,16 @@
|
|||||||
},
|
},
|
||||||
getCurrentDictOptions(){
|
getCurrentDictOptions(){
|
||||||
return this.options
|
return this.options
|
||||||
|
},
|
||||||
|
getParentContainer(node){
|
||||||
|
if(typeof this.getPopupContainer === 'function'){
|
||||||
|
return this.getPopupContainer(node)
|
||||||
|
} else if(!this.popContainer){
|
||||||
|
return node.parentNode
|
||||||
|
}else{
|
||||||
|
return document.querySelector(this.popContainer)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
|
|||||||
@ -1,7 +1,16 @@
|
|||||||
import T from './JDictSelectTag.vue'
|
import JDictSelectTag from './JDictSelectTag.vue'
|
||||||
const JDictSelectTag = {
|
import JMultiSelectTag from './JMultiSelectTag.vue'
|
||||||
|
import JSearchSelectTag from './JSearchSelectTag.vue'
|
||||||
|
import { filterMultiDictText,filterDictText,initDictOptions,filterDictTextByCache } from './JDictSelectUtil'
|
||||||
|
|
||||||
|
export default {
|
||||||
install: function (Vue) {
|
install: function (Vue) {
|
||||||
Vue.component('JDictSelectTag',T);
|
Vue.component('JDictSelectTag',JDictSelectTag);
|
||||||
|
Vue.component('JMultiSelectTag',JMultiSelectTag);
|
||||||
|
Vue.component('JSearchSelectTag',JSearchSelectTag);
|
||||||
|
Vue.prototype.$initDictOptions = (dictCode) => initDictOptions(dictCode)
|
||||||
|
Vue.prototype.$filterMultiDictText = (dictOptions, text) => filterMultiDictText(dictOptions, text)
|
||||||
|
Vue.prototype.$filterDictText = (dictOptions, text) => filterDictText(dictOptions, text)
|
||||||
|
Vue.prototype.$filterDictTextByCache = (...param) => filterDictTextByCache(...param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default JDictSelectTag;
|
|
||||||
@ -251,6 +251,9 @@
|
|||||||
},
|
},
|
||||||
style: {}
|
style: {}
|
||||||
}
|
}
|
||||||
|
if(isIE() || isIE11()){
|
||||||
|
props.style['height'] = '240px'
|
||||||
|
}
|
||||||
if (this.fullCoder) {
|
if (this.fullCoder) {
|
||||||
props.style['z-index'] = this.zIndex
|
props.style['z-index'] = this.zIndex
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="components-input-demo-presuffix">
|
<div class="components-input-demo-presuffix">
|
||||||
<a-input @click="openModal" placeholder="corn表达式" v-model="cron" @change="handleOK">
|
<a-input @click="openModal" placeholder="cron表达式" v-model="cron" @change="(e)=>handleOK(e.target.value)">
|
||||||
<a-icon slot="prefix" type="schedule" title="corn控件"/>
|
<a-icon slot="prefix" type="schedule" title="cron控件"/>
|
||||||
<a-icon v-if="cron" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
|
<a-icon v-if="cron" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
|
||||||
</a-input>
|
</a-input>
|
||||||
<JCronModal ref="innerVueCron" :data="cron" @ok="handleOK"></JCronModal>
|
<JCronModal ref="innerVueCron" :data="cron" @ok="handleOK"></JCronModal>
|
||||||
|
|||||||
246
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue
Normal file
246
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
<template>
|
||||||
|
<div class="j-easy-cron">
|
||||||
|
<div class="content">
|
||||||
|
<div>
|
||||||
|
<a-tabs size="small" v-model="curtab">
|
||||||
|
<a-tab-pane tab="秒" key="second" v-if="!hideSecond">
|
||||||
|
<second-ui v-model="second" :disabled="disabled"></second-ui>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="分" key="minute">
|
||||||
|
<minute-ui v-model="minute" :disabled="disabled"></minute-ui>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="时" key="hour">
|
||||||
|
<hour-ui v-model="hour" :disabled="disabled"></hour-ui>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="日" key="day">
|
||||||
|
<day-ui v-model="day" :week="week" :disabled="disabled"></day-ui>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="月" key="month">
|
||||||
|
<month-ui v-model="month" :disabled="disabled"></month-ui>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="周" key="week">
|
||||||
|
<week-ui v-model="week" :day="day" :disabled="disabled"></week-ui>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="年" key="year" v-if="!hideYear && !hideSecond">
|
||||||
|
<year-ui v-model="year" :disabled="disabled"></year-ui>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</div>
|
||||||
|
<a-divider/>
|
||||||
|
<!-- 执行时间预览 -->
|
||||||
|
<a-row :gutter="8">
|
||||||
|
<a-col :span="18" style="margin-top: 22px;">
|
||||||
|
<a-row :gutter="8">
|
||||||
|
<a-col :span="8" style="margin-bottom: 8px;">
|
||||||
|
<a-input addon-before="秒" v-model="inputValues.second" @blur="onInputBlur"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8" style="margin-bottom: 8px;">
|
||||||
|
<a-input addon-before="分" v-model="inputValues.minute" @blur="onInputBlur"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8" style="margin-bottom: 8px;">
|
||||||
|
<a-input addon-before="时" v-model="inputValues.hour" @blur="onInputBlur"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8" style="margin-bottom: 8px;">
|
||||||
|
<a-input addon-before="日" v-model="inputValues.day" @blur="onInputBlur"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8" style="margin-bottom: 8px;">
|
||||||
|
<a-input addon-before="月" v-model="inputValues.month" @blur="onInputBlur"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8" style="margin-bottom: 8px;">
|
||||||
|
<a-input addon-before="周" v-model="inputValues.week" @blur="onInputBlur"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="8" style="margin-bottom: 8px;">
|
||||||
|
<a-input addon-before="年" v-model="inputValues.year" @blur="onInputBlur"/>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="16" style="margin-bottom: 8px;">
|
||||||
|
<a-input addon-before="Cron" v-model="inputValues.cron" @blur="onInputCronBlur"/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
|
||||||
|
<div>近十次执行时间(不含年)</div>
|
||||||
|
<a-textarea type="textarea" :value="preTimeList" :rows="5"/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SecondUi from './tabs/second'
|
||||||
|
import MinuteUi from './tabs/minute'
|
||||||
|
import HourUi from './tabs/hour'
|
||||||
|
import DayUi from './tabs/day'
|
||||||
|
import WeekUi from './tabs/week'
|
||||||
|
import MonthUi from './tabs/month'
|
||||||
|
import YearUi from './tabs/year'
|
||||||
|
import CronParser from 'cron-parser'
|
||||||
|
import dateFormat from './format-date'
|
||||||
|
import { simpleDebounce } from '@/utils/util'
|
||||||
|
import ACol from 'ant-design-vue/es/grid/Col'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'easy-cron',
|
||||||
|
components: {
|
||||||
|
ACol,
|
||||||
|
SecondUi,
|
||||||
|
MinuteUi,
|
||||||
|
HourUi,
|
||||||
|
DayUi,
|
||||||
|
WeekUi,
|
||||||
|
MonthUi,
|
||||||
|
YearUi
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cronValue: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hideSecond: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hideYear: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
type: Function,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
curtab: this.hideSecond ? 'minute' : 'second',
|
||||||
|
second: '*',
|
||||||
|
minute: '*',
|
||||||
|
hour: '*',
|
||||||
|
day: '*',
|
||||||
|
month: '*',
|
||||||
|
week: '?',
|
||||||
|
year: '*',
|
||||||
|
inputValues: {second: '', minute: '', hour: '', day: '', month: '', week: '', year: '', cron: ''},
|
||||||
|
preTimeList: '执行预览,会忽略年份参数',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
cronValue_c() {
|
||||||
|
let result = []
|
||||||
|
if (!this.hideSecond) result.push(this.second ? this.second : '*')
|
||||||
|
result.push(this.minute ? this.minute : '*')
|
||||||
|
result.push(this.hour ? this.hour : '*')
|
||||||
|
result.push(this.day ? this.day : '*')
|
||||||
|
result.push(this.month ? this.month : '*')
|
||||||
|
result.push(this.week ? this.week : '?')
|
||||||
|
if (!this.hideYear && !this.hideSecond) result.push(this.year ? this.year : '*')
|
||||||
|
return result.join(' ')
|
||||||
|
},
|
||||||
|
cronValue_c2() {
|
||||||
|
const v = this.cronValue_c
|
||||||
|
if (this.hideYear || this.hideSecond) return v
|
||||||
|
const vs = v.split(' ')
|
||||||
|
return vs.slice(0, vs.length - 1).join(' ')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
cronValue(newVal, oldVal) {
|
||||||
|
if (newVal === this.cronValue_c) {
|
||||||
|
// console.info('same cron value: ' + newVal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.formatValue()
|
||||||
|
},
|
||||||
|
cronValue_c(newVal, oldVal) {
|
||||||
|
this.calTriggerList()
|
||||||
|
this.$emit('change', newVal)
|
||||||
|
|
||||||
|
Object.assign(this.inputValues, {
|
||||||
|
second: this.second,
|
||||||
|
minute: this.minute,
|
||||||
|
hour: this.hour,
|
||||||
|
day: this.day,
|
||||||
|
month: this.month,
|
||||||
|
week: this.week,
|
||||||
|
year: this.year,
|
||||||
|
cron: this.cronValue_c,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.formatValue()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.calTriggerListInner()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatValue() {
|
||||||
|
if (!this.cronValue) return
|
||||||
|
const values = this.cronValue.split(' ').filter(item => !!item)
|
||||||
|
if (!values || values.length <= 0) return
|
||||||
|
let i = 0
|
||||||
|
if (!this.hideSecond) this.second = values[i++]
|
||||||
|
if (values.length > i) this.minute = values[i++]
|
||||||
|
if (values.length > i) this.hour = values[i++]
|
||||||
|
if (values.length > i) this.day = values[i++]
|
||||||
|
if (values.length > i) this.month = values[i++]
|
||||||
|
if (values.length > i) this.week = values[i++]
|
||||||
|
if (values.length > i) this.year = values[i]
|
||||||
|
},
|
||||||
|
calTriggerList: simpleDebounce(function () {
|
||||||
|
this.calTriggerListInner()
|
||||||
|
}, 500),
|
||||||
|
calTriggerListInner() {
|
||||||
|
// 设置了回调函数
|
||||||
|
if (this.remote) {
|
||||||
|
this.remote(this.cronValue_c, +new Date(), v => {
|
||||||
|
this.preTimeList = v
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const format = 'yyyy-MM-dd hh:mm:ss'
|
||||||
|
const options = {
|
||||||
|
currentDate: dateFormat(new Date(), format)
|
||||||
|
}
|
||||||
|
const iter = CronParser.parseExpression(this.cronValue_c2, options)
|
||||||
|
const result = []
|
||||||
|
for (let i = 1; i <= 10; i++) {
|
||||||
|
result.push(dateFormat(new Date(iter.next()), format))
|
||||||
|
}
|
||||||
|
this.preTimeList = result.length > 0 ? result.join('\n') : '无执行时间'
|
||||||
|
},
|
||||||
|
onInputBlur(){
|
||||||
|
this.second = this.inputValues.second
|
||||||
|
this.minute = this.inputValues.minute
|
||||||
|
this.hour = this.inputValues.hour
|
||||||
|
this.day = this.inputValues.day
|
||||||
|
this.month = this.inputValues.month
|
||||||
|
this.week = this.inputValues.week
|
||||||
|
this.year = this.inputValues.year
|
||||||
|
},
|
||||||
|
onInputCronBlur(event){
|
||||||
|
this.$emit('change', event.target.value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
prop: 'cronValue',
|
||||||
|
event: 'change'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.j-easy-cron {
|
||||||
|
|
||||||
|
/deep/ .content {
|
||||||
|
.ant-checkbox-wrapper + .ant-checkbox-wrapper {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<div class="input-cron">
|
||||||
|
<a-input :placeholder="placeholder" v-model="editCronValue" :disabled="disabled">
|
||||||
|
<a slot="addonAfter" @click="showConfigDlg" class="config-btn" :disabled="disabled">
|
||||||
|
<a-icon type="setting"></a-icon>
|
||||||
|
选择
|
||||||
|
</a>
|
||||||
|
</a-input>
|
||||||
|
<j-modal :visible.sync="show" title="Cron表达式" width="800px">
|
||||||
|
<easy-cron
|
||||||
|
v-model="editCronValue"
|
||||||
|
:exeStartTime="exeStartTime"
|
||||||
|
:hideYear="hideYear"
|
||||||
|
:remote="remote"
|
||||||
|
:hideSecond="hideSecond"
|
||||||
|
style="width: 100%"
|
||||||
|
></easy-cron>
|
||||||
|
</j-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import EasyCron from './EasyCron.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'input-cron',
|
||||||
|
components: {EasyCron},
|
||||||
|
model: {
|
||||||
|
prop: 'cronValue',
|
||||||
|
event: 'change'
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cronValue: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '800px'
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入cron表达式'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
exeStartTime: {
|
||||||
|
type: [Number, String, Object],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
hideSecond: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hideYear: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
type: Function,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editCronValue: this.cronValue,
|
||||||
|
show: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
cronValue(newVal, oldVal) {
|
||||||
|
if (newVal === this.editCronValue) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.editCronValue = newVal
|
||||||
|
},
|
||||||
|
editCronValue(newVal, oldVal) {
|
||||||
|
this.$emit('change', newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showConfigDlg() {
|
||||||
|
if (!this.disabled) {
|
||||||
|
this.show = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.config-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
const dateFormat = (date, block) => {
|
||||||
|
if (!date) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
let format = block || 'yyyy-MM-dd'
|
||||||
|
|
||||||
|
date = new Date(date)
|
||||||
|
|
||||||
|
const map = {
|
||||||
|
M: date.getMonth() + 1, // 月份
|
||||||
|
d: date.getDate(), // 日
|
||||||
|
h: date.getHours(), // 小时
|
||||||
|
m: date.getMinutes(), // 分
|
||||||
|
s: date.getSeconds(), // 秒
|
||||||
|
q: Math.floor((date.getMonth() + 3) / 3), // 季度
|
||||||
|
S: date.getMilliseconds() // 毫秒
|
||||||
|
}
|
||||||
|
|
||||||
|
format = format.replace(/([yMdhmsqS])+/g, (all, t) => {
|
||||||
|
let v = map[t]
|
||||||
|
if (v !== undefined) {
|
||||||
|
if (all.length > 1) {
|
||||||
|
v = `0${v}`
|
||||||
|
v = v.substr(v.length - 2)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
} else if (t === 'y') {
|
||||||
|
return (date.getFullYear().toString()).substr(4 - all.length)
|
||||||
|
}
|
||||||
|
return all
|
||||||
|
})
|
||||||
|
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
export default dateFormat
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
// 原开源项目地址:https://gitee.com/toktok/easy-cron
|
||||||
|
|
||||||
|
import InputCron from './InputCron.vue'
|
||||||
|
|
||||||
|
InputCron.name = 'JEasyCron'
|
||||||
|
export default InputCron
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
export const WEEK_MAP_EN = {
|
||||||
|
'SUN': '0',
|
||||||
|
'MON': '1',
|
||||||
|
'TUE': '2',
|
||||||
|
'WED': '3',
|
||||||
|
'THU': '4',
|
||||||
|
'FRI': '5',
|
||||||
|
'SAT': '6'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const replaceWeekName = (c) => {
|
||||||
|
// console.info('after: ' + c)
|
||||||
|
if (c) {
|
||||||
|
Object.keys(WEEK_MAP_EN).forEach(k => {
|
||||||
|
c = c.replace(new RegExp(k, 'g'), WEEK_MAP_EN[k])
|
||||||
|
})
|
||||||
|
c = c.replace(new RegExp('7', 'g'), '0')
|
||||||
|
}
|
||||||
|
// console.info('after: ' + c)
|
||||||
|
return c
|
||||||
|
}
|
||||||
101
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/day.vue
Normal file
101
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/day.vue
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-list">
|
||||||
|
<a-radio-group v-model="type">
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_NOT_SET" class="choice" :disabled="disableChoice">不设置</a-radio>
|
||||||
|
<span class="tip-info">日和周只能设置其中之一</span>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_EVERY" class="choice" :disabled="disableChoice">每日</a-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_RANGE" class="choice" :disabled="disableChoice">区间</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||||
|
日
|
||||||
|
至
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||||
|
日
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_LOOP" class="choice" :disabled="disableChoice">循环</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||||
|
日开始,间隔
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||||
|
日
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_WORK" class="choice" :disabled="disableChoice">工作日</a-radio>
|
||||||
|
本月
|
||||||
|
<a-input-number :disabled="type!==TYPE_WORK || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueWork"/>
|
||||||
|
日,最近的工作日
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_LAST" class="choice" :disabled="disableChoice">最后一日</a-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disableChoice">指定</a-radio>
|
||||||
|
<div class="list">
|
||||||
|
<a-checkbox-group v-model="valueList">
|
||||||
|
<template v-for="i in maxValue+1">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||||
|
</template>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mixin from './mixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'day',
|
||||||
|
mixins: [mixin],
|
||||||
|
props: {
|
||||||
|
week: {
|
||||||
|
type: String,
|
||||||
|
default: '?'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
disableChoice() {
|
||||||
|
return (this.week && this.week !== '?') || this.disabled
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value_c(newVal, oldVal) {
|
||||||
|
// 数值变化
|
||||||
|
this.updateValue()
|
||||||
|
},
|
||||||
|
week(newVal, oldVal) {
|
||||||
|
// console.info('new week: ' + newVal)
|
||||||
|
this.updateValue()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateValue() {
|
||||||
|
this.$emit('change', this.disableChoice ? '?' : this.value_c)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.DEFAULT_VALUE = '*'
|
||||||
|
this.minValue = 1
|
||||||
|
this.maxValue = 31
|
||||||
|
this.valueRange.start = 1
|
||||||
|
this.valueRange.end = 31
|
||||||
|
this.valueLoop.start = 1
|
||||||
|
this.valueLoop.interval = 1
|
||||||
|
this.parseProp(this.prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "mixin.less";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-list">
|
||||||
|
<a-radio-group v-model="type">
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每时</a-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||||
|
时
|
||||||
|
至
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||||
|
时
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||||
|
时开始,间隔
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||||
|
时
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
|
||||||
|
<div class="list">
|
||||||
|
<a-checkbox-group v-model="valueList">
|
||||||
|
<template v-for="i in maxValue+1">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||||
|
</template>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mixin from './mixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'minute',
|
||||||
|
mixins: [mixin],
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value_c(newVal, oldVal) {
|
||||||
|
this.$emit('change', newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.DEFAULT_VALUE = '*'
|
||||||
|
this.minValue = 0
|
||||||
|
this.maxValue = 23
|
||||||
|
this.valueRange.start = 0
|
||||||
|
this.valueRange.end = 23
|
||||||
|
this.valueLoop.start = 0
|
||||||
|
this.valueLoop.interval = 1
|
||||||
|
this.parseProp(this.prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "mixin.less";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-list">
|
||||||
|
<a-radio-group v-model="type">
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每分</a-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||||
|
分
|
||||||
|
至
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||||
|
分
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||||
|
分开始,间隔
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||||
|
分
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
|
||||||
|
<div class="list">
|
||||||
|
<a-checkbox-group v-model="valueList">
|
||||||
|
<template v-for="i in maxValue+1">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||||
|
</template>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mixin from './mixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'minute',
|
||||||
|
mixins: [mixin],
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value_c(newVal, oldVal) {
|
||||||
|
this.$emit('change', newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.DEFAULT_VALUE = '*'
|
||||||
|
this.minValue = 0
|
||||||
|
this.maxValue = 59
|
||||||
|
this.valueRange.start = 0
|
||||||
|
this.valueRange.end = 59
|
||||||
|
this.valueLoop.start = 0
|
||||||
|
this.valueLoop.interval = 1
|
||||||
|
this.parseProp(this.prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "mixin.less";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,151 @@
|
|||||||
|
// 主要用于日和星期的互斥使用
|
||||||
|
const TYPE_NOT_SET = 'TYPE_NOT_SET'
|
||||||
|
const TYPE_EVERY = 'TYPE_EVERY'
|
||||||
|
const TYPE_RANGE = 'TYPE_RANGE'
|
||||||
|
const TYPE_LOOP = 'TYPE_LOOP'
|
||||||
|
const TYPE_WORK = 'TYPE_WORK'
|
||||||
|
const TYPE_LAST = 'TYPE_LAST'
|
||||||
|
const TYPE_SPECIFY = 'TYPE_SPECIFY'
|
||||||
|
|
||||||
|
const DEFAULT_VALUE = '?'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
model: {
|
||||||
|
prop: 'prop',
|
||||||
|
event: 'change'
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
prop: {
|
||||||
|
type: String,
|
||||||
|
default: DEFAULT_VALUE
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
const type = TYPE_EVERY
|
||||||
|
return {
|
||||||
|
DEFAULT_VALUE,
|
||||||
|
// 类型
|
||||||
|
type,
|
||||||
|
// 启用日或者星期互斥用
|
||||||
|
TYPE_NOT_SET,
|
||||||
|
TYPE_EVERY,
|
||||||
|
TYPE_RANGE,
|
||||||
|
TYPE_LOOP,
|
||||||
|
TYPE_WORK,
|
||||||
|
TYPE_LAST,
|
||||||
|
TYPE_SPECIFY,
|
||||||
|
// 对于不同的类型,所定义的值也有所不同
|
||||||
|
valueRange: {
|
||||||
|
start: 0,
|
||||||
|
end: 0
|
||||||
|
},
|
||||||
|
valueLoop: {
|
||||||
|
start: 0,
|
||||||
|
interval: 1
|
||||||
|
},
|
||||||
|
valueWeek: {
|
||||||
|
start: 0,
|
||||||
|
end: 0
|
||||||
|
},
|
||||||
|
valueList: [],
|
||||||
|
valueWork: 1,
|
||||||
|
maxValue: 0,
|
||||||
|
minValue: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
prop (newVal, oldVal) {
|
||||||
|
if (newVal === this.value_c) {
|
||||||
|
// console.info('skip ' + newVal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.parseProp(newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
value_c () {
|
||||||
|
let result = []
|
||||||
|
switch (this.type) {
|
||||||
|
case TYPE_NOT_SET:
|
||||||
|
result.push('?')
|
||||||
|
break
|
||||||
|
case TYPE_EVERY:
|
||||||
|
result.push('*')
|
||||||
|
break
|
||||||
|
case TYPE_RANGE:
|
||||||
|
result.push(`${this.valueRange.start}-${this.valueRange.end}`)
|
||||||
|
break
|
||||||
|
case TYPE_LOOP:
|
||||||
|
result.push(`${this.valueLoop.start}/${this.valueLoop.interval}`)
|
||||||
|
break
|
||||||
|
case TYPE_WORK:
|
||||||
|
result.push(`${this.valueWork}W`)
|
||||||
|
break
|
||||||
|
case TYPE_LAST:
|
||||||
|
result.push('L')
|
||||||
|
break
|
||||||
|
case TYPE_SPECIFY:
|
||||||
|
result.push(this.valueList.join(','))
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
result.push(this.DEFAULT_VALUE)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return result.length > 0 ? result.join('') : this.DEFAULT_VALUE
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
parseProp (value) {
|
||||||
|
if (value === this.value_c) {
|
||||||
|
// console.info('same ' + value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (typeof (this.preProcessProp) === 'function') {
|
||||||
|
value = this.preProcessProp(value)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!value || value === this.DEFAULT_VALUE) {
|
||||||
|
this.type = TYPE_EVERY
|
||||||
|
} else if (value.indexOf('?') >= 0) {
|
||||||
|
this.type = TYPE_NOT_SET
|
||||||
|
} else if (value.indexOf('-') >= 0) {
|
||||||
|
this.type = TYPE_RANGE
|
||||||
|
const values = value.split('-')
|
||||||
|
if (values.length >= 2) {
|
||||||
|
this.valueRange.start = parseInt(values[0])
|
||||||
|
this.valueRange.end = parseInt(values[1])
|
||||||
|
}
|
||||||
|
} else if (value.indexOf('/') >= 0) {
|
||||||
|
this.type = TYPE_LOOP
|
||||||
|
const values = value.split('/')
|
||||||
|
if (values.length >= 2) {
|
||||||
|
this.valueLoop.start = value[0] === '*' ? 0 : parseInt(values[0])
|
||||||
|
this.valueLoop.interval = parseInt(values[1])
|
||||||
|
}
|
||||||
|
} else if (value.indexOf('W') >= 0) {
|
||||||
|
this.type = TYPE_WORK
|
||||||
|
const values = value.split('W')
|
||||||
|
if (!values[0] && !isNaN(values[0])) {
|
||||||
|
this.valueWork = parseInt(values[0])
|
||||||
|
}
|
||||||
|
} else if (value.indexOf('L') >= 0) {
|
||||||
|
this.type = TYPE_LAST
|
||||||
|
const values = value.split('L')
|
||||||
|
this.valueLast = parseInt(values[0])
|
||||||
|
} else if (value.indexOf(',') >= 0 || !isNaN(value)) {
|
||||||
|
this.type = TYPE_SPECIFY
|
||||||
|
this.valueList = value.split(',').map(item => parseInt(item))
|
||||||
|
} else {
|
||||||
|
this.type = TYPE_EVERY
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// console.info(e)
|
||||||
|
this.type = TYPE_EVERY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
.config-list {
|
||||||
|
text-align: left;
|
||||||
|
margin: 0 10px 10px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choice {
|
||||||
|
padding: 5px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.w60 {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
.w80 {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
margin: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-check-item {
|
||||||
|
padding: 1px 3px;
|
||||||
|
width: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-info {
|
||||||
|
color: #999
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-list">
|
||||||
|
<a-radio-group v-model="type">
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每月</a-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||||
|
月
|
||||||
|
至
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||||
|
月
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||||
|
月开始,间隔
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||||
|
月
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
|
||||||
|
<div class="list">
|
||||||
|
<a-checkbox-group v-model="valueList">
|
||||||
|
<template v-for="i in maxValue+1">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||||
|
</template>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mixin from './mixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'month',
|
||||||
|
mixins: [mixin],
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value_c(newVal, oldVal) {
|
||||||
|
this.$emit('change', newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.DEFAULT_VALUE = '*'
|
||||||
|
this.minValue = 1
|
||||||
|
this.maxValue = 12
|
||||||
|
this.valueRange.start = 1
|
||||||
|
this.valueRange.end = 12
|
||||||
|
this.valueLoop.start = 1
|
||||||
|
this.valueLoop.interval = 1
|
||||||
|
this.parseProp(this.prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "mixin.less";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-list">
|
||||||
|
<a-radio-group v-model="type">
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每秒</a-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||||
|
秒
|
||||||
|
至
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||||
|
秒
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||||
|
秒开始,间隔
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||||
|
秒
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
|
||||||
|
<div class="list">
|
||||||
|
<a-checkbox-group v-model="valueList">
|
||||||
|
<template v-for="i in maxValue+1">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||||
|
</template>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mixin from './mixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'second',
|
||||||
|
mixins: [mixin],
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value_c(newVal, oldVal) {
|
||||||
|
this.$emit('change', newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.DEFAULT_VALUE = '*'
|
||||||
|
this.minValue = 0
|
||||||
|
this.maxValue = 59
|
||||||
|
this.valueRange.start = 0
|
||||||
|
this.valueRange.end = 59
|
||||||
|
this.valueLoop.start = 0
|
||||||
|
this.valueLoop.interval = 1
|
||||||
|
// console.info('created')
|
||||||
|
this.parseProp(this.prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "mixin.less";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-list">
|
||||||
|
<a-radio-group v-model="type">
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_NOT_SET" class="choice" :disabled="disableChoice">不设置</a-radio>
|
||||||
|
<span class="tip-info">日和周只能设置其中之一</span>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_RANGE" class="choice" :disabled="disableChoice">区间</a-radio>
|
||||||
|
从
|
||||||
|
<a-select v-model="valueRange.start" class="w80" :disabled="type!==TYPE_RANGE || disableChoice">
|
||||||
|
<template v-for="(v, k) of WEEK_MAP">
|
||||||
|
<a-select-option :value="v">{{k}}</a-select-option>
|
||||||
|
</template>
|
||||||
|
</a-select>
|
||||||
|
至
|
||||||
|
<a-select v-model="valueRange.end" class="w80" :disabled="type!==TYPE_RANGE || disableChoice">
|
||||||
|
<template v-for="(v, k) of WEEK_MAP">
|
||||||
|
<a-select-option :value="v">{{k}}</a-select-option>
|
||||||
|
</template>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_LOOP" class="choice" :disabled="disableChoice">循环</a-radio>
|
||||||
|
从
|
||||||
|
<a-select v-model="valueLoop.start" class="w80" :disabled="type!==TYPE_LOOP || disableChoice">
|
||||||
|
<template v-for="(v, k) of WEEK_MAP">
|
||||||
|
<a-select-option :value="v">{{k}}</a-select-option>
|
||||||
|
</template>
|
||||||
|
</a-select>
|
||||||
|
开始,间隔
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||||
|
天
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disableChoice">指定</a-radio>
|
||||||
|
<div class="list">
|
||||||
|
<a-checkbox-group v-model="valueList">
|
||||||
|
<template v-for="i in maxValue+1">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||||
|
</template>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mixin from './mixin'
|
||||||
|
import { replaceWeekName, WEEK_MAP_EN } from './const.js'
|
||||||
|
|
||||||
|
const WEEK_MAP = {
|
||||||
|
'周日': 0,
|
||||||
|
'周一': 1,
|
||||||
|
'周二': 2,
|
||||||
|
'周三': 3,
|
||||||
|
'周四': 4,
|
||||||
|
'周五': 5,
|
||||||
|
'周六': 6
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'week',
|
||||||
|
mixins: [mixin],
|
||||||
|
props: {
|
||||||
|
day: {
|
||||||
|
type: String,
|
||||||
|
default: '*'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
WEEK_MAP,
|
||||||
|
WEEK_MAP_EN
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
disableChoice() {
|
||||||
|
return (this.day && this.day !== '?') || this.disabled
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value_c(newVal, oldVal) {
|
||||||
|
// 如果设置日,那么星期就直接不设置
|
||||||
|
this.updateValue()
|
||||||
|
},
|
||||||
|
day(newVal) {
|
||||||
|
// console.info('new day: ' + newVal)
|
||||||
|
this.updateValue()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateValue() {
|
||||||
|
this.$emit('change', this.disableChoice ? '?' : this.value_c)
|
||||||
|
},
|
||||||
|
preProcessProp(c) {
|
||||||
|
return replaceWeekName(c)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.DEFAULT_VALUE = '*'
|
||||||
|
// 0,7表示周日 1表示周一
|
||||||
|
this.minValue = 0
|
||||||
|
this.maxValue = 6
|
||||||
|
this.valueRange.start = 0
|
||||||
|
this.valueRange.end = 6
|
||||||
|
this.valueLoop.start = 2
|
||||||
|
this.valueLoop.interval = 1
|
||||||
|
this.parseProp(this.prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "mixin.less";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-list">
|
||||||
|
<a-radio-group v-model="type">
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每年</a-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :min="0" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||||
|
年
|
||||||
|
至
|
||||||
|
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :min="1" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||||
|
年
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||||
|
从
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :min="0" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||||
|
年开始,间隔
|
||||||
|
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :min="1" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||||
|
年
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mixin from './mixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'year',
|
||||||
|
mixins: [mixin],
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value_c(newVal, oldVal) {
|
||||||
|
// console.info('change:' + newVal)
|
||||||
|
this.$emit('change', newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
const nowYear = (new Date()).getFullYear()
|
||||||
|
this.DEFAULT_VALUE = '*'
|
||||||
|
this.minValue = 0
|
||||||
|
this.maxValue = 0
|
||||||
|
this.valueRange.start = nowYear
|
||||||
|
this.valueRange.end = nowYear + 100
|
||||||
|
this.valueLoop.start = nowYear
|
||||||
|
this.valueLoop.interval = 1
|
||||||
|
// console.info('created')
|
||||||
|
this.parseProp(this.prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "mixin.less";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
import CronParser from 'cron-parser'
|
||||||
|
import { replaceWeekName } from './tabs/const'
|
||||||
|
|
||||||
|
export default (rule, value, callback) => {
|
||||||
|
// 没填写就不校验
|
||||||
|
if (!value) {
|
||||||
|
callback()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const values = value.split(' ').filter(item => !!item)
|
||||||
|
if (values.length > 7) {
|
||||||
|
callback(new Error('Cron表达式最多7项!'))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 检查第7项
|
||||||
|
let e = value
|
||||||
|
if (values.length === 7) {
|
||||||
|
const year = replaceWeekName(values[6])
|
||||||
|
if (year !== '*' && year !== '?') {
|
||||||
|
let yearValues = []
|
||||||
|
if (year.indexOf('-') >= 0) {
|
||||||
|
yearValues = year.split('-')
|
||||||
|
} else if (year.indexOf('/')) {
|
||||||
|
yearValues = year.split('/')
|
||||||
|
} else {
|
||||||
|
yearValues = [year]
|
||||||
|
}
|
||||||
|
// console.info(yearValues)
|
||||||
|
// 判断是否都是数字
|
||||||
|
const checkYear = yearValues.some(item => isNaN(item))
|
||||||
|
if (checkYear) {
|
||||||
|
callback(new Error('Cron表达式参数[年]错误:' + year))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 取其中的前六项
|
||||||
|
e = values.slice(0, 6).join(' ')
|
||||||
|
}
|
||||||
|
// 6位 没有年
|
||||||
|
// 5位没有秒、年
|
||||||
|
let result = true
|
||||||
|
try {
|
||||||
|
const iter = CronParser.parseExpression(e)
|
||||||
|
iter.next()
|
||||||
|
callback()
|
||||||
|
} catch (e) {
|
||||||
|
callback(new Error('Cron表达式错误:' + e))
|
||||||
|
result = false
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
@ -11,13 +11,13 @@
|
|||||||
<a-col>
|
<a-col>
|
||||||
<!-- 操作按钮 -->
|
<!-- 操作按钮 -->
|
||||||
<div v-if="actionButton" class="action-button">
|
<div v-if="actionButton" class="action-button">
|
||||||
<a-button type="primary" icon="plus" @click="handleClickAdd" :disabled="disabled">新增</a-button>
|
<a-button v-if="buttonPermission('add')" type="primary" icon="plus" @click="handleClickAdd" :disabled="disabled">新增</a-button>
|
||||||
<span class="gap"></span>
|
<span class="gap"></span>
|
||||||
<template v-if="selectedRowIds.length>0">
|
<template v-if="selectedRowIds.length>0">
|
||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
:title="`确定要删除这 ${selectedRowIds.length} 项吗?`"
|
:title="`确定要删除这 ${selectedRowIds.length} 项吗?`"
|
||||||
@confirm="handleConfirmDelete">
|
@confirm="handleConfirmDelete">
|
||||||
<a-button type="primary" icon="minus" :disabled="disabled">删除</a-button>
|
<a-button v-if="buttonPermission('batch_delete')" type="primary" icon="minus" :disabled="disabled">删除</a-button>
|
||||||
<span class="gap"></span>
|
<span class="gap"></span>
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
<template v-if="showClearSelectButton">
|
<template v-if="showClearSelectButton">
|
||||||
@ -39,7 +39,7 @@
|
|||||||
<div class="thead" ref="thead">
|
<div class="thead" ref="thead">
|
||||||
<div class="tr" :style="{width: this.realTrWidth}">
|
<div class="tr" :style="{width: this.realTrWidth}">
|
||||||
<!-- 左侧固定td -->
|
<!-- 左侧固定td -->
|
||||||
<div v-if="dragSort" class="td td-ds" :style="style.tdLeftDs">
|
<div v-if="dragSort" class="td td-ds" :style="style.tdLeft">
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
|
<div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
|
||||||
@ -104,7 +104,7 @@
|
|||||||
>
|
>
|
||||||
<!-- 左侧固定td -->
|
<!-- 左侧固定td -->
|
||||||
|
|
||||||
<div v-if="dragSort" class="td td-ds" :style="style.tdLeftDs" @dblclick="_handleRowInsertDown(rowIndex)" >
|
<div v-if="dragSort" class="td td-ds" :style="style.tdLeft" @dblclick="_handleRowInsertDown(rowIndex)" >
|
||||||
<a-dropdown :trigger="['click']" :getPopupContainer="getParentContainer">
|
<a-dropdown :trigger="['click']" :getPopupContainer="getParentContainer">
|
||||||
<div class="td-ds-icons">
|
<div class="td-ds-icons">
|
||||||
<a-icon type="align-left"/>
|
<a-icon type="align-left"/>
|
||||||
@ -188,6 +188,7 @@
|
|||||||
:getPopupContainer="getParentContainer"
|
:getPopupContainer="getParentContainer"
|
||||||
:placeholder="replaceProps(col, col.placeholder)"
|
:placeholder="replaceProps(col, col.placeholder)"
|
||||||
:filterOption="(i,o)=>handleSelectFilterOption(i,o,col)"
|
:filterOption="(i,o)=>handleSelectFilterOption(i,o,col)"
|
||||||
|
:maxTagCount="1"
|
||||||
@change="(v)=>handleChangeSelectCommon(v,id,row,col)"
|
@change="(v)=>handleChangeSelectCommon(v,id,row,col)"
|
||||||
@search="(v)=>handleSearchSelect(v,id,row,col)"
|
@search="(v)=>handleSearchSelect(v,id,row,col)"
|
||||||
@blur="(v)=>handleBlurSearch(v,id,row,col)"
|
@blur="(v)=>handleBlurSearch(v,id,row,col)"
|
||||||
@ -201,6 +202,55 @@
|
|||||||
>{{ getSelectTranslateText(selectValues[id], row, col) }}</span>
|
>{{ getSelectTranslateText(selectValues[id], row, col) }}</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- 部门选择 -->
|
||||||
|
<template v-else-if="col.type === formTypes.sel_depart">
|
||||||
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
|
<j-select-depart
|
||||||
|
v-if="isEditRow(row, col)"
|
||||||
|
:id="id"
|
||||||
|
:key="i"
|
||||||
|
v-bind="buildProps(row,col)"
|
||||||
|
style="width: 100%;"
|
||||||
|
:value="departCompValues[id]"
|
||||||
|
:placeholder="replaceProps(col, col.placeholder)"
|
||||||
|
:trigger-change="true"
|
||||||
|
:multi="true"
|
||||||
|
@change="(v)=>handleChangeDepartCommon(v,id,row,col)"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="j-td-span no-edit"
|
||||||
|
:class="{disabled: buildProps(row,col).disabled}"
|
||||||
|
@click="handleEditRow(row, col)"
|
||||||
|
>{{ departCompValues[id] }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 用户选择 -->
|
||||||
|
<template v-else-if="col.type === formTypes.sel_user">
|
||||||
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
|
<j-select-user-by-dep
|
||||||
|
v-if="isEditRow(row, col)"
|
||||||
|
:id="id"
|
||||||
|
:key="i"
|
||||||
|
v-bind="buildProps(row,col)"
|
||||||
|
style="width: 100%;"
|
||||||
|
:value="userCompValues[id]"
|
||||||
|
:placeholder="replaceProps(col, col.placeholder)"
|
||||||
|
:trigger-change="true"
|
||||||
|
:multi="true"
|
||||||
|
@change="(v)=>handleChangeUserCommon(v,id,row,col)"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="j-td-span no-edit"
|
||||||
|
:class="{disabled: buildProps(row,col).disabled}"
|
||||||
|
@click="handleEditRow(row, col)"
|
||||||
|
>{{ userCompValues[id] }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- date -->
|
<!-- date -->
|
||||||
<template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime">
|
<template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime">
|
||||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
@ -300,7 +350,7 @@
|
|||||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
:data="{'isup':1}"
|
:data="{'isup':1, ...(col.data||{})}"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
:action="col.action"
|
:action="col.action"
|
||||||
:headers="uploadGetHeaders(row,col)"
|
:headers="uploadGetHeaders(row,col)"
|
||||||
@ -331,6 +381,8 @@
|
|||||||
:dest-fields="col.destFields"
|
:dest-fields="col.destFields"
|
||||||
:code="col.popupCode"
|
:code="col.popupCode"
|
||||||
:groupId="caseId"
|
:groupId="caseId"
|
||||||
|
:param="col.param"
|
||||||
|
:sorter="col.sorter"
|
||||||
@input="(value,others)=>popupCallback(value,others,id,row,col,rowIndex)"
|
@input="(value,others)=>popupCallback(value,others,id,row,col,rowIndex)"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
@ -375,7 +427,7 @@
|
|||||||
<a-menu-item @click="handleClickDelFile(id)">
|
<a-menu-item @click="handleClickDelFile(id)">
|
||||||
<span><a-icon type="delete"/> 删除</span>
|
<span><a-icon type="delete"/> 删除</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleMoreOperation(id)">
|
<a-menu-item @click="handleMoreOperation(id,col,col)">
|
||||||
<span><a-icon type="bars" /> 更多</span>
|
<span><a-icon type="bars" /> 更多</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
@ -410,7 +462,7 @@
|
|||||||
<a-icon type="loading"/>
|
<a-icon type="loading"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="uploadValues[id]['path']">
|
<template v-else-if="uploadValues[id]['path']">
|
||||||
<img class="j-editable-image" :src="getCellImageView(id)" alt="无图片" @click="handleMoreOperation(id,'img')"/>
|
<img class="j-editable-image" :src="getCellImageView(id)" alt="无图片" @click="handleMoreOperation(id,'img',col)"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError(id)"/>
|
<a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError(id)"/>
|
||||||
@ -443,7 +495,7 @@
|
|||||||
<a-menu-item @click="handleClickDelFile(id)">
|
<a-menu-item @click="handleClickDelFile(id)">
|
||||||
<span><a-icon type="delete"/> 删除</span>
|
<span><a-icon type="delete"/> 删除</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleMoreOperation(id,'img')">
|
<a-menu-item @click="handleMoreOperation(id,'img',col)">
|
||||||
<span><a-icon type="bars" /> 更多</span>
|
<span><a-icon type="bars" /> 更多</span>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
@ -545,6 +597,33 @@
|
|||||||
</template>
|
</template>
|
||||||
<!-- select搜索 -end -->
|
<!-- select搜索 -end -->
|
||||||
|
|
||||||
|
<!-- select异步搜索 -begin -->
|
||||||
|
<template v-else-if="col.type === formTypes.sel_search_async">
|
||||||
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
|
<j-search-select-tag
|
||||||
|
v-if="isEditRow(row, col)"
|
||||||
|
:id="id"
|
||||||
|
:key="i"
|
||||||
|
:value="searchSelectAsyncValues[id]"
|
||||||
|
:placeholder="replaceProps(col, col.placeholder)"
|
||||||
|
:dict="col.dict"
|
||||||
|
:async="true"
|
||||||
|
:getPopupContainer="getParentContainer"
|
||||||
|
v-bind="buildProps(row,col)"
|
||||||
|
style="width: 100%;"
|
||||||
|
@change="(v)=>handleSearchSelectAsyncChange(v,id,row,col)"
|
||||||
|
>
|
||||||
|
</j-search-select-tag>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="j-td-span no-edit"
|
||||||
|
:class="{disabled: buildProps(row,col).disabled}"
|
||||||
|
@click="handleEditRow(row, col)"
|
||||||
|
>{{ searchSelectAsyncValues[id] }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<!-- select异步搜索 -end -->
|
||||||
|
|
||||||
<div v-else-if="col.type === formTypes.slot" :key="i">
|
<div v-else-if="col.type === formTypes.slot" :key="i">
|
||||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
<slot
|
<slot
|
||||||
@ -565,7 +644,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- else (normal) -->
|
<!-- else (normal) -->
|
||||||
<span v-else :key="i" v-bind="buildProps(row,col)">{{ inputValues[rowIndex][col.key] }}</span>
|
<span class="comp-normal" v-else :key="i" :title="inputValues[rowIndex][col.key]" v-bind="buildProps(row,col)">{{ inputValues[rowIndex][col.key] }}</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -584,7 +663,7 @@
|
|||||||
height: '32px'
|
height: '32px'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div v-if="dragSort" class="td td-ds" :style="style.tdLeftDs">
|
<div v-if="dragSort" class="td td-ds" :style="style.tdLeft">
|
||||||
</div>
|
</div>
|
||||||
<div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
|
<div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
|
||||||
统计
|
统计
|
||||||
@ -612,7 +691,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<j-file-pop ref="filePop" @ok="handleFileSuccess"></j-file-pop>
|
<j-file-pop ref="filePop" @ok="handleFileSuccess" :number="number"></j-file-pop>
|
||||||
</div>
|
</div>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</template>
|
</template>
|
||||||
@ -622,12 +701,13 @@
|
|||||||
import Draggable from 'vuedraggable'
|
import Draggable from 'vuedraggable'
|
||||||
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
import { FormTypes, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil'
|
import { FormTypes, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil'
|
||||||
import { cloneObject, randomString, randomNumber, getEventPath } from '@/utils/util'
|
import { cloneObject, getEventPath, randomNumber, randomString } from '@/utils/util'
|
||||||
import JDate from '@/components/jeecg/JDate'
|
import JDate from '@/components/jeecg/JDate'
|
||||||
import { filterDictText, initDictOptions } from '@/components/dict/JDictSelectUtil'
|
import { filterDictText, initDictOptions } from '@/components/dict/JDictSelectUtil'
|
||||||
import { getFileAccessHttpUrl } from '@/api/manage';
|
import { getFileAccessHttpUrl } from '@/api/manage'
|
||||||
import JInputPop from '@/components/jeecg/minipop/JInputPop'
|
import JInputPop from '@/components/jeecg/minipop/JInputPop'
|
||||||
import JFilePop from '@/components/jeecg/minipop/JFilePop'
|
import JFilePop from '@/components/jeecg/minipop/JFilePop'
|
||||||
|
import { getNoAuthCols } from '@/utils/authFilter'
|
||||||
|
|
||||||
// 行高,需要在实例加载完成前用到
|
// 行高,需要在实例加载完成前用到
|
||||||
let rowHeight = 61
|
let rowHeight = 61
|
||||||
@ -673,7 +753,7 @@
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
// 页面是否在加载中
|
// 表格内容区域最大高度
|
||||||
maxHeight: {
|
maxHeight: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 400
|
default: 400
|
||||||
@ -704,6 +784,11 @@
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
authPre: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -725,8 +810,7 @@
|
|||||||
// 'max-height': '400px'
|
// 'max-height': '400px'
|
||||||
tbody: { left: '0px' },
|
tbody: { left: '0px' },
|
||||||
// 左侧固定td的style
|
// 左侧固定td的style
|
||||||
tdLeft: { 'min-width': '4%', 'max-width': '45px' },
|
tdLeft: {},
|
||||||
tdLeftDs: { 'min-width': '30px', 'max-width': '35px' },
|
|
||||||
},
|
},
|
||||||
// 表单的类型
|
// 表单的类型
|
||||||
formTypes: FormTypes,
|
formTypes: FormTypes,
|
||||||
@ -750,11 +834,16 @@
|
|||||||
uploadValues: {},
|
uploadValues: {},
|
||||||
//popup信息
|
//popup信息
|
||||||
popupValues: {},
|
popupValues: {},
|
||||||
|
//部门组件信息
|
||||||
|
departCompValues:{},
|
||||||
|
//用户组件信息
|
||||||
|
userCompValues: {},
|
||||||
|
|
||||||
radioValues: {},
|
radioValues: {},
|
||||||
metaCheckboxValues: {},
|
metaCheckboxValues: {},
|
||||||
multiSelectValues: {},
|
multiSelectValues: {},
|
||||||
searchSelectValues: {},
|
searchSelectValues: {},
|
||||||
|
searchSelectAsyncValues: {},
|
||||||
// 绑定左侧选择框已选择的id
|
// 绑定左侧选择框已选择的id
|
||||||
selectedRowIds: [],
|
selectedRowIds: [],
|
||||||
// 存储被删除行的id
|
// 存储被删除行的id
|
||||||
@ -775,6 +864,9 @@
|
|||||||
currentEditRows: {},
|
currentEditRows: {},
|
||||||
// 上次push数据的事件,用于判断是否点击过快
|
// 上次push数据的事件,用于判断是否点击过快
|
||||||
lastPushTimeMap: new Map(),
|
lastPushTimeMap: new Map(),
|
||||||
|
number:0,
|
||||||
|
//不显示的按钮编码
|
||||||
|
excludeCode:[]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -883,6 +975,8 @@
|
|||||||
columns: {
|
columns: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(columns) {
|
handler(columns) {
|
||||||
|
//列改变的时候重新设置按钮权限信息
|
||||||
|
this.loadExcludeCode()
|
||||||
// 兼容IE
|
// 兼容IE
|
||||||
this.getElementPromise('tbody').then(() => {
|
this.getElementPromise('tbody').then(() => {
|
||||||
columns.forEach(column => {
|
columns.forEach(column => {
|
||||||
@ -964,6 +1058,13 @@
|
|||||||
this.visibleTrEls = []
|
this.visibleTrEls = []
|
||||||
// 判断是否是首次进入该方法,如果是就不清空行,防止删除了预添加的数据
|
// 判断是否是首次进入该方法,如果是就不清空行,防止删除了预添加的数据
|
||||||
if (!this.isFirst) {
|
if (!this.isFirst) {
|
||||||
|
this.clearRow();
|
||||||
|
} else {
|
||||||
|
this.isFirst = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**清空行*/
|
||||||
|
clearRow(){
|
||||||
// inputValues:用来存储input表单的值
|
// inputValues:用来存储input表单的值
|
||||||
// 数组里的每项都是一个对象,对象里每个key都是input的rowKey,值就是input的值,其中有个id的字段来区分
|
// 数组里的每项都是一个对象,对象里每个key都是input的rowKey,值就是input的值,其中有个id的字段来区分
|
||||||
// 示例:
|
// 示例:
|
||||||
@ -977,28 +1078,32 @@
|
|||||||
this.inputValues = []
|
this.inputValues = []
|
||||||
this.rows = []
|
this.rows = []
|
||||||
this.deleteIds = []
|
this.deleteIds = []
|
||||||
|
this.selectedRowIds = []
|
||||||
|
this.tooltips = {}
|
||||||
|
this.notPassedIds = []
|
||||||
|
// 重置values
|
||||||
this.selectValues = {}
|
this.selectValues = {}
|
||||||
this.checkboxValues = {}
|
this.checkboxValues = {}
|
||||||
this.jdateValues = {}
|
this.jdateValues = {}
|
||||||
this.jInputPopValues = {}
|
this.jInputPopValues = {}
|
||||||
|
this.departCompValues = {}
|
||||||
|
this.userCompValues = {}
|
||||||
this.slotValues = {}
|
this.slotValues = {}
|
||||||
this.selectedRowIds = []
|
//update-begin-author:shunjlei date:20210415 for:类型赋值错误
|
||||||
this.tooltips = {}
|
this.uploadValues = {}
|
||||||
this.notPassedIds = []
|
this.popupValues = {}
|
||||||
this.uploadValues = []
|
this.radioValues = {}
|
||||||
this.popupValues = []
|
this.multiSelectValues = {}
|
||||||
this.radioValues = []
|
this.searchSelectValues = {}
|
||||||
this.multiSelectValues = []
|
this.searchSelectAsyncValues = {}
|
||||||
this.searchSelectValues = []
|
//update-end-author:shunjlei date:20210415 for:类型赋值错误
|
||||||
|
|
||||||
|
// 重置滚动条
|
||||||
this.scrollTop = 0
|
this.scrollTop = 0
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.getElement('tbody').scrollTop = 0
|
this.getElement('tbody').scrollTop = 0
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
this.isFirst = false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 同步滚动条状态 */
|
/** 同步滚动条状态 */
|
||||||
syncScrollBar(scrollLeft) {
|
syncScrollBar(scrollLeft) {
|
||||||
// this.style.tbody.left = `${scrollLeft}px`
|
// this.style.tbody.left = `${scrollLeft}px`
|
||||||
@ -1058,6 +1163,8 @@
|
|||||||
let checkboxValues = { ...this.checkboxValues }
|
let checkboxValues = { ...this.checkboxValues }
|
||||||
let selectValues = { ...this.selectValues }
|
let selectValues = { ...this.selectValues }
|
||||||
let jdateValues = { ...this.jdateValues }
|
let jdateValues = { ...this.jdateValues }
|
||||||
|
let departCompValues = { ...this.departCompValues }
|
||||||
|
let userCompValues = { ...this.userCompValues }
|
||||||
let jInputPopValues = { ...this.jInputPopValues }
|
let jInputPopValues = { ...this.jInputPopValues }
|
||||||
let slotValues = { ...this.slotValues }
|
let slotValues = { ...this.slotValues }
|
||||||
let uploadValues = { ...this.uploadValues }
|
let uploadValues = { ...this.uploadValues }
|
||||||
@ -1065,6 +1172,7 @@
|
|||||||
let radioValues = { ...this.radioValues }
|
let radioValues = { ...this.radioValues }
|
||||||
let multiSelectValues = { ...this.multiSelectValues }
|
let multiSelectValues = { ...this.multiSelectValues }
|
||||||
let searchSelectValues = { ...this.searchSelectValues }
|
let searchSelectValues = { ...this.searchSelectValues }
|
||||||
|
let searchSelectAsyncValues = { ...this.searchSelectAsyncValues }
|
||||||
// 禁用行的id
|
// 禁用行的id
|
||||||
let disabledRowIds = (this.disabledRowIds || [])
|
let disabledRowIds = (this.disabledRowIds || [])
|
||||||
dataSource.forEach((data, newValueIndex) => {
|
dataSource.forEach((data, newValueIndex) => {
|
||||||
@ -1144,12 +1252,18 @@
|
|||||||
|
|
||||||
} else if (column.type === FormTypes.popup) {
|
} else if (column.type === FormTypes.popup) {
|
||||||
popupValues[inputId] = sourceValue
|
popupValues[inputId] = sourceValue
|
||||||
|
} else if (column.type === FormTypes.sel_depart) {
|
||||||
|
departCompValues[inputId] = sourceValue
|
||||||
|
} else if (column.type === FormTypes.sel_user) {
|
||||||
|
userCompValues[inputId] = sourceValue
|
||||||
} else if (column.type === FormTypes.input_pop) {
|
} else if (column.type === FormTypes.input_pop) {
|
||||||
jInputPopValues[inputId] = sourceValue
|
jInputPopValues[inputId] = sourceValue
|
||||||
} else if (column.type === FormTypes.radio) {
|
} else if (column.type === FormTypes.radio) {
|
||||||
radioValues[inputId] = sourceValue
|
radioValues[inputId] = sourceValue
|
||||||
} else if (column.type === FormTypes.sel_search) {
|
} else if (column.type === FormTypes.sel_search) {
|
||||||
searchSelectValues[inputId] = sourceValue
|
searchSelectValues[inputId] = sourceValue
|
||||||
|
} else if (column.type === FormTypes.sel_search_async) {
|
||||||
|
searchSelectAsyncValues[inputId] = sourceValue
|
||||||
} else if (column.type === FormTypes.list_multi) {
|
} else if (column.type === FormTypes.list_multi) {
|
||||||
if (typeof sourceValue === 'string' && sourceValue.length > 0) {
|
if (typeof sourceValue === 'string' && sourceValue.length > 0) {
|
||||||
multiSelectValues[inputId] = sourceValue.split(',')
|
multiSelectValues[inputId] = sourceValue.split(',')
|
||||||
@ -1170,6 +1284,8 @@
|
|||||||
status: 'done',
|
status: 'done',
|
||||||
path: sourceValue
|
path: sourceValue
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
uploadValues[inputId] = null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value[column.key] = sourceValue
|
value[column.key] = sourceValue
|
||||||
@ -1204,6 +1320,12 @@
|
|||||||
this.inputValues.splice(insertIndex, 0, value)
|
this.inputValues.splice(insertIndex, 0, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//update-begin-author:lvdandan date:20201105 for:LOWCOD-987 【online】js增强的问题--数据对象带有id,且和现有数据一致时,替换患有数据
|
||||||
|
if(-1 !== rows.findIndex(item => item.id === row.id)){
|
||||||
|
added = true
|
||||||
|
this.inputValues = this.inputValues.map(item => item.id === row.id ? value : item)
|
||||||
|
}
|
||||||
|
//update-begin-author:lvdandan date:20201105 for:LOWCOD-987 【online】js增强的问题--数据对象带有id,且和现有数据一致时,替换患有数据
|
||||||
if (!added) {
|
if (!added) {
|
||||||
rows.push(row)
|
rows.push(row)
|
||||||
this.inputValues.push(value)
|
this.inputValues.push(value)
|
||||||
@ -1219,6 +1341,8 @@
|
|||||||
this.checkboxValues = checkboxValues
|
this.checkboxValues = checkboxValues
|
||||||
this.selectValues = selectValues
|
this.selectValues = selectValues
|
||||||
this.jdateValues = jdateValues
|
this.jdateValues = jdateValues
|
||||||
|
this.departCompValues = departCompValues
|
||||||
|
this.userCompValues = userCompValues
|
||||||
this.jInputPopValues = jInputPopValues
|
this.jInputPopValues = jInputPopValues
|
||||||
this.slotValues = slotValues
|
this.slotValues = slotValues
|
||||||
this.uploadValues = uploadValues
|
this.uploadValues = uploadValues
|
||||||
@ -1226,6 +1350,7 @@
|
|||||||
this.radioValues = radioValues
|
this.radioValues = radioValues
|
||||||
this.multiSelectValues = multiSelectValues
|
this.multiSelectValues = multiSelectValues
|
||||||
this.searchSelectValues = searchSelectValues
|
this.searchSelectValues = searchSelectValues
|
||||||
|
this.searchSelectAsyncValues = searchSelectAsyncValues
|
||||||
// 重新计算所有统计列
|
// 重新计算所有统计列
|
||||||
this.recalcAllStatisticsColumns()
|
this.recalcAllStatisticsColumns()
|
||||||
// 更新到 dom
|
// 更新到 dom
|
||||||
@ -1398,7 +1523,6 @@
|
|||||||
let values = []
|
let values = []
|
||||||
// 遍历inputValues来获取每行的值
|
// 遍历inputValues来获取每行的值
|
||||||
for (let value of inputValues) {
|
for (let value of inputValues) {
|
||||||
if (value == null) console.warn(this.caseId, '+++++++++ value.1: ', value, cloneObject(inputValues))
|
|
||||||
let rowIdsFlag = false
|
let rowIdsFlag = false
|
||||||
// 如果带有rowIds,那么就只存这几行的数据
|
// 如果带有rowIds,那么就只存这几行的数据
|
||||||
if (rowIds == null) {
|
if (rowIds == null) {
|
||||||
@ -1435,6 +1559,12 @@
|
|||||||
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
|
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
|
||||||
value[column.key] = this.jdateValues[inputId]
|
value[column.key] = this.jdateValues[inputId]
|
||||||
|
|
||||||
|
} else if (column.type === FormTypes.sel_depart) {
|
||||||
|
value[column.key] = this.departCompValues[inputId]
|
||||||
|
|
||||||
|
} else if (column.type === FormTypes.sel_user) {
|
||||||
|
value[column.key] = this.userCompValues[inputId]
|
||||||
|
|
||||||
} else if (column.type === FormTypes.input_pop) {
|
} else if (column.type === FormTypes.input_pop) {
|
||||||
value[column.key] = this.jInputPopValues[inputId]
|
value[column.key] = this.jInputPopValues[inputId]
|
||||||
|
|
||||||
@ -1455,6 +1585,8 @@
|
|||||||
value[column.key] = this.radioValues[inputId]
|
value[column.key] = this.radioValues[inputId]
|
||||||
} else if (column.type === FormTypes.sel_search) {
|
} else if (column.type === FormTypes.sel_search) {
|
||||||
value[column.key] = this.searchSelectValues[inputId]
|
value[column.key] = this.searchSelectValues[inputId]
|
||||||
|
} else if (column.type === FormTypes.sel_search_async) {
|
||||||
|
value[column.key] = this.searchSelectAsyncValues[inputId]
|
||||||
} else if (column.type === FormTypes.list_multi) {
|
} else if (column.type === FormTypes.list_multi) {
|
||||||
if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length === 0) {
|
if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length === 0) {
|
||||||
value[column.key] = ''
|
value[column.key] = ''
|
||||||
@ -1574,6 +1706,8 @@
|
|||||||
selectValues: this.selectValues,
|
selectValues: this.selectValues,
|
||||||
checkboxValues: this.checkboxValues,
|
checkboxValues: this.checkboxValues,
|
||||||
jdateValues: this.jdateValues,
|
jdateValues: this.jdateValues,
|
||||||
|
departCompValues: this.departCompValues,
|
||||||
|
userCompValues: this.userCompValues,
|
||||||
jInputPopValues: this.jInputPopValues,
|
jInputPopValues: this.jInputPopValues,
|
||||||
slotValues: this.slotValues,
|
slotValues: this.slotValues,
|
||||||
uploadValues: this.uploadValues,
|
uploadValues: this.uploadValues,
|
||||||
@ -1581,6 +1715,7 @@
|
|||||||
radioValues: this.radioValues,
|
radioValues: this.radioValues,
|
||||||
multiSelectValues: this.multiSelectValues,
|
multiSelectValues: this.multiSelectValues,
|
||||||
searchSelectValues: this.searchSelectValues,
|
searchSelectValues: this.searchSelectValues,
|
||||||
|
searchSelectAsyncValues: this.searchSelectAsyncValues,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/** 设置某行某列的值 */
|
/** 设置某行某列的值 */
|
||||||
@ -1591,8 +1726,10 @@
|
|||||||
rowKey = this.getCleanId(rowKey)
|
rowKey = this.getCleanId(rowKey)
|
||||||
for (let newValueKey in newValues) {
|
for (let newValueKey in newValues) {
|
||||||
if (newValues.hasOwnProperty(newValueKey)) {
|
if (newValues.hasOwnProperty(newValueKey)) {
|
||||||
let newValue = newValues[newValueKey]
|
|
||||||
let edited = false // 已被修改
|
let edited = false // 已被修改
|
||||||
|
for (let column of this.columns) {
|
||||||
|
if (column.key === newValueKey) {
|
||||||
|
let newValue = newValues[newValueKey]
|
||||||
this.inputValues.forEach(value => {
|
this.inputValues.forEach(value => {
|
||||||
// 在inputValues中找到了该字段
|
// 在inputValues中找到了该字段
|
||||||
if (rowKey === this.getCleanId(value.id)) {
|
if (rowKey === this.getCleanId(value.id)) {
|
||||||
@ -1602,24 +1739,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let modelKey = `${newValueKey}${this.caseId}${rowKey}`
|
|
||||||
// 在 selectValues 中寻找值
|
|
||||||
if (!edited) {
|
if (!edited) {
|
||||||
|
let modelKey = `${newValueKey}${this.caseId}${rowKey}`
|
||||||
|
if (column.type === FormTypes.select) {
|
||||||
if (newValue !== 0 && !newValue) {
|
if (newValue !== 0 && !newValue) {
|
||||||
edited = this.setOneValue(this.selectValues, modelKey, undefined)
|
edited = this.setOneValue(this.selectValues, modelKey, undefined)
|
||||||
} else {
|
} else {
|
||||||
edited = this.setOneValue(this.selectValues, modelKey, newValue)
|
edited = this.setOneValue(this.selectValues, modelKey, newValue)
|
||||||
}
|
}
|
||||||
}
|
} else if (column.type === FormTypes.checkbox) {
|
||||||
// 在 checkboxValues 中寻找值
|
|
||||||
if (!edited) {
|
|
||||||
// checkbox 特殊处理 CustomValue
|
// checkbox 特殊处理 CustomValue
|
||||||
let key = this.valuesHasOwnProperty(this.checkboxValues, modelKey)
|
let key = this.valuesHasOwnProperty(this.checkboxValues, modelKey)
|
||||||
// 找到对应的column
|
// 找到对应的column
|
||||||
let sourceValue
|
let sourceValue
|
||||||
for (let column of this.columns) {
|
|
||||||
if (column.key === newValueKey) {
|
|
||||||
edited = true
|
|
||||||
// 判断是否设定了customValue(自定义值)
|
// 判断是否设定了customValue(自定义值)
|
||||||
if (column.customValue instanceof Array) {
|
if (column.customValue instanceof Array) {
|
||||||
let customValue = (column.customValue[0] || '').toString()
|
let customValue = (column.customValue[0] || '').toString()
|
||||||
@ -1628,41 +1760,40 @@
|
|||||||
sourceValue = !!newValue
|
sourceValue = !!newValue
|
||||||
}
|
}
|
||||||
this.$set(this.checkboxValues, key, sourceValue)
|
this.$set(this.checkboxValues, key, sourceValue)
|
||||||
break
|
edited = true
|
||||||
}
|
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
|
||||||
}
|
|
||||||
}
|
|
||||||
// 在 jdateValues 中寻找值
|
|
||||||
if (!edited) {
|
|
||||||
edited = this.setOneValue(this.jdateValues, modelKey, newValue)
|
edited = this.setOneValue(this.jdateValues, modelKey, newValue)
|
||||||
}
|
} else if (column.type === FormTypes.sel_depart) {
|
||||||
// 在 jInputPopValues 中寻找值
|
edited = this.setOneValue(this.departCompValues, modelKey, newValue)
|
||||||
if (!edited) {
|
} else if (column.type === FormTypes.sel_user) {
|
||||||
|
edited = this.setOneValue(this.userCompValues, modelKey, newValue)
|
||||||
|
} else if (column.type === FormTypes.input_pop) {
|
||||||
edited = this.setOneValue(this.jInputPopValues, modelKey, newValue)
|
edited = this.setOneValue(this.jInputPopValues, modelKey, newValue)
|
||||||
}
|
} else if (column.type === FormTypes.slot) {
|
||||||
// 在 slotValues 中寻找值
|
|
||||||
if (!edited) {
|
|
||||||
edited = this.setOneValue(this.slotValues, modelKey, newValue)
|
edited = this.setOneValue(this.slotValues, modelKey, newValue)
|
||||||
}
|
} else if (column.type === FormTypes.upload || column.type === FormTypes.image || column.type === FormTypes.file) {
|
||||||
// 在 uploadValues 中寻找值
|
|
||||||
if (!edited) {
|
|
||||||
edited = this.setOneValue(this.uploadValues, modelKey, newValue)
|
edited = this.setOneValue(this.uploadValues, modelKey, newValue)
|
||||||
}
|
} else if (column.type === FormTypes.popup) {
|
||||||
// 在 popupValues 中寻找值
|
|
||||||
if (!edited) {
|
|
||||||
edited = this.setOneValue(this.popupValues, modelKey, newValue)
|
edited = this.setOneValue(this.popupValues, modelKey, newValue)
|
||||||
}
|
} else if (column.type === FormTypes.radio) {
|
||||||
// 在 radioValues 中寻找值
|
|
||||||
if (!edited) {
|
|
||||||
edited = this.setOneValue(this.radioValues, modelKey, newValue)
|
edited = this.setOneValue(this.radioValues, modelKey, newValue)
|
||||||
}
|
} else if (column.type === FormTypes.list_multi) {
|
||||||
// 在 multiSelectValues 中寻找值
|
|
||||||
if (!edited) {
|
|
||||||
edited = this.setOneValue(this.multiSelectValues, modelKey, newValue, true)
|
edited = this.setOneValue(this.multiSelectValues, modelKey, newValue, true)
|
||||||
}
|
} else if (column.type === FormTypes.sel_search) {
|
||||||
// 在 searchSelectValues 中寻找值
|
|
||||||
if (!edited) {
|
|
||||||
edited = this.setOneValue(this.searchSelectValues, modelKey, newValue)
|
edited = this.setOneValue(this.searchSelectValues, modelKey, newValue)
|
||||||
|
} else if (column.type === FormTypes.sel_search_async) {
|
||||||
|
edited = this.setOneValue(this.searchSelectAsyncValues, modelKey, newValue)
|
||||||
|
} else {
|
||||||
|
edited = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (edited) {
|
||||||
|
this.elemValueChange(column.type, {[newValueKey]: newValue}, column, newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!edited) {
|
||||||
|
console.warn(`JEditableTable.setValues:没有找到"${newValueKey}"列`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1814,7 +1945,7 @@
|
|||||||
|
|
||||||
// 兼容 online 的规则
|
// 兼容 online 的规则
|
||||||
let foo = [
|
let foo = [
|
||||||
{ title: '6到16位数字', value: 'n6-16', pattern: /^\d{6,18}$/ },
|
{ title: '6到16位数字', value: 'n6-16', pattern: /^\d{6,16}$/ },
|
||||||
{ title: '6到16位任意字符', value: '*6-16', pattern: /^.{6,16}$/ },
|
{ title: '6到16位任意字符', value: '*6-16', pattern: /^.{6,16}$/ },
|
||||||
{ title: '6到18位字母', value: 's6-18', pattern: /^[a-z|A-Z]{6,18}$/ },
|
{ title: '6到18位字母', value: 's6-18', pattern: /^[a-z|A-Z]{6,18}$/ },
|
||||||
{ title: '网址', value: 'url', pattern: /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/ },
|
{ title: '网址', value: 'url', pattern: /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/ },
|
||||||
@ -2155,8 +2286,12 @@
|
|||||||
}
|
}
|
||||||
target.value = value
|
target.value = value
|
||||||
}
|
}
|
||||||
|
//update--begin--autor:lvdandan-----date:20201126------for:LOWCOD-1088 JEditableTable输入校验提示框位置偏移 #2005
|
||||||
|
setTimeout(()=>{
|
||||||
// 做单个表单验证
|
// 做单个表单验证
|
||||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'blur')
|
this.validateOneInput(value, row, column, this.notPassedIds, true, 'blur')
|
||||||
|
}, 100)
|
||||||
|
//update--end--autor:lvdandan-----date:20201126------for:LOWCOD-1088 JEditableTable输入校验提示框位置偏移 #2005
|
||||||
},
|
},
|
||||||
handleChangeCheckboxCommon(event, row, column) {
|
handleChangeCheckboxCommon(event, row, column) {
|
||||||
let { id, checked } = event.target
|
let { id, checked } = event.target
|
||||||
@ -2184,6 +2319,20 @@
|
|||||||
this.elemValueChange(FormTypes.date, row, column, value)
|
this.elemValueChange(FormTypes.date, row, column, value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
//部门组件值改变
|
||||||
|
handleChangeDepartCommon(value, id, row, column){
|
||||||
|
this.departCompValues = this.bindValuesChange(value, id, 'departCompValues')
|
||||||
|
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||||
|
// 触发valueChange 事件
|
||||||
|
this.elemValueChange(FormTypes.sel_depart, row, column, value)
|
||||||
|
},
|
||||||
|
//用户组件值改变
|
||||||
|
handleChangeUserCommon(value, id, row, column){
|
||||||
|
this.userCompValues = this.bindValuesChange(value, id, 'userCompValues')
|
||||||
|
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||||
|
// 触发valueChange 事件
|
||||||
|
this.elemValueChange(FormTypes.sel_user, row, column, value)
|
||||||
|
},
|
||||||
handleChangeJInputPopCommon(value, id, row, column){
|
handleChangeJInputPopCommon(value, id, row, column){
|
||||||
this.jInputPopValues = this.bindValuesChange(value, id, 'jInputPopValues')
|
this.jInputPopValues = this.bindValuesChange(value, id, 'jInputPopValues')
|
||||||
// 做单个表单验证
|
// 做单个表单验证
|
||||||
@ -2209,8 +2358,22 @@
|
|||||||
value['message'] = file.response.message || '未知错误'
|
value['message'] = file.response.message || '未知错误'
|
||||||
}
|
}
|
||||||
this.uploadValues = this.bindValuesChange(value, id, 'uploadValues')
|
this.uploadValues = this.bindValuesChange(value, id, 'uploadValues')
|
||||||
|
|
||||||
|
// 触发valueChange 事件
|
||||||
|
this.elemValueChange(column.type, row, column, value)
|
||||||
},
|
},
|
||||||
handleMoreOperation(id,flag){
|
handleMoreOperation(id,flag,column){
|
||||||
|
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number,用于控制上传文件
|
||||||
|
if(column.number){
|
||||||
|
this.number = column.number;
|
||||||
|
}else{
|
||||||
|
this.number = 0;
|
||||||
|
}
|
||||||
|
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number,用于控制上传文件
|
||||||
|
if(column && column.fieldExtendJson){
|
||||||
|
let json = JSON.parse(column.fieldExtendJson);
|
||||||
|
this.number = json.uploadnum?json.uploadnum:0;
|
||||||
|
}
|
||||||
//console.log("this.uploadValues[id]",this.uploadValues[id])
|
//console.log("this.uploadValues[id]",this.uploadValues[id])
|
||||||
let path = ''
|
let path = ''
|
||||||
if(this.uploadValues && this.uploadValues[id]){
|
if(this.uploadValues && this.uploadValues[id]){
|
||||||
@ -2461,6 +2624,19 @@
|
|||||||
} else {
|
} else {
|
||||||
style['width'] = '120px'
|
style['width'] = '120px'
|
||||||
}
|
}
|
||||||
|
//update-begin-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
|
||||||
|
//如果是时间控件设为200px
|
||||||
|
if(col.type === FormTypes.datetime){
|
||||||
|
style['width'] = '200px'
|
||||||
|
}
|
||||||
|
if(col.type === FormTypes.sel_user && !col.width){
|
||||||
|
style['width'] = '220px'
|
||||||
|
}
|
||||||
|
if(col.type === FormTypes.sel_depart && !col.width){
|
||||||
|
style['width'] = '160px'
|
||||||
|
}
|
||||||
|
//update-end-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
|
||||||
|
|
||||||
// checkbox 居中显示
|
// checkbox 居中显示
|
||||||
let isCheckbox = col.type === FormTypes.checkbox
|
let isCheckbox = col.type === FormTypes.checkbox
|
||||||
if (isCheckbox) {
|
if (isCheckbox) {
|
||||||
@ -2575,7 +2751,7 @@
|
|||||||
}
|
}
|
||||||
this.setOneValue(this.popupValues, id, popupValue)
|
this.setOneValue(this.popupValues, id, popupValue)
|
||||||
// 做单个表单验证
|
// 做单个表单验证
|
||||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
this.validateOneInput(popupValue, row, column, this.notPassedIds, true, 'change')
|
||||||
// 触发valueChange 事件
|
// 触发valueChange 事件
|
||||||
this.elemValueChange('input', row, column, value)
|
this.elemValueChange('input', row, column, value)
|
||||||
},
|
},
|
||||||
@ -2602,6 +2778,11 @@
|
|||||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||||
this.elemValueChange(FormTypes.sel_search, row, column, value)
|
this.elemValueChange(FormTypes.sel_search, row, column, value)
|
||||||
},
|
},
|
||||||
|
handleSearchSelectAsyncChange(value, id, row, column) {
|
||||||
|
this.searchSelectAsyncValues = this.bindValuesChange(value, id, 'searchSelectAsyncValues')
|
||||||
|
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||||
|
this.elemValueChange(FormTypes.sel_search_async, row, column, value)
|
||||||
|
},
|
||||||
filterOption(input, option) {
|
filterOption(input, option) {
|
||||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
},
|
},
|
||||||
@ -2694,15 +2875,35 @@
|
|||||||
removeEventListener() {
|
removeEventListener() {
|
||||||
window.removeEventListener('mouseup', this.handleMouseup)
|
window.removeEventListener('mouseup', this.handleMouseup)
|
||||||
},
|
},
|
||||||
|
|
||||||
/* --------------------------- 2020年5月18日 默认span模式 ------------------------------ */
|
/* --------------------------- 2020年5月18日 默认span模式 ------------------------------ */
|
||||||
|
|
||||||
|
//获取没有授权的按钮编码
|
||||||
|
loadExcludeCode(){
|
||||||
|
if(!this.authPre || this.authPre.length==0){
|
||||||
|
this.excludeCode = []
|
||||||
|
}else{
|
||||||
|
let pre = this.authPre
|
||||||
|
if(!pre.endsWith(':')){
|
||||||
|
pre += ':'
|
||||||
|
}
|
||||||
|
this.excludeCode = getNoAuthCols(pre)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//判断button是否显示
|
||||||
|
buttonPermission(code){
|
||||||
|
if(!this.excludeCode || this.excludeCode.length==0){
|
||||||
|
return true
|
||||||
|
}else{
|
||||||
|
return this.excludeCode.indexOf(code)<0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.removeEventListener()
|
this.removeEventListener()
|
||||||
this.destroyCleanGroupRequest = true
|
this.destroyCleanGroupRequest = true
|
||||||
},
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -2747,8 +2948,9 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
&.td-cb, &.td-num {
|
&.td-cb, &.td-num {
|
||||||
min-width: 4%;
|
width: 45px;
|
||||||
max-width: 45px;
|
min-width: 45px;
|
||||||
|
max-width: 50px;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
@ -2757,6 +2959,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.td-ds {
|
&.td-ds {
|
||||||
|
width: 30px;
|
||||||
|
min-width: 30px;
|
||||||
|
max-width: 35px;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
@ -2839,6 +3044,8 @@
|
|||||||
border-bottom: @border;
|
border-bottom: @border;
|
||||||
transition: background-color 300ms;
|
transition: background-color 300ms;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 61px;
|
||||||
|
overflow: hidden;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
@ -2942,6 +3149,16 @@
|
|||||||
|
|
||||||
label {
|
label {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
||||||
|
&.ant-checkbox-wrapper {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comp-normal {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.j-td-span {
|
.j-td-span {
|
||||||
|
|||||||
@ -128,6 +128,16 @@
|
|||||||
this.reload()
|
this.reload()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
//update--begin--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------
|
||||||
|
this.reload()
|
||||||
|
//update--end--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------
|
||||||
|
}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无法修改------
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div class="img">
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
listType="picture-card"
|
listType="picture-card"
|
||||||
@ -10,18 +11,22 @@
|
|||||||
:beforeUpload="beforeUpload"
|
:beforeUpload="beforeUpload"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:isMultiple="isMultiple"
|
:isMultiple="isMultiple"
|
||||||
:showUploadList="isMultiple"
|
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
@preview="handlePreview">
|
@preview="handlePreview"
|
||||||
<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="height:104px;max-width:300px"/>
|
:class="[!isMultiple?'imgupload':'', (!isMultiple && picUrl)?'image-upload-single-over':'' ]">
|
||||||
<div v-else >
|
<div>
|
||||||
|
<!--<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="width:100%;height:100%"/>-->
|
||||||
|
<div class="iconp">
|
||||||
<a-icon :type="uploadLoading ? 'loading' : 'plus'" />
|
<a-icon :type="uploadLoading ? 'loading' : 'plus'" />
|
||||||
<div class="ant-upload-text">{{ text }}</div>
|
<div class="ant-upload-text">{{ text }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
|
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
|
||||||
<img alt="example" style="width: 100%" :src="previewImage"/>
|
<img alt="example" style="width: 100%" :src="previewImage"/>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -77,10 +82,18 @@
|
|||||||
type:Boolean,
|
type:Boolean,
|
||||||
required:false,
|
required:false,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 新增number属性,用于判断上传数量
|
||||||
|
number:{
|
||||||
|
type:Number,
|
||||||
|
required:false,
|
||||||
|
default:0
|
||||||
}
|
}
|
||||||
|
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 新增number属性,用于判断上传数量
|
||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
value(val){
|
value: {
|
||||||
|
handler(val,oldValue) {
|
||||||
if (val instanceof Array) {
|
if (val instanceof Array) {
|
||||||
this.initFileList(val.join(','))
|
this.initFileList(val.join(','))
|
||||||
} else {
|
} else {
|
||||||
@ -89,6 +102,9 @@
|
|||||||
if(!val || val.length==0){
|
if(!val || val.length==0){
|
||||||
this.picUrl = false;
|
this.picUrl = false;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
//立刻执行handler
|
||||||
|
immediate: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
@ -129,6 +145,11 @@
|
|||||||
handleChange(info) {
|
handleChange(info) {
|
||||||
this.picUrl = false;
|
this.picUrl = false;
|
||||||
let fileList = info.fileList
|
let fileList = info.fileList
|
||||||
|
//update-begin-author:wangshuai date:20201022 for:LOWCOD-969 判断number是否大于0和是否多选,返回选定的元素。
|
||||||
|
if(this.number>0 && this.isMultiple){
|
||||||
|
fileList = fileList.slice(-this.number);
|
||||||
|
}
|
||||||
|
//update-end-author:wangshuai date:20201022 for:LOWCOD-969 判断number是否大于0和是否多选,返回选定的元素。
|
||||||
if(info.file.status==='done'){
|
if(info.file.status==='done'){
|
||||||
if(info.file.response.success){
|
if(info.file.response.success){
|
||||||
this.picUrl = true;
|
this.picUrl = true;
|
||||||
@ -168,11 +189,17 @@
|
|||||||
path = ''
|
path = ''
|
||||||
}
|
}
|
||||||
let arr = [];
|
let arr = [];
|
||||||
if(!this.isMultiple){
|
if(!this.isMultiple && uploadFiles.length>0){
|
||||||
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++){
|
||||||
|
// update-begin-author:taoyan date:20200819 for:【开源问题z】上传图片组件 LOWCOD-783
|
||||||
|
if(uploadFiles[a].status === 'done' ) {
|
||||||
arr.push(uploadFiles[a].response.message)
|
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){
|
||||||
@ -200,5 +227,13 @@
|
|||||||
</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 .iconp{padding:20px;}
|
||||||
|
/* update--end--autor:lvdandan-----date:20201016------for:j-image-upload图片组件单张图片详情回显空白*/
|
||||||
|
|
||||||
|
/deep/ .image-upload-single-over .ant-upload-select{display: none}
|
||||||
</style>
|
</style>
|
||||||
@ -6,6 +6,13 @@
|
|||||||
:confirmLoading="uploading"
|
:confirmLoading="uploading"
|
||||||
@cancel="handleClose">
|
@cancel="handleClose">
|
||||||
|
|
||||||
|
<div style="margin: 0px 0px 5px 1px" v-if="online">
|
||||||
|
<span style="display: inline-block;height: 32px;line-height: 32px;vertical-align: middle;">是否开启校验:</span>
|
||||||
|
<span style="display: inline-block;height: 32px;margin-left: 6px">
|
||||||
|
<a-switch :checked="validateStatus==1" @change="handleChangeValidateStatus" checked-children="是" un-checked-children="否" size="small"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
@ -47,6 +54,12 @@
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
required: false
|
required: false
|
||||||
|
},
|
||||||
|
//是否online导入
|
||||||
|
online:{
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
@ -55,7 +68,8 @@
|
|||||||
uploading:false,
|
uploading:false,
|
||||||
fileList:[],
|
fileList:[],
|
||||||
uploadAction:'',
|
uploadAction:'',
|
||||||
foreignKeys:''
|
foreignKeys:'',
|
||||||
|
validateStatus: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -78,6 +92,7 @@
|
|||||||
this.uploading = false
|
this.uploading = false
|
||||||
this.visible = true
|
this.visible = true
|
||||||
this.foreignKeys = arg;
|
this.foreignKeys = arg;
|
||||||
|
this.validateStatus = 0
|
||||||
},
|
},
|
||||||
handleRemove(file) {
|
handleRemove(file) {
|
||||||
const index = this.fileList.indexOf(file);
|
const index = this.fileList.indexOf(file);
|
||||||
@ -98,6 +113,9 @@
|
|||||||
if(this.foreignKeys && this.foreignKeys.length>0){
|
if(this.foreignKeys && this.foreignKeys.length>0){
|
||||||
formData.append('foreignKeys',this.foreignKeys);
|
formData.append('foreignKeys',this.foreignKeys);
|
||||||
}
|
}
|
||||||
|
if(this.online==true){
|
||||||
|
formData.append('validateStatus',this.validateStatus);
|
||||||
|
}
|
||||||
fileList.forEach((file) => {
|
fileList.forEach((file) => {
|
||||||
formData.append('files[]', file);
|
formData.append('files[]', file);
|
||||||
});
|
});
|
||||||
@ -105,14 +123,41 @@
|
|||||||
postAction(this.uploadAction, formData).then((res) => {
|
postAction(this.uploadAction, formData).then((res) => {
|
||||||
this.uploading = false
|
this.uploading = false
|
||||||
if(res.success){
|
if(res.success){
|
||||||
|
if(res.code == 201){
|
||||||
|
this.errorTip(res.message, res.result)
|
||||||
|
}else{
|
||||||
this.$message.success(res.message)
|
this.$message.success(res.message)
|
||||||
|
}
|
||||||
this.visible=false
|
this.visible=false
|
||||||
this.$emit('ok')
|
this.$emit('ok')
|
||||||
}else{
|
}else{
|
||||||
this.$message.warning(res.message)
|
this.$message.warning(res.message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
// 是否开启校验 开关改变事件
|
||||||
|
handleChangeValidateStatus(checked){
|
||||||
|
this.validateStatus = checked==true?1:0
|
||||||
|
},
|
||||||
|
// 错误信息提示
|
||||||
|
errorTip(tipMessage, fileUrl) {
|
||||||
|
const h = this.$createElement;
|
||||||
|
let href = window._CONFIG['domianURL'] + fileUrl
|
||||||
|
this.$warning({
|
||||||
|
title: '导入成功,但是有错误数据!',
|
||||||
|
content: h('div', {}, [
|
||||||
|
h('div', tipMessage),
|
||||||
|
h('span', '具体详情请 '),
|
||||||
|
h('a', {
|
||||||
|
attrs: {
|
||||||
|
href: href,
|
||||||
|
target: '_blank'
|
||||||
|
},
|
||||||
|
},'点击下载'),
|
||||||
|
]),
|
||||||
|
onOk() {},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,7 @@
|
|||||||
let text = this.value
|
let text = this.value
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case JINPUT_QUERY_LIKE:
|
case JINPUT_QUERY_LIKE:
|
||||||
//修复路由传参的值传送到jinput框被前后各截取了一位
|
//修复路由传参的值传送到jinput框被前后各截取了一位 #1336
|
||||||
if(text.indexOf("*") != -1){
|
if(text.indexOf("*") != -1){
|
||||||
text = text.substring(1,text.length-1);
|
text = text.substring(1,text.length-1);
|
||||||
}
|
}
|
||||||
@ -77,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+"*";
|
||||||
|
|||||||
@ -21,7 +21,6 @@ export default {
|
|||||||
'outdent',
|
'outdent',
|
||||||
'divider',
|
'divider',
|
||||||
'table',
|
'table',
|
||||||
'image',
|
|
||||||
'link',
|
'link',
|
||||||
'divider',
|
'divider',
|
||||||
'code',
|
'code',
|
||||||
|
|||||||
@ -1,5 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
<div class="j-markdown-editor" :id="id"/>
|
<div class="j-markdown-editor" :id="id"/>
|
||||||
|
<div v-if="isShow">
|
||||||
|
<j-modal
|
||||||
|
title="图片上传"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
width="30%"
|
||||||
|
:before-close="handleClose"
|
||||||
|
@ok="handleOk">
|
||||||
|
<a-tabs default-active-key="1" @change="handleChange">
|
||||||
|
<a-tab-pane tab="本地图片上传" key="1" :forceRender="true">
|
||||||
|
<j-upload v-model="fileList" :number="1"></j-upload>
|
||||||
|
<div style="margin-top: 20px">
|
||||||
|
<a-input v-model="remark" placeholder="请填写备注"></a-input>
|
||||||
|
</div>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane tab="网络图片地址" key="2" :forceRender="true">
|
||||||
|
<a-input v-model="networkPic" placeholder="请填写网络图片地址"></a-input>
|
||||||
|
<a-input style="margin-top: 20px" v-model="remark" placeholder="请填写备注"></a-input>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</j-modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -9,9 +32,14 @@ import '@toast-ui/editor/dist/i18n/zh-cn';
|
|||||||
|
|
||||||
import Editor from '@toast-ui/editor';
|
import Editor from '@toast-ui/editor';
|
||||||
import defaultOptions from './default-options'
|
import defaultOptions from './default-options'
|
||||||
|
import JUpload from '@/components/jeecg/JUpload'
|
||||||
|
import { getFileAccessHttpUrl } from '@/api/manage'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JMarkdownEditor',
|
name: 'JMarkdownEditor',
|
||||||
|
components: {
|
||||||
|
JUpload,
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -47,7 +75,16 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
editor: null
|
editor: null,
|
||||||
|
isShow:false,
|
||||||
|
activeIndex:"1",
|
||||||
|
dialogVisible:false,
|
||||||
|
index:"1",
|
||||||
|
fileList:[],
|
||||||
|
remark:"",
|
||||||
|
imageName:"",
|
||||||
|
imageUrl:"",
|
||||||
|
networkPic:""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -94,6 +131,40 @@ export default {
|
|||||||
this.editor.on('change', () => {
|
this.editor.on('change', () => {
|
||||||
this.$emit('change', this.editor.getMarkdown())
|
this.$emit('change', this.editor.getMarkdown())
|
||||||
})
|
})
|
||||||
|
//--begin 添加自定义上传按钮
|
||||||
|
/*
|
||||||
|
* 添加自定义按钮
|
||||||
|
*/
|
||||||
|
//获取编辑器上的功能条
|
||||||
|
let toolbar = this.editor.getUI().getToolbar();
|
||||||
|
let fileDom = this.$refs.files;
|
||||||
|
//添加图片点击事件
|
||||||
|
this.editor.eventManager.addEventType('isShowClickEvent');
|
||||||
|
this.editor.eventManager.listen('isShowClickEvent', () => {
|
||||||
|
this.isShow = true
|
||||||
|
this.dialogVisible = true
|
||||||
|
});
|
||||||
|
//addImageBlobHook图片上传、剪切、拖拽都会走此方法
|
||||||
|
// 删除默认监听事件
|
||||||
|
this.editor.eventManager.removeEventHandler('addImageBlobHook')
|
||||||
|
// 添加自定义监听事件
|
||||||
|
this.editor.eventManager.listen('addImageBlobHook', (blob, callback) => {
|
||||||
|
this.upload(blob, url => {
|
||||||
|
callback(url)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// 添加自定义按钮 第二个参数代表位置,不传默认放在最后
|
||||||
|
toolbar.insertItem(15,{
|
||||||
|
type: 'button',
|
||||||
|
options:{
|
||||||
|
name: 'customize',
|
||||||
|
className: 'tui-image tui-toolbar-icons',
|
||||||
|
event: 'isShowClickEvent',
|
||||||
|
tooltip: '上传图片',
|
||||||
|
}
|
||||||
|
//
|
||||||
|
});
|
||||||
|
//--end 添加自定义上传按钮
|
||||||
},
|
},
|
||||||
destroyEditor() {
|
destroyEditor() {
|
||||||
if (!this.editor) return
|
if (!this.editor) return
|
||||||
@ -111,7 +182,57 @@ export default {
|
|||||||
},
|
},
|
||||||
getHtml() {
|
getHtml() {
|
||||||
return this.editor.getHtml()
|
return this.editor.getHtml()
|
||||||
|
},
|
||||||
|
handleOk(){
|
||||||
|
if(this.index=='1'){
|
||||||
|
this.imageUrl = getFileAccessHttpUrl(this.fileList)
|
||||||
|
if(this.remark){
|
||||||
|
this.addImgToMd(this.imageUrl,this.remark)
|
||||||
|
}else{
|
||||||
|
this.addImgToMd(this.imageUrl,"")
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
if(this.remark){
|
||||||
|
this.addImgToMd(this.networkPic,this.remark)
|
||||||
|
}else{
|
||||||
|
this.addImgToMd(this.networkPic,"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.index="1"
|
||||||
|
this.fileList=[]
|
||||||
|
this.imageName="";
|
||||||
|
this.imageUrl="";
|
||||||
|
this.remark=""
|
||||||
|
this.networkPic=""
|
||||||
|
this.dialogVisible=false
|
||||||
|
this.isShow=false;
|
||||||
|
},
|
||||||
|
handleClose(done) {
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
handleChange(val){
|
||||||
|
this.fileList=[]
|
||||||
|
this.remark=""
|
||||||
|
this.imageName=""
|
||||||
|
this.imageUrl=""
|
||||||
|
this.networkPic=""
|
||||||
|
this.index=val
|
||||||
|
},
|
||||||
|
//添加图片到markdown
|
||||||
|
addImgToMd(data,name) {
|
||||||
|
let editor = this.editor.getCodeMirror();
|
||||||
|
let editorHtml = this.editor.getCurrentModeEditor();
|
||||||
|
let isMarkdownMode = this.editor.isMarkdownMode();
|
||||||
|
if (isMarkdownMode) {
|
||||||
|
editor.replaceSelection(``);
|
||||||
|
} else {
|
||||||
|
let range = editorHtml.getRange();
|
||||||
|
let img = document.createElement('img');
|
||||||
|
img.src = `${data}`;
|
||||||
|
img.alt = name;
|
||||||
|
range.insertNode(img);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
prop: 'value',
|
prop: 'value',
|
||||||
|
|||||||
@ -8,10 +8,11 @@
|
|||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
@ok="handleOk"
|
@ok="handleOk"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
|
destroyOnClose
|
||||||
>
|
>
|
||||||
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
<!--有设置标题-->
|
||||||
<template v-if="!isNoTitle" slot="title">
|
<template v-if="!isNoTitle" slot="title">
|
||||||
<a-row class="j-modal-title-row" type="flex">
|
<a-row class="j-modal-title-row" type="flex">
|
||||||
<a-col class="left">
|
<a-col class="left">
|
||||||
@ -22,6 +23,14 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</template>
|
</template>
|
||||||
|
<!--没有设置标题-->
|
||||||
|
<template v-else slot="title">
|
||||||
|
<a-row class="j-modal-title-row" type="flex">
|
||||||
|
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
|
||||||
|
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- 处理 scopedSlots -->
|
<!-- 处理 scopedSlots -->
|
||||||
<template v-for="slotName of scopedSlotsKeys" :slot="slotName">
|
<template v-for="slotName of scopedSlotsKeys" :slot="slotName">
|
||||||
@ -110,7 +119,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() {
|
||||||
@ -161,7 +170,6 @@
|
|||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.j-modal-box {
|
.j-modal-box {
|
||||||
|
|
||||||
&.fullscreen {
|
&.fullscreen {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -190,7 +198,6 @@
|
|||||||
height: calc(100% - 55px);
|
height: calc(100% - 55px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.no-title.no-footer {
|
&.no-title.no-footer {
|
||||||
.ant-modal-body {
|
.ant-modal-body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -217,6 +224,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.no-title{
|
||||||
|
.ant-modal-header {
|
||||||
|
padding: 0px 24px;
|
||||||
|
border-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
|
|||||||
@ -10,7 +10,9 @@
|
|||||||
ref="jPopupOnlReport"
|
ref="jPopupOnlReport"
|
||||||
:code="code"
|
:code="code"
|
||||||
:multi="multi"
|
:multi="multi"
|
||||||
|
:sorter="sorter"
|
||||||
:groupId="uniqGroupId"
|
:groupId="uniqGroupId"
|
||||||
|
:param="param"
|
||||||
@ok="callBack"
|
@ok="callBack"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -46,6 +48,11 @@
|
|||||||
default: '',
|
default: '',
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
/** 排序列,指定要排序的列,使用方式:列名=desc|asc */
|
||||||
|
sorter: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
width: {
|
width: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1200,
|
default: 1200,
|
||||||
@ -75,6 +82,17 @@
|
|||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
//popup动态参数 支持系统变量语法
|
||||||
|
param:{
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: ()=>{}
|
||||||
|
},
|
||||||
|
spliter:{
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ','
|
||||||
|
},
|
||||||
/** 分组ID,用于将多个popup的请求合并到一起,不传不分组 */
|
/** 分组ID,用于将多个popup的请求合并到一起,不传不分组 */
|
||||||
groupId: String
|
groupId: String
|
||||||
|
|
||||||
@ -101,7 +119,7 @@
|
|||||||
if (!val) {
|
if (!val) {
|
||||||
this.showText = ''
|
this.showText = ''
|
||||||
} else {
|
} else {
|
||||||
this.showText = val
|
this.showText = val.split(this.spliter).join(',')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,7 +199,11 @@
|
|||||||
} else {
|
} else {
|
||||||
//v-model时 需要传一个参数field 表示当前这个字段 从而根据这个字段的顺序找到原始值
|
//v-model时 需要传一个参数field 表示当前这个字段 从而根据这个字段的顺序找到原始值
|
||||||
// this.$emit("input",row[orgFieldsArr[destFieldsArr.indexOf(this.field)]])
|
// this.$emit("input",row[orgFieldsArr[destFieldsArr.indexOf(this.field)]])
|
||||||
this.$emit('input', this.showText, res)
|
let str = ''
|
||||||
|
if(this.showText){
|
||||||
|
str = this.showText.split(',').join(this.spliter)
|
||||||
|
}
|
||||||
|
this.$emit('input', str, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="(item,index) in options"
|
v-for="(item,index) in options"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
:getPopupContainer="getParentContainer"
|
||||||
:value="item.value">
|
:value="item.value">
|
||||||
{{ item.text || item.label }}
|
{{ item.text || item.label }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@ -36,11 +37,21 @@
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
}
|
},
|
||||||
|
spliter:{
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ','
|
||||||
|
},
|
||||||
|
popContainer:{
|
||||||
|
type:String,
|
||||||
|
default:'',
|
||||||
|
required:false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
arrayValue:!this.value?[]:this.value.split(",")
|
arrayValue:!this.value?[]:this.value.split(this.spliter)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
@ -48,18 +59,25 @@
|
|||||||
if(!val){
|
if(!val){
|
||||||
this.arrayValue = []
|
this.arrayValue = []
|
||||||
}else{
|
}else{
|
||||||
this.arrayValue = this.value.split(",")
|
this.arrayValue = this.value.split(this.spliter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
onChange (selectedValue) {
|
onChange (selectedValue) {
|
||||||
if(this.triggerChange){
|
if(this.triggerChange){
|
||||||
this.$emit('change', selectedValue.join(","));
|
this.$emit('change', selectedValue.join(this.spliter));
|
||||||
}else{
|
}else{
|
||||||
this.$emit('input', selectedValue.join(","));
|
this.$emit('input', selectedValue.join(this.spliter));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getParentContainer(node){
|
||||||
|
if(!this.popContainer){
|
||||||
|
return node.parentNode
|
||||||
|
}else{
|
||||||
|
return document.querySelector(this.popContainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,7 +101,15 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<a-col :md="8" :xs="24" style="margin-bottom: 12px;">
|
<a-col :md="8" :xs="24" style="margin-bottom: 12px;">
|
||||||
<template v-if="item.dictCode">
|
<!-- 下拉搜索 -->
|
||||||
|
<j-search-select-tag v-if="item.type==='sel_search'" v-model="item.val" :dict="getDictInfo(item)" placeholder="请选择"/>
|
||||||
|
<!-- 下拉多选 -->
|
||||||
|
<template v-else-if="item.type==='list_multi'">
|
||||||
|
<j-multi-select-tag v-if="item.options" v-model="item.val" :options="item.options" placeholder="请选择"/>
|
||||||
|
<j-multi-select-tag v-else v-model="item.val" :dictCode="getDictInfo(item)" placeholder="请选择"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="item.dictCode">
|
||||||
<template v-if="item.type === 'table-dict'">
|
<template v-if="item.type === 'table-dict'">
|
||||||
<j-popup
|
<j-popup
|
||||||
v-model="item.val"
|
v-model="item.val"
|
||||||
@ -109,6 +117,7 @@
|
|||||||
:field="item.dictCode"
|
:field="item.dictCode"
|
||||||
:orgFields="item.dictCode"
|
:orgFields="item.dictCode"
|
||||||
:destFields="item.dictCode"
|
:destFields="item.dictCode"
|
||||||
|
:multi="true"
|
||||||
></j-popup>
|
></j-popup>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@ -116,7 +125,13 @@
|
|||||||
<j-dict-select-tag v-show="!allowMultiple(item)" v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/>
|
<j-dict-select-tag v-show="!allowMultiple(item)" v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<j-popup v-else-if="item.type === 'popup'" :value="item.val" v-bind="item.popup" group-id="superQuery" @input="(e,v)=>handleChangeJPopup(item,e,v)"/>
|
<j-popup
|
||||||
|
v-else-if="item.type === 'popup'"
|
||||||
|
:value="item.val"
|
||||||
|
v-bind="item.popup"
|
||||||
|
group-id="superQuery"
|
||||||
|
@input="(e,v)=>handleChangeJPopup(item,e,v)"
|
||||||
|
:multi="true"/>
|
||||||
<j-select-multi-user
|
<j-select-multi-user
|
||||||
v-else-if="item.type === 'select-user' || item.type === 'sel_user'"
|
v-else-if="item.type === 'select-user' || item.type === 'sel_user'"
|
||||||
v-model="item.val"
|
v-model="item.val"
|
||||||
@ -338,6 +353,17 @@
|
|||||||
}
|
}
|
||||||
this.visible = true
|
this.visible = true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getDictInfo(item) {
|
||||||
|
let str = ''
|
||||||
|
if(!item.dictTable){
|
||||||
|
str = item.dictCode
|
||||||
|
}else{
|
||||||
|
str = item.dictTable+','+item.dictText+','+item.dictCode
|
||||||
|
}
|
||||||
|
console.log('高级查询字典信息',str)
|
||||||
|
return str
|
||||||
|
},
|
||||||
handleOk() {
|
handleOk() {
|
||||||
if (!this.isNullArray(this.queryParamsModel)) {
|
if (!this.isNullArray(this.queryParamsModel)) {
|
||||||
let event = {
|
let event = {
|
||||||
@ -386,11 +412,12 @@
|
|||||||
this.queryParamsModel.splice(index, 1)
|
this.queryParamsModel.splice(index, 1)
|
||||||
},
|
},
|
||||||
handleSelected(node, item) {
|
handleSelected(node, item) {
|
||||||
let { type, options, dictCode, dictTable, customReturnField, popup } = node.dataRef
|
let { type, options, dictCode, dictTable, dictText, customReturnField, popup } = node.dataRef
|
||||||
item['type'] = type
|
item['type'] = type
|
||||||
item['options'] = options
|
item['options'] = options
|
||||||
item['dictCode'] = dictCode
|
item['dictCode'] = dictCode
|
||||||
item['dictTable'] = dictTable
|
item['dictTable'] = dictTable
|
||||||
|
item['dictText'] = dictText
|
||||||
item['customReturnField'] = customReturnField
|
item['customReturnField'] = customReturnField
|
||||||
if (popup) {
|
if (popup) {
|
||||||
item['popup'] = popup
|
item['popup'] = popup
|
||||||
@ -498,10 +525,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
:multiple="true"
|
:multiple="multiple"
|
||||||
:action="uploadAction"
|
:action="uploadAction"
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
:data="{'biz':bizPath}"
|
:data="{'biz':bizPath}"
|
||||||
@ -135,6 +135,10 @@
|
|||||||
required:false,
|
required:false,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
value:{
|
value:{
|
||||||
@ -374,6 +378,7 @@
|
|||||||
},
|
},
|
||||||
mounted(){
|
mounted(){
|
||||||
const moverObj = document.getElementById(this.containerId+'-mover');
|
const moverObj = document.getElementById(this.containerId+'-mover');
|
||||||
|
if(moverObj){
|
||||||
moverObj.addEventListener('mouseover',()=>{
|
moverObj.addEventListener('mouseover',()=>{
|
||||||
this.moverHold = true
|
this.moverHold = true
|
||||||
this.moveDisplay = 'block';
|
this.moveDisplay = 'block';
|
||||||
@ -382,6 +387,8 @@
|
|||||||
this.moverHold = false
|
this.moverHold = false
|
||||||
this.moveDisplay = 'none';
|
this.moveDisplay = 'none';
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let picList = document.getElementById(this.containerId)?document.getElementById(this.containerId).getElementsByClassName('ant-upload-list-picture-card'):[];
|
let picList = document.getElementById(this.containerId)?document.getElementById(this.containerId).getElementsByClassName('ant-upload-list-picture-card'):[];
|
||||||
if(picList && picList.length>0){
|
if(picList && picList.length>0){
|
||||||
picList[0].addEventListener('mouseover',(ev)=>{
|
picList[0].addEventListener('mouseover',(ev)=>{
|
||||||
|
|||||||
@ -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,182 @@
|
|||||||
|
<template>
|
||||||
|
<a-popover :visible="visible" :placement="placement" 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
|
||||||
|
},
|
||||||
|
placement: 'bottom'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
toggle(event) {
|
||||||
|
|
||||||
|
//update-begin-author:taoyan date:20200921 for: 弹出子表时,子表会闪一下,类似重新计算子表的位置
|
||||||
|
if(document.body.clientHeight - event.$event.clientY > 350){
|
||||||
|
this.placement = 'bottom'
|
||||||
|
}else{
|
||||||
|
this.placement = 'top'
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:20200921 for: 弹出子表时,子表会闪一下,类似重新计算子表的位置
|
||||||
|
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
|
||||||
|
//update-begin-author:taoyan date:20200921 for: 子表弹出位置存在现实位置问题。
|
||||||
|
//let realTable = getParentNodeByTagName(tr, 'table')
|
||||||
|
//let left = realTable.parentNode.scrollLeft
|
||||||
|
let h = event.$event.clientY
|
||||||
|
if(h){
|
||||||
|
h = h-140
|
||||||
|
}
|
||||||
|
let toolbar = this.$refs.div.nextSibling
|
||||||
|
domAlign(this.$refs.div, toolbar, {
|
||||||
|
points: ['tl', 'tl'],
|
||||||
|
offset: [0, h],
|
||||||
|
overflow: {
|
||||||
|
alwaysByViewport: true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
//update-end-author:taoyan date:20200921 for: 子表弹出位置存在现实位置问题。
|
||||||
|
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.push('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,68 @@
|
|||||||
|
<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.call(this, event, 'ant-calendar-picker', el => el.children[0].dispatchEvent(event.$event))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-input
|
||||||
|
v-show="!departIds"
|
||||||
|
@click="openSelect"
|
||||||
|
placeholder="请点击选择部门"
|
||||||
|
v-model="departNames"
|
||||||
|
readOnly
|
||||||
|
:disabled="componentDisabled"
|
||||||
|
class="jvxe-select-input">
|
||||||
|
<a-icon slot="prefix" type="cluster" title="部门选择控件"/>
|
||||||
|
</a-input>
|
||||||
|
<j-select-depart-modal
|
||||||
|
ref="innerDepartSelectModal"
|
||||||
|
:modal-width="modalWidth"
|
||||||
|
:multi="multi"
|
||||||
|
:rootOpened="rootOpened"
|
||||||
|
:depart-id="departIds"
|
||||||
|
@ok="handleOK"
|
||||||
|
@initComp="initComp"/>
|
||||||
|
<span style="display: inline-block;height:100%;padding-left:14px" v-if="departIds" >
|
||||||
|
<span @click="openSelect" style="display: inline-block;vertical-align: middle">{{ departNames }}</span>
|
||||||
|
<a-icon style="margin-left:5px;vertical-align: middle" type="close-circle" @click="handleEmpty" title="清空"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
import JSelectDepartModal from '@/components/jeecgbiz/modal/JSelectDepartModal'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeDepartSelectCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
components:{
|
||||||
|
JSelectDepartModal
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
departNames: '',
|
||||||
|
departIds: '',
|
||||||
|
selectedOptions: [],
|
||||||
|
customReturnField: 'id'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
custProps() {
|
||||||
|
const {departIds, originColumn: col, caseId, cellProps} = this
|
||||||
|
return {
|
||||||
|
...cellProps,
|
||||||
|
value: departIds,
|
||||||
|
field: col.field || col.key,
|
||||||
|
groupId: caseId,
|
||||||
|
class: 'jvxe-select'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentDisabled(){
|
||||||
|
if(this.cellProps.disabled==true){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
modalWidth(){
|
||||||
|
if(this.cellProps.modalWidth){
|
||||||
|
return this.cellProps.modalWidth
|
||||||
|
}else{
|
||||||
|
return 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
multi(){
|
||||||
|
if(this.cellProps.multi==false){
|
||||||
|
return false
|
||||||
|
}else{
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rootOpened(){
|
||||||
|
if(this.cellProps.open==false){
|
||||||
|
return false
|
||||||
|
}else{
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val == null || val === '') {
|
||||||
|
this.departIds = ''
|
||||||
|
} else {
|
||||||
|
this.departIds = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openSelect(){
|
||||||
|
this.$refs.innerDepartSelectModal.show()
|
||||||
|
},
|
||||||
|
handleEmpty(){
|
||||||
|
this.handleOK('')
|
||||||
|
},
|
||||||
|
handleOK(rows, idstr) {
|
||||||
|
let value = ''
|
||||||
|
if (!rows && rows.length <= 0) {
|
||||||
|
this.departNames = ''
|
||||||
|
this.departIds = ''
|
||||||
|
} else {
|
||||||
|
value = rows.map(row => row[this.customReturnField]).join(',')
|
||||||
|
this.departNames = rows.map(row => row['departName']).join(',')
|
||||||
|
this.departIds = idstr
|
||||||
|
}
|
||||||
|
this.handleChangeCommon(this.departIds)
|
||||||
|
},
|
||||||
|
initComp(departNames){
|
||||||
|
this.departNames = departNames
|
||||||
|
},
|
||||||
|
handleChange(value) {
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enhanced: {
|
||||||
|
switches: {
|
||||||
|
visible: true
|
||||||
|
},
|
||||||
|
translate: {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/deep/ .jvxe-select-input .ant-input{
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
</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.fullDataLength - 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,152 @@
|
|||||||
|
<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.call(this, 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,36 @@
|
|||||||
|
<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.call(this, 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,136 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-input
|
||||||
|
v-show="!userIds"
|
||||||
|
@click="openSelect"
|
||||||
|
placeholder="请选择用户"
|
||||||
|
v-model="userNames"
|
||||||
|
readOnly
|
||||||
|
class="jvxe-select-input"
|
||||||
|
:disabled="componentDisabled">
|
||||||
|
<a-icon slot="prefix" type="user" title="用户选择控件"/>
|
||||||
|
</a-input>
|
||||||
|
<j-select-user-by-dep-modal
|
||||||
|
ref="selectModal"
|
||||||
|
:modal-width="modalWidth"
|
||||||
|
:multi="multi"
|
||||||
|
:user-ids="userIds"
|
||||||
|
@ok="selectOK"
|
||||||
|
@initComp="initComp"/>
|
||||||
|
<span style="display: inline-block;height:100%;padding-left:14px" v-if="userIds" >
|
||||||
|
<span @click="openSelect" style="display: inline-block;vertical-align: middle">{{ userNames }}</span>
|
||||||
|
<a-icon style="margin-left:5px;vertical-align: middle" type="close-circle" @click="handleEmpty" title="清空"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <j-select-user-by-dep
|
||||||
|
v-bind="custProps"
|
||||||
|
@change="handleChange"
|
||||||
|
:trigger-change="true">
|
||||||
|
</j-select-user-by-dep>-->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
import JSelectUserByDepModal from '@/components/jeecgbiz/modal/JSelectUserByDepModal'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeUserSelectCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
components: { JSelectUserByDepModal },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userIds:'',
|
||||||
|
userNames:'',
|
||||||
|
innerUserValue: '',
|
||||||
|
selectedOptions: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
custProps() {
|
||||||
|
const {userIds, originColumn: col, caseId, cellProps} = this
|
||||||
|
return {
|
||||||
|
...cellProps,
|
||||||
|
value: userIds,
|
||||||
|
field: col.field || col.key,
|
||||||
|
groupId: caseId,
|
||||||
|
class: 'jvxe-select'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentDisabled(){
|
||||||
|
console.log('333',this.cellProps)
|
||||||
|
if(this.cellProps.disabled==true){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
modalWidth(){
|
||||||
|
if(this.cellProps.modalWidth){
|
||||||
|
return this.cellProps.modalWidth
|
||||||
|
}else{
|
||||||
|
return 1250
|
||||||
|
}
|
||||||
|
},
|
||||||
|
multi(){
|
||||||
|
if(this.cellProps.multi==false){
|
||||||
|
return false
|
||||||
|
}else{
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val == null || val === '') {
|
||||||
|
this.userIds = ''
|
||||||
|
} else {
|
||||||
|
this.userIds = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openSelect() {
|
||||||
|
this.$refs.selectModal.showModal()
|
||||||
|
},
|
||||||
|
selectOK(rows, idstr) {
|
||||||
|
console.log("当前选中用户", rows)
|
||||||
|
console.log("当前选中用户ID", idstr)
|
||||||
|
if (!rows) {
|
||||||
|
this.userNames = ''
|
||||||
|
this.userIds = ''
|
||||||
|
} else {
|
||||||
|
let temp = ''
|
||||||
|
for (let item of rows) {
|
||||||
|
temp += ',' + item.realname
|
||||||
|
}
|
||||||
|
this.userNames = temp.substring(1)
|
||||||
|
this.userIds = idstr
|
||||||
|
}
|
||||||
|
this.handleChangeCommon(this.userIds)
|
||||||
|
},
|
||||||
|
handleEmpty(){
|
||||||
|
this.selectOK('')
|
||||||
|
},
|
||||||
|
initComp(userNames) {
|
||||||
|
this.userNames = userNames
|
||||||
|
},
|
||||||
|
},
|
||||||
|
enhanced: {
|
||||||
|
switches: {
|
||||||
|
visible: true
|
||||||
|
},
|
||||||
|
translate: {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/deep/ .jvxe-select-input .ant-input {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
</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()])
|
||||||
|
},
|
||||||
|
}
|
||||||
51
ant-design-vue-jeecg/src/components/jeecg/JVxeTable/index.js
Normal file
51
ant-design-vue-jeecg/src/components/jeecg/JVxeTable/index.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import * as jvxeTypes from './jvxeTypes'
|
||||||
|
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'
|
||||||
|
import JVxeDepartSelectCell from './components/cells/JVxeDepartSelectCell'
|
||||||
|
import JVxeUserSelectCell from './components/cells/JVxeUserSelectCell'
|
||||||
|
|
||||||
|
//update--begin--autor:lvdandan-----date:20201216------for:JVxeTable--JVXETypes 【online】代码结构调整,便于online打包
|
||||||
|
// 组件类型
|
||||||
|
export const JVXETypes = jvxeTypes.JVXETypes
|
||||||
|
//update--end--autor:lvdandan-----date:20201216------for:JVxeTable--JVXETypes 【online】代码结构调整,便于online打包
|
||||||
|
|
||||||
|
// 注册自定义组件
|
||||||
|
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),
|
||||||
|
...mapCell(JVXETypes.departSelect, JVxeDepartSelectCell),
|
||||||
|
...mapCell(JVXETypes.userSelect, JVxeUserSelectCell)
|
||||||
|
|
||||||
|
/* 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') || className.includes('j-depart-select-modal') || className.includes('j-user-select-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,44 @@
|
|||||||
|
// 组件类型
|
||||||
|
export default JVXETypes
|
||||||
|
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',
|
||||||
|
//部门选择
|
||||||
|
departSelect: 'sel_depart',
|
||||||
|
//用户选择
|
||||||
|
userSelect: 'sel_user',
|
||||||
|
|
||||||
|
// 拖轮Tags(暂无用)
|
||||||
|
tags: 'tags',
|
||||||
|
|
||||||
|
slot: 'slot',
|
||||||
|
normal: 'normal',
|
||||||
|
hidden: 'hidden',
|
||||||
|
}
|
||||||
@ -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,314 @@
|
|||||||
|
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
|
||||||
|
},
|
||||||
|
fullDataLength() {
|
||||||
|
return this.params.$table.tableFullData.length
|
||||||
|
},
|
||||||
|
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
|
||||||
|
//online增强参数兼容
|
||||||
|
event.column['key'] = this.column['property']
|
||||||
|
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) {
|
||||||
|
// alwaysEdit 下不模拟触发事件,否者会导致触发两次
|
||||||
|
if (this && this.alwaysEdit) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
window.setTimeout(() => {
|
||||||
|
let element = cell.getElementsByClassName(className)
|
||||||
|
if (element && element.length > 0) {
|
||||||
|
if (typeof handler === 'function') {
|
||||||
|
handler(element[0])
|
||||||
|
} else {
|
||||||
|
// 模拟触发点击事件
|
||||||
|
if($event){
|
||||||
|
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,217 @@
|
|||||||
|
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 form 主表单 form 对象
|
||||||
|
* @param cases 接收一个数组,每项都是一个JVxeTable实例
|
||||||
|
* @param autoJumpTab
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
* @author sunjianlei
|
||||||
|
*/
|
||||||
|
export async function validateFormModelAndTables(form,formData, cases, autoJumpTab) {
|
||||||
|
if (!(form && typeof form.validate === 'function')) {
|
||||||
|
throw `form 参数需要的是一个form对象,而传入的却是${typeof form}`
|
||||||
|
}
|
||||||
|
let dataMap = {}
|
||||||
|
let values = await new Promise((resolve, reject) => {
|
||||||
|
// 验证主表表单
|
||||||
|
form.validate((valid,obj) => {
|
||||||
|
valid ?resolve(formData): reject({error: VALIDATE_FAILED, originError: valid})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
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})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})()
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -258,7 +258,7 @@ export default {
|
|||||||
components: { JTreeTable },
|
components: { JTreeTable },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
url: '/api/asynTreeList',
|
url: '/mock/api/asynTreeList',
|
||||||
columns: [
|
columns: [
|
||||||
{ title: '菜单名称', dataIndex: 'name' },
|
{ title: '菜单名称', dataIndex: 'name' },
|
||||||
{ title: '组件', dataIndex: 'component' },
|
{ title: '组件', dataIndex: 'component' },
|
||||||
|
|||||||
@ -1,11 +1,77 @@
|
|||||||
import JModal from './JModal'
|
import JModal from './JModal'
|
||||||
import JFormContainer from './JFormContainer.vue'
|
import JFormContainer from './JFormContainer.vue'
|
||||||
import JPopup from './JPopup.vue'
|
import JPopup from './JPopup.vue'
|
||||||
|
import JMarkdownEditor from './JMarkdownEditor'
|
||||||
|
import JCodeEditor from './JCodeEditor.vue'
|
||||||
|
import JEditor from './JEditor.vue'
|
||||||
|
import JEditableTable from './JEditableTable.vue'
|
||||||
|
import JAreaLinkage from './JAreaLinkage.vue'
|
||||||
|
import JSuperQuery from './JSuperQuery.vue'
|
||||||
|
import JUpload from './JUpload.vue'
|
||||||
|
import JTreeSelect from './JTreeSelect.vue'
|
||||||
|
import JCategorySelect from './JCategorySelect.vue'
|
||||||
|
import JImageUpload from './JImageUpload.vue'
|
||||||
|
import JImportModal from './JImportModal.vue'
|
||||||
|
import JTreeDict from './JTreeDict.vue'
|
||||||
|
import JCheckbox from './JCheckbox.vue'
|
||||||
|
import JCron from './JCron.vue'
|
||||||
|
import JDate from './JDate.vue'
|
||||||
|
import JEllipsis from './JEllipsis.vue'
|
||||||
|
import JInput from './JInput.vue'
|
||||||
|
import JPopupOnlReport from './modal/JPopupOnlReport.vue'
|
||||||
|
import JFilePop from './minipop/JFilePop.vue'
|
||||||
|
import JInputPop from './minipop/JInputPop.vue'
|
||||||
|
import JSelectMultiple from './JSelectMultiple.vue'
|
||||||
|
import JSlider from './JSlider.vue'
|
||||||
|
import JSwitch from './JSwitch.vue'
|
||||||
|
import JTime from './JTime.vue'
|
||||||
|
import JTreeTable from './JTreeTable.vue'
|
||||||
|
import JEasyCron from "@/components/jeecg/JEasyCron";
|
||||||
|
|
||||||
|
//jeecgbiz
|
||||||
|
import JSelectDepart from '../jeecgbiz/JSelectDepart.vue'
|
||||||
|
import JSelectMultiUser from '../jeecgbiz/JSelectMultiUser.vue'
|
||||||
|
import JSelectPosition from '../jeecgbiz/JSelectPosition.vue'
|
||||||
|
import JSelectRole from '../jeecgbiz/JSelectRole.vue'
|
||||||
|
import JSelectUserByDep from '../jeecgbiz/JSelectUserByDep.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(Vue) {
|
install(Vue) {
|
||||||
Vue.component('JFormContainer', JFormContainer)
|
Vue.component('JMarkdownEditor', JMarkdownEditor)
|
||||||
Vue.component('JPopup', JPopup)
|
|
||||||
Vue.component(JModal.name, JModal)
|
Vue.component(JModal.name, JModal)
|
||||||
|
Vue.component('JPopupOnlReport', JPopupOnlReport)
|
||||||
|
Vue.component('JFilePop', JFilePop)
|
||||||
|
Vue.component('JInputPop', JInputPop)
|
||||||
|
Vue.component('JAreaLinkage', JAreaLinkage)
|
||||||
|
Vue.component('JCategorySelect', JCategorySelect)
|
||||||
|
Vue.component('JCheckbox', JCheckbox)
|
||||||
|
Vue.component('JCodeEditor', JCodeEditor)
|
||||||
|
Vue.component('JCron', JCron)
|
||||||
|
Vue.component('JDate', JDate)
|
||||||
|
Vue.component('JEditableTable', JEditableTable)
|
||||||
|
Vue.component('JEditor', JEditor)
|
||||||
|
Vue.component('JEllipsis', JEllipsis)
|
||||||
|
Vue.component('JFormContainer', JFormContainer)
|
||||||
|
Vue.component('JImageUpload', JImageUpload)
|
||||||
|
Vue.component('JImportModal', JImportModal)
|
||||||
|
Vue.component('JInput', JInput)
|
||||||
|
Vue.component('JPopup', JPopup)
|
||||||
|
Vue.component('JSelectMultiple', JSelectMultiple)
|
||||||
|
Vue.component('JSlider', JSlider)
|
||||||
|
Vue.component('JSuperQuery', JSuperQuery)
|
||||||
|
Vue.component('JSwitch', JSwitch)
|
||||||
|
Vue.component('JTime', JTime)
|
||||||
|
Vue.component('JTreeDict', JTreeDict)
|
||||||
|
Vue.component('JTreeSelect', JTreeSelect)
|
||||||
|
Vue.component('JTreeTable', JTreeTable)
|
||||||
|
Vue.component('JUpload', JUpload)
|
||||||
|
|
||||||
|
//jeecgbiz
|
||||||
|
Vue.component('JSelectDepart', JSelectDepart)
|
||||||
|
Vue.component('JSelectMultiUser', JSelectMultiUser)
|
||||||
|
Vue.component('JSelectPosition', JSelectPosition)
|
||||||
|
Vue.component('JSelectRole', JSelectRole)
|
||||||
|
Vue.component('JSelectUserByDep', JSelectUserByDep)
|
||||||
|
Vue.component(JEasyCron.name, JEasyCron)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,20 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<a-modal
|
<a-modal
|
||||||
title="文件上传"
|
:title="fileType === 'image' ? '图片上传' : '文件上传'"
|
||||||
:width="width"
|
:width="width"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
@ok="ok"
|
@ok="ok"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
@cancel="close">
|
@cancel="close">
|
||||||
<!--style="top: 20px;"-->
|
<!--style="top: 20px;"-->
|
||||||
<j-upload :file-type="fileType" :value="filePath" @change="handleChange" :disabled="disabled"></j-upload>
|
<j-upload :file-type="fileType" :value="filePath" @change="handleChange" :disabled="disabled" :number="number"></j-upload>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import JUpload from '@/components/jeecg/JUpload'
|
|
||||||
import { getFileAccessHttpUrl } from '@/api/manage';
|
import { getFileAccessHttpUrl } from '@/api/manage';
|
||||||
|
|
||||||
const getFileName=(path)=>{
|
const getFileName=(path)=>{
|
||||||
@ -27,7 +26,7 @@
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JFilePop',
|
name: 'JFilePop',
|
||||||
components: { JUpload },
|
components: { },
|
||||||
props:{
|
props:{
|
||||||
title:{
|
title:{
|
||||||
type:String,
|
type:String,
|
||||||
@ -59,6 +58,11 @@
|
|||||||
type:Boolean,
|
type:Boolean,
|
||||||
default:false,
|
default:false,
|
||||||
required:false
|
required:false
|
||||||
|
},
|
||||||
|
number:{
|
||||||
|
type:Number,
|
||||||
|
required:false,
|
||||||
|
default: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
<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" :disabled="disabled" @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>
|
||||||
@ -84,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){
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal
|
||||||
title="corn表达式"
|
title="cron表达式"
|
||||||
:width="modalWidth"
|
:width="modalWidth"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
:confirmLoading="confirmLoading"
|
:confirmLoading="confirmLoading"
|
||||||
|
|||||||
@ -78,7 +78,7 @@
|
|||||||
const MODAL_WIDTH = 1200;
|
const MODAL_WIDTH = 1200;
|
||||||
export default {
|
export default {
|
||||||
name: 'JPopupOnlReport',
|
name: 'JPopupOnlReport',
|
||||||
props: ['multi', 'code', 'groupId'],
|
props: ['multi', 'code', 'sorter', 'groupId', 'param'],
|
||||||
components:{
|
components:{
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
@ -121,17 +121,47 @@
|
|||||||
},
|
},
|
||||||
cgRpConfigId:"",
|
cgRpConfigId:"",
|
||||||
modalWidth:MODAL_WIDTH,
|
modalWidth:MODAL_WIDTH,
|
||||||
tableScroll:{x:MODAL_WIDTH-100}
|
tableScroll:{x:true},
|
||||||
|
dynamicParam:{},
|
||||||
|
// 排序字段,默认无排序
|
||||||
|
iSorter: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.loadColumnsInfo()
|
//this.loadColumnsInfo()
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
code() {
|
code() {
|
||||||
this.loadColumnsInfo()
|
this.loadColumnsInfo()
|
||||||
|
},
|
||||||
|
param:{
|
||||||
|
deep:true,
|
||||||
|
handler(){
|
||||||
|
this.dynamicParamHandler()
|
||||||
|
this.loadData();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sorter: {
|
||||||
|
immediate: true,
|
||||||
|
handler() {
|
||||||
|
if (this.sorter) {
|
||||||
|
let arr = this.sorter.split('=')
|
||||||
|
if (arr.length === 2 && ['asc', 'desc'].includes(arr[1].toLowerCase())) {
|
||||||
|
this.iSorter = {column: arr[0], order: arr[1].toLowerCase()}
|
||||||
|
// 排序字段受控
|
||||||
|
this.table.columns.forEach(col => {
|
||||||
|
if (col.dataIndex === this.iSorter.column) {
|
||||||
|
this.$set(col, 'sortOrder', this.iSorter.order === 'asc' ? 'ascend' : 'descend')
|
||||||
|
} else {
|
||||||
|
this.$set(col, 'sortOrder', false)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.warn('【JPopup】sorter参数不合法')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed:{
|
computed:{
|
||||||
showSearchFlag(){
|
showSearchFlag(){
|
||||||
@ -159,10 +189,13 @@
|
|||||||
return filterMultiDictText(this.dictOptions[dictCode], text+"");
|
return filterMultiDictText(this.dictOptions[dictCode], text+"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 排序字段受控
|
||||||
|
if (this.iSorter && currColumns[a].dataIndex === this.iSorter.column) {
|
||||||
|
currColumns[a].sortOrder = this.iSorter.order === 'asc' ? 'ascend' : 'descend'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.table.columns = [...currColumns]
|
this.table.columns = [...currColumns]
|
||||||
this.initQueryInfo()
|
this.initQueryInfo()
|
||||||
this.loadData(1)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -176,12 +209,43 @@
|
|||||||
httpGroupRequest(() => getAction(url), groupIdKey).then((res) => {
|
httpGroupRequest(() => getAction(url), groupIdKey).then((res) => {
|
||||||
// console.log("获取查询条件", res);
|
// console.log("获取查询条件", res);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
|
this.dynamicParamHandler(res.result)
|
||||||
this.queryInfo = res.result
|
this.queryInfo = res.result
|
||||||
|
//查询条件加载后再请求数据
|
||||||
|
this.loadData(1)
|
||||||
} else {
|
} else {
|
||||||
this.$message.warning(res.message)
|
this.$message.warning(res.message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
//处理动态参数
|
||||||
|
dynamicParamHandler(arr){
|
||||||
|
if(arr && arr.length>0){
|
||||||
|
//第一次加载查询条件前 初始化queryParam为空对象
|
||||||
|
let queryTemp = {}
|
||||||
|
for(let item of arr){
|
||||||
|
if(item.mode==='single'){
|
||||||
|
queryTemp[item.field] = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.queryParam = {...queryTemp}
|
||||||
|
}
|
||||||
|
let dynamicTemp = {}
|
||||||
|
if(this.param){
|
||||||
|
Object.keys(this.param).map(key=>{
|
||||||
|
let str = this.param[key]
|
||||||
|
if(key in this.queryParam){
|
||||||
|
if(str && str.startsWith("'") && str.endsWith("'")){
|
||||||
|
str = str.substring(1,str.length-1)
|
||||||
|
}
|
||||||
|
//如果查询条件包含参数 设置值
|
||||||
|
this.queryParam[key]=str
|
||||||
|
}
|
||||||
|
dynamicTemp[key] = this.param[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.dynamicParam = {...dynamicTemp}
|
||||||
|
},
|
||||||
loadData(arg) {
|
loadData(arg) {
|
||||||
if (arg == 1) {
|
if (arg == 1) {
|
||||||
this.table.pagination.current = 1
|
this.table.pagination.current = 1
|
||||||
@ -208,20 +272,60 @@
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
getQueryParams() {
|
getQueryParams() {
|
||||||
let param = Object.assign({}, this.queryParam, this.sorter);
|
let paramTarget = {}
|
||||||
|
if(this.dynamicParam){
|
||||||
|
//处理自定义参数
|
||||||
|
Object.keys(this.dynamicParam).map(key=>{
|
||||||
|
paramTarget['self_'+key] = this.dynamicParam[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let param = Object.assign(paramTarget, this.queryParam, this.iSorter);
|
||||||
param.pageNo = this.table.pagination.current;
|
param.pageNo = this.table.pagination.current;
|
||||||
param.pageSize = this.table.pagination.pageSize;
|
param.pageSize = this.table.pagination.pageSize;
|
||||||
return filterObj(param);
|
return filterObj(param);
|
||||||
},
|
},
|
||||||
handleChangeInTableSelect(selectedRowKeys, selectionRows) {
|
handleChangeInTableSelect(selectedRowKeys, selectionRows) {
|
||||||
this.table.selectedRowKeys = selectedRowKeys
|
//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
|
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) {
|
handleChangeInTable(pagination, filters, sorter) {
|
||||||
//分页、排序、筛选变化时触发
|
//分页、排序、筛选变化时触发
|
||||||
if (Object.keys(sorter).length > 0) {
|
if (Object.keys(sorter).length > 0) {
|
||||||
this.sorter.column = sorter.field
|
this.iSorter = {
|
||||||
this.sorter.order = 'ascend' == sorter.order ? 'asc' : 'desc'
|
column: sorter.field,
|
||||||
|
order: 'ascend' === sorter.order ? 'asc' : 'desc'
|
||||||
|
}
|
||||||
|
// 排序字段受控
|
||||||
|
this.table.columns.forEach(col => {
|
||||||
|
if (col.dataIndex === sorter.field) {
|
||||||
|
this.$set(col, 'sortOrder',sorter.order)
|
||||||
|
} else {
|
||||||
|
this.$set(col, 'sortOrder', false)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
this.table.pagination = pagination
|
this.table.pagination = pagination
|
||||||
this.loadData()
|
this.loadData()
|
||||||
@ -249,7 +353,8 @@
|
|||||||
this.onClearSelected()
|
this.onClearSelected()
|
||||||
},
|
},
|
||||||
show(){
|
show(){
|
||||||
this.visible = true;
|
this.visible = true
|
||||||
|
this.loadColumnsInfo()
|
||||||
},
|
},
|
||||||
handleToggleSearch(){
|
handleToggleSearch(){
|
||||||
this.toggleSearchStatus = !this.toggleSearchStatus;
|
this.toggleSearchStatus = !this.toggleSearchStatus;
|
||||||
@ -273,7 +378,13 @@
|
|||||||
combineRowKey(record){
|
combineRowKey(record){
|
||||||
let res = ''
|
let res = ''
|
||||||
Object.keys(record).forEach(key=>{
|
Object.keys(record).forEach(key=>{
|
||||||
|
//update-begin---author:liusq Date:20210203 for:pop选择器列主键问题 issues/I29P9Q------------
|
||||||
|
if(key=='id'){
|
||||||
|
res=record[key]+res
|
||||||
|
}else{
|
||||||
res+=record[key]
|
res+=record[key]
|
||||||
|
}
|
||||||
|
//update-end---author:liusq Date:20210203 for:pop选择器列主键问题 issues/I29P9Q------------
|
||||||
})
|
})
|
||||||
if(res.length>50){
|
if(res.length>50){
|
||||||
res = res.substring(0,50)
|
res = res.substring(0,50)
|
||||||
|
|||||||
@ -12,25 +12,21 @@
|
|||||||
<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-col :span="14">
|
|
||||||
<a-form-item :label="(queryParamText||name)">
|
<a-form-item :label="(queryParamText||name)">
|
||||||
<a-input v-model="queryParam[queryParamCode||valueKey]" :placeholder="'请输入' + (queryParamText||name)" @pressEnter="searchQuery"/>
|
<a-input v-model="queryParam[queryParamCode||valueKey]" :placeholder="'请输入' + (queryParamText||name)" @pressEnter="searchQuery"/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
<!-- 动态生成的查询条件 -->
|
||||||
<a-col :span="8">
|
<j-select-biz-query-item v-if="queryConfig.length>0" v-show="showMoreQueryItems" :queryParam="queryParam" :queryConfig="queryConfig" @pressEnter="searchQuery"/>
|
||||||
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
|
<!-- 按钮 -->
|
||||||
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
|
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
|
||||||
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
|
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
|
||||||
</span>
|
<a v-if="queryConfig.length>0" @click="showMoreQueryItems=!showMoreQueryItems" style="margin-left: 8px">
|
||||||
</a-col>
|
{{ showMoreQueryItems ? '收起' : '展开' }}
|
||||||
|
<a-icon :type="showMoreQueryItems ? 'up' : 'down'"/>
|
||||||
</a-row>
|
</a>
|
||||||
</a-form>
|
</a-form>
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-table
|
<a-table
|
||||||
size="middle"
|
size="middle"
|
||||||
@ -67,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,
|
||||||
@ -127,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'
|
||||||
@ -169,6 +171,7 @@
|
|||||||
},
|
},
|
||||||
options: [],
|
options: [],
|
||||||
dataSourceMap: {},
|
dataSourceMap: {},
|
||||||
|
showMoreQueryItems: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -206,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) {
|
||||||
@ -299,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) {
|
||||||
@ -332,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>
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -12,7 +12,7 @@
|
|||||||
:open="selectOpen"
|
:open="selectOpen"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
@dropdownVisibleChange="handleDropdownVisibleChange"
|
@dropdownVisibleChange="handleDropdownVisibleChange"
|
||||||
@click.native="visible=(buttons?visible:true)"
|
@click.native="visible=(buttons || disabled ?visible:true)"
|
||||||
/>
|
/>
|
||||||
</slot>
|
</slot>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|||||||
@ -53,6 +53,11 @@
|
|||||||
customReturnField: {
|
customReturnField: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'id'
|
default: 'id'
|
||||||
|
},
|
||||||
|
backDepart: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
@ -68,9 +73,11 @@
|
|||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
value(val){
|
value(val){
|
||||||
if (this.customReturnField === 'id') {
|
//update-begin-author:wangshuai date:20201124 for:组件 JSelectDepart.vue不是默认id时新内容编辑问题 gitee I247X2
|
||||||
|
// if (this.customReturnField === 'id') {
|
||||||
this.departIds = val
|
this.departIds = val
|
||||||
}
|
// }
|
||||||
|
//update-end-author:wangshuai date:20201124 for:组件 JSelectDepart.vue不是默认id时新内容编辑问题 gitee I247X2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
@ -89,6 +96,23 @@
|
|||||||
}
|
}
|
||||||
//update-end-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
|
//update-end-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
|
||||||
},
|
},
|
||||||
|
//返回选中的部门信息
|
||||||
|
backDeparInfo(){
|
||||||
|
if(this.backDepart===true){
|
||||||
|
if(this.departIds && this.departIds.length>0){
|
||||||
|
let arr1 = this.departIds.split(',')
|
||||||
|
let arr2 = this.departNames.split(',')
|
||||||
|
let info = []
|
||||||
|
for(let i=0;i<arr1.length;i++){
|
||||||
|
info.push({
|
||||||
|
value: arr1[i],
|
||||||
|
text: arr2[i]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.$emit('back', info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
openModal(){
|
openModal(){
|
||||||
this.$refs.innerDepartSelectModal.show()
|
this.$refs.innerDepartSelectModal.show()
|
||||||
},
|
},
|
||||||
@ -103,6 +127,7 @@
|
|||||||
this.departIds = idstr
|
this.departIds = idstr
|
||||||
}
|
}
|
||||||
this.$emit("change", value)
|
this.$emit("change", value)
|
||||||
|
this.backDeparInfo()
|
||||||
},
|
},
|
||||||
getDepartNames(){
|
getDepartNames(){
|
||||||
return this.departNames
|
return this.departNames
|
||||||
|
|||||||
@ -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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user