mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
298 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| efd17cdd60 | |||
| 63505e8f6e | |||
| bd4814581a | |||
| c7840a7382 | |||
| c3e049cbd0 | |||
| a6ae4080cb | |||
| 2e90f73da2 | |||
| 85b26230d1 | |||
| fa70a83391 | |||
| bbf85093d5 | |||
| d712776c46 | |||
| 9710b8bc7d | |||
| 3909eb5610 | |||
| cd5fd2f4d4 | |||
| c8a26d73e3 | |||
| e89423c666 | |||
| 67d8cdbc6c | |||
| c14a793906 | |||
| 7f87042e59 | |||
| 4aac17a5e2 | |||
| 5f1d0dafa4 | |||
| 727b67a50d | |||
| dfbbd1bd1f | |||
| 2d9de317c4 | |||
| 56912b766d | |||
| 8baced93a3 | |||
| 0c545517b6 | |||
| a3d6e0ce08 | |||
| 9dcff93372 | |||
| 948e1668b6 | |||
| b17908b581 | |||
| 3bfe099e21 | |||
| 93e755a09c | |||
| 6196f0a463 | |||
| 1481b86fb3 | |||
| eacaa7ed81 | |||
| bc711932f7 | |||
| 44d6f3228f | |||
| dad784228b | |||
| ce02dbbd30 | |||
| d4c2c02602 | |||
| 7935ce86de | |||
| 1224660d1d | |||
| 1b9fc77ec4 | |||
| 4a21f16ade | |||
| a9e6d2ec0c | |||
| e00ac210fe | |||
| cdc245699e | |||
| 9de7f261bb | |||
| ae434bfce4 | |||
| 0ee985da5a | |||
| dbba190980 | |||
| 07c538a1b2 | |||
| 472bf3f35a | |||
| b66fff6c42 | |||
| 2be616ee49 | |||
| 51c63e8057 | |||
| 758c347eb0 | |||
| 7bdc1b06d3 | |||
| e364b950ca | |||
| 3690a6e014 | |||
| 897dcbca78 | |||
| f8c7ddd223 | |||
| 8c143f35f8 | |||
| a5f30ec51f | |||
| 9226ae0aeb | |||
| baefc1338d | |||
| bb6ec4cc2f | |||
| 94053034b4 | |||
| bdbc714233 | |||
| 84f3ce8340 | |||
| b6219301e1 | |||
| a4603a2963 | |||
| 5bfa15d628 | |||
| a39bb0ce5f | |||
| a43ccf6f31 | |||
| 1e2a74a65f | |||
| 6c362861a0 | |||
| 2a5ec11660 | |||
| 509be1e382 | |||
| 80601e0ccd | |||
| 435f467646 | |||
| 644c6801a0 | |||
| 1f75c124f1 | |||
| bcbdd383ae | |||
| 7a1d4cda96 | |||
| 8bae42049c | |||
| 09a63610cf | |||
| 46e024bfbc | |||
| c767f094fc | |||
| 42e0a938da | |||
| 3f4b40ea74 | |||
| f210df80e6 | |||
| 0f79e8efef | |||
| d6251419e6 | |||
| 7db5f7f3e9 | |||
| cd79eb7597 | |||
| 812cbce06b | |||
| 3b92086047 | |||
| 0fa24b8518 | |||
| 7e7ea37857 | |||
| e550843fd1 | |||
| 3cb20a6a43 | |||
| 0acea1abff | |||
| 9760185bf6 | |||
| 75be8dd5b1 | |||
| a7893c4941 | |||
| ef97f700ab | |||
| 6fb01abbc5 | |||
| fe1b58ade2 | |||
| 1998867ca6 | |||
| a351204865 | |||
| 4da1948cb0 | |||
| 55ebea88af | |||
| 4b830b37c9 | |||
| 537cc05601 | |||
| 8f9f27c550 | |||
| 57f72dd4d0 | |||
| e2e19fa456 | |||
| 98a5148e52 | |||
| c2ae049ad7 | |||
| b44acde9b5 | |||
| db467f22a7 | |||
| 53c91fc349 | |||
| 92028a7e44 | |||
| 8ce40fa3d4 | |||
| 05c7f76484 | |||
| 71a1e9a63b | |||
| 0606aa560a | |||
| 1bbca48ba8 | |||
| d0c15f2302 | |||
| c9ff5d51b4 | |||
| cce5d785e4 | |||
| 234022d905 | |||
| ab529aaf6c | |||
| 07c6d1a23d | |||
| 8f780e180e | |||
| 87f17b9fc5 | |||
| 5a93d001b4 | |||
| d822552e0c | |||
| 832fa30cc9 | |||
| 3af1b390f1 | |||
| a3695151dc | |||
| c269d7637f | |||
| 664413e5d7 | |||
| 986f909628 | |||
| 221940cc5f | |||
| 2a392fb738 | |||
| 2b47cd0c34 | |||
| 1900f3fe77 | |||
| 37fe6fea69 | |||
| 3fbb5ee4ad | |||
| b1958fd295 | |||
| 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 | |||
| 94c0610496 |
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
|
||||||
|
|||||||
7
.github/ISSUE_TEMPLATE.md
vendored
7
.github/ISSUE_TEMPLATE.md
vendored
@ -9,4 +9,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
友情提示: 未按格式要求发帖,会直接删掉。
|
#### 友情提示(为了提高issue处理效率):
|
||||||
|
- 未按格式要求发帖,会被直接删掉;
|
||||||
|
- 请自己初判问题描述是否清楚,是否方便我们调查处理;
|
||||||
|
- 针对问题请说明是Online在线功能(需说明用的主题模板),还是生成的代码功能;
|
||||||
|
- 描述过于简单或模糊,导致无法处理的,会被直接删掉;
|
||||||
|
|
||||||
|
|||||||
14
LICENSE
14
LICENSE
@ -198,4 +198,16 @@
|
|||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
|
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||||
|
|
||||||
|
开源协议补充
|
||||||
|
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||||
|
本软件受适用的国家软件著作权法(包括国际条约)和双重保护许可。
|
||||||
|
|
||||||
|
1.允许基于本平台软件开展业务系统开发。
|
||||||
|
2.不得基于该平台软件的基础,修改包装成一个与JeecgBoot平台软件功能类似的产品进行发布、销售,或与JeecgBoot参与同类软件产品市场的竞争。
|
||||||
|
违反此条款属于侵权行为,须赔偿侵权经济损失,同时立即停止著作权侵权行为。
|
||||||
|
解释权归:http://www.jeecg.com
|
||||||
|
|
||||||
271
README.md
271
README.md
@ -1,18 +1,19 @@
|
|||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
JEECG BOOT 低代码开发平台(前后端分离版本)
|
JEECG BOOT 低代码开发平台(前后端分离版本)
|
||||||
===============
|
===============
|
||||||
|
|
||||||
当前最新版本: 2.4.0(发布日期:2020-12-01)
|
当前最新版本: 3.2.0(发布日期:2022-04-25)
|
||||||
|
|
||||||
|
|
||||||
[](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://jeecg.blog.csdn.net)
|
||||||
|
[](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,7 +24,7 @@ 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,SpringCloud,Ant Design&Vue,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
JeecgBoot 是一款基于代码生成器的`低代码平台`!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||||
|
|
||||||
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)等等!
|
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)等等!
|
||||||
|
|
||||||
@ -44,36 +45,31 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
|
|
||||||
- 技术官网: [http://www.jeecg.com](http://www.jeecg.com)
|
- 技术官网: [http://www.jeecg.com](http://www.jeecg.com)
|
||||||
|
|
||||||
- 开发文档: [http://doc.jeecg.com](http://doc.jeecg.com)
|
|
||||||
|
|
||||||
- 微服务启动: [单体升级为微服务启动文档2.4+](http://doc.jeecg.com/2043906)
|
|
||||||
|
|
||||||
- 在线演示 : [http://boot.jeecg.com](http://boot.jeecg.com)
|
- 在线演示 : [http://boot.jeecg.com](http://boot.jeecg.com)
|
||||||
|
|
||||||
- 视频教程 :[JeecgBoot入门视频](http://www.jeecg.com/doc/video)
|
- 开发文档: [http://doc.jeecg.com](http://doc.jeecg.com)
|
||||||
|
|
||||||
- 常见问题: [入门常见问题Q&A](http://jeecg.com/doc/qa)
|
- 入门视频: [https://space.bilibili.com/454617261/channel/series](https://space.bilibili.com/454617261/channel/series)
|
||||||
|
|
||||||
- 更新日志: [版本日志](http://www.jeecg.com/doc/log)
|
- 新手指南: [快速入门](http://www.jeecg.com/doc/quickstart) | [常见问题 ](http://www.jeecg.com/doc/qa) | [技术支持](http://jeecg.com/doc/help) | [1分钟体验低代码](https://my.oschina.net/jeecg/blog/3083313)
|
||||||
|
|
||||||
|
- 微服务开发: [单体切换为微服务](http://doc.jeecg.com/2704725)
|
||||||
|
|
||||||
|
- QQ交流群 : ⑤860162132、683903138(VUE3版)、~~④774126647(满)、③816531124(满)、②769925425(满)、①284271917(满)~~
|
||||||
|
|
||||||
交流互动
|
Vue3版前端(Beta版)
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- QQ交流群 : ③816531124、②769925425(满)、①284271917(满)
|
> 采用Vue3.0、Vite、 Ant-Design-Vue、TypeScript 等新技术方案,包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能! 是在 Vben-Admin 基础上研发的,适合于JeecgBoot的新版前端VUE3框架。
|
||||||
|
|
||||||
- 反馈问题: [反馈问题,请按格式发Issues](https://github.com/zhangdaiscott/jeecg-boot/issues/new)
|
- 源码下载:https://github.com/jeecgboot/jeecgboot-vue3
|
||||||
|
- 入门指南: [开发文档](http://vue3.jeecg.com/2398845) | [ VUE3版演示 ](http://boot3.jeecg.com) | [入门视频](https://www.bilibili.com/video/BV1V34y187Y9)
|
||||||
- 参与开源: [欢迎加入JEECG开源团队,共同进步!!](http://www.jeecg.com/doc/join)
|
|
||||||
|
|
||||||
- Online一分钟: [1分钟快速学习](https://jeecg.blog.csdn.net/article/details/106078912)
|
|
||||||
|
|
||||||
|
|
||||||
为什么选择JEECG-BOOT?
|
为什么选择JEECG-BOOT?
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
||||||
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywarking),提供切换机制支持单体和微服务自由切换
|
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywalking),提供切换机制支持单体和微服务自由切换
|
||||||
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
|
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
|
||||||
* 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
|
* 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
|
||||||
* 5.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大幅度提升开发效率,不再为重复工作发愁。
|
* 5.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大幅度提升开发效率,不再为重复工作发愁。
|
||||||
@ -90,7 +86,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
* 16.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等);
|
* 16.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等);
|
||||||
* 17.支持SAAS服务模式,提供SaaS多租户架构方案。
|
* 17.支持SAAS服务模式,提供SaaS多租户架构方案。
|
||||||
* 18.分布式文件服务,集成minio、阿里OSS等优秀的第三方,提供便捷的文件上传与管理,同时也支持本地存储。
|
* 18.分布式文件服务,集成minio、阿里OSS等优秀的第三方,提供便捷的文件上传与管理,同时也支持本地存储。
|
||||||
* 19.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle三大主流数据库。
|
* 19.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle、Sqlserver、MariaDB、达梦等主流数据库。
|
||||||
* 20.集成工作流activiti,并实现了只需在页面配置流程转向,可极大的简化bpm工作流的开发;用bpm的流程设计器画出了流程走向,一个工作流基本就完成了,只需写很少量的java代码;
|
* 20.集成工作流activiti,并实现了只需在页面配置流程转向,可极大的简化bpm工作流的开发;用bpm的流程设计器画出了流程走向,一个工作流基本就完成了,只需写很少量的java代码;
|
||||||
* 21.低代码能力:在线流程设计,采用开源Activiti流程引擎,实现在线画流程,自定义表单,表单挂靠,业务流转
|
* 21.低代码能力:在线流程设计,采用开源Activiti流程引擎,实现在线画流程,自定义表单,表单挂靠,业务流转
|
||||||
* 22.多数据源:及其简易的使用方式,在线配置数据源配置,便捷的从其他数据抓取数据;
|
* 22.多数据源:及其简易的使用方式,在线配置数据源配置,便捷的从其他数据抓取数据;
|
||||||
@ -121,37 +117,38 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
-----------------------------------
|
-----------------------------------
|
||||||
#### 开发环境
|
#### 开发环境
|
||||||
|
|
||||||
- 语言:Java 8
|
- 语言:Java 8+ (小于17)
|
||||||
|
|
||||||
- IDE(JAVA): IDEA / Eclipse安装lombok插件
|
- IDE(JAVA): IDEA (必须安装lombok插件 )
|
||||||
|
|
||||||
- IDE(前端): WebStorm 或者 IDEA
|
- IDE(前端): IDEA 或者 WebStorm
|
||||||
|
|
||||||
- 依赖管理:Maven
|
- 依赖管理:Maven
|
||||||
|
|
||||||
- 数据库:MySQL5.7+ & Oracle 11g & Sqlserver2017
|
|
||||||
|
|
||||||
- 缓存:Redis
|
- 缓存:Redis
|
||||||
|
|
||||||
|
- 数据库脚本:MySQL5.7+ & Oracle 11g & Sqlserver2017(默认只提供三个库脚本,其他库需要自己转)
|
||||||
|
|
||||||
|
|
||||||
#### 后端
|
#### 后端
|
||||||
- 基础框架:Spring Boot 2.3.5.RELEASE
|
|
||||||
|
|
||||||
- 微服务框架: Spring Cloud Alibaba 2.2.3.RELEASE
|
- 基础框架:Spring Boot 2.6.6
|
||||||
|
|
||||||
- 持久层框架:Mybatis-plus 3.4.1
|
- 微服务框架: Spring Cloud Alibaba 2021.1
|
||||||
|
|
||||||
- 安全框架:Apache Shiro 1.7.0,Jwt 3.11.0
|
- 持久层框架:MybatisPlus 3.5.1
|
||||||
|
|
||||||
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywarking
|
- 报表工具: JimuReport 1.5.0-beta
|
||||||
|
|
||||||
|
- 安全框架:Apache Shiro 1.8.0,Jwt 3.11.0
|
||||||
|
|
||||||
|
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
||||||
|
|
||||||
- 数据库连接池:阿里巴巴Druid 1.1.22
|
- 数据库连接池:阿里巴巴Druid 1.1.22
|
||||||
|
|
||||||
- 缓存框架:redis
|
|
||||||
|
|
||||||
- 日志打印:logback
|
- 日志打印:logback
|
||||||
|
|
||||||
- 其他:fastjson,poi,Swagger-ui,quartz, lombok(简化代码)等。
|
- 其他:autopoi, fastjson,poi,Swagger-ui,quartz, lombok(简化代码)等。
|
||||||
|
|
||||||
|
|
||||||
#### 前端
|
#### 前端
|
||||||
@ -164,9 +161,68 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
- [@antv/g2](https://antv.alipay.com/zh-cn/index.html) - Alipay AntV 数据可视化图表
|
- [@antv/g2](https://antv.alipay.com/zh-cn/index.html) - Alipay AntV 数据可视化图表
|
||||||
- [Viser-vue](https://viserjs.github.io/docs.html#/viser/guide/installation) - antv/g2 封装实现
|
- [Viser-vue](https://viserjs.github.io/docs.html#/viser/guide/installation) - antv/g2 封装实现
|
||||||
- eslint,[@vue/cli 3.2.1](https://cli.vuejs.org/zh/guide)
|
- eslint,[@vue/cli 3.2.1](https://cli.vuejs.org/zh/guide)
|
||||||
- vue-print-nb - 打印
|
- vue-print-nb-jeecg - 打印
|
||||||
|
|
||||||
|
|
||||||
|
#### 支持库
|
||||||
|
|
||||||
|
| 数据库 | 支持 |
|
||||||
|
| --- | --- |
|
||||||
|
| MySQL | √ |
|
||||||
|
| Oracle11g | √ |
|
||||||
|
| Sqlserver2017 | √ |
|
||||||
|
| PostgreSQL | √ |
|
||||||
|
| DB2、Informix | √ |
|
||||||
|
| MariaDB | √ |
|
||||||
|
| SQLite、Hsqldb、Derby、H2 | √ |
|
||||||
|
| 达梦、人大金仓、神通 | √ |
|
||||||
|
| 华为高斯、虚谷、瀚高数据库 | √ |
|
||||||
|
| 阿里云PolarDB、PPAS、HerdDB | √ |
|
||||||
|
| Hive、HBase、CouchBase | √ |
|
||||||
|
|
||||||
|
|
||||||
|
## 微服务解决方案
|
||||||
|
|
||||||
|
|
||||||
|
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 产品功能蓝图
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -304,105 +360,14 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
|||||||
│ └─我的抄送
|
│ └─我的抄送
|
||||||
│ └─流程委派、抄送、跳转
|
│ └─流程委派、抄送、跳转
|
||||||
│ └─。。。
|
│ └─。。。
|
||||||
└─其他模块
|
│─OA办公组件 (暂不开源)
|
||||||
|
│ ├─更多功能
|
||||||
|
│ └─。。。
|
||||||
|
└─其他模块 (暂不开源)
|
||||||
└─更多功能开发中。。
|
└─更多功能开发中。。
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 微服务整体解决方案(2.4+版本)
|
|
||||||
|
|
||||||
|
|
||||||
1、服务注册和发现 Nacos √
|
|
||||||
|
|
||||||
2、统一配置中心 Nacos √
|
|
||||||
|
|
||||||
3、路由网关 gateway(三种加载方式) √
|
|
||||||
|
|
||||||
4、分布式 http feign √
|
|
||||||
|
|
||||||
5、熔断和降级 Sentinel √
|
|
||||||
|
|
||||||
6、分布式文件 Minio、阿里OSS √
|
|
||||||
|
|
||||||
7、统一权限控制 JWT + Shiro √
|
|
||||||
|
|
||||||
8、服务监控 SpringBootAdmin√
|
|
||||||
|
|
||||||
9、链路跟踪 Skywarking [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1771670)
|
|
||||||
|
|
||||||
10、消息中间件 RabbitMQ √
|
|
||||||
|
|
||||||
11、分布式任务 xxl-job √
|
|
||||||
|
|
||||||
12、分布式事务 Seata
|
|
||||||
|
|
||||||
13、分布式日志 elk + kafa
|
|
||||||
|
|
||||||
14、支持 docker-compose、k8s、jenkins
|
|
||||||
|
|
||||||
15、CAS 单点登录 √
|
|
||||||
|
|
||||||
16、路由限流 √
|
|
||||||
|
|
||||||
|
|
||||||
#### 微服务架构图
|
|
||||||

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

|
|
||||||
|
|
||||||
|
|
||||||
后台开发环境和依赖
|
|
||||||
----
|
|
||||||
- java
|
|
||||||
- maven
|
|
||||||
- jdk8
|
|
||||||
- mysql
|
|
||||||
- redis
|
|
||||||
- 数据库脚本:jeecg-boot/db/jeecgboot-mysql-5.7.sql
|
|
||||||
- 默认登录账号: admin/123456
|
|
||||||
|
|
||||||
|
|
||||||
前端开发环境和依赖
|
|
||||||
----
|
|
||||||
- node
|
|
||||||
- yarn
|
|
||||||
- webpack
|
|
||||||
- eslint
|
|
||||||
- @vue/cli 3.2.1
|
|
||||||
- [ant-design-vue](https://github.com/vueComponent/ant-design-vue) - Ant Design Of Vue 实现
|
|
||||||
- [vue-cropper](https://github.com/xyxiao001/vue-cropper) - 头像裁剪组件
|
|
||||||
- [@antv/g2](https://antv.alipay.com/zh-cn/index.html) - Alipay AntV 数据可视化图表
|
|
||||||
- [Viser-vue](https://viserjs.github.io/docs.html#/viser/guide/installation) - antv/g2 封装实现
|
|
||||||
- [jeecg-boot-angular 版本](https://gitee.com/dangzhenghui/jeecg-boot)
|
|
||||||
|
|
||||||
项目下载和运行
|
|
||||||
----
|
|
||||||
|
|
||||||
- 拉取项目代码
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/zhangdaiscott/jeecg-boot.git
|
|
||||||
cd jeecg-boot/ant-design-jeecg-vue
|
|
||||||
```
|
|
||||||
|
|
||||||
1. 安装node.js
|
|
||||||
2. 切换到ant-design-jeecg-vue文件夹下
|
|
||||||
```
|
|
||||||
# 安装yarn
|
|
||||||
npm install -g yarn
|
|
||||||
|
|
||||||
# 下载依赖
|
|
||||||
yarn install
|
|
||||||
|
|
||||||
# 启动
|
|
||||||
yarn run serve
|
|
||||||
|
|
||||||
# 编译项目
|
|
||||||
yarn run build
|
|
||||||
|
|
||||||
# Lints and fixes files
|
|
||||||
yarn run lint
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -452,54 +417,6 @@ yarn run lint
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
其他说明
|
|
||||||
----
|
|
||||||
|
|
||||||
- 项目使用的 [vue-cli3](https://cli.vuejs.org/guide/), 请更新您的 cli
|
|
||||||
|
|
||||||
- 关闭 Eslint (不推荐) 移除 `package.json` 中 `eslintConfig` 整个节点代码
|
|
||||||
|
|
||||||
- 修改 Ant Design 配色,在文件 `vue.config.js` 中,其他 less 变量覆盖参考 [ant design](https://ant.design/docs/react/customize-theme-cn) 官方说明
|
|
||||||
```ecmascript 6
|
|
||||||
css: {
|
|
||||||
loaderOptions: {
|
|
||||||
less: {
|
|
||||||
modifyVars: {
|
|
||||||
/* less 变量覆盖,用于自定义 ant design 主题 */
|
|
||||||
|
|
||||||
'primary-color': '#F5222D',
|
|
||||||
'link-color': '#F5222D',
|
|
||||||
'border-radius-base': '4px',
|
|
||||||
},
|
|
||||||
javascriptEnabled: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
附属文档
|
|
||||||
----
|
|
||||||
- [Ant Design Vue](https://www.antdv.com/docs/vue/introduce-cn)
|
|
||||||
|
|
||||||
- [报表 viser-vue](https://viserjs.github.io/demo.html#/viser/line/basic-line)
|
|
||||||
|
|
||||||
- [Vue](https://cn.vuejs.org/v2/guide)
|
|
||||||
|
|
||||||
- [路由/菜单说明](https://gitee.com/jeecg/jeecg-boot/tree/v1.1/ant-design-jeecg-vue/src/router/README.md)
|
|
||||||
|
|
||||||
- [ANTD 默认配置项](https://gitee.com/jeecg/jeecg-boot/blob/v1.1/ant-design-jeecg-vue/src/defaultSettings.js)
|
|
||||||
|
|
||||||
- 其他待补充...
|
|
||||||
|
|
||||||
|
|
||||||
备注
|
|
||||||
----
|
|
||||||
|
|
||||||
> @vue/cli 升级后,eslint 规则更新了。由于影响到全部 .vue 文件,需要逐个验证。既暂时关闭部分原本不验证的规则,后期维护时,在逐步修正这些 rules
|
|
||||||
|
|
||||||
|
|
||||||
## 捐赠
|
## 捐赠
|
||||||
|
|
||||||
如果觉得还不错,请作者喝杯咖啡吧 ☺
|
如果觉得还不错,请作者喝杯咖啡吧 ☺
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
VUE_APP_PLATFORM_NAME=Jeecg-Boot 企业级快速开发平台
|
VUE_APP_PLATFORM_NAME=JeecgBoot 企业级低代码平台
|
||||||
VUE_APP_SSO=false
|
# 开启单点登录
|
||||||
|
VUE_APP_SSO=false
|
||||||
|
# 开启微应用模式
|
||||||
|
VUE_APP_QIANKUN=false
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot
|
VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot
|
||||||
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
|
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
|
||||||
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
|
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
|
||||||
|
|
||||||
|
# 微应用列表必须VUE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径
|
||||||
|
VUE_APP_SUB_jeecg-app-1 = '//localhost:8092'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
VUE_APP_API_BASE_URL=https://bootapi.jeecg.com
|
VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot
|
||||||
VUE_APP_CAS_BASE_URL=http://localhost:8888/cas
|
VUE_APP_CAS_BASE_URL=http://localhost:8888/cas
|
||||||
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
|
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
|
||||||
@ -1,21 +1,213 @@
|
|||||||
MIT License
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
Copyright (c) 2019 DaiHao Zhang
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
1. Definitions.
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
copies or substantial portions of the Software.
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
the copyright owner that is granting the License.
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
other entities that control, are controlled by, or are under common
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
control with that entity. For the purposes of this definition,
|
||||||
SOFTWARE.
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright (c) 2019 <a href="http://www.jeecg.com">Jeecg Boot</a> All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||||
|
|
||||||
|
开源协议补充
|
||||||
|
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||||
|
本软件受适用的国家软件著作权法(包括国际条约)和双重保护许可。
|
||||||
|
|
||||||
|
1.允许基于本平台软件开展业务系统开发。
|
||||||
|
2.不得基于该平台软件的基础,修改包装成一个与JeecgBoot平台软件功能类似的产品进行发布、销售,或与JeecgBoot参与同类软件产品市场的竞争。
|
||||||
|
违反此条款属于侵权行为,须赔偿侵权经济损失,同时立即停止著作权侵权行为。
|
||||||
|
解释权归:http://www.jeecg.com
|
||||||
|
|
||||||
@ -1,13 +1,13 @@
|
|||||||
Ant Design Jeecg Vue
|
Ant Design Jeecg Vue
|
||||||
====
|
====
|
||||||
|
|
||||||
当前最新版本: 2.4.0(发布日期:20201201)
|
当前最新版本: 3.1.0(发布日期:20220301)
|
||||||
|
|
||||||
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一贯的强大!!
|
||||||
|
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ Jeecg-boot 的前段UI框架,采用前后端分离方案,提供强大代码
|
|||||||
- 拉取项目代码
|
- 拉取项目代码
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/zhangdaiscott/jeecg-boot.git
|
git clone https://github.com/zhangdaiscott/jeecg-boot.git
|
||||||
cd jeecg-boot/ant-design-jeecg-vue
|
cd jeecg-boot/ant-design-vue-jeecg
|
||||||
```
|
```
|
||||||
|
|
||||||
- 安装依赖
|
- 安装依赖
|
||||||
@ -93,9 +93,9 @@ yarn run lint
|
|||||||
|
|
||||||
- [Vue](https://cn.vuejs.org/v2/guide)
|
- [Vue](https://cn.vuejs.org/v2/guide)
|
||||||
|
|
||||||
- [路由/菜单说明](https://github.com/zhangdaiscott/jeecg-boot/tree/master/ant-design-jeecg-vue/src/router/README.md)
|
- [路由/菜单说明](https://github.com/zhangdaiscott/jeecg-boot/tree/master/ant-design-vue-jeecg/src/router/README.md)
|
||||||
|
|
||||||
- [ANTD 默认配置项](https://github.com/zhangdaiscott/jeecg-boot/tree/master/ant-design-jeecg-vue/src/defaultSettings.js)
|
- [ANTD 默认配置项](https://github.com/zhangdaiscott/jeecg-boot/tree/master/ant-design-vue-jeecg/src/defaultSettings.js)
|
||||||
|
|
||||||
- 其他待补充...
|
- 其他待补充...
|
||||||
|
|
||||||
@ -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.先进入打包前端项目
|
||||||
|
|||||||
11002
ant-design-vue-jeecg/package-lock.json
generated
11002
ant-design-vue-jeecg/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-antd-jeecg",
|
"name": "vue-antd-jeecg",
|
||||||
"version": "2.4.0",
|
"version": "3.1.0",
|
||||||
"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 ",
|
||||||
@ -10,8 +10,8 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jeecg/antd-online-mini": "2.4.0-beta4",
|
|
||||||
"ant-design-vue": "^1.7.2",
|
"ant-design-vue": "^1.7.2",
|
||||||
|
"@jeecg/antd-online-mini": "3.1.0-beta",
|
||||||
"@antv/data-set": "^0.11.4",
|
"@antv/data-set": "^0.11.4",
|
||||||
"viser-vue": "^2.4.8",
|
"viser-vue": "^2.4.8",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
@ -35,15 +35,17 @@
|
|||||||
"vue-splitpane": "^1.0.4",
|
"vue-splitpane": "^1.0.4",
|
||||||
"vuedraggable": "^2.20.0",
|
"vuedraggable": "^2.20.0",
|
||||||
"codemirror": "^5.46.0",
|
"codemirror": "^5.46.0",
|
||||||
"@tinymce/tinymce-vue": "^2.1.0",
|
"@tinymce/tinymce-vue": "2.1.0",
|
||||||
"tinymce": "^5.3.2",
|
"tinymce": "5.4.1",
|
||||||
"@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",
|
"china-area-data": "^5.0.1",
|
||||||
"dom-align": "1.12.0",
|
"dom-align": "1.12.0",
|
||||||
"xe-utils": "2.4.8",
|
"xe-utils": "2.4.8",
|
||||||
"vxe-table": "2.9.13",
|
"vxe-table": "2.9.13",
|
||||||
"vxe-table-plugin-antd": "1.8.10"
|
"vxe-table-plugin-antd": "1.8.10",
|
||||||
|
"cron-parser": "^2.10.0",
|
||||||
|
"qiankun": "^2.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/polyfill": "^7.2.5",
|
"@babel/polyfill": "^7.2.5",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
7
ant-design-vue-jeecg/public/color.less
vendored
7
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;
|
||||||
@ -7687,9 +7689,6 @@ font.weak {
|
|||||||
color: @primary-color;
|
color: @primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ant-menu-submenu-selected {
|
|
||||||
color: @primary-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
// begin -------- JAreaLinkage 三级联动样式 --------------
|
// begin -------- JAreaLinkage 三级联动样式 --------------
|
||||||
.cascader-menu-list .cascader-menu-option.hover,
|
.cascader-menu-list .cascader-menu-option.hover,
|
||||||
|
|||||||
8
ant-design-vue-jeecg/public/index.html
vendored
8
ant-design-vue-jeecg/public/index.html
vendored
@ -5,7 +5,7 @@
|
|||||||
<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="<%= BASE_URL %>cdn/babel-polyfill/polyfill_7_2_5.js"></script>
|
<script src="<%= BASE_URL %>cdn/babel-polyfill/polyfill_7_2_5.js"></script>
|
||||||
<style>
|
<style>
|
||||||
@ -240,9 +240,7 @@
|
|||||||
/* 滚动条优化 end */
|
/* 滚动条优化 end */
|
||||||
</style>
|
</style>
|
||||||
<!-- 全局配置 -->
|
<!-- 全局配置 -->
|
||||||
<script>
|
<script src="<%= BASE_URL %>static/config.js"></script>
|
||||||
window._CONFIG = {};
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@ -251,7 +249,7 @@
|
|||||||
<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>
|
||||||
|
|||||||
11
ant-design-vue-jeecg/public/static/config.js
Normal file
11
ant-design-vue-jeecg/public/static/config.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* 存放配置常量(当值不为空时会覆盖env配置)
|
||||||
|
*/
|
||||||
|
window._CONFIG = {
|
||||||
|
//接口父路径
|
||||||
|
VUE_APP_API_BASE_URL: '',
|
||||||
|
//单点登录地址
|
||||||
|
VUE_APP_CAS_BASE_URL: '',
|
||||||
|
//文件预览路径
|
||||||
|
VUE_APP_ONLINE_BASE_URL: ''
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@ const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
|
|||||||
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
|
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
|
||||||
//改变密码
|
//改变密码
|
||||||
const changePassword = (params)=>putAction("/sys/user/changePassword",params);
|
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);
|
||||||
@ -25,7 +26,6 @@ const getPermissionList = (params)=>getAction("/sys/permission/list",params);
|
|||||||
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);
|
||||||
@ -38,6 +38,7 @@ const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermission
|
|||||||
|
|
||||||
// 部门管理
|
// 部门管理
|
||||||
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);
|
||||||
@ -68,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,8 +80,10 @@ const doReovkeData = (params)=>getAction("/sys/annountCement/doReovkeData",param
|
|||||||
//获取系统访问量
|
//获取系统访问量
|
||||||
const getLoginfo = (params)=>getAction("/sys/loginfo",params);
|
const getLoginfo = (params)=>getAction("/sys/loginfo",params);
|
||||||
const getVisitInfo = (params)=>getAction("/sys/visitInfo",params);
|
const getVisitInfo = (params)=>getAction("/sys/visitInfo",params);
|
||||||
|
|
||||||
// 根据部门主键查询用户信息
|
// 根据部门主键查询用户信息
|
||||||
const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params);
|
const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params);
|
||||||
|
|
||||||
// 重复校验
|
// 重复校验
|
||||||
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
|
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
|
||||||
// 加载分类字典
|
// 加载分类字典
|
||||||
@ -98,6 +101,8 @@ export const transitRESTful = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
// imgView,
|
||||||
|
// doMian,
|
||||||
addRole,
|
addRole,
|
||||||
editRole,
|
editRole,
|
||||||
checkRoleCode,
|
checkRoleCode,
|
||||||
@ -121,6 +126,7 @@ export {
|
|||||||
getPermissionRuleList,
|
getPermissionRuleList,
|
||||||
queryPermissionRule,
|
queryPermissionRule,
|
||||||
queryDepartTreeList,
|
queryDepartTreeList,
|
||||||
|
queryDepartTreeSync,
|
||||||
queryIdTree,
|
queryIdTree,
|
||||||
queryParentName,
|
queryParentName,
|
||||||
searchByKeywords,
|
searchByKeywords,
|
||||||
|
|||||||
@ -71,4 +71,17 @@ export function thirdLogin(token,thirdType) {
|
|||||||
'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,5 +1,6 @@
|
|||||||
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: '/mock/api/user',
|
user: '/mock/api/user',
|
||||||
@ -13,19 +14,29 @@ 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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
33
ant-design-vue-jeecg/src/assets/less/AppIcon.less
Normal file
33
ant-design-vue-jeecg/src/assets/less/AppIcon.less
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
@active-color: #11da75;
|
||||||
|
ul {
|
||||||
|
max-height: 700px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-left: .5rem;
|
||||||
|
img {
|
||||||
|
width:64px;
|
||||||
|
height:64px;
|
||||||
|
padding: .2rem;
|
||||||
|
margin: .3rem;
|
||||||
|
cursor: pointer;
|
||||||
|
&.active, &:hover {
|
||||||
|
border: 1px solid @active-color;
|
||||||
|
border-radius: 2px;
|
||||||
|
color: #fff;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
float: left;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #555;
|
||||||
|
transition: color .3s ease-in-out,background-color .3s ease-in-out;
|
||||||
|
position: relative;
|
||||||
|
margin: 3px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 10px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,9 +12,9 @@
|
|||||||
<span style="margin-left:5px">{{ ellipsisFileName }}</span>
|
<span style="margin-left:5px">{{ ellipsisFileName }}</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
|
||||||
<a-tooltip v-else :title="file.name">
|
<a-tooltip v-else :title="file.message||'上传失败'">
|
||||||
<a-icon type="paper-clip" style="color:red;"/>
|
<a-icon type="exclamation-circle" style="color:red;"/>
|
||||||
<span style="color:red;margin-left:5px">{{ ellipsisFileName }}</span>
|
<span style="margin-left:5px">{{ ellipsisFileName }}</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
|
||||||
<template style="width: 30px">
|
<template style="width: 30px">
|
||||||
@ -179,8 +179,19 @@
|
|||||||
value['responseName'] = file.response[this.responseName]
|
value['responseName'] = file.response[this.responseName]
|
||||||
}
|
}
|
||||||
if (file.status === 'done') {
|
if (file.status === 'done') {
|
||||||
value['path'] = file.response[this.responseName]
|
if (typeof file.response.success === 'boolean') {
|
||||||
this.handleChangeCommon(value)
|
if (file.response.success) {
|
||||||
|
value['path'] = file.response[this.responseName]
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
} else {
|
||||||
|
value['status'] = 'error'
|
||||||
|
value['message'] = file.response.message || '未知错误'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 考虑到如果设置action上传路径为非jeecg-boot后台,可能不会返回 success 属性的情况,就默认为成功
|
||||||
|
value['path'] = file.response[this.responseName]
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
}
|
||||||
} else if (file.status === 'error') {
|
} else if (file.status === 'error') {
|
||||||
value['message'] = file.response.message || '未知错误'
|
value['message'] = file.response.message || '未知错误'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,20 +10,9 @@
|
|||||||
<template v-else-if="file['path']">
|
<template v-else-if="file['path']">
|
||||||
<img class="j-editable-image" :src="imgSrc" alt="无图片" @click="handleMoreOperation"/>
|
<img class="j-editable-image" :src="imgSrc" alt="无图片" @click="handleMoreOperation"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<a-tooltip v-else :title="file.message||'上传失败'" @click="handleClickShowImageError">
|
||||||
<a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError"/>
|
<a-icon type="exclamation-circle" style="color:red;"/>
|
||||||
</template>
|
</a-tooltip>
|
||||||
<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">
|
<template style="width: 30px">
|
||||||
<a-dropdown :trigger="['click']" placement="bottomRight" style="margin-left: 10px;">
|
<a-dropdown :trigger="['click']" placement="bottomRight" style="margin-left: 10px;">
|
||||||
@ -196,8 +185,19 @@
|
|||||||
value['responseName'] = file.response[this.responseName]
|
value['responseName'] = file.response[this.responseName]
|
||||||
}
|
}
|
||||||
if (file.status === 'done') {
|
if (file.status === 'done') {
|
||||||
value['path'] = file.response[this.responseName]
|
if (typeof file.response.success === 'boolean') {
|
||||||
this.handleChangeCommon(value)
|
if (file.response.success) {
|
||||||
|
value['path'] = file.response[this.responseName]
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
} else {
|
||||||
|
value['status'] = 'error'
|
||||||
|
value['message'] = file.response.message || '未知错误'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 考虑到如果设置action上传路径为非jeecg-boot后台,可能不会返回 success 属性的情况,就默认为成功
|
||||||
|
value['path'] = file.response[this.responseName]
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
}
|
||||||
} else if (file.status === 'error') {
|
} else if (file.status === 'error') {
|
||||||
value['message'] = file.response.message || '未知错误'
|
value['message'] = file.response.message || '未知错误'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import JVxeCellMixins, { vModel, dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
import JVxeCellMixins, { dispatchEvent, vModel } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JVxePopupCell',
|
name: 'JVxePopupCell',
|
||||||
@ -22,6 +22,8 @@
|
|||||||
orgFields: col.orgFields,
|
orgFields: col.orgFields,
|
||||||
destFields: col.destFields,
|
destFields: col.destFields,
|
||||||
groupId: caseId,
|
groupId: caseId,
|
||||||
|
param: col.param,
|
||||||
|
sorter: col.sorter,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -48,7 +50,9 @@
|
|||||||
// 【组件增强】注释详见:JVxeCellMixins.js
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
enhanced: {
|
enhanced: {
|
||||||
aopEvents: {
|
aopEvents: {
|
||||||
editActived: event => dispatchEvent(event, 'ant-input'),
|
editActived(event) {
|
||||||
|
dispatchEvent.call(this, event, 'ant-input')
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -254,7 +254,9 @@ export const DictSearchInputCell = {
|
|||||||
// 【组件增强】注释详见:JVxeCellMixins.js
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
enhanced: {
|
enhanced: {
|
||||||
aopEvents: {
|
aopEvents: {
|
||||||
editActived: event => dispatchEvent(event, 'ant-select'),
|
editActived(event) {
|
||||||
|
dispatchEvent.call(this, event, 'ant-select')
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,5 +39,5 @@ UserMenu.vue:首页右上侧的内容
|
|||||||

|

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

|

|
||||||

|

|
||||||

|

|
||||||
@ -1,5 +1,4 @@
|
|||||||
import { pcaa } from 'area-data'
|
import Vue from 'vue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 省市区
|
* 省市区
|
||||||
*/
|
*/
|
||||||
@ -8,18 +7,23 @@ export default class Area {
|
|||||||
* 构造器
|
* 构造器
|
||||||
* @param express
|
* @param express
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor(pcaa) {
|
||||||
|
if(!pcaa){
|
||||||
|
pcaa = Vue.prototype.$Jpcaa;
|
||||||
|
}
|
||||||
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=>{
|
if(qu){
|
||||||
arr.push({id:key3, text:qu[key3], pid:key2});
|
Object.keys(qu).map(key3=>{
|
||||||
})
|
arr.push({id:key3, text:qu[key3], pid:key2, index:3});
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
this.all = arr;
|
this.all = arr;
|
||||||
@ -45,33 +49,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)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,4 +32,15 @@ export const cutStrByFullLength = (str = '', maxLength) => {
|
|||||||
}
|
}
|
||||||
return pre
|
return pre
|
||||||
}, '')
|
}, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下划线转换驼峰
|
||||||
|
export function underLinetoHump(name) {
|
||||||
|
return name.replace(/\_(\w)/g, function(all, letter){
|
||||||
|
return letter.toUpperCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 驼峰转换下划线
|
||||||
|
export function humptoUnderLine(name) {
|
||||||
|
return name.replace(/([A-Z])/g,"_$1").toLowerCase();
|
||||||
}
|
}
|
||||||
@ -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,17 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
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);
|
//LOWCOD-2146 【菜单】数据规则,选择自定义SQL 规则值无法输入空格
|
||||||
}else{
|
this.$emit('input', val);
|
||||||
this.$emit('input', val);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
setCurrentDictOptions(dictOptions){
|
setCurrentDictOptions(dictOptions){
|
||||||
this.dictOptions = dictOptions
|
this.dictOptions = dictOptions
|
||||||
@ -102,6 +99,10 @@
|
|||||||
getCurrentDictOptions(){
|
getCurrentDictOptions(){
|
||||||
return this.dictOptions
|
return this.dictOptions
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
model:{
|
||||||
|
prop: 'value',
|
||||||
|
event: 'change'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:getPopupContainer="(node) => node.parentNode"
|
:getPopupContainer="getParentContainer"
|
||||||
optionFilterProp="children"
|
optionFilterProp="children"
|
||||||
:filterOption="filterOption"
|
:filterOption="filterOption"
|
||||||
allowClear>
|
allowClear>
|
||||||
@ -36,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() {
|
||||||
@ -68,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -78,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, 初始化字典数组
|
||||||
@ -92,7 +103,7 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
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
|
||||||
@ -100,6 +111,13 @@
|
|||||||
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搜索
|
// update--begin--autor:lvdandan-----date:20201120------for:LOWCOD-1086 下拉多选框,搜索时只字典code进行搜索不能通过字典text搜索
|
||||||
filterOption(input, option) {
|
filterOption(input, option) {
|
||||||
return option.componentOptions.children[0].children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
return option.componentOptions.children[0].children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
|||||||
@ -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"
|
||||||
@ -48,14 +48,32 @@
|
|||||||
props:{
|
props:{
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
value: [String, Number],
|
value: [String, Number],
|
||||||
dict: String,
|
|
||||||
dictOptions: Array,
|
dictOptions: Array,
|
||||||
async: Boolean,
|
async: Boolean,
|
||||||
placeholder:{
|
placeholder:{
|
||||||
type:String,
|
type:String,
|
||||||
default:"请选择",
|
default:"请选择",
|
||||||
required:false
|
required:false
|
||||||
}
|
},
|
||||||
|
dict:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
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);//消抖
|
||||||
@ -105,7 +123,17 @@
|
|||||||
if(this.async){
|
if(this.async){
|
||||||
if(!this.selectedAsyncValue || !this.selectedAsyncValue.key || this.selectedAsyncValue.key!=this.value){
|
if(!this.selectedAsyncValue || !this.selectedAsyncValue.key || this.selectedAsyncValue.key!=this.value){
|
||||||
console.log("这才请求后台")
|
console.log("这才请求后台")
|
||||||
getAction(`/sys/dict/loadDictItem/${this.dict}`,{key:this.value}).then(res=>{
|
//update-begin-author:taoyan date:20220112 for: 方法initSelectValue 根据下拉框实际值查询下拉框的显示的文本 因后台接口只处理3个参数,所以将过滤条件去掉
|
||||||
|
// TODO 隐患 查询效率问题 还是应该在后台作筛选
|
||||||
|
let itemDictStr = this.dict
|
||||||
|
let arr = itemDictStr.split(',')
|
||||||
|
if(arr && arr.length==4){
|
||||||
|
// 删除最后一个元素
|
||||||
|
arr.pop();
|
||||||
|
itemDictStr = arr.join(',')
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:20220112 for: 方法initSelectValue 根据下拉框实际值查询下拉框的显示的文本 因后台接口只处理3个参数,所以将过滤条件去掉
|
||||||
|
getAction(`/sys/dict/loadDictItem/${itemDictStr}`,{key:this.value}).then(res=>{
|
||||||
if(res.success){
|
if(res.success){
|
||||||
let obj = {
|
let obj = {
|
||||||
key:this.value,
|
key:this.value,
|
||||||
@ -126,7 +154,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){
|
||||||
@ -171,6 +199,21 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
if(!this.dict){
|
||||||
|
console.error('搜索组件未配置字典项')
|
||||||
|
}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) {
|
||||||
@ -182,9 +225,18 @@
|
|||||||
this.callback()
|
this.callback()
|
||||||
},
|
},
|
||||||
handleAsyncChange(selectedObj){
|
handleAsyncChange(selectedObj){
|
||||||
this.selectedAsyncValue = selectedObj
|
//update-begin-author:scott date:20201222 for:【搜索】搜索查询组件,删除条件,默认下拉还是上次的缓存数据,不好 JT-191
|
||||||
this.selectedValue = selectedObj.key
|
if(selectedObj){
|
||||||
|
this.selectedAsyncValue = selectedObj
|
||||||
|
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);
|
||||||
@ -194,7 +246,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,11 +1,16 @@
|
|||||||
import JDictSelectTag from './JDictSelectTag.vue'
|
import JDictSelectTag from './JDictSelectTag.vue'
|
||||||
import JMultiSelectTag from './JMultiSelectTag.vue'
|
import JMultiSelectTag from './JMultiSelectTag.vue'
|
||||||
import JSearchSelectTag from './JSearchSelectTag.vue'
|
import JSearchSelectTag from './JSearchSelectTag.vue'
|
||||||
|
import { filterMultiDictText,filterDictText,initDictOptions,filterDictTextByCache } from './JDictSelectUtil'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install: function (Vue) {
|
install: function (Vue) {
|
||||||
Vue.component('JDictSelectTag',JDictSelectTag);
|
Vue.component('JDictSelectTag',JDictSelectTag);
|
||||||
Vue.component('JMultiSelectTag',JMultiSelectTag);
|
Vue.component('JMultiSelectTag',JMultiSelectTag);
|
||||||
Vue.component('JSearchSelectTag',JSearchSelectTag);
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,7 +29,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { pcaa } from 'area-data'
|
|
||||||
import Area from '@/components/_util/Area'
|
import Area from '@/components/_util/Area'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -53,7 +52,7 @@
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
pcaa,
|
pcaa: this.$Jpcaa,
|
||||||
innerValue: [],
|
innerValue: [],
|
||||||
usedListeners: ['change'],
|
usedListeners: ['change'],
|
||||||
enums: {
|
enums: {
|
||||||
@ -114,7 +113,7 @@
|
|||||||
/** 通过地区code获取子级 */
|
/** 通过地区code获取子级 */
|
||||||
loadDataByCode(value) {
|
loadDataByCode(value) {
|
||||||
let options = []
|
let options = []
|
||||||
let data = pcaa[value]
|
let data = this.pcaa[value]
|
||||||
if (data) {
|
if (data) {
|
||||||
for (let key in data) {
|
for (let key in data) {
|
||||||
if (data.hasOwnProperty(key)) {
|
if (data.hasOwnProperty(key)) {
|
||||||
@ -139,7 +138,7 @@
|
|||||||
},
|
},
|
||||||
initAreaData(){
|
initAreaData(){
|
||||||
if(!this.areaData){
|
if(!this.areaData){
|
||||||
this.areaData = new Area();
|
this.areaData = new Area(this.$Jpcaa);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -397,6 +400,10 @@
|
|||||||
.null-tip-hidden{
|
.null-tip-hidden{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
/**选中样式偶然出现高度不够的情况*/
|
||||||
|
.CodeMirror-selected{
|
||||||
|
min-height: 19px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 全屏样式 */
|
/* 全屏样式 */
|
||||||
|
|||||||
@ -1,282 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-bind="fullScreenParentProps">
|
|
||||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
|
||||||
|
|
||||||
<div class="code-editor-cust full-screen-child">
|
|
||||||
<a-textarea auto-size v-model="textareaValue" :placeholder="placeholderShow" @change="handleChange" :style="{'max-height': maxHeight+'px','min-height': minHeight+'px'}"></a-textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script type="text/ecmascript-6">
|
|
||||||
export default {
|
|
||||||
name: 'JCodeEditor',
|
|
||||||
props: {
|
|
||||||
value: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
// 是否显示全屏按钮
|
|
||||||
fullScreen: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 全屏以后的z-index
|
|
||||||
zIndex: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: 999
|
|
||||||
},
|
|
||||||
// 是否自适应高度,可以传String或Boolean
|
|
||||||
// 传 String 类型只能写"!ie" ,
|
|
||||||
// 填写这个字符串,代表其他浏览器自适应高度
|
|
||||||
// 唯独IE下不自适应高度,因为IE下不支持min、max-height样式
|
|
||||||
// 如果填写的不是"!ie"就视为true
|
|
||||||
autoHeight: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
// 不自适应高度的情况下生效的固定高度
|
|
||||||
height: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: '240px'
|
|
||||||
},
|
|
||||||
language: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
minHeight:{
|
|
||||||
type:Number,
|
|
||||||
default: 100,
|
|
||||||
required:false
|
|
||||||
},
|
|
||||||
maxHeight:{
|
|
||||||
type:Number,
|
|
||||||
default: 320,
|
|
||||||
required:false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
textareaValue: '',
|
|
||||||
// 内部真实的内容
|
|
||||||
code: '',
|
|
||||||
iconType: 'fullscreen',
|
|
||||||
hasCode:false,
|
|
||||||
// 默认的语法类型
|
|
||||||
mode: 'javascript',
|
|
||||||
// 编辑器实例
|
|
||||||
coder: null,
|
|
||||||
// 默认配置
|
|
||||||
options: {
|
|
||||||
// 缩进格式
|
|
||||||
tabSize: 2,
|
|
||||||
// 主题,对应主题库 JS 需要提前引入
|
|
||||||
theme: 'panda-syntax',
|
|
||||||
line: true,
|
|
||||||
// extraKeys: {'Ctrl': 'autocomplete'},//自定义快捷键
|
|
||||||
hintOptions: {
|
|
||||||
tables: {
|
|
||||||
users: ['name', 'score', 'birthDate'],
|
|
||||||
countries: ['name', 'population', 'size']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// code 编辑器 是否全屏
|
|
||||||
fullCoder: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
fullCoder:{
|
|
||||||
handler(value) {
|
|
||||||
if(value){
|
|
||||||
this.iconType="fullscreen-exit"
|
|
||||||
}else{
|
|
||||||
this.iconType="fullscreen"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
placeholderShow() {
|
|
||||||
if (this.placeholder == null) {
|
|
||||||
return `请在此输入代码`
|
|
||||||
} else {
|
|
||||||
return this.placeholder
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isAutoHeight() {
|
|
||||||
let {autoHeight} = this
|
|
||||||
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
|
||||||
autoHeight = !(isIE() || isIE11())
|
|
||||||
} else {
|
|
||||||
autoHeight = true
|
|
||||||
}
|
|
||||||
return autoHeight
|
|
||||||
},
|
|
||||||
fullScreenParentProps() {
|
|
||||||
let props = {
|
|
||||||
class: {
|
|
||||||
'full-screen-parent': true,
|
|
||||||
'full-screen': this.fullCoder,
|
|
||||||
'auto-height': this.isAutoHeight
|
|
||||||
},
|
|
||||||
style: {}
|
|
||||||
}
|
|
||||||
if (this.fullCoder) {
|
|
||||||
props.style['z-index'] = this.zIndex
|
|
||||||
}
|
|
||||||
if (!this.isAutoHeight) {
|
|
||||||
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
|
||||||
}
|
|
||||||
return props
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
// 初始化
|
|
||||||
this._initialize()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 初始化
|
|
||||||
_initialize () {
|
|
||||||
this.setCodeContent(this.value)
|
|
||||||
},
|
|
||||||
handleChange(e){
|
|
||||||
this.$emit('input', e.target.value)
|
|
||||||
},
|
|
||||||
getCodeContent(){
|
|
||||||
return this.value
|
|
||||||
},
|
|
||||||
setCodeContent(val){
|
|
||||||
setTimeout(()=>{
|
|
||||||
if(!val){
|
|
||||||
this.textareaValue = ''
|
|
||||||
}else{
|
|
||||||
this.textareaValue = val
|
|
||||||
}
|
|
||||||
},300)
|
|
||||||
},
|
|
||||||
nullTipClick(){
|
|
||||||
this.coder.focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less">
|
|
||||||
.code-editor-cust{
|
|
||||||
flex-grow:1;
|
|
||||||
display:flex;
|
|
||||||
position:relative;
|
|
||||||
height:100%;
|
|
||||||
.CodeMirror{
|
|
||||||
flex-grow:1;
|
|
||||||
z-index:1;
|
|
||||||
.CodeMirror-code{
|
|
||||||
line-height:19px;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
.code-mode-select{
|
|
||||||
position:absolute;
|
|
||||||
z-index:2;
|
|
||||||
right:10px;
|
|
||||||
top:10px;
|
|
||||||
max-width:130px;
|
|
||||||
}
|
|
||||||
.CodeMirror{
|
|
||||||
height: auto;
|
|
||||||
min-height:100%;
|
|
||||||
}
|
|
||||||
.null-tip{
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
left: 36px;
|
|
||||||
z-index: 10;
|
|
||||||
color: #ffffffc9;
|
|
||||||
line-height: initial;
|
|
||||||
}
|
|
||||||
.null-tip-hidden{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 全屏样式 */
|
|
||||||
.full-screen-parent {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.full-screen-icon {
|
|
||||||
opacity: 0;
|
|
||||||
color: black;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
line-height: 24px;
|
|
||||||
background-color: white;
|
|
||||||
position: absolute;
|
|
||||||
top: 2px;
|
|
||||||
right: 2px;
|
|
||||||
z-index: 9;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.full-screen-icon {
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(255, 255, 255, 0.88);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.full-screen {
|
|
||||||
position: fixed;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
width: calc(100% - 20px);
|
|
||||||
height: calc(100% - 20px);
|
|
||||||
padding: 10px;
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
|
|
||||||
.full-screen-icon {
|
|
||||||
top: 12px;
|
|
||||||
right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-screen-child {
|
|
||||||
height: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-screen-child {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.auto-height {
|
|
||||||
.full-screen-child {
|
|
||||||
min-height: 120px;
|
|
||||||
max-height: 320px;
|
|
||||||
height: unset;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.full-screen .full-screen-child {
|
|
||||||
height: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-cursor{
|
|
||||||
height:18.4px !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,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>
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
:showTime="showTime"
|
:showTime="showTime"
|
||||||
:format="dateFormat"
|
:format="dateFormat"
|
||||||
:getCalendarContainer="getCalendarContainer"
|
:getCalendarContainer="getCalendarContainer"
|
||||||
/>
|
v-bind="$attrs"/>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|||||||
317
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue
Normal file
317
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
<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(' ')
|
||||||
|
if (vs.length >= 6) {
|
||||||
|
// 将 Quartz 星期 的规则转换为 CronParser 的规则
|
||||||
|
vs[5] = this.convertQuartzWeekToCParser(vs[5])
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
this.assignInput()
|
||||||
|
},
|
||||||
|
minute() {
|
||||||
|
if (this.second === '*') {
|
||||||
|
this.second = '0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hour() {
|
||||||
|
if (this.minute === '*') {
|
||||||
|
this.minute = '0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
day(day) {
|
||||||
|
if (day !== '?' && this.hour === '*') {
|
||||||
|
this.hour = '0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
week(week) {
|
||||||
|
if (week !== '?' && this.hour === '*') {
|
||||||
|
this.hour = '0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
month() {
|
||||||
|
if (this.day === '?' && this.week === '*') {
|
||||||
|
this.week = '1'
|
||||||
|
} else if (this.week === '?' && this.day === '*') {
|
||||||
|
this.day = '1'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
year() {
|
||||||
|
if (this.month === '*') {
|
||||||
|
this.month = '1'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.formatValue()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.calTriggerListInner()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
assignInput() {
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
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]
|
||||||
|
this.assignInput()
|
||||||
|
},
|
||||||
|
// 将 Quartz 星期 的规则转换为 CronParser 的规则:
|
||||||
|
// Quartz 的规则:1 = 周日,2 = 周一,3 = 周二,4 = 周三,5 = 周四,6 = 周五,7 = 周六
|
||||||
|
// CronParser 的规则: 0 = 周日,1 = 周一,2 = 周二,3 = 周三,4 = 周四,5 = 周五,6 = 周六,7 = 周日
|
||||||
|
convertQuartzWeekToCParser(week) {
|
||||||
|
let convert = (v) => {
|
||||||
|
if (v === '0') {
|
||||||
|
return '1'
|
||||||
|
}
|
||||||
|
if (v === '1') {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
return (Number.parseInt(v) - 1).toString()
|
||||||
|
}
|
||||||
|
// 匹配示例 1-7 or 1/7
|
||||||
|
let patten1 = /^([0-7])([-/])([0-7])$/
|
||||||
|
// 匹配示例 1,4,7
|
||||||
|
let patten2 = /^([0-7])(,[0-7])+$/
|
||||||
|
if (/^[0-7]$/.test(week)) {
|
||||||
|
return convert(week)
|
||||||
|
} else if (patten1.test(week)) {
|
||||||
|
return week.replace(patten1, ($0, before, separator, after) => {
|
||||||
|
if (separator === '/') {
|
||||||
|
return convert(before) + separator + after
|
||||||
|
} else {
|
||||||
|
return convert(before) + separator + convert(after)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (patten2.test(week)) {
|
||||||
|
return week.split(',').map(v => convert(v)).join(',')
|
||||||
|
}
|
||||||
|
return week
|
||||||
|
},
|
||||||
|
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': '1',
|
||||||
|
'MON': '2',
|
||||||
|
'TUE': '3',
|
||||||
|
'WED': '4',
|
||||||
|
'THU': '5',
|
||||||
|
'FRI': '6',
|
||||||
|
'SAT': '7'
|
||||||
|
}
|
||||||
|
|
||||||
|
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 of specifyRange">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</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 specifyRange">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</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 specifyRange">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</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,162 @@
|
|||||||
|
// 主要用于日和星期的互斥使用
|
||||||
|
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:
|
||||||
|
if (this.valueList.length === 0) {
|
||||||
|
this.valueList.push(this.minValue)
|
||||||
|
}
|
||||||
|
result.push(this.valueList.join(','))
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
result.push(this.DEFAULT_VALUE)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return result.length > 0 ? result.join('') : this.DEFAULT_VALUE
|
||||||
|
},
|
||||||
|
// 指定值范围区间,介于最小值和最大值之间
|
||||||
|
specifyRange() {
|
||||||
|
let range = []
|
||||||
|
for (let i = this.minValue; i <= this.maxValue; i++) {
|
||||||
|
range.push(i)
|
||||||
|
}
|
||||||
|
return range
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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,42 @@
|
|||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week {
|
||||||
|
.list-check-item {
|
||||||
|
width: 5em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 of specifyRange">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</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 specifyRange">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</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,118 @@
|
|||||||
|
<template>
|
||||||
|
<div class="config-list week">
|
||||||
|
<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="(v,k) in WEEK_MAP">
|
||||||
|
<a-checkbox class="list-check-item" :key="`key-${v}`" :value="v" :disabled="type!==TYPE_SPECIFY || disabled">{{k}}</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 = {
|
||||||
|
'周一': 2,
|
||||||
|
'周二': 3,
|
||||||
|
'周三': 4,
|
||||||
|
'周四': 5,
|
||||||
|
'周五': 6,
|
||||||
|
'周六': 7,
|
||||||
|
// 按照国人习惯,将周日放到每周的最后一天
|
||||||
|
'周日': 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 1
|
||||||
|
this.maxValue = 7
|
||||||
|
this.valueRange.start = 1
|
||||||
|
this.valueRange.end = 7
|
||||||
|
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
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<!-- JEditableTable -->
|
<!-- JEditableTable -->
|
||||||
<!-- @version 1.6.1 -->
|
<!-- @version 1.6.2 -->
|
||||||
<!-- @author sjlei -->
|
<!-- @author sjlei -->
|
||||||
<template>
|
<template>
|
||||||
<a-spin :spinning="loading">
|
<a-spin :spinning="loading">
|
||||||
@ -11,13 +11,39 @@
|
|||||||
<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-group v-if="buttonPermission('add')">
|
||||||
|
<a-button type="primary" icon="plus" @click="handleClickAdd" :disabled="disabled">新增</a-button>
|
||||||
|
<a-popover v-if="addButtonSettings" placement="right" overlayClassName="j-add-btn-settings">
|
||||||
|
<a-row slot="title">
|
||||||
|
<a-col :span="12">选项</a-col>
|
||||||
|
<a-col :span="12" style="text-align: right;">
|
||||||
|
<a-tooltip title="保存为默认值">
|
||||||
|
<a-button type="link" icon="save" size="small" style="position: relative;left:4px;" @click="onAddButtonSettingsSave"/>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<template slot="content">
|
||||||
|
<a-form-model layout="horizontal" :labelCol="{span:8}" :wrapperCol="{span:16}">
|
||||||
|
<a-form-model-item label="添加行数">
|
||||||
|
<a-input-number v-model="settings.addRowNum" :min="1"/>
|
||||||
|
</a-form-model-item>
|
||||||
|
<a-form-model-item label="添加位置">
|
||||||
|
<a-input-number v-model="settings.addIndex" :min="0" :max="rows.length"/>
|
||||||
|
<p style="font-size: 12px;color:#aaa;line-height: 14px;text-align: right;margin: 0;">0 = 最底部</p>
|
||||||
|
</a-form-model-item>
|
||||||
|
<a-divider style="margin: 8px 0;"/>
|
||||||
|
<a-checkbox v-model="settings.addScrollToBottom">添加后滚动到底部</a-checkbox>
|
||||||
|
</a-form-model>
|
||||||
|
</template>
|
||||||
|
<a-button icon="setting" type="primary"></a-button>
|
||||||
|
</a-popover>
|
||||||
|
</a-button-group>
|
||||||
<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">
|
||||||
@ -59,7 +85,7 @@
|
|||||||
v-show="col.type !== formTypes.hidden"
|
v-show="col.type !== formTypes.hidden"
|
||||||
class="td"
|
class="td"
|
||||||
:key="col.key"
|
:key="col.key"
|
||||||
:style="buildTdStyle(col,true)">
|
:style="buildTdStyle(col)">
|
||||||
|
|
||||||
<span>{{ col.title }}</span>
|
<span>{{ col.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -188,6 +214,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 +228,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="isMultipleSelect(col)"
|
||||||
|
@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="isMultipleSelect(col)"
|
||||||
|
@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)">
|
||||||
@ -227,8 +303,33 @@
|
|||||||
>{{ jdateValues[id] }}</span>
|
>{{ jdateValues[id] }}</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- time -->
|
||||||
|
<template v-else-if="col.type === formTypes.time">
|
||||||
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
|
<j-time
|
||||||
|
v-if="isEditRow(row, col)"
|
||||||
|
:id="id"
|
||||||
|
:key="i"
|
||||||
|
v-bind="buildProps(row,col)"
|
||||||
|
style="width: 100%;"
|
||||||
|
:value="jdateValues[id]"
|
||||||
|
:getCalendarContainer="getParentContainer"
|
||||||
|
:placeholder="replaceProps(col, col.placeholder)"
|
||||||
|
allowClear
|
||||||
|
@change="(v)=>handleChangeJDateCommon(v,id,row,col)"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="j-td-span no-edit"
|
||||||
|
:class="{disabled: buildProps(row,col).disabled}"
|
||||||
|
@click="handleEditRow(row, col)"
|
||||||
|
>{{ jdateValues[id] }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- input_pop -->
|
<!-- input_pop -->
|
||||||
<template v-else-if="col.type === formTypes.input_pop">
|
<template v-else-if="col.type === formTypes.input_pop||col.type === 'textarea'">
|
||||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
<j-input-pop
|
<j-input-pop
|
||||||
v-if="isEditRow(row, col)"
|
v-if="isEditRow(row, col)"
|
||||||
@ -268,7 +369,7 @@
|
|||||||
<a-tooltip v-else-if="file.status==='done'" title="上传完成">
|
<a-tooltip v-else-if="file.status==='done'" title="上传完成">
|
||||||
<a-icon type="check-circle" style="color:#00DB00;"/>
|
<a-icon type="check-circle" style="color:#00DB00;"/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip v-else title="上传失败">
|
<a-tooltip v-else :title="file.message||'上传失败'">
|
||||||
<a-icon type="exclamation-circle" style="color:red;"/>
|
<a-icon type="exclamation-circle" style="color:red;"/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
@ -300,7 +401,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 +432,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
|
||||||
@ -345,7 +448,7 @@
|
|||||||
|
|
||||||
<!-- update-beign-author:taoyan date:0827 for:文件/图片逻辑新增 -->
|
<!-- update-beign-author:taoyan date:0827 for:文件/图片逻辑新增 -->
|
||||||
<div v-else-if="col.type === formTypes.file" :key="i">
|
<div v-else-if="col.type === formTypes.file" :key="i">
|
||||||
<template v-if="uploadValues[id] != null" v-for="(file,fileKey) of [(uploadValues[id]||{})]">
|
<template v-if="hasUploadValue(id)" v-for="(file,fileKey) of [(uploadValues[id]||{})]">
|
||||||
<div :key="fileKey" style="position: relative;">
|
<div :key="fileKey" style="position: relative;">
|
||||||
<a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
|
<a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
|
||||||
<a-icon type="loading" style="color:red;"/>
|
<a-icon type="loading" style="color:red;"/>
|
||||||
@ -357,9 +460,9 @@
|
|||||||
<span style="margin-left:5px">{{ getEllipsisWord(file.name,5) }}</span>
|
<span style="margin-left:5px">{{ getEllipsisWord(file.name,5) }}</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
|
||||||
<a-tooltip v-else :title="file.name">
|
<a-tooltip v-else :title="file.message||'上传失败'">
|
||||||
<a-icon type="paper-clip" style="color:red;"/>
|
<a-icon type="exclamation-circle" style="color:red;"/>
|
||||||
<span style="color:red;margin-left:5px">{{ getEllipsisWord(file.name,5) }}</span>
|
<span style="margin-left:5px">{{ getEllipsisWord(file.name,5) }}</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
|
||||||
<template style="width: 30px">
|
<template style="width: 30px">
|
||||||
@ -384,7 +487,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div :hidden="uploadValues[id] != null">
|
<div :hidden="hasUploadValue(id)">
|
||||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
@ -404,7 +507,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="col.type === formTypes.image" :key="i">
|
<div v-else-if="col.type === formTypes.image" :key="i">
|
||||||
<template v-if="uploadValues[id] != null" v-for="(file,fileKey) of [(uploadValues[id]||{})]">
|
<template v-if="hasUploadValue(id)" v-for="(file,fileKey) of [(uploadValues[id]||{})]">
|
||||||
<div :key="fileKey" style="position: relative;">
|
<div :key="fileKey" style="position: relative;">
|
||||||
<template v-if="!uploadValues[id] || !(uploadValues[id]['url'] || uploadValues[id]['path'] || uploadValues[id]['message'])">
|
<template v-if="!uploadValues[id] || !(uploadValues[id]['url'] || uploadValues[id]['path'] || uploadValues[id]['message'])">
|
||||||
<a-icon type="loading"/>
|
<a-icon type="loading"/>
|
||||||
@ -412,20 +515,9 @@
|
|||||||
<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',col)"/>
|
<img class="j-editable-image" :src="getCellImageView(id)" alt="无图片" @click="handleMoreOperation(id,'img',col)"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<a-tooltip v-else :title="file.message||'上传失败'" @click="handleClickShowImageError(id)">
|
||||||
<a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError(id)"/>
|
<a-icon type="exclamation-circle" style="color:red;"/>
|
||||||
</template>
|
</a-tooltip>
|
||||||
<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">
|
<template style="width: 30px">
|
||||||
<a-dropdown :trigger="['click']" placement="bottomRight" :getPopupContainer="getParentContainer" style="margin-left: 10px;">
|
<a-dropdown :trigger="['click']" placement="bottomRight" :getPopupContainer="getParentContainer" style="margin-left: 10px;">
|
||||||
@ -453,7 +545,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div :hidden="uploadValues[id] != null">
|
<div :hidden="hasUploadValue(id)">
|
||||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
@ -545,8 +637,36 @@
|
|||||||
</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)">
|
||||||
|
<!-- update:sunjianlei date:2022-1-17 for:buildProps新增参数 -->
|
||||||
<slot
|
<slot
|
||||||
:name="(col.slot || col.slotName) || col.key"
|
:name="(col.slot || col.slotName) || col.key"
|
||||||
:index="rowIndex"
|
:index="rowIndex"
|
||||||
@ -560,12 +680,13 @@
|
|||||||
:target="getVM()"
|
:target="getVM()"
|
||||||
:handleChange="(v)=>handleChangeSlotCommon(v,id,row,col)"
|
:handleChange="(v)=>handleChangeSlotCommon(v,id,row,col)"
|
||||||
:isNotPass="notPassedIds.includes(col.key+row.id)"
|
:isNotPass="notPassedIds.includes(col.key+row.id)"
|
||||||
|
:buildProps="()=>buildProps(row,col)"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</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>
|
||||||
@ -622,12 +743,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
|
||||||
@ -658,6 +780,11 @@
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
// 是否显示添加按钮选项
|
||||||
|
addButtonSettings: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
// 是否显示行号
|
// 是否显示行号
|
||||||
rowNumber: {
|
rowNumber: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -704,6 +831,11 @@
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
authPre: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -749,11 +881,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 +912,17 @@
|
|||||||
// 上次push数据的事件,用于判断是否点击过快
|
// 上次push数据的事件,用于判断是否点击过快
|
||||||
lastPushTimeMap: new Map(),
|
lastPushTimeMap: new Map(),
|
||||||
number:0,
|
number:0,
|
||||||
|
//不显示的按钮编码
|
||||||
|
excludeCode:[],
|
||||||
|
// 选项配置
|
||||||
|
settings: {
|
||||||
|
// 添加行数
|
||||||
|
addRowNum: 1,
|
||||||
|
// 添加位置(下标),0 = 最底部
|
||||||
|
addIndex: 0,
|
||||||
|
// 添加后滚动到底部
|
||||||
|
addScrollToBottom: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -789,6 +937,7 @@
|
|||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.getSavedAddButtonSettings()
|
||||||
},
|
},
|
||||||
// 计算属性
|
// 计算属性
|
||||||
computed: {
|
computed: {
|
||||||
@ -883,6 +1032,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 => {
|
||||||
@ -939,7 +1090,11 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 判断文件/图片是否存在
|
||||||
|
hasUploadValue(id){
|
||||||
|
let flag = this.uploadValues[id] != null && this.uploadValues[id].toString().length>0
|
||||||
|
return flag;
|
||||||
|
},
|
||||||
getElement(id, noCaseId = false) {
|
getElement(id, noCaseId = false) {
|
||||||
if (!this.el[id]) {
|
if (!this.el[id]) {
|
||||||
this.el[id] = document.getElementById((noCaseId ? '' : this.caseId) + id)
|
this.el[id] = document.getElementById((noCaseId ? '' : this.caseId) + id)
|
||||||
@ -964,41 +1119,52 @@
|
|||||||
this.visibleTrEls = []
|
this.visibleTrEls = []
|
||||||
// 判断是否是首次进入该方法,如果是就不清空行,防止删除了预添加的数据
|
// 判断是否是首次进入该方法,如果是就不清空行,防止删除了预添加的数据
|
||||||
if (!this.isFirst) {
|
if (!this.isFirst) {
|
||||||
// inputValues:用来存储input表单的值
|
this.clearRow();
|
||||||
// 数组里的每项都是一个对象,对象里每个key都是input的rowKey,值就是input的值,其中有个id的字段来区分
|
|
||||||
// 示例:
|
|
||||||
// [{
|
|
||||||
// id: "_jet-4sp0iu-15541771111770"
|
|
||||||
// dbDefaultVal: "aaa",
|
|
||||||
// dbFieldName: "bbb",
|
|
||||||
// dbFieldTxt: "ccc",
|
|
||||||
// dbLength: 32
|
|
||||||
// }]
|
|
||||||
this.inputValues = []
|
|
||||||
this.rows = []
|
|
||||||
this.deleteIds = []
|
|
||||||
this.selectValues = {}
|
|
||||||
this.checkboxValues = {}
|
|
||||||
this.jdateValues = {}
|
|
||||||
this.jInputPopValues = {}
|
|
||||||
this.slotValues = {}
|
|
||||||
this.selectedRowIds = []
|
|
||||||
this.tooltips = {}
|
|
||||||
this.notPassedIds = []
|
|
||||||
this.uploadValues = []
|
|
||||||
this.popupValues = []
|
|
||||||
this.radioValues = []
|
|
||||||
this.multiSelectValues = []
|
|
||||||
this.searchSelectValues = []
|
|
||||||
this.scrollTop = 0
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.getElement('tbody').scrollTop = 0
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
this.isFirst = false
|
this.isFirst = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**清空行*/
|
||||||
|
clearRow(){
|
||||||
|
// inputValues:用来存储input表单的值
|
||||||
|
// 数组里的每项都是一个对象,对象里每个key都是input的rowKey,值就是input的值,其中有个id的字段来区分
|
||||||
|
// 示例:
|
||||||
|
// [{
|
||||||
|
// id: "_jet-4sp0iu-15541771111770"
|
||||||
|
// dbDefaultVal: "aaa",
|
||||||
|
// dbFieldName: "bbb",
|
||||||
|
// dbFieldTxt: "ccc",
|
||||||
|
// dbLength: 32
|
||||||
|
// }]
|
||||||
|
this.inputValues = []
|
||||||
|
this.rows = []
|
||||||
|
this.deleteIds = []
|
||||||
|
this.selectedRowIds = []
|
||||||
|
this.tooltips = {}
|
||||||
|
this.notPassedIds = []
|
||||||
|
// 重置values
|
||||||
|
this.selectValues = {}
|
||||||
|
this.checkboxValues = {}
|
||||||
|
this.jdateValues = {}
|
||||||
|
this.jInputPopValues = {}
|
||||||
|
this.departCompValues = {}
|
||||||
|
this.userCompValues = {}
|
||||||
|
this.slotValues = {}
|
||||||
|
//update-begin-author:shunjlei date:20210415 for:类型赋值错误
|
||||||
|
this.uploadValues = {}
|
||||||
|
this.popupValues = {}
|
||||||
|
this.radioValues = {}
|
||||||
|
this.multiSelectValues = {}
|
||||||
|
this.searchSelectValues = {}
|
||||||
|
this.searchSelectAsyncValues = {}
|
||||||
|
//update-end-author:shunjlei date:20210415 for:类型赋值错误
|
||||||
|
|
||||||
|
// 重置滚动条
|
||||||
|
this.scrollTop = 0
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.getElement('tbody').scrollTop = 0
|
||||||
|
})
|
||||||
|
},
|
||||||
/** 同步滚动条状态 */
|
/** 同步滚动条状态 */
|
||||||
syncScrollBar(scrollLeft) {
|
syncScrollBar(scrollLeft) {
|
||||||
// this.style.tbody.left = `${scrollLeft}px`
|
// this.style.tbody.left = `${scrollLeft}px`
|
||||||
@ -1058,6 +1224,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 +1233,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) => {
|
||||||
@ -1136,7 +1305,7 @@
|
|||||||
selectValues[inputId] = undefined
|
selectValues[inputId] = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
|
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime || column.type === FormTypes.time) {
|
||||||
jdateValues[inputId] = sourceValue
|
jdateValues[inputId] = sourceValue
|
||||||
|
|
||||||
} else if (column.type === FormTypes.slot) {
|
} else if (column.type === FormTypes.slot) {
|
||||||
@ -1144,12 +1313,18 @@
|
|||||||
|
|
||||||
} else if (column.type === FormTypes.popup) {
|
} else if (column.type === FormTypes.popup) {
|
||||||
popupValues[inputId] = sourceValue
|
popupValues[inputId] = sourceValue
|
||||||
} else if (column.type === FormTypes.input_pop) {
|
} 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 || column.type === 'textarea') {
|
||||||
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 +1345,8 @@
|
|||||||
status: 'done',
|
status: 'done',
|
||||||
path: sourceValue
|
path: sourceValue
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
uploadValues[inputId] = null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value[column.key] = sourceValue
|
value[column.key] = sourceValue
|
||||||
@ -1225,6 +1402,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
|
||||||
@ -1232,6 +1411,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
|
||||||
@ -1293,22 +1473,18 @@
|
|||||||
let tbody = this.getElement('tbody')
|
let tbody = this.getElement('tbody')
|
||||||
let offsetHeight = tbody.offsetHeight
|
let offsetHeight = tbody.offsetHeight
|
||||||
let realScrollTop = tbody.scrollTop + offsetHeight
|
let realScrollTop = tbody.scrollTop + offsetHeight
|
||||||
if (forceScrollToBottom === false) {
|
if (forceScrollToBottom) {
|
||||||
// 只有滚动条在底部的时候才自动滚动
|
this.$nextTick(() => {
|
||||||
if (!((tbody.scrollHeight - realScrollTop) <= 10)) {
|
this.resetScrollTop(this.$refs.scrollView.scrollHeight)
|
||||||
return
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.$nextTick(() => {
|
|
||||||
tbody.scrollTop = tbody.scrollHeight
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 在指定位置添加一行
|
* 在指定位置添加一行
|
||||||
* @param insertIndex 添加位置下标
|
* @param insertIndex 添加位置下标
|
||||||
* @param num 添加的行数,默认1
|
* @param num 添加的行数,默认1
|
||||||
*/
|
*/
|
||||||
insert(insertIndex, num = 1) {
|
insert(insertIndex, num = 1, forceScrollToBottom = false) {
|
||||||
if (this.checkTooFastClick('insert', 1500)) {
|
if (this.checkTooFastClick('insert', 1500)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1336,6 +1512,12 @@
|
|||||||
num, insertIndex,
|
num, insertIndex,
|
||||||
target: this
|
target: this
|
||||||
})
|
})
|
||||||
|
// 设置滚动条位置
|
||||||
|
if (forceScrollToBottom) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.resetScrollTop(this.$refs.scrollView.scrollHeight)
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/** 删除被选中的行 */
|
/** 删除被选中的行 */
|
||||||
removeSelectedRows() {
|
removeSelectedRows() {
|
||||||
@ -1437,10 +1619,16 @@
|
|||||||
value[column.key] = selected
|
value[column.key] = selected
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
|
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime || column.type === FormTypes.time) {
|
||||||
value[column.key] = this.jdateValues[inputId]
|
value[column.key] = this.jdateValues[inputId]
|
||||||
|
|
||||||
} else if (column.type === FormTypes.input_pop) {
|
} 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 || column.type === 'textarea') {
|
||||||
value[column.key] = this.jInputPopValues[inputId]
|
value[column.key] = this.jInputPopValues[inputId]
|
||||||
|
|
||||||
} else if (column.type === FormTypes.upload) {
|
} else if (column.type === FormTypes.upload) {
|
||||||
@ -1460,6 +1648,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] = ''
|
||||||
@ -1579,6 +1769,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,
|
||||||
@ -1586,6 +1778,7 @@
|
|||||||
radioValues: this.radioValues,
|
radioValues: this.radioValues,
|
||||||
multiSelectValues: this.multiSelectValues,
|
multiSelectValues: this.multiSelectValues,
|
||||||
searchSelectValues: this.searchSelectValues,
|
searchSelectValues: this.searchSelectValues,
|
||||||
|
searchSelectAsyncValues: this.searchSelectAsyncValues,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/** 设置某行某列的值 */
|
/** 设置某行某列的值 */
|
||||||
@ -1631,9 +1824,13 @@
|
|||||||
}
|
}
|
||||||
this.$set(this.checkboxValues, key, sourceValue)
|
this.$set(this.checkboxValues, key, sourceValue)
|
||||||
edited = true
|
edited = true
|
||||||
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
|
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime || column.type === FormTypes.time) {
|
||||||
edited = this.setOneValue(this.jdateValues, modelKey, newValue)
|
edited = this.setOneValue(this.jdateValues, modelKey, newValue)
|
||||||
} else if (column.type === FormTypes.input_pop) {
|
} else if (column.type === FormTypes.sel_depart) {
|
||||||
|
edited = this.setOneValue(this.departCompValues, modelKey, newValue)
|
||||||
|
} else if (column.type === FormTypes.sel_user) {
|
||||||
|
edited = this.setOneValue(this.userCompValues, modelKey, newValue)
|
||||||
|
} else if (column.type === FormTypes.input_pop || column.type === 'textarea') {
|
||||||
edited = this.setOneValue(this.jInputPopValues, modelKey, newValue)
|
edited = this.setOneValue(this.jInputPopValues, modelKey, newValue)
|
||||||
} else if (column.type === FormTypes.slot) {
|
} else if (column.type === FormTypes.slot) {
|
||||||
edited = this.setOneValue(this.slotValues, modelKey, newValue)
|
edited = this.setOneValue(this.slotValues, modelKey, newValue)
|
||||||
@ -1647,12 +1844,16 @@
|
|||||||
edited = this.setOneValue(this.multiSelectValues, modelKey, newValue, true)
|
edited = this.setOneValue(this.multiSelectValues, modelKey, newValue, true)
|
||||||
} else if (column.type === FormTypes.sel_search) {
|
} else if (column.type === FormTypes.sel_search) {
|
||||||
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 {
|
} else {
|
||||||
edited = false
|
edited = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (edited) {
|
if (edited) {
|
||||||
this.elemValueChange(column.type, {[newValueKey]: newValue}, column, newValue)
|
// update-begin-author:sunjianlei date:20211222 for: 修复 setValues 触发的 valueChange 事件没有id的问题
|
||||||
|
this.elemValueChange(column.type, {id: rowKey}, column, newValue)
|
||||||
|
// update-end-author:sunjianlei date:20211222 for: 修复 setValues 触发的 valueChange 事件没有id的问题
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1809,13 +2010,13 @@
|
|||||||
|
|
||||||
// 兼容 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+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/ },
|
||||||
{ title: '电子邮件', value: 'e', pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/ },
|
{ title: '电子邮件', value: 'e', pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/ },
|
||||||
{ title: '手机号码', value: 'm', pattern: /^1[3456789]\d{9}$/ },
|
{ title: '手机号码', value: 'm', pattern: /^1[3456789]\d{9}$/ },
|
||||||
{ title: '邮政编码', value: 'p', pattern: /^[1-9]\d{5}$/ },
|
{ title: '邮政编码', value: 'p', pattern: /^[0-9]{6}$/ },
|
||||||
{ title: '字母', value: 's', pattern: /^[A-Z|a-z]+$/ },
|
{ title: '字母', value: 's', pattern: /^[A-Z|a-z]+$/ },
|
||||||
{ title: '数字', value: 'n', pattern: /^-?\d+(\.?\d+|\d?)$/ },
|
{ title: '数字', value: 'n', pattern: /^-?\d+(\.?\d+|\d?)$/ },
|
||||||
{ title: '整数', value: 'z', pattern: /^-?\d+$/ },
|
{ title: '整数', value: 'z', pattern: /^-?\d+$/ },
|
||||||
@ -1959,7 +2160,12 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
handleClickAdd() {
|
handleClickAdd() {
|
||||||
this.add()
|
let {addRowNum, addIndex, addScrollToBottom} = this.settings
|
||||||
|
if (addIndex <= 0) {
|
||||||
|
this.add(addRowNum, addScrollToBottom)
|
||||||
|
} else {
|
||||||
|
this.insert(addIndex, addRowNum, addScrollToBottom)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleConfirmDelete() {
|
handleConfirmDelete() {
|
||||||
this.removeSelectedRows()
|
this.removeSelectedRows()
|
||||||
@ -1970,6 +2176,29 @@
|
|||||||
clearSelection() {
|
clearSelection() {
|
||||||
this.selectedRowIds = []
|
this.selectedRowIds = []
|
||||||
},
|
},
|
||||||
|
// 获取当前选中的行
|
||||||
|
getSelection() {
|
||||||
|
return this.selectedRowIds.map(id => this.getCleanId(id))
|
||||||
|
},
|
||||||
|
// 设置当前选中的行
|
||||||
|
async setSelection(selectedRowIds) {
|
||||||
|
if (Array.isArray(selectedRowIds) && selectedRowIds.length > 0) {
|
||||||
|
// 兼容IE
|
||||||
|
await this.getElementPromise('tbody')
|
||||||
|
await this.$nextTick()
|
||||||
|
this.selectedRowIds = selectedRowIds.map(id => {
|
||||||
|
let temp = id
|
||||||
|
if (!this.hasCaseId(id)) {
|
||||||
|
temp = this.caseId + id
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 切换全选状态
|
||||||
|
toggleSelectionAll() {
|
||||||
|
this.handleChangeCheckedAll()
|
||||||
|
},
|
||||||
/** 用于搜索下拉框中的内容 */
|
/** 用于搜索下拉框中的内容 */
|
||||||
handleSelectFilterOption(input, option, column) {
|
handleSelectFilterOption(input, option, column) {
|
||||||
if (column.allowSearch === true || column.allowInput === true) {
|
if (column.allowSearch === true || column.allowInput === true) {
|
||||||
@ -2177,11 +2406,21 @@
|
|||||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||||
|
|
||||||
// 触发valueChange 事件
|
// 触发valueChange 事件
|
||||||
if (showTime) {
|
this.elemValueChange(column.type, row, column, value)
|
||||||
this.elemValueChange(FormTypes.datetime, row, column, value)
|
},
|
||||||
} else {
|
//部门组件值改变
|
||||||
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')
|
||||||
@ -2203,7 +2442,21 @@
|
|||||||
value['responseName'] = file.response[column.responseName]
|
value['responseName'] = file.response[column.responseName]
|
||||||
}
|
}
|
||||||
if (file.status === 'done') {
|
if (file.status === 'done') {
|
||||||
value['path'] = file.response[column.responseName]
|
if (typeof file.response.success === 'boolean') {
|
||||||
|
// 如果文件上传,被拦截器拦下,还会返回最外层的status = done
|
||||||
|
// 但是内部的success会返回false并携带异常信息
|
||||||
|
// 整个上传操作还是失败的
|
||||||
|
// https://github.com/zhangdaiscott/jeecg-boot/issues/2691
|
||||||
|
if (file.response.success) {
|
||||||
|
value['path'] = file.response[column.responseName]
|
||||||
|
} else {
|
||||||
|
value['status'] = 'error'
|
||||||
|
value['message'] = file.response.message || '未知错误'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 考虑到如果设置action上传路径为非jeecg-boot后台,可能不会返回 success 属性的情况,就默认为成功
|
||||||
|
value['path'] = file.response[column.responseName]
|
||||||
|
}
|
||||||
} else if (file.status === 'error') {
|
} else if (file.status === 'error') {
|
||||||
value['message'] = file.response.message || '未知错误'
|
value['message'] = file.response.message || '未知错误'
|
||||||
}
|
}
|
||||||
@ -2265,6 +2518,25 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 添加按钮设置保存为默认值 */
|
||||||
|
onAddButtonSettingsSave() {
|
||||||
|
let obj = {
|
||||||
|
addRowNum: this.settings.addRowNum,
|
||||||
|
addIndex: this.settings.addIndex,
|
||||||
|
addScrollToBottom: this.settings.addScrollToBottom,
|
||||||
|
}
|
||||||
|
this.$ls.set('jet-add-btn-settings', obj)
|
||||||
|
this.$message.success('保存成功')
|
||||||
|
},
|
||||||
|
/** 获取保存的添加按钮默认值 */
|
||||||
|
getSavedAddButtonSettings() {
|
||||||
|
let obj= this.$ls.get('jet-add-btn-settings')
|
||||||
|
if (obj) {
|
||||||
|
Object.assign(this.settings, obj)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/** 记录用到数据绑定的组件的值 */
|
/** 记录用到数据绑定的组件的值 */
|
||||||
bindValuesChange(value, id, key) {
|
bindValuesChange(value, id, key) {
|
||||||
this.$set(this[key], id, value)
|
this.$set(this[key], id, value)
|
||||||
@ -2462,7 +2734,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** view辅助方法:构建 td style */
|
/** view辅助方法:构建 td style */
|
||||||
buildTdStyle(col,isTitle) {
|
buildTdStyle(col) {
|
||||||
const isEmptyWidth = (column) => (column.type === FormTypes.hidden || column.width === '0px' || column.width === '0' || column.width === 0)
|
const isEmptyWidth = (column) => (column.type === FormTypes.hidden || column.width === '0px' || column.width === '0' || column.width === 0)
|
||||||
|
|
||||||
let style = {}
|
let style = {}
|
||||||
@ -2475,13 +2747,15 @@
|
|||||||
style['width'] = '120px'
|
style['width'] = '120px'
|
||||||
}
|
}
|
||||||
//update-begin-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
|
//update-begin-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
|
||||||
//是否为标题,如果是时间控件设为200,时间控件的标题设为240 时间
|
//如果是时间控件设为200px
|
||||||
if(col.type === FormTypes.datetime){
|
if(col.type === FormTypes.datetime){
|
||||||
if(true === isTitle){
|
style['width'] = '200px'
|
||||||
style['width'] = '240px'
|
}
|
||||||
}else{
|
if(col.type === FormTypes.sel_user && !col.width){
|
||||||
style['width'] = '200px'
|
style['width'] = '220px'
|
||||||
}
|
}
|
||||||
|
if(col.type === FormTypes.sel_depart && !col.width){
|
||||||
|
style['width'] = '160px'
|
||||||
}
|
}
|
||||||
//update-end-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
|
//update-end-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
|
||||||
|
|
||||||
@ -2514,6 +2788,11 @@
|
|||||||
if (col.type === FormTypes.select && (col.allowInput === true || col.allowSearch === true)) {
|
if (col.type === FormTypes.select && (col.allowInput === true || col.allowSearch === true)) {
|
||||||
props['showSearch'] = true
|
props['showSearch'] = true
|
||||||
}
|
}
|
||||||
|
if (col.type === FormTypes.sel_depart || col.type === FormTypes.sel_user) {
|
||||||
|
let { storeField, textField } = this.getStoreAndTextField(col)
|
||||||
|
props['store'] = storeField
|
||||||
|
props['text'] = textField
|
||||||
|
}
|
||||||
|
|
||||||
// 判断是否是禁用的列
|
// 判断是否是禁用的列
|
||||||
props['disabled'] = (typeof col['disabled'] === 'boolean' ? col['disabled'] : props['disabled'])
|
props['disabled'] = (typeof col['disabled'] === 'boolean' ? col['disabled'] : props['disabled'])
|
||||||
@ -2531,6 +2810,42 @@
|
|||||||
return props
|
return props
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**获取部门选择 、用户选择的存储字段、展示字段*/
|
||||||
|
getStoreAndTextField(col){
|
||||||
|
let storeField = '', textField = ''
|
||||||
|
if(col.type === FormTypes.sel_depart){
|
||||||
|
storeField = 'id'
|
||||||
|
textField = 'departName'
|
||||||
|
}else if(col.type === FormTypes.sel_user){
|
||||||
|
storeField = 'username'
|
||||||
|
textField = 'realname'
|
||||||
|
}
|
||||||
|
if(col.fieldExtendJson){
|
||||||
|
// online逻辑
|
||||||
|
let tempJson = JSON.parse(col.fieldExtendJson)
|
||||||
|
if(tempJson){
|
||||||
|
if(tempJson.store){
|
||||||
|
storeField = tempJson.store
|
||||||
|
}
|
||||||
|
if(tempJson.text){
|
||||||
|
textField = tempJson.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// 实际开发逻辑
|
||||||
|
if(col.store){
|
||||||
|
storeField = col.store
|
||||||
|
}
|
||||||
|
if(col.text){
|
||||||
|
textField = col.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
storeField,
|
||||||
|
textField
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/** 辅助方法:防止过快点击,如果点击过快的话就返回 true */
|
/** 辅助方法:防止过快点击,如果点击过快的话就返回 true */
|
||||||
checkTooFastClick(key = 'default', ms = 300) {
|
checkTooFastClick(key = 'default', ms = 300) {
|
||||||
let nowTime = Date.now()
|
let nowTime = Date.now()
|
||||||
@ -2599,7 +2914,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)
|
||||||
},
|
},
|
||||||
@ -2626,6 +2941,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
|
||||||
},
|
},
|
||||||
@ -2718,15 +3038,50 @@
|
|||||||
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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 判断用户、部门组件是否多选
|
||||||
|
isMultipleSelect(column){
|
||||||
|
let jsonStr = column.fieldExtendJson
|
||||||
|
if(jsonStr){
|
||||||
|
// online
|
||||||
|
let config = JSON.parse(jsonStr)
|
||||||
|
if(config && config['multiSelect']==false){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}else if(column.multi==false){
|
||||||
|
// 实际开发
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.removeEventListener()
|
this.removeEventListener()
|
||||||
this.destroyCleanGroupRequest = true
|
this.destroyCleanGroupRequest = true
|
||||||
},
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -2867,6 +3222,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;
|
||||||
@ -2976,6 +3333,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comp-normal {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.j-td-span {
|
.j-td-span {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 4px 11px;
|
padding: 4px 11px;
|
||||||
@ -3095,3 +3458,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
<style lang="less">
|
||||||
|
// 新增按钮配置气泡的样式
|
||||||
|
.j-add-btn-settings {
|
||||||
|
width: 240px;
|
||||||
|
|
||||||
|
.ant-form {
|
||||||
|
.ant-form-item {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
.ant-input-number {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -128,12 +128,23 @@
|
|||||||
this.reload()
|
this.reload()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
//update--begin--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------
|
||||||
|
this.reload()
|
||||||
|
//update--end--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------
|
||||||
}else{
|
}else{
|
||||||
//update--begin--autor:wangshuai-----date:20200724------for:富文本编辑器切换tab无法修改------
|
//update--begin--autor:wangshuai-----date:20200724------for:富文本编辑器切换tab无法修改------
|
||||||
let tabLayout = getVmParentByName(this, 'TabLayout')
|
let tabLayout = getVmParentByName(this, 'TabLayout')
|
||||||
tabLayout.excuteCallback(()=>{
|
//update--begin--autor:liusq-----date:20210713------for:处理特殊情况excuteCallback不能使用------
|
||||||
this.reload()
|
try {
|
||||||
})
|
tabLayout.excuteCallback(() => {
|
||||||
|
this.reload()
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
if (tabLayout) {
|
||||||
|
this.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update--end--autor:liusq-----date:20210713------for:处理特殊情况excuteCallback不能使用------
|
||||||
//update--begin--autor:wangshuai-----date:20200724------for:文本编辑器切换tab无法修改------
|
//update--begin--autor:wangshuai-----date:20200724------for:文本编辑器切换tab无法修改------
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -11,13 +11,13 @@
|
|||||||
:beforeUpload="beforeUpload"
|
:beforeUpload="beforeUpload"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:isMultiple="isMultiple"
|
:isMultiple="isMultiple"
|
||||||
:showUploadList="isMultiple"
|
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
@preview="handlePreview"
|
@preview="handlePreview"
|
||||||
:class="!isMultiple?'imgupload':''">
|
:class="[!isMultiple?'imgupload':'', (!isMultiple && picUrl)?'image-upload-single-over':'' ]">
|
||||||
<div style="width:104px;height:104px">
|
<div>
|
||||||
<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="width:100%;height:100%"/>
|
<!--<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="width:100%;height:100%"/>-->
|
||||||
<div v-else class="iconp">
|
<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>
|
||||||
@ -189,7 +189,7 @@
|
|||||||
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(let a=0;a<uploadFiles.length;a++){
|
for(let a=0;a<uploadFiles.length;a++){
|
||||||
@ -231,8 +231,9 @@
|
|||||||
* https://github.com/zhangdaiscott/jeecg-boot/issues/1810
|
* https://github.com/zhangdaiscott/jeecg-boot/issues/1810
|
||||||
* https://github.com/zhangdaiscott/jeecg-boot/issues/1779
|
* https://github.com/zhangdaiscott/jeecg-boot/issues/1779
|
||||||
*/
|
*/
|
||||||
/deep/ .imgupload .ant-upload-select{display:block}
|
|
||||||
/deep/ .imgupload .ant-upload.ant-upload-select-picture-card{ width:120px;height: 120px;}
|
/deep/ .imgupload .iconp{padding:20px;}
|
||||||
/deep/ .imgupload .iconp{padding:32px;}
|
|
||||||
/* update--end--autor:lvdandan-----date:20201016------for:j-image-upload图片组件单张图片详情回显空白*/
|
/* 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){
|
||||||
this.$message.success(res.message)
|
if(res.code == 201){
|
||||||
|
this.errorTip(res.message, res.result)
|
||||||
|
}else{
|
||||||
|
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() {},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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">
|
||||||
@ -38,10 +47,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { getClass, getStyle } from '@/utils/props-util'
|
import { getClass, getStyle } from '@/utils/props-util'
|
||||||
import { triggerWindowResizeEvent } from '@/utils/util'
|
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JModal',
|
name: 'JModal',
|
||||||
props: {
|
props: {
|
||||||
title: String,
|
title: String,
|
||||||
@ -160,8 +169,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
||||||
.j-modal-box {
|
.j-modal-box {
|
||||||
|
|
||||||
&.fullscreen {
|
&.fullscreen {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -190,7 +199,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 +225,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.no-title{
|
||||||
|
.ant-modal-header {
|
||||||
|
padding: 0px 24px;
|
||||||
|
border-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
124
ant-design-vue-jeecg/src/components/jeecg/JModal/JPrompt.vue
Normal file
124
ant-design-vue-jeecg/src/components/jeecg/JModal/JPrompt.vue
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<template>
|
||||||
|
<j-modal :visible="visible" :confirmLoading="loading" :after-close="afterClose" v-bind="modalProps" @ok="onOk" @cancel="onCancel">
|
||||||
|
<a-spin :spinning="loading">
|
||||||
|
<div v-html="content"></div>
|
||||||
|
<a-form-model ref="form" :model="model" :rules="rules">
|
||||||
|
<a-form-model-item prop="input">
|
||||||
|
<a-input ref="input" v-model="model.input" v-bind="inputProps" @pressEnter="onInputPressEnter"/>
|
||||||
|
</a-form-model-item>
|
||||||
|
</a-form-model>
|
||||||
|
</a-spin>
|
||||||
|
</j-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import pick from 'lodash.pick'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JPrompt',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
loading: false,
|
||||||
|
content: '',
|
||||||
|
// 弹窗参数
|
||||||
|
modalProps: {
|
||||||
|
title: '',
|
||||||
|
},
|
||||||
|
inputProps: {
|
||||||
|
placeholder: '',
|
||||||
|
},
|
||||||
|
// form model
|
||||||
|
model: {
|
||||||
|
input: '',
|
||||||
|
},
|
||||||
|
// 校验
|
||||||
|
rule: [],
|
||||||
|
// 回调函数
|
||||||
|
callback: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
rules() {
|
||||||
|
return {
|
||||||
|
input: this.rule
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
show(options) {
|
||||||
|
this.content = options.content
|
||||||
|
if (Array.isArray(options.rule)) {
|
||||||
|
this.rule = options.rule
|
||||||
|
}
|
||||||
|
if (options.defaultValue != null) {
|
||||||
|
this.model.input = options.defaultValue
|
||||||
|
}
|
||||||
|
// 取出常用的弹窗参数
|
||||||
|
let pickModalProps = pick(options, 'title', 'centered', 'cancelText', 'closable', 'mask', 'maskClosable', 'okText', 'okType', 'okButtonProps', 'cancelButtonProps', 'width', 'wrapClassName', 'zIndex', 'dialogStyle', 'dialogClass')
|
||||||
|
this.modalProps = Object.assign({}, pickModalProps, options.modalProps)
|
||||||
|
// 取出常用的input参数
|
||||||
|
let pickInputProps = pick(options, 'placeholder', 'allowClear')
|
||||||
|
this.inputProps = Object.assign({}, pickInputProps, options.inputProps)
|
||||||
|
// 回调函数
|
||||||
|
this.callback = pick(options, 'onOk', 'onOkAsync', 'onCancel')
|
||||||
|
this.visible = true
|
||||||
|
this.$nextTick(() => this.$refs.input.focus())
|
||||||
|
},
|
||||||
|
|
||||||
|
onOk() {
|
||||||
|
this.$refs.form.validate((ok, err) => {
|
||||||
|
if (ok) {
|
||||||
|
let event = {value: this.model.input, target: this}
|
||||||
|
// 异步方法优先级高于同步方法
|
||||||
|
if (typeof this.callback.onOkAsync === 'function') {
|
||||||
|
this.callback.onOkAsync(event)
|
||||||
|
} else if (typeof this.callback.onOk === 'function') {
|
||||||
|
this.callback.onOk(event)
|
||||||
|
this.close()
|
||||||
|
} else {
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
if (typeof this.callback.onCancel === 'function') {
|
||||||
|
this.callback.onCancel(this.model.input)
|
||||||
|
}
|
||||||
|
this.close()
|
||||||
|
},
|
||||||
|
|
||||||
|
onInputPressEnter() {
|
||||||
|
this.onOk()
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.visible = this.loading ? this.visible : false
|
||||||
|
},
|
||||||
|
|
||||||
|
forceClose() {
|
||||||
|
this.visible = false
|
||||||
|
},
|
||||||
|
|
||||||
|
showLoading() {
|
||||||
|
this.loading = true
|
||||||
|
},
|
||||||
|
hideLoading() {
|
||||||
|
this.loading = false
|
||||||
|
},
|
||||||
|
|
||||||
|
afterClose(e) {
|
||||||
|
if (typeof this.modalProps.afterClose === 'function') {
|
||||||
|
this.modalProps.afterClose(e)
|
||||||
|
}
|
||||||
|
this.$emit('after-close', e)
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
18
ant-design-vue-jeecg/src/components/jeecg/JModal/index.js
Normal file
18
ant-design-vue-jeecg/src/components/jeecg/JModal/index.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import JModal from './JModal'
|
||||||
|
import JPrompt from './JPrompt'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install(Vue) {
|
||||||
|
Vue.component(JModal.name, JModal)
|
||||||
|
|
||||||
|
const JPromptExtend = Vue.extend(JPrompt)
|
||||||
|
Vue.prototype.$JPrompt = function (options = {}) {
|
||||||
|
// 创建prompt实例
|
||||||
|
const vm = new JPromptExtend().$mount()
|
||||||
|
vm.show(options)
|
||||||
|
// 关闭后销毁
|
||||||
|
vm.$on('after-close', () => vm.$destroy())
|
||||||
|
return vm
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@
|
|||||||
ref="jPopupOnlReport"
|
ref="jPopupOnlReport"
|
||||||
:code="code"
|
:code="code"
|
||||||
:multi="multi"
|
:multi="multi"
|
||||||
|
:sorter="sorter"
|
||||||
:groupId="uniqGroupId"
|
:groupId="uniqGroupId"
|
||||||
:param="param"
|
:param="param"
|
||||||
@ok="callBack"
|
@ok="callBack"
|
||||||
@ -47,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,
|
||||||
@ -82,6 +88,11 @@
|
|||||||
required: false,
|
required: false,
|
||||||
default: ()=>{}
|
default: ()=>{}
|
||||||
},
|
},
|
||||||
|
spliter:{
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ','
|
||||||
|
},
|
||||||
/** 分组ID,用于将多个popup的请求合并到一起,不传不分组 */
|
/** 分组ID,用于将多个popup的请求合并到一起,不传不分组 */
|
||||||
groupId: String
|
groupId: String
|
||||||
|
|
||||||
@ -108,7 +119,7 @@
|
|||||||
if (!val) {
|
if (!val) {
|
||||||
this.showText = ''
|
this.showText = ''
|
||||||
} else {
|
} else {
|
||||||
this.showText = val
|
this.showText = val.split(this.spliter).join(',')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,6 +143,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleEmpty() {
|
handleEmpty() {
|
||||||
|
// 禁用时,不允许清空内容
|
||||||
|
if (this.disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.showText = ''
|
this.showText = ''
|
||||||
let destFieldsArr = this.destFields.split(',')
|
let destFieldsArr = this.destFields.split(',')
|
||||||
if (destFieldsArr.length === 0) {
|
if (destFieldsArr.length === 0) {
|
||||||
@ -162,9 +177,11 @@
|
|||||||
let tempDestArr = []
|
let tempDestArr = []
|
||||||
for(let rw of rows){
|
for(let rw of rows){
|
||||||
let val = rw[orgFieldsArr[i]]
|
let val = rw[orgFieldsArr[i]]
|
||||||
if(!val){
|
// update--begin--autor:liusq-----date:20210713------for:处理val等于0的情况issues/I3ZL4T------
|
||||||
|
if(typeof val=='undefined'|| val==null || val.toString()==""){
|
||||||
val = ""
|
val = ""
|
||||||
}
|
}
|
||||||
|
// update--end--autor:liusq-----date:20210713------for:处理val等于0的情况issues/I3ZL4T------
|
||||||
tempDestArr.push(val)
|
tempDestArr.push(val)
|
||||||
}
|
}
|
||||||
res[destFieldsArr[i]] = tempDestArr.join(",")
|
res[destFieldsArr[i]] = tempDestArr.join(",")
|
||||||
@ -188,7 +205,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-select :value="arrayValue" @change="onChange" mode="multiple" :placeholder="placeholder">
|
<a-select :value="arrayValue" @change="onChange" mode="multiple" :placeholder="placeholder" allowClear>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="(item,index) in options"
|
v-for="(item,index) in selectOptions"
|
||||||
: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>
|
||||||
@ -11,6 +12,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
//option {label:,value:}
|
//option {label:,value:}
|
||||||
|
import { getAction } from '@api/manage'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectMultiple',
|
name: 'JSelectMultiple',
|
||||||
props: {
|
props: {
|
||||||
@ -30,36 +33,80 @@
|
|||||||
},
|
},
|
||||||
options:{
|
options:{
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true
|
default:()=>[],
|
||||||
|
required: false
|
||||||
},
|
},
|
||||||
triggerChange:{
|
triggerChange:{
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
}
|
},
|
||||||
|
spliter:{
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ','
|
||||||
|
},
|
||||||
|
popContainer:{
|
||||||
|
type:String,
|
||||||
|
default:'',
|
||||||
|
required:false
|
||||||
|
},
|
||||||
|
dictCode:{
|
||||||
|
type:String,
|
||||||
|
required:false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
arrayValue:!this.value?[]:this.value.split(",")
|
arrayValue:!this.value?[]:this.value.split(this.spliter),
|
||||||
|
dictOptions: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed:{
|
||||||
|
selectOptions(){
|
||||||
|
return this.dictOptions.length > 0 ? this.dictOptions : this.options
|
||||||
|
},
|
||||||
|
},
|
||||||
watch:{
|
watch:{
|
||||||
value (val) {
|
value (val) {
|
||||||
if(!val){
|
if(!val){
|
||||||
this.arrayValue = []
|
this.arrayValue = []
|
||||||
}else{
|
}else{
|
||||||
this.arrayValue = this.value.split(",")
|
this.arrayValue = this.value.split(this.spliter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted(){
|
||||||
|
if (this.dictCode) {
|
||||||
|
this.loadDictOptions()
|
||||||
|
}
|
||||||
|
},
|
||||||
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)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 根据字典code查询字典项
|
||||||
|
loadDictOptions(){
|
||||||
|
getAction(`/sys/dict/getDictItems/${this.dictCode}`,{}).then(res=>{
|
||||||
|
if (res.success) {
|
||||||
|
this.dictOptions = res.result.map(item => ({value: item.value, label: item.text}))
|
||||||
|
} else {
|
||||||
|
console.error('getDictItems error: : ', res)
|
||||||
|
this.dictOptions = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,7 +101,17 @@
|
|||||||
</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="请选择"/>
|
||||||
|
<!-- 下拉框 -->
|
||||||
|
<j-search-select-tag v-else-if="item.type==='list' && item.dictTable" 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 +119,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,19 +127,25 @@
|
|||||||
<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"
|
||||||
:buttons="false"
|
:buttons="false"
|
||||||
:multiple="false"
|
:multiple="allowMultiple(item)"
|
||||||
placeholder="请选择用户"
|
placeholder="请选择用户"
|
||||||
:returnKeys="['id', item.customReturnField || 'username']"
|
:returnKeys="['id', item.customReturnField || 'username']"
|
||||||
/>
|
/>
|
||||||
<j-select-depart
|
<j-select-depart
|
||||||
v-else-if="item.type === 'select-depart' || item.type === 'sel_depart'"
|
v-else-if="item.type === 'select-depart' || item.type === 'sel_depart'"
|
||||||
v-model="item.val"
|
v-model="item.val"
|
||||||
:multi="false"
|
:multi="allowMultiple(item)"
|
||||||
placeholder="请选择部门"
|
placeholder="请选择部门"
|
||||||
:customReturnField="item.customReturnField || 'id'"
|
:customReturnField="item.customReturnField || 'id'"
|
||||||
/>
|
/>
|
||||||
@ -316,7 +333,12 @@
|
|||||||
let child = { ...item2 }
|
let child = { ...item2 }
|
||||||
child.label = child.label || child.text
|
child.label = child.label || child.text
|
||||||
child.label = data.label + '-' + child.label
|
child.label = data.label + '-' + child.label
|
||||||
child.value = data.value + ',' + child.value
|
// update--begin--author:sunjianlei-----date:20220121------for:【JTC-1167】【表单设计器】高级查询,一对一字段查询不好使
|
||||||
|
// 是否仅包含字段名,不需要拼接子表表名
|
||||||
|
if (!data.onlyFieldName) {
|
||||||
|
child.value = data.value + ',' + child.value
|
||||||
|
}
|
||||||
|
// update--end--author:sunjianlei-----date:20220121------for:【JTC-1167】【表单设计器】高级查询,一对一字段查询不好使
|
||||||
child.val = ''
|
child.val = ''
|
||||||
return child
|
return child
|
||||||
})
|
})
|
||||||
@ -338,6 +360,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 = {
|
||||||
@ -353,7 +386,7 @@
|
|||||||
this.$message.warn("不能查询空条件")
|
this.$message.warn("不能查询空条件")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emitCallback(event = {}) {
|
emitCallback(event = {}, loadStatus = true) {
|
||||||
let { params = [], matchType = this.matchType } = event
|
let { params = [], matchType = this.matchType } = event
|
||||||
this.superQueryFlag = (params && params.length > 0)
|
this.superQueryFlag = (params && params.length > 0)
|
||||||
for (let param of params) {
|
for (let param of params) {
|
||||||
@ -362,7 +395,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.debug('---高级查询参数--->', { params, matchType })
|
console.debug('---高级查询参数--->', { params, matchType })
|
||||||
this.$emit(this.callback, params, matchType)
|
this.$emit(this.callback, params, matchType, loadStatus)
|
||||||
},
|
},
|
||||||
handleCancel() {
|
handleCancel() {
|
||||||
this.close()
|
this.close()
|
||||||
@ -386,11 +419,13 @@
|
|||||||
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, dbType, options, dictCode, dictTable, dictText, customReturnField, popup } = node.dataRef
|
||||||
item['type'] = type
|
item['type'] = type
|
||||||
|
item['dbType'] = dbType
|
||||||
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
|
||||||
@ -400,9 +435,13 @@
|
|||||||
handleOpen() {
|
handleOpen() {
|
||||||
this.show()
|
this.show()
|
||||||
},
|
},
|
||||||
|
handleOutReset(loadStaus=true) {
|
||||||
|
this.resetLine()
|
||||||
|
this.emitCallback({}, loadStaus)
|
||||||
|
},
|
||||||
handleReset() {
|
handleReset() {
|
||||||
this.resetLine()
|
this.resetLine()
|
||||||
this.emitCallback()
|
this.emitCallback({}, true)
|
||||||
},
|
},
|
||||||
handleSave() {
|
handleSave() {
|
||||||
let queryParams = this.removeEmptyObject(this.queryParamsModel)
|
let queryParams = this.removeEmptyObject(this.queryParamsModel)
|
||||||
|
|||||||
@ -12,12 +12,12 @@
|
|||||||
|
|
||||||
<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}"
|
||||||
:fileList="fileList"
|
:fileList="fileList"
|
||||||
:beforeUpload="beforeUpload"
|
:beforeUpload="doBeforeUpload"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:returnUrl="returnUrl"
|
:returnUrl="returnUrl"
|
||||||
@ -135,6 +135,13 @@
|
|||||||
required:false,
|
required:false,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
beforeUpload: {
|
||||||
|
type: Function
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
value:{
|
value:{
|
||||||
@ -238,7 +245,7 @@
|
|||||||
}
|
}
|
||||||
this.$emit('change', path);
|
this.$emit('change', path);
|
||||||
},
|
},
|
||||||
beforeUpload(file){
|
doBeforeUpload(file){
|
||||||
this.uploadGoOn=true
|
this.uploadGoOn=true
|
||||||
var fileType = file.type;
|
var fileType = file.type;
|
||||||
if(this.fileType===FILE_TYPE_IMG){
|
if(this.fileType===FILE_TYPE_IMG){
|
||||||
@ -248,7 +255,10 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO 扩展功能验证文件大小
|
// 扩展 beforeUpload 验证
|
||||||
|
if (typeof this.beforeUpload === 'function') {
|
||||||
|
return this.beforeUpload(file)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
handleChange(info) {
|
handleChange(info) {
|
||||||
@ -374,14 +384,17 @@
|
|||||||
},
|
},
|
||||||
mounted(){
|
mounted(){
|
||||||
const moverObj = document.getElementById(this.containerId+'-mover');
|
const moverObj = document.getElementById(this.containerId+'-mover');
|
||||||
moverObj.addEventListener('mouseover',()=>{
|
if(moverObj){
|
||||||
this.moverHold = true
|
moverObj.addEventListener('mouseover',()=>{
|
||||||
this.moveDisplay = 'block';
|
this.moverHold = true
|
||||||
});
|
this.moveDisplay = 'block';
|
||||||
moverObj.addEventListener('mouseout',()=>{
|
});
|
||||||
this.moverHold = false
|
moverObj.addEventListener('mouseout',()=>{
|
||||||
this.moveDisplay = 'none';
|
this.moverHold = false
|
||||||
});
|
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)=>{
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-popover :visible="visible" placement="bottom" overlayClassName="j-vxe-popover-overlay" :overlayStyle="overlayStyle">
|
<a-popover :visible="visible" :placement="placement" overlayClassName="j-vxe-popover-overlay" :overlayStyle="overlayStyle">
|
||||||
<div class="j-vxe-popover-title" slot="title">
|
<div class="j-vxe-popover-title" slot="title">
|
||||||
<div>子表</div>
|
<div>子表</div>
|
||||||
<div class="j-vxe-popover-title-close" @click="close">
|
<div class="j-vxe-popover-title-close" @click="close">
|
||||||
@ -34,6 +34,7 @@
|
|||||||
width: null,
|
width: null,
|
||||||
zIndex: 100
|
zIndex: 100
|
||||||
},
|
},
|
||||||
|
placement: 'bottom'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -41,6 +42,14 @@
|
|||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
toggle(event) {
|
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) {
|
if (this.row == null) {
|
||||||
this.open(event)
|
this.open(event)
|
||||||
} else {
|
} else {
|
||||||
@ -83,13 +92,22 @@
|
|||||||
this.$refs.div.style.height = clientHeight + 'px'
|
this.$refs.div.style.height = clientHeight + 'px'
|
||||||
this.overlayStyle.width = Number.parseInt((clientWidth - clientWidth * 0.04)) + 'px'
|
this.overlayStyle.width = Number.parseInt((clientWidth - clientWidth * 0.04)) + 'px'
|
||||||
this.overlayStyle.maxWidth = this.overlayStyle.width
|
this.overlayStyle.maxWidth = this.overlayStyle.width
|
||||||
domAlign(this.$refs.div, tr, {
|
//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'],
|
points: ['tl', 'tl'],
|
||||||
offset: [0, 0],
|
offset: [0, h],
|
||||||
overflow: {
|
overflow: {
|
||||||
alwaysByViewport: true
|
alwaysByViewport: true
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
//update-end-author:taoyan date:20200921 for: 子表弹出位置存在现实位置问题。
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.visible = true
|
this.visible = true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||||
import { JVXETypes } from '@/components/jeecg/JVxeTable/index'
|
import { JVXETypes } from '@/components/jeecg/JVxeTable/jvxeTypes'
|
||||||
import VxeWebSocketMixins from '../mixins/vxe.web.socket.mixins'
|
import VxeWebSocketMixins from '../mixins/vxe.web.socket.mixins'
|
||||||
import { initDictOptions } from '@/components/dict/JDictSelectUtil'
|
import { initDictOptions } from '@/components/dict/JDictSelectUtil'
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ import JVxeDetailsModal from './JVxeDetailsModal'
|
|||||||
import JVxePagination from './JVxePagination'
|
import JVxePagination from './JVxePagination'
|
||||||
import { cloneObject, getVmParentByName, pushIfNotExist, randomString, simpleDebounce } from '@/utils/util'
|
import { cloneObject, getVmParentByName, pushIfNotExist, randomString, simpleDebounce } from '@/utils/util'
|
||||||
import { UtilTools } from 'vxe-table/packages/tools/src/utils'
|
import { UtilTools } from 'vxe-table/packages/tools/src/utils'
|
||||||
import { getNoAuthCols } from "@/utils/authFilter"
|
import { getNoAuthCols } from '@/utils/authFilter'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JVxeTable',
|
name: 'JVxeTable',
|
||||||
@ -95,6 +95,11 @@ export default {
|
|||||||
// 是否异步删除行,如果你要实现异步删除,那么需要把这个选项开启,
|
// 是否异步删除行,如果你要实现异步删除,那么需要把这个选项开启,
|
||||||
// 在remove事件里调用confirmRemove方法才会真正删除(除非删除的全是新增的行)
|
// 在remove事件里调用confirmRemove方法才会真正删除(除非删除的全是新增的行)
|
||||||
asyncRemove: PropTypes.bool.def(false),
|
asyncRemove: PropTypes.bool.def(false),
|
||||||
|
// 是否一直显示组件,如果为false则只有点击的时候才出现组件
|
||||||
|
// 注:该参数不能动态修改;如果行、列字段多的情况下,会根据机器性能造成不同程度的卡顿。
|
||||||
|
alwaysEdit: PropTypes.bool.def(false),
|
||||||
|
// 联动配置,数组,详情配置见文档
|
||||||
|
linkageConfig: PropTypes.array.def(() => []),
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -148,7 +153,10 @@ export default {
|
|||||||
// 允许执行刷新特效的行ID
|
// 允许执行刷新特效的行ID
|
||||||
reloadEffectRowKeysMap: {},
|
reloadEffectRowKeysMap: {},
|
||||||
//配置了但是没有授权的按钮和列 集合
|
//配置了但是没有授权的按钮和列 集合
|
||||||
excludeCode:[]
|
excludeCode:[],
|
||||||
|
// 联动下拉选项(用于隔离不同的下拉选项)
|
||||||
|
// 内部联动配置,map
|
||||||
|
_innerLinkageConfig: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -175,6 +183,18 @@ export default {
|
|||||||
renderOptions.target = this
|
renderOptions.target = this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 处理联动列,联动列只能作用于 select 组件
|
||||||
|
if (column.$type === JVXETypes.select && this._innerLinkageConfig != null) {
|
||||||
|
// 判断当前列是否是联动列
|
||||||
|
if (this._innerLinkageConfig.has(column.key)) {
|
||||||
|
renderOptions.linkage = {
|
||||||
|
config: this._innerLinkageConfig.get(column.key),
|
||||||
|
getLinkageOptionsSibling: this.getLinkageOptionsSibling,
|
||||||
|
getLinkageOptionsAsync: this.getLinkageOptionsAsync,
|
||||||
|
linkageSelectChange: this.linkageSelectChange,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (column.editRender) {
|
if (column.editRender) {
|
||||||
Object.assign(column.editRender, renderOptions)
|
Object.assign(column.editRender, renderOptions)
|
||||||
}
|
}
|
||||||
@ -188,6 +208,21 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// update--begin--autor:lvdandan-----date:20201019------for:LOWCOD-882 【新行编辑】列表上带按钮的遮挡问题
|
// update--begin--autor:lvdandan-----date:20201019------for:LOWCOD-882 【新行编辑】列表上带按钮的遮挡问题
|
||||||
|
|
||||||
|
// update--begin--autor:lvdandan-----date:20201211------for:JT-118 【online】 日期、时间控件长度较小
|
||||||
|
if (column.$type === JVXETypes.datetime || column.$type === JVXETypes.userSelect || column.$type === JVXETypes.departSelect) {
|
||||||
|
let width = column.width && column.width.endsWith('px')?Number.parseInt(column.width.substr(0,column.width.length-2)):0;
|
||||||
|
if(width <= 190){
|
||||||
|
column.width = '190px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (column.$type === JVXETypes.date) {
|
||||||
|
let width = column.width && column.width.endsWith('px')?Number.parseInt(column.width.substr(0,column.width.length-2)):0;
|
||||||
|
if(width <= 135){
|
||||||
|
column.width = '135px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update--end--autor:lvdandan-----date:20201211------for:JT-118 【online】 日期、时间控件长度较小
|
||||||
})
|
})
|
||||||
return this._innerColumns
|
return this._innerColumns
|
||||||
},
|
},
|
||||||
@ -260,15 +295,21 @@ export default {
|
|||||||
immediate: true,
|
immediate: true,
|
||||||
async handler() {
|
async handler() {
|
||||||
let vxe = await getRefPromise(this, 'vxe')
|
let vxe = await getRefPromise(this, 'vxe')
|
||||||
// 阻断vue监听大数据,提高性能
|
|
||||||
|
|
||||||
// 开启了排序就自动计算排序值
|
this.dataSource.forEach((data, idx) => {
|
||||||
if (this.dragSort) {
|
// 开启了排序就自动计算排序值
|
||||||
this.dataSource.forEach((data, idx) => {
|
if (this.dragSort) {
|
||||||
this.$set(data, this.dragSortKey, idx + 1)
|
this.$set(data, this.dragSortKey, idx + 1)
|
||||||
})
|
}
|
||||||
}
|
// 处理联动回显数据
|
||||||
|
if (this._innerLinkageConfig != null) {
|
||||||
|
for (let configItem of this._innerLinkageConfig.values()) {
|
||||||
|
this.autoSetLinkageOptionsByData(data, '', configItem, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 阻断vue监听大数据,提高性能
|
||||||
vxe.loadData(this.dataSource)
|
vxe.loadData(this.dataSource)
|
||||||
|
|
||||||
// TODO 解析disabledRows
|
// TODO 解析disabledRows
|
||||||
@ -339,7 +380,7 @@ export default {
|
|||||||
col.visible = false
|
col.visible = false
|
||||||
} else if (enhanced.switches.editRender) {
|
} else if (enhanced.switches.editRender) {
|
||||||
renderName = 'editRender'
|
renderName = 'editRender'
|
||||||
renderOptions.type = enhanced.switches.visible ? 'visible' : 'default'
|
renderOptions.type = (enhanced.switches.visible || this.alwaysEdit) ? 'visible' : 'default'
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
renderOptions.name = JVXETypes._prefix + JVXETypes.normal
|
renderOptions.name = JVXETypes._prefix + JVXETypes.normal
|
||||||
@ -451,7 +492,40 @@ export default {
|
|||||||
this._innerColumns = _innerColumns
|
this._innerColumns = _innerColumns
|
||||||
this._innerEditRules = _innerEditRules
|
this._innerEditRules = _innerEditRules
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
// watch linkageConfig
|
||||||
|
// 整理多级联动配置
|
||||||
|
linkageConfig: {
|
||||||
|
immediate: true,
|
||||||
|
handler() {
|
||||||
|
if (Array.isArray(this.linkageConfig) && this.linkageConfig.length > 0) {
|
||||||
|
// 获取联动的key顺序
|
||||||
|
let getLcKeys = (key, arr) => {
|
||||||
|
let col = this._innerColumns.find(col => col.key === key)
|
||||||
|
if (col) {
|
||||||
|
arr.push(col.key)
|
||||||
|
if (col.linkageKey) {
|
||||||
|
return getLcKeys(col.linkageKey, arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
let configMap = new Map()
|
||||||
|
this.linkageConfig.forEach(lc => {
|
||||||
|
let keys = getLcKeys(lc.key, [])
|
||||||
|
// 多个key共享一个,引用地址
|
||||||
|
let configItem = {
|
||||||
|
...lc, keys,
|
||||||
|
optionsMap: new Map()
|
||||||
|
}
|
||||||
|
keys.forEach(k => configMap.set(k, configItem))
|
||||||
|
})
|
||||||
|
this._innerLinkageConfig = configMap
|
||||||
|
} else {
|
||||||
|
this._innerLinkageConfig = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
},
|
},
|
||||||
@ -650,7 +724,24 @@ export default {
|
|||||||
async loadNewData(dataSource) {
|
async loadNewData(dataSource) {
|
||||||
if (Array.isArray(dataSource)) {
|
if (Array.isArray(dataSource)) {
|
||||||
let {xTable} = this.$refs.vxe.$refs
|
let {xTable} = this.$refs.vxe.$refs
|
||||||
return await xTable.loadData(dataSource)
|
// issues/2784
|
||||||
|
// 先清空所有数据
|
||||||
|
xTable.loadData([])
|
||||||
|
|
||||||
|
dataSource.forEach((data, idx) => {
|
||||||
|
// 开启了排序就自动计算排序值
|
||||||
|
if (this.dragSort) {
|
||||||
|
this.$set(data, this.dragSortKey, idx + 1)
|
||||||
|
}
|
||||||
|
// 处理联动回显数据
|
||||||
|
if (this._innerLinkageConfig != null) {
|
||||||
|
for (let configItem of this._innerLinkageConfig.values()) {
|
||||||
|
this.autoSetLinkageOptionsByData(data, '', configItem, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 再新增
|
||||||
|
return xTable.insertAt(dataSource)
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
@ -709,6 +800,11 @@ export default {
|
|||||||
deleteData: this.getDeleteData()
|
deleteData: this.getDeleteData()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/** 获取表格表单里的值 */
|
||||||
|
getValues(callback, rowIds) {
|
||||||
|
let tableData = this.getTableData({rowIds: rowIds})
|
||||||
|
callback('', tableData)
|
||||||
|
},
|
||||||
/** 获取表格数据 */
|
/** 获取表格数据 */
|
||||||
getTableData(options = {}) {
|
getTableData(options = {}) {
|
||||||
let {rowIds} = options
|
let {rowIds} = options
|
||||||
@ -770,6 +866,7 @@ export default {
|
|||||||
* 添加一行或多行
|
* 添加一行或多行
|
||||||
*
|
*
|
||||||
* @param rows
|
* @param rows
|
||||||
|
* @param isOnlJs 是否是onlineJS增强触发的
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
async addRows(rows = {}, isOnlJs) {
|
async addRows(rows = {}, isOnlJs) {
|
||||||
@ -864,9 +961,94 @@ export default {
|
|||||||
trigger(name, event = {}) {
|
trigger(name, event = {}) {
|
||||||
event.$target = this
|
event.$target = this
|
||||||
event.$table = this.$refs.vxe
|
event.$table = this.$refs.vxe
|
||||||
|
//online增强参数兼容
|
||||||
|
event.target = this
|
||||||
this.$emit(name, event)
|
this.$emit(name, event)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 【多级联动】获取同级联动下拉选项 */
|
||||||
|
getLinkageOptionsSibling(row, col, config, request) {
|
||||||
|
// 如果当前列不是顶级列
|
||||||
|
let key = ''
|
||||||
|
if (col.key !== config.key) {
|
||||||
|
// 就找出联动上级列
|
||||||
|
let idx = config.keys.findIndex(k => col.key === k)
|
||||||
|
let parentKey = config.keys[idx - 1]
|
||||||
|
key = row[parentKey]
|
||||||
|
// 如果联动上级列没有选择数据,就直接返回空数组
|
||||||
|
if (key === '' || key == null) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
key = 'root'
|
||||||
|
}
|
||||||
|
let options = config.optionsMap.get(key)
|
||||||
|
if (!Array.isArray(options)) {
|
||||||
|
if (request) {
|
||||||
|
let parent = key === 'root' ? '' : key
|
||||||
|
return this.getLinkageOptionsAsync(config, parent)
|
||||||
|
} else {
|
||||||
|
options = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
},
|
||||||
|
/** 【多级联动】获取联动下拉选项(异步) */
|
||||||
|
getLinkageOptionsAsync(config, parent) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let key = parent ? parent : 'root'
|
||||||
|
let options
|
||||||
|
if (config.optionsMap.has(key)) {
|
||||||
|
options = config.optionsMap.get(key)
|
||||||
|
if (options instanceof Promise) {
|
||||||
|
options.then(opt => {
|
||||||
|
config.optionsMap.set(key, opt)
|
||||||
|
resolve(opt)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
resolve(options)
|
||||||
|
}
|
||||||
|
} else if (typeof config.requestData === 'function') {
|
||||||
|
// 调用requestData方法,通过传入parent来获取子级
|
||||||
|
let promise = config.requestData(parent)
|
||||||
|
config.optionsMap.set(key, promise)
|
||||||
|
promise.then(opt => {
|
||||||
|
config.optionsMap.set(key, opt)
|
||||||
|
resolve(opt)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
resolve([])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 【多级联动】 用于回显数据,自动填充 optionsMap
|
||||||
|
autoSetLinkageOptionsByData(data, parent, config, level) {
|
||||||
|
if (level === 0) {
|
||||||
|
this.getLinkageOptionsAsync(config, '')
|
||||||
|
} else {
|
||||||
|
this.getLinkageOptionsAsync(config, parent)
|
||||||
|
}
|
||||||
|
if (config.keys.length - 1 > level) {
|
||||||
|
let value = data[config.keys[level]]
|
||||||
|
if (value) {
|
||||||
|
this.autoSetLinkageOptionsByData(data, value, config, level + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 【多级联动】联动组件change时,清空下级组件
|
||||||
|
linkageSelectChange(row, col, config, value) {
|
||||||
|
if (col.linkageKey) {
|
||||||
|
this.getLinkageOptionsAsync(config, value)
|
||||||
|
let idx = config.keys.findIndex(k => k === col.key)
|
||||||
|
let values = {}
|
||||||
|
for (let i = idx; i < config.keys.length; i++) {
|
||||||
|
values[config.keys[i]] = ''
|
||||||
|
}
|
||||||
|
// 清空后几列的数据
|
||||||
|
this.setValues([{rowKey: row.id, values}])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/** 加载数据字典并合并到 options */
|
/** 加载数据字典并合并到 options */
|
||||||
_loadDictConcatToOptions(column) {
|
_loadDictConcatToOptions(column) {
|
||||||
initDictOptions(column.dictCode).then((res) => {
|
initDictOptions(column.dictCode).then((res) => {
|
||||||
@ -885,7 +1067,11 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
//options自定义赋值 刷新
|
||||||
|
virtualRefresh(){
|
||||||
|
this.scrolling = true
|
||||||
|
this.closeScrolling()
|
||||||
|
},
|
||||||
// 设置 this.scrolling 防抖模式
|
// 设置 this.scrolling 防抖模式
|
||||||
closeScrolling: simpleDebounce(function () {
|
closeScrolling: simpleDebounce(function () {
|
||||||
this.scrolling = false
|
this.scrolling = false
|
||||||
@ -1050,11 +1236,20 @@ export default {
|
|||||||
// 添加默认值
|
// 添加默认值
|
||||||
xTable.tableFullColumn.forEach(column => {
|
xTable.tableFullColumn.forEach(column => {
|
||||||
let col = column.own
|
let col = column.own
|
||||||
if (record[col.key] == null || record[col.key] === '') {
|
if (col.key && (record[col.key] == null || record[col.key] === '')) {
|
||||||
// 设置默认值
|
// 设置默认值
|
||||||
let createValue = getEnhancedMixins(col.$type || col.type, 'createValue')
|
let createValue = getEnhancedMixins(col.$type || col.type, 'createValue')
|
||||||
record[col.key] = createValue({row: record, column, $table: xTable})
|
record[col.key] = createValue({row: record, column, $table: xTable})
|
||||||
}
|
}
|
||||||
|
// update-begin--author:sunjianlei---date:20210819------for: 处理联动列,联动列只能作用于 select 组件
|
||||||
|
if (col.$type === JVXETypes.select && this._innerLinkageConfig != null) {
|
||||||
|
// 判断当前列是否是联动列
|
||||||
|
if (this._innerLinkageConfig.has(col.key)) {
|
||||||
|
let configItem = this._innerLinkageConfig.get(col.key)
|
||||||
|
this.getLinkageOptionsAsync(configItem, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update-end--author:sunjianlei---date:20210819------for: 处理联动列,联动列只能作用于 select 组件
|
||||||
})
|
})
|
||||||
return record
|
return record
|
||||||
},
|
},
|
||||||
@ -1201,13 +1396,13 @@ export default {
|
|||||||
// 兼容 online 的规则
|
// 兼容 online 的规则
|
||||||
const fooPatterns = [
|
const fooPatterns = [
|
||||||
{title: '非空', value: '*', pattern: /^.+$/},
|
{title: '非空', value: '*', pattern: /^.+$/},
|
||||||
{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+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/},
|
||||||
{title: '电子邮件', value: 'e', pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/},
|
{title: '电子邮件', value: 'e', pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/},
|
||||||
{title: '手机号码', value: 'm', pattern: /^1[3456789]\d{9}$/},
|
{title: '手机号码', value: 'm', pattern: /^1[3456789]\d{9}$/},
|
||||||
{title: '邮政编码', value: 'p', pattern: /^[1-9]\d{5}$/},
|
{title: '邮政编码', value: 'p', pattern: /^[0-9]{6}$/},
|
||||||
{title: '字母', value: 's', pattern: /^[A-Z|a-z]+$/},
|
{title: '字母', value: 's', pattern: /^[A-Z|a-z]+$/},
|
||||||
{title: '数字', value: 'n', pattern: /^-?\d+(\.?\d+|\d?)$/},
|
{title: '数字', value: 'n', pattern: /^-?\d+(\.?\d+|\d?)$/},
|
||||||
{title: '整数', value: 'z', pattern: /^-?\d+$/},
|
{title: '整数', value: 'z', pattern: /^-?\d+$/},
|
||||||
@ -1247,4 +1442,4 @@ function uniqueValidator(event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
v-if="showRemove"
|
v-if="showRemove"
|
||||||
:title="`确定要删除这 ${selectedRowIds.length} 项吗?`"
|
:title="`确定要删除这 ${selectedRowIds.length} 项吗?`"
|
||||||
|
:disabled="disabled"
|
||||||
@confirm="trigger('remove')"
|
@confirm="trigger('remove')"
|
||||||
>
|
>
|
||||||
<a-button icon="minus" :disabled="disabled">删除</a-button>
|
<a-button icon="minus" :disabled="disabled">删除</a-button>
|
||||||
@ -59,7 +60,7 @@
|
|||||||
// TODO 需要将remove替换batch_delete
|
// TODO 需要将remove替换batch_delete
|
||||||
// 系统默认的批量删除编码配置为 batch_delete 此处需要转化一下
|
// 系统默认的批量删除编码配置为 batch_delete 此处需要转化一下
|
||||||
if(exclude.indexOf('batch_delete')>=0){
|
if(exclude.indexOf('batch_delete')>=0){
|
||||||
exclude.add('remove')
|
exclude.push('remove')
|
||||||
}
|
}
|
||||||
// 按钮权限 需要去掉不被授权的按钮
|
// 按钮权限 需要去掉不被授权的按钮
|
||||||
return arr.filter(item=>{
|
return arr.filter(item=>{
|
||||||
|
|||||||
@ -55,7 +55,9 @@
|
|||||||
// 【组件增强】注释详见:JVxeCellMixins.js
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
enhanced: {
|
enhanced: {
|
||||||
aopEvents: {
|
aopEvents: {
|
||||||
editActived: event => dispatchEvent(event, 'ant-calendar-picker', el => el.children[0].dispatchEvent(event.$event)),
|
editActived(event) {
|
||||||
|
dispatchEvent.call(this, event, 'ant-calendar-picker', el => el.children[0].dispatchEvent(event.$event))
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,174 @@
|
|||||||
|
<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"
|
||||||
|
:store="storeField()"
|
||||||
|
:text="textField()"
|
||||||
|
@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 v-if="!componentDisabled" 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 || this.originColumn.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(){
|
||||||
|
// disabled 不弹窗
|
||||||
|
if (this.componentDisabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$refs.innerDepartSelectModal.show()
|
||||||
|
},
|
||||||
|
handleEmpty(){
|
||||||
|
this.handleOK('')
|
||||||
|
},
|
||||||
|
handleOK(rows) {
|
||||||
|
let value = ''
|
||||||
|
if (!rows && rows.length <= 0) {
|
||||||
|
this.departNames = ''
|
||||||
|
this.departIds = ''
|
||||||
|
} else {
|
||||||
|
let storeField = this.storeField();
|
||||||
|
let textField = this.textField();
|
||||||
|
value = rows.map(row => row[storeField]).join(',')
|
||||||
|
this.departNames = rows.map(row => row[textField]).join(',')
|
||||||
|
this.departIds = value
|
||||||
|
}
|
||||||
|
this.handleChangeCommon(this.departIds)
|
||||||
|
},
|
||||||
|
initComp(departNames){
|
||||||
|
this.departNames = departNames
|
||||||
|
},
|
||||||
|
handleChange(value) {
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
},
|
||||||
|
storeField(){
|
||||||
|
if(this.originColumn){
|
||||||
|
const str = this.originColumn.fieldExtendJson
|
||||||
|
if(str){
|
||||||
|
let json = JSON.parse(str)
|
||||||
|
if(json && json.store){
|
||||||
|
return json.store
|
||||||
|
}
|
||||||
|
}else if(this.originColumn.store){
|
||||||
|
return this.originColumn.store
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'id'
|
||||||
|
},
|
||||||
|
textField(){
|
||||||
|
if(this.originColumn){
|
||||||
|
const str = this.originColumn.fieldExtendJson
|
||||||
|
if(str){
|
||||||
|
let json = JSON.parse(str)
|
||||||
|
if(json && json.text){
|
||||||
|
return json.text
|
||||||
|
}
|
||||||
|
}else if(this.originColumn.text){
|
||||||
|
return this.originColumn.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'departName'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enhanced: {
|
||||||
|
switches: {
|
||||||
|
visible: true
|
||||||
|
},
|
||||||
|
translate: {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/deep/ .jvxe-select-input .ant-input{
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
return this.rowIndex === 0
|
return this.rowIndex === 0
|
||||||
},
|
},
|
||||||
disabledMoveDown() {
|
disabledMoveDown() {
|
||||||
return this.rowIndex === (this.rows.length - 1)
|
return this.rowIndex === (this.fullDataLength - 1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@ -7,11 +7,16 @@
|
|||||||
v-bind="selectProps"
|
v-bind="selectProps"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
@blur="handleBlur"
|
@blur="handleBlur"
|
||||||
@change="handleChangeCommon"
|
@change="handleChange"
|
||||||
@search="handleSearchSelect"
|
@search="handleSearchSelect"
|
||||||
>
|
>
|
||||||
|
|
||||||
<template v-for="option of originColumn.options">
|
<div v-if="loading" slot="notFoundContent">
|
||||||
|
<a-icon type="loading" />
|
||||||
|
<span> 加载中…</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-for="option of selectOptions">
|
||||||
<a-select-option :key="option.value" :value="option.value" :disabled="option.disabled">
|
<a-select-option :key="option.value" :value="option.value" :disabled="option.disabled">
|
||||||
<span>{{option.text || option.label || option.title|| option.value}}</span>
|
<span>{{option.text || option.label || option.title|| option.value}}</span>
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@ -23,10 +28,18 @@
|
|||||||
<script>
|
<script>
|
||||||
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
import { JVXETypes } from '@comp/jeecg/JVxeTable/index'
|
import { JVXETypes } from '@comp/jeecg/JVxeTable/index'
|
||||||
|
import { filterDictText } from '@comp/dict/JDictSelectUtil'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JVxeSelectCell',
|
name: 'JVxeSelectCell',
|
||||||
mixins: [JVxeCellMixins],
|
mixins: [JVxeCellMixins],
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
// 异步加载的options(用于多级联动)
|
||||||
|
asyncOptions: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
selectProps() {
|
selectProps() {
|
||||||
let props = {...this.cellProps}
|
let props = {...this.cellProps}
|
||||||
@ -37,6 +50,32 @@
|
|||||||
}
|
}
|
||||||
return props
|
return props
|
||||||
},
|
},
|
||||||
|
// 下拉选项
|
||||||
|
selectOptions() {
|
||||||
|
if (this.asyncOptions) {
|
||||||
|
return this.asyncOptions
|
||||||
|
}
|
||||||
|
let {linkage} = this.renderOptions
|
||||||
|
if (linkage) {
|
||||||
|
let {getLinkageOptionsSibling, config} = linkage
|
||||||
|
let res = getLinkageOptionsSibling(this.row, this.originColumn, config, true)
|
||||||
|
// 当返回Promise时,说明是多级联动
|
||||||
|
if (res instanceof Promise) {
|
||||||
|
this.loading = true
|
||||||
|
res.then(opt => {
|
||||||
|
this.asyncOptions = opt
|
||||||
|
this.loading = false
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.asyncOptions = null
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.originColumn.options
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
let multiple = [JVXETypes.selectMultiple, JVXETypes.list_multi]
|
let multiple = [JVXETypes.selectMultiple, JVXETypes.list_multi]
|
||||||
@ -54,6 +93,15 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
handleChange(value) {
|
||||||
|
// 处理下级联动
|
||||||
|
let linkage = this.renderOptions.linkage
|
||||||
|
if (linkage) {
|
||||||
|
linkage.linkageSelectChange(this.row, this.originColumn, linkage.config, value)
|
||||||
|
}
|
||||||
|
this.handleChangeCommon(value)
|
||||||
|
},
|
||||||
|
|
||||||
/** 处理blur失去焦点事件 */
|
/** 处理blur失去焦点事件 */
|
||||||
handleBlur(value) {
|
handleBlur(value) {
|
||||||
let {allowInput, options} = this.originColumn
|
let {allowInput, options} = this.originColumn
|
||||||
@ -116,9 +164,32 @@
|
|||||||
// 【组件增强】注释详见:JVxeCellMixins.js
|
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||||
enhanced: {
|
enhanced: {
|
||||||
aopEvents: {
|
aopEvents: {
|
||||||
editActived: event => dispatchEvent(event, 'ant-select'),
|
editActived(event) {
|
||||||
|
dispatchEvent.call(this, event, 'ant-select')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
translate: {
|
||||||
|
enabled: true,
|
||||||
|
async handler(value,) {
|
||||||
|
let options
|
||||||
|
let {linkage} = this.renderOptions
|
||||||
|
// 判断是否是多级联动,如果是就通过接口异步翻译
|
||||||
|
if (linkage) {
|
||||||
|
let {getLinkageOptionsSibling, config} = linkage
|
||||||
|
options = getLinkageOptionsSibling(this.row, this.originColumn, config, true)
|
||||||
|
if (options instanceof Promise) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
options.then(opt => {
|
||||||
|
resolve(filterDictText(opt, value))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
options = this.column.own.options
|
||||||
|
}
|
||||||
|
return filterDictText(options, value)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
translate: {enabled: true},
|
|
||||||
getValue(value) {
|
getValue(value) {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.join(',')
|
return value.join(',')
|
||||||
|
|||||||
@ -23,7 +23,9 @@
|
|||||||
autofocus: '.ant-input',
|
autofocus: '.ant-input',
|
||||||
},
|
},
|
||||||
aopEvents: {
|
aopEvents: {
|
||||||
editActived: event => dispatchEvent(event, 'anticon-fullscreen'),
|
editActived(event) {
|
||||||
|
dispatchEvent.call(this, event, 'anticon-fullscreen')
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<a-time-picker
|
||||||
|
ref="timePicker"
|
||||||
|
:value="innerDateValue"
|
||||||
|
allowClear
|
||||||
|
dropdownClassName="j-vxe-date-picker"
|
||||||
|
style="min-width: 0;"
|
||||||
|
v-bind="cellProps"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import moment from 'moment'
|
||||||
|
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JVxeTimeCell',
|
||||||
|
mixins: [JVxeCellMixins],
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
innerDateValue: null,
|
||||||
|
dateFormat: 'HH:mm:ss'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<a-tooltip v-else-if="file.status === 'done'" title="上传完成">
|
<a-tooltip v-else-if="file.status === 'done'" title="上传完成">
|
||||||
<a-icon type="check-circle" style="color:#00DB00;"/>
|
<a-icon type="check-circle" style="color:#00DB00;"/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip v-else title="上传失败">
|
<a-tooltip v-else :title="file.message||'上传失败'">
|
||||||
<a-icon type="exclamation-circle" style="color:red;"/>
|
<a-icon type="exclamation-circle" style="color:red;"/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
@ -118,8 +118,17 @@
|
|||||||
value['responseName'] = file.response[col.responseName]
|
value['responseName'] = file.response[col.responseName]
|
||||||
}
|
}
|
||||||
if (file.status === 'done') {
|
if (file.status === 'done') {
|
||||||
value['path'] = file.response[col.responseName]
|
if (typeof file.response.success === 'boolean') {
|
||||||
this.handleChangeCommon(value)
|
if (file.response.success) {
|
||||||
|
value['path'] = file.response[col.responseName]
|
||||||
|
} else {
|
||||||
|
value['status'] = 'error'
|
||||||
|
value['message'] = file.response.message || '未知错误'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 考虑到如果设置action上传路径为非jeecg-boot后台,可能不会返回 success 属性的情况,就默认为成功
|
||||||
|
value['path'] = file.response[col.responseName]
|
||||||
|
}
|
||||||
} else if (file.status === 'error') {
|
} else if (file.status === 'error') {
|
||||||
value['message'] = file.response.message || '未知错误'
|
value['message'] = file.response.message || '未知错误'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,162 @@
|
|||||||
|
<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"
|
||||||
|
:store="storeField"
|
||||||
|
:text="textField"
|
||||||
|
@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 v-if="!componentDisabled" 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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
storeField(){
|
||||||
|
if(this.originColumn){
|
||||||
|
const str = this.originColumn.fieldExtendJson
|
||||||
|
if(str){
|
||||||
|
let json = JSON.parse(str)
|
||||||
|
if(json && json.store){
|
||||||
|
return json.store
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'username'
|
||||||
|
},
|
||||||
|
textField(){
|
||||||
|
if(this.originColumn){
|
||||||
|
const str = this.originColumn.fieldExtendJson
|
||||||
|
if(str){
|
||||||
|
let json = JSON.parse(str)
|
||||||
|
if(json && json.text){
|
||||||
|
return json.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'realname'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
innerValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val == null || val === '') {
|
||||||
|
this.userIds = ''
|
||||||
|
} else {
|
||||||
|
this.userIds = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openSelect() {
|
||||||
|
// disabled 不弹窗
|
||||||
|
if (this.componentDisabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$refs.selectModal.showModal()
|
||||||
|
},
|
||||||
|
selectOK(rows, idstr) {
|
||||||
|
console.log("当前选中用户", rows)
|
||||||
|
console.log("当前选中用户ID", idstr)
|
||||||
|
if (!rows) {
|
||||||
|
this.userNames = ''
|
||||||
|
this.userIds = ''
|
||||||
|
} else {
|
||||||
|
this.userIds = rows.map(row => row[this.storeField]).join(',')
|
||||||
|
this.userNames = rows.map(row => row[this.textField]).join(',')
|
||||||
|
}
|
||||||
|
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>
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import * as jvxeTypes from './jvxeTypes'
|
||||||
import { installCell, mapCell } from './install'
|
import { installCell, mapCell } from './install'
|
||||||
import JVxeTable from './components/JVxeTable'
|
import JVxeTable from './components/JVxeTable'
|
||||||
|
|
||||||
@ -5,6 +6,7 @@ import JVxeSlotCell from './components/cells/JVxeSlotCell'
|
|||||||
import JVxeNormalCell from './components/cells/JVxeNormalCell'
|
import JVxeNormalCell from './components/cells/JVxeNormalCell'
|
||||||
import JVxeInputCell from './components/cells/JVxeInputCell'
|
import JVxeInputCell from './components/cells/JVxeInputCell'
|
||||||
import JVxeDateCell from './components/cells/JVxeDateCell'
|
import JVxeDateCell from './components/cells/JVxeDateCell'
|
||||||
|
import JVxeTimeCell from './components/cells/JVxeTimeCell'
|
||||||
import JVxeSelectCell from './components/cells/JVxeSelectCell'
|
import JVxeSelectCell from './components/cells/JVxeSelectCell'
|
||||||
import JVxeCheckboxCell from './components/cells/JVxeCheckboxCell'
|
import JVxeCheckboxCell from './components/cells/JVxeCheckboxCell'
|
||||||
import JVxeUploadCell from './components/cells/JVxeUploadCell'
|
import JVxeUploadCell from './components/cells/JVxeUploadCell'
|
||||||
@ -12,46 +14,13 @@ import { TagsInputCell, TagsSpanCell } from './components/cells/JVxeTagsCell'
|
|||||||
import JVxeProgressCell from './components/cells/JVxeProgressCell'
|
import JVxeProgressCell from './components/cells/JVxeProgressCell'
|
||||||
import JVxeTextareaCell from './components/cells/JVxeTextareaCell'
|
import JVxeTextareaCell from './components/cells/JVxeTextareaCell'
|
||||||
import JVxeDragSortCell from './components/cells/JVxeDragSortCell'
|
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 = {
|
export const JVXETypes = jvxeTypes.JVXETypes
|
||||||
// 为了防止和 vxe 内置的类型冲突,所以加上一个前缀
|
//update--end--autor:lvdandan-----date:20201216------for:JVxeTable--JVXETypes 【online】代码结构调整,便于online打包
|
||||||
// 前缀是自动加的,代码中直接用就行(JVXETypes.input)
|
|
||||||
_prefix: 'j-',
|
|
||||||
|
|
||||||
// 行号列
|
|
||||||
rowNumber: 'row-number',
|
|
||||||
// 选择列
|
|
||||||
rowCheckbox: 'row-checkbox',
|
|
||||||
// 单选列
|
|
||||||
rowRadio: 'row-radio',
|
|
||||||
// 展开列
|
|
||||||
rowExpand: 'row-expand',
|
|
||||||
// 上下排序
|
|
||||||
rowDragSort: 'row-drag-sort',
|
|
||||||
|
|
||||||
input: 'input',
|
|
||||||
inputNumber: 'inputNumber',
|
|
||||||
textarea: 'textarea',
|
|
||||||
select: 'select',
|
|
||||||
date: 'date',
|
|
||||||
datetime: 'datetime',
|
|
||||||
checkbox: 'checkbox',
|
|
||||||
upload: 'upload',
|
|
||||||
// 下拉搜索
|
|
||||||
selectSearch: 'select-search',
|
|
||||||
// 下拉多选
|
|
||||||
selectMultiple: 'select-multiple',
|
|
||||||
// 进度条
|
|
||||||
progress: 'progress',
|
|
||||||
|
|
||||||
// 拖轮Tags(暂无用)
|
|
||||||
tags: 'tags',
|
|
||||||
|
|
||||||
slot: 'slot',
|
|
||||||
normal: 'normal',
|
|
||||||
hidden: 'hidden',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册自定义组件
|
// 注册自定义组件
|
||||||
export const AllCells = {
|
export const AllCells = {
|
||||||
@ -64,6 +33,7 @@ export const AllCells = {
|
|||||||
...mapCell(JVXETypes.selectMultiple, JVxeSelectCell), // 下拉多选
|
...mapCell(JVXETypes.selectMultiple, JVxeSelectCell), // 下拉多选
|
||||||
...mapCell(JVXETypes.date, JVxeDateCell),
|
...mapCell(JVXETypes.date, JVxeDateCell),
|
||||||
...mapCell(JVXETypes.datetime, JVxeDateCell),
|
...mapCell(JVXETypes.datetime, JVxeDateCell),
|
||||||
|
...mapCell(JVXETypes.time, JVxeTimeCell),
|
||||||
...mapCell(JVXETypes.upload, JVxeUploadCell),
|
...mapCell(JVXETypes.upload, JVxeUploadCell),
|
||||||
...mapCell(JVXETypes.textarea, JVxeTextareaCell),
|
...mapCell(JVXETypes.textarea, JVxeTextareaCell),
|
||||||
|
|
||||||
@ -72,6 +42,8 @@ export const AllCells = {
|
|||||||
|
|
||||||
...mapCell(JVXETypes.rowDragSort, JVxeDragSortCell),
|
...mapCell(JVXETypes.rowDragSort, JVxeDragSortCell),
|
||||||
...mapCell(JVXETypes.slot, JVxeSlotCell),
|
...mapCell(JVXETypes.slot, JVxeSlotCell),
|
||||||
|
...mapCell(JVXETypes.departSelect, JVxeDepartSelectCell),
|
||||||
|
...mapCell(JVXETypes.userSelect, JVxeUserSelectCell)
|
||||||
|
|
||||||
/* hidden 是特殊的组件,不在这里注册 */
|
/* hidden 是特殊的组件,不在这里注册 */
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,8 +62,8 @@ VXETable.interceptor.add('event.clearActived', function (params, event, target)
|
|||||||
if (className.includes('j-input-pop')) {
|
if (className.includes('j-input-pop')) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// 点击的标签是JPopup的弹出层
|
// 点击的标签是JPopup的弹出层、部门选择、用户选择
|
||||||
if (className.includes('j-popup-modal')) {
|
if (className.includes('j-popup-modal') || className.includes('j-depart-select-modal') || className.includes('j-user-select-modal')) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// 执行增强
|
// 执行增强
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
// 组件类型
|
||||||
|
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',
|
||||||
|
time: 'time',
|
||||||
|
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',
|
||||||
|
}
|
||||||
@ -36,6 +36,9 @@ export default {
|
|||||||
rows() {
|
rows() {
|
||||||
return this.params.data
|
return this.params.data
|
||||||
},
|
},
|
||||||
|
fullDataLength() {
|
||||||
|
return this.params.$table.tableFullData.length
|
||||||
|
},
|
||||||
rowIndex() {
|
rowIndex() {
|
||||||
return this.params.rowIndex
|
return this.params.rowIndex
|
||||||
},
|
},
|
||||||
@ -70,6 +73,16 @@ export default {
|
|||||||
props['disabled'] = true
|
props['disabled'] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update-begin-author:taoyan date:20211011 for: online表单,附表用户选择器{"multiSelect":false}不生效,单表可以生效 #3036
|
||||||
|
let jsonStr = col['fieldExtendJson']
|
||||||
|
if(jsonStr){
|
||||||
|
let fieldExtendJson = JSON.parse(jsonStr)
|
||||||
|
if(fieldExtendJson && fieldExtendJson['multiSelect']==false){
|
||||||
|
props['multi'] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update-end-author:taoyan date:20211011 for: online表单,附表用户选择器{"multiSelect":false}不生效,单表可以生效 #3036
|
||||||
|
|
||||||
return props
|
return props
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -99,7 +112,13 @@ export default {
|
|||||||
|
|
||||||
// 判断是否启用翻译
|
// 判断是否启用翻译
|
||||||
if (this.renderType === JVXERenderType.spaner && this.enhanced.translate.enabled) {
|
if (this.renderType === JVXERenderType.spaner && this.enhanced.translate.enabled) {
|
||||||
this.innerValue = this.enhanced.translate.handler.call(this, value)
|
let res = this.enhanced.translate.handler.call(this, value)
|
||||||
|
// 异步翻译,目前仅【多级联动】使用
|
||||||
|
if (res instanceof Promise) {
|
||||||
|
res.then(value => this.innerValue = value)
|
||||||
|
} else {
|
||||||
|
this.innerValue = res
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -149,6 +168,8 @@ export default {
|
|||||||
packageEvent(name, event = {}) {
|
packageEvent(name, event = {}) {
|
||||||
event.row = this.row
|
event.row = this.row
|
||||||
event.column = this.column
|
event.column = this.column
|
||||||
|
//online增强参数兼容
|
||||||
|
event.column['key'] = this.column['property']
|
||||||
event.cellTarget = this
|
event.cellTarget = this
|
||||||
if (!event.type) {
|
if (!event.type) {
|
||||||
event.type = name
|
event.type = name
|
||||||
@ -289,6 +310,10 @@ export function vModel(value, row, property) {
|
|||||||
|
|
||||||
/** 模拟触发事件 */
|
/** 模拟触发事件 */
|
||||||
export function dispatchEvent({cell, $event}, className, handler) {
|
export function dispatchEvent({cell, $event}, className, handler) {
|
||||||
|
// alwaysEdit 下不模拟触发事件,否者会导致触发两次
|
||||||
|
if (this && this.alwaysEdit) {
|
||||||
|
return
|
||||||
|
}
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
let element = cell.getElementsByClassName(className)
|
let element = cell.getElementsByClassName(className)
|
||||||
if (element && element.length > 0) {
|
if (element && element.length > 0) {
|
||||||
@ -296,7 +321,9 @@ export function dispatchEvent({cell, $event}, className, handler) {
|
|||||||
handler(element[0])
|
handler(element[0])
|
||||||
} else {
|
} else {
|
||||||
// 模拟触发点击事件
|
// 模拟触发点击事件
|
||||||
element[0].dispatchEvent($event)
|
if($event){
|
||||||
|
element[0].dispatchEvent($event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 10)
|
}, 10)
|
||||||
|
|||||||
@ -141,6 +141,33 @@ export async function validateFormAndTables(form, cases, autoJumpTab) {
|
|||||||
return dataMap
|
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
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证并获取一个或多个表格的所有值
|
* 验证并获取一个或多个表格的所有值
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,246 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="tinymce-containerty" :style="{width:containerWidth}">
|
|
||||||
<textarea :id="tinymceId" class="tinymce-textarea" @change="ada"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
/**
|
|
||||||
* docs:
|
|
||||||
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
|
|
||||||
*/
|
|
||||||
import load from './load'
|
|
||||||
//const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
|
|
||||||
//const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
|
|
||||||
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
|
|
||||||
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'JEditorDyn',
|
|
||||||
props: {
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: function() {
|
|
||||||
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
toolbar: {
|
|
||||||
type: [String, Array],
|
|
||||||
required: false,
|
|
||||||
default: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists link unlink image media table | removeformat | fullscreen',
|
|
||||||
},
|
|
||||||
menubar: {
|
|
||||||
type: String,
|
|
||||||
default: 'file edit insert view format table'
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: [Number, String],
|
|
||||||
required: false,
|
|
||||||
default: 360
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: [Number, String],
|
|
||||||
required: false,
|
|
||||||
default: 'auto'
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
type: [String, Array],
|
|
||||||
default: 'lists image link media table textcolor wordcount contextmenu fullscreen'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
hasChange: false,
|
|
||||||
hasInit: false,
|
|
||||||
tinymceId: this.id,
|
|
||||||
fullscreen: false,
|
|
||||||
languageTypeList: {
|
|
||||||
'en': 'en',
|
|
||||||
'zh': 'zh_CN',
|
|
||||||
'es': 'es_MX',
|
|
||||||
'ja': 'ja'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
containerWidth() {
|
|
||||||
const width = this.width
|
|
||||||
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
|
|
||||||
return `${width}px`
|
|
||||||
}
|
|
||||||
return width
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
value(val) {
|
|
||||||
if (!this.hasChange && this.hasInit) {
|
|
||||||
this.$nextTick(() =>
|
|
||||||
window.tinymce.get(this.tinymceId).setContent(val || ''))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.init()
|
|
||||||
},
|
|
||||||
activated() {
|
|
||||||
if (window.tinymce) {
|
|
||||||
this.initTinymce()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deactivated() {
|
|
||||||
this.destroyTinymce()
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.destroyTinymce()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
ada() {
|
|
||||||
console.log('change')
|
|
||||||
},
|
|
||||||
init() {
|
|
||||||
// dynamic load tinymce from cdn
|
|
||||||
load(tinymceCDN, (err) => {
|
|
||||||
if (err) {
|
|
||||||
this.$message.error(err.message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.initTinymce()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
initTinymce() {
|
|
||||||
const _this = this
|
|
||||||
window.tinymce.init({
|
|
||||||
selector: `#${this.tinymceId}`,
|
|
||||||
language: this.languageTypeList['zh'],
|
|
||||||
height: this.height,
|
|
||||||
body_class: 'panel-body ',
|
|
||||||
object_resizing: false,
|
|
||||||
toolbar: this.toolbar,
|
|
||||||
menubar: false,
|
|
||||||
plugins: this.plugins,
|
|
||||||
end_container_on_empty_block: true,
|
|
||||||
powerpaste_word_import: 'clean',
|
|
||||||
code_dialog_height: 450,
|
|
||||||
code_dialog_width: 1000,
|
|
||||||
advlist_bullet_styles: 'square',
|
|
||||||
advlist_number_styles: 'default',
|
|
||||||
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
|
|
||||||
default_link_target: '_blank',
|
|
||||||
link_title: false,
|
|
||||||
nonbreaking_force_tab: true, // inserting nonbreaking space need Nonbreaking Space Plugin
|
|
||||||
init_instance_callback: editor => {
|
|
||||||
if (_this.value) {
|
|
||||||
editor.setContent(_this.value)
|
|
||||||
}
|
|
||||||
_this.hasInit = true
|
|
||||||
editor.on('NodeChange Change KeyUp SetContent', () => {
|
|
||||||
this.hasChange = true
|
|
||||||
this.$emit('input', editor.getContent())
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setup(editor) {
|
|
||||||
editor.on('FullscreenStateChanged', (e) => {
|
|
||||||
_this.fullscreen = e.state
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// it will try to keep these URLs intact
|
|
||||||
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
|
|
||||||
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
|
|
||||||
convert_urls: false
|
|
||||||
// 整合七牛上传
|
|
||||||
// images_dataimg_filter(img) {
|
|
||||||
// setTimeout(() => {
|
|
||||||
// const $image = $(img);
|
|
||||||
// $image.removeAttr('width');
|
|
||||||
// $image.removeAttr('height');
|
|
||||||
// if ($image[0].height && $image[0].width) {
|
|
||||||
// $image.attr('data-wscntype', 'image');
|
|
||||||
// $image.attr('data-wscnh', $image[0].height);
|
|
||||||
// $image.attr('data-wscnw', $image[0].width);
|
|
||||||
// $image.addClass('wscnph');
|
|
||||||
// }
|
|
||||||
// }, 0);
|
|
||||||
// return img
|
|
||||||
// },
|
|
||||||
// images_upload_handler(blobInfo, success, failure, progress) {
|
|
||||||
// progress(0);
|
|
||||||
// const token = _this.$store.getters.token;
|
|
||||||
// getToken(token).then(response => {
|
|
||||||
// const url = response.data.qiniu_url;
|
|
||||||
// const formData = new FormData();
|
|
||||||
// formData.append('token', response.data.qiniu_token);
|
|
||||||
// formData.append('key', response.data.qiniu_key);
|
|
||||||
// formData.append('file', blobInfo.blob(), url);
|
|
||||||
// upload(formData).then(() => {
|
|
||||||
// success(url);
|
|
||||||
// progress(100);
|
|
||||||
// })
|
|
||||||
// }).catch(err => {
|
|
||||||
// failure('err')
|
|
||||||
// console.log(err);
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
})
|
|
||||||
},
|
|
||||||
destroyTinymce() {
|
|
||||||
const tinymce = window.tinymce.get(this.tinymceId)
|
|
||||||
if (this.fullscreen) {
|
|
||||||
tinymce.execCommand('mceFullScreen')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tinymce) {
|
|
||||||
tinymce.destroy()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setContent(value) {
|
|
||||||
window.tinymce.get(this.tinymceId).setContent(value)
|
|
||||||
},
|
|
||||||
getContent() {
|
|
||||||
window.tinymce.get(this.tinymceId).getContent()
|
|
||||||
},
|
|
||||||
imageSuccessCBK(arr) {
|
|
||||||
arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.tinymce-containerty {
|
|
||||||
position: relative;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tinymce-containerty {
|
|
||||||
::v-deep {
|
|
||||||
.mce-fullscreen {
|
|
||||||
z-index: 10000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tinymce-textarea {
|
|
||||||
visibility: hidden;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-custom-btn-container {
|
|
||||||
position: absolute;
|
|
||||||
right: 4px;
|
|
||||||
top: 4px;
|
|
||||||
/*z-index: 2005;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.fullscreen .editor-custom-btn-container {
|
|
||||||
z-index: 10000;
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-upload-btn {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,142 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="j-markdown-editor" :id="dynamicId"/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import load from './load'
|
|
||||||
import { md_js, md_zh_cn_js } from './Resource'
|
|
||||||
import defaultOptions from '@/components/jeecg/JMarkdownEditor/default-options.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'JMdEditorDyn',
|
|
||||||
props: {
|
|
||||||
value: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default() {
|
|
||||||
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return defaultOptions
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mode: {
|
|
||||||
type: String,
|
|
||||||
default: 'markdown'
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: '300px'
|
|
||||||
},
|
|
||||||
language: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: 'zh-CN'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
editor: null,
|
|
||||||
dynamicId: this.id
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
editorOptions() {
|
|
||||||
const options = Object.assign({}, defaultOptions, this.options)
|
|
||||||
options.initialEditType = this.mode
|
|
||||||
options.height = this.height
|
|
||||||
options.language = this.language
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
value(newValue, preValue) {
|
|
||||||
if (newValue !== preValue && newValue !== this.editor.getMarkdown()) {
|
|
||||||
this.editor.setMarkdown(newValue)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
language(val) {
|
|
||||||
this.destroyEditor()
|
|
||||||
this.initEditor()
|
|
||||||
},
|
|
||||||
height(newValue) {
|
|
||||||
this.editor.height(newValue)
|
|
||||||
},
|
|
||||||
mode(newValue) {
|
|
||||||
this.editor.changeMode(newValue)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.init()
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.destroyEditor()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
init(){
|
|
||||||
|
|
||||||
this.initEditor()
|
|
||||||
/* load(md_js,'',()=>{
|
|
||||||
load(md_zh_cn_js,'',()=>{
|
|
||||||
|
|
||||||
})
|
|
||||||
})*/
|
|
||||||
},
|
|
||||||
initEditor() {
|
|
||||||
const Editor = toastui.Editor
|
|
||||||
this.editor = new Editor({
|
|
||||||
el: document.getElementById(this.dynamicId),
|
|
||||||
...this.editorOptions
|
|
||||||
})
|
|
||||||
if (this.value) {
|
|
||||||
this.editor.setMarkdown(this.value)
|
|
||||||
}
|
|
||||||
this.editor.on('change', () => {
|
|
||||||
this.$emit('change', this.editor.getMarkdown())
|
|
||||||
})
|
|
||||||
},
|
|
||||||
destroyEditor() {
|
|
||||||
if (!this.editor) return
|
|
||||||
this.editor.off('change')
|
|
||||||
this.editor.remove()
|
|
||||||
},
|
|
||||||
setMarkdown(value) {
|
|
||||||
this.editor.setMarkdown(value)
|
|
||||||
},
|
|
||||||
getMarkdown() {
|
|
||||||
return this.editor.getMarkdown()
|
|
||||||
},
|
|
||||||
setHtml(value) {
|
|
||||||
this.editor.setHtml(value)
|
|
||||||
},
|
|
||||||
getHtml() {
|
|
||||||
return this.editor.getHtml()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
prop: 'value',
|
|
||||||
event: 'change'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped lang="less">
|
|
||||||
|
|
||||||
.j-markdown-editor {
|
|
||||||
/deep/ .tui-editor-defaultUI {
|
|
||||||
.te-mode-switch,
|
|
||||||
.tui-scrollsync
|
|
||||||
{
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@ -1,325 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="jeecg-editor-ty" :class="fullCoder?'jeecg-editor-max':'jeecg-editor-min'">
|
|
||||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
|
||||||
<textarea :id="dynamicId" />
|
|
||||||
<span @click="nullTipClick" class="null-tip" :class="{'null-tip-hidden': hasCode}" :style="nullTipStyle">{{ placeholderShow }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import load from './load'
|
|
||||||
import '@/assets/less/codemirror_idea.css'
|
|
||||||
import './cm_sql_hint.js'
|
|
||||||
import { sql_keyword } from './Resource'
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'JSqlCodeEditorDyn',
|
|
||||||
props:{
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: function() {
|
|
||||||
return 'vue-editor-' + new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 显示行号
|
|
||||||
lineNumbers: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
zIndex: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: 999
|
|
||||||
},
|
|
||||||
autoHeight: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
// 不自适应高度的情况下生效的固定高度
|
|
||||||
height: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: '240px'
|
|
||||||
},
|
|
||||||
autoHeight: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
// 是否显示全屏按钮
|
|
||||||
fullScreen: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
autoHint:{
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
dynamicId: this.id,
|
|
||||||
coder: '',
|
|
||||||
hasCode: false,
|
|
||||||
code: '',
|
|
||||||
// code 编辑器 是否全屏
|
|
||||||
fullCoder: false,
|
|
||||||
iconType: 'fullscreen',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed:{
|
|
||||||
placeholderShow() {
|
|
||||||
if (this.placeholder == null) {
|
|
||||||
return `请在此输入javascript代码`
|
|
||||||
} else {
|
|
||||||
return this.placeholder
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nullTipStyle(){
|
|
||||||
if (this.lineNumbers) {
|
|
||||||
return { left: '36px' }
|
|
||||||
} else {
|
|
||||||
return { left: '12px' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isAutoHeight() {
|
|
||||||
let {autoHeight} = this
|
|
||||||
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
|
||||||
autoHeight = !(isIE() || isIE11())
|
|
||||||
} else {
|
|
||||||
autoHeight = true
|
|
||||||
}
|
|
||||||
return autoHeight
|
|
||||||
},
|
|
||||||
fullScreenParentProps() {
|
|
||||||
let props = {
|
|
||||||
class: {
|
|
||||||
'full-screen-parent': true,
|
|
||||||
'full-screen': this.fullCoder,
|
|
||||||
'auto-height': this.isAutoHeight
|
|
||||||
},
|
|
||||||
style: {}
|
|
||||||
}
|
|
||||||
if (this.fullCoder) {
|
|
||||||
props.style['z-index'] = this.zIndex
|
|
||||||
}
|
|
||||||
if (!this.isAutoHeight) {
|
|
||||||
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
|
||||||
}
|
|
||||||
return props
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
fullCoder:{
|
|
||||||
handler(value) {
|
|
||||||
if(value){
|
|
||||||
this.iconType="fullscreen-exit"
|
|
||||||
}else{
|
|
||||||
this.iconType="fullscreen"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.init()
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
init(){
|
|
||||||
this.main();
|
|
||||||
},
|
|
||||||
main(){
|
|
||||||
let obj = document.getElementById(this.dynamicId);
|
|
||||||
const that = this;
|
|
||||||
let editor = CodeMirror.fromTextArea(obj,{
|
|
||||||
theme:'idea',
|
|
||||||
lineNumbers: this.lineNumbers,
|
|
||||||
lineWrapping: true,
|
|
||||||
mode: "sql",
|
|
||||||
indentUnit: 1,
|
|
||||||
indentWithTabs: true,
|
|
||||||
styleActiveLine: true,
|
|
||||||
/* styleSelectedText: false, */
|
|
||||||
extraKeys: {
|
|
||||||
"F11": function(cm) {
|
|
||||||
that.fullCoder = !that.fullCoder
|
|
||||||
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
|
|
||||||
},
|
|
||||||
"Esc": function(cm) {
|
|
||||||
that.fullCoder = false
|
|
||||||
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
|
||||||
},
|
|
||||||
"Alt-/": function(cm) {
|
|
||||||
cm.showHint();
|
|
||||||
},
|
|
||||||
"Tab": (cm) => {
|
|
||||||
if (cm.somethingSelected()) {
|
|
||||||
cm.indentSelection('add');
|
|
||||||
} else {
|
|
||||||
//cm.indentLine(cm.getCursor().line, "add");
|
|
||||||
//走两格 第三格输入
|
|
||||||
cm.replaceSelection(Array(3).join(" "), "end", "+input");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shift-Tab": (cm) => {
|
|
||||||
if (cm.somethingSelected()) {
|
|
||||||
cm.indentSelection('subtract');
|
|
||||||
} else {
|
|
||||||
// cm.indentLine(cm.getCursor().line, "subtract");
|
|
||||||
const cursor = cm.getCursor();
|
|
||||||
// 光标回退 indexUnit 字符
|
|
||||||
cm.setCursor({line: cursor.line, ch: cursor.ch - 4});
|
|
||||||
}
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.coder = editor
|
|
||||||
this.addEvent();
|
|
||||||
this.setCoderValue();
|
|
||||||
this.addSystemHint();
|
|
||||||
},
|
|
||||||
setCoderValue(){
|
|
||||||
if(this.value||this.code){
|
|
||||||
this.hasCode=true
|
|
||||||
this.setCodeContent(this.value || this.code)
|
|
||||||
}else{
|
|
||||||
this.coder.setValue('')
|
|
||||||
this.hasCode=false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getCodeContent(){
|
|
||||||
return this.code
|
|
||||||
},
|
|
||||||
setCodeContent(val){
|
|
||||||
setTimeout(()=>{
|
|
||||||
if(!val){
|
|
||||||
this.coder.setValue('')
|
|
||||||
}else{
|
|
||||||
this.coder.setValue(val)
|
|
||||||
}
|
|
||||||
},300)
|
|
||||||
},
|
|
||||||
addSystemHint(){
|
|
||||||
this.coder.setOption('hintOptions', {
|
|
||||||
completeSingle: false,
|
|
||||||
tables: sql_keyword
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addEvent(){
|
|
||||||
if(this.autoHint){
|
|
||||||
this.coder.on('cursorActivity', ()=>{
|
|
||||||
this.coder.showHint();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.coder.on('change', (coder) => {
|
|
||||||
this.code = coder.getValue()
|
|
||||||
if(this.code){
|
|
||||||
this.hasCode=true
|
|
||||||
}else{
|
|
||||||
this.hasCode=false
|
|
||||||
}
|
|
||||||
if (this.$emit) {
|
|
||||||
this.$emit('input', this.code)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.coder.on('focus', () => {
|
|
||||||
this.hasCode=true
|
|
||||||
});
|
|
||||||
this.coder.on('blur', () => {
|
|
||||||
if(this.code){
|
|
||||||
this.hasCode=true
|
|
||||||
}else{
|
|
||||||
this.hasCode=false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
loadResource(src,type){
|
|
||||||
return new Promise((resolve,reject)=>{
|
|
||||||
load(src,type,(msg)=>{
|
|
||||||
if(!msg){
|
|
||||||
resolve();
|
|
||||||
}else{
|
|
||||||
reject(msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
nullTipClick(){
|
|
||||||
this.coder.focus()
|
|
||||||
},
|
|
||||||
fullToggle(){
|
|
||||||
this.fullCoder = !this.fullCoder
|
|
||||||
this.coder.setOption("fullScreen", this.fullCoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="less" >
|
|
||||||
.jeecg-editor-ty{
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.full-screen-icon {
|
|
||||||
opacity: 0;
|
|
||||||
color: black;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
line-height: 24px;
|
|
||||||
background-color: white;
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
right: 2px;
|
|
||||||
z-index: 9;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
.full-screen-icon {
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(255, 255, 255, 0.88);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.null-tip{
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
left: 36px;
|
|
||||||
z-index: 10;
|
|
||||||
font-size:16px;
|
|
||||||
color: #acaaaac9;
|
|
||||||
line-height: initial;
|
|
||||||
}
|
|
||||||
.null-tip-hidden{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.jeecg-editor-max{
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 999;
|
|
||||||
height: 100%;
|
|
||||||
width: 100% !important;
|
|
||||||
|
|
||||||
.CodeMirror{
|
|
||||||
position: inherit !important;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.full-screen-icon{
|
|
||||||
z-index:9999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,319 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="jeecg-editor-ty" :class="fullCoder?'jeecg-editor-max':'jeecg-editor-min'">
|
|
||||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
|
||||||
<textarea :id="dynamicId" />
|
|
||||||
<span @click="nullTipClick" class="null-tip" :class="{'null-tip-hidden': hasCode}" :style="nullTipStyle">{{ placeholderShow }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
import '@/assets/less/codemirror_idea.css'
|
|
||||||
import './cm_hint.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'JsCodeEditorDyn',
|
|
||||||
props:{
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: function() {
|
|
||||||
return 'vue-editor-' + new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 显示行号
|
|
||||||
lineNumbers: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
zIndex: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: 999
|
|
||||||
},
|
|
||||||
autoHeight: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
// 不自适应高度的情况下生效的固定高度
|
|
||||||
height: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: '240px'
|
|
||||||
},
|
|
||||||
autoHeight: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
// 是否显示全屏按钮
|
|
||||||
fullScreen: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
dynamicId: this.id,
|
|
||||||
coder: '',
|
|
||||||
hasCode: false,
|
|
||||||
code: '',
|
|
||||||
// code 编辑器 是否全屏
|
|
||||||
fullCoder: false,
|
|
||||||
iconType: 'fullscreen',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed:{
|
|
||||||
placeholderShow() {
|
|
||||||
if (this.placeholder == null) {
|
|
||||||
return `请在此输入javascript代码`
|
|
||||||
} else {
|
|
||||||
return this.placeholder
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nullTipStyle(){
|
|
||||||
if (this.lineNumbers) {
|
|
||||||
return { left: '36px' }
|
|
||||||
} else {
|
|
||||||
return { left: '12px' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isAutoHeight() {
|
|
||||||
let {autoHeight} = this
|
|
||||||
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
|
||||||
autoHeight = !(isIE() || isIE11())
|
|
||||||
} else {
|
|
||||||
autoHeight = true
|
|
||||||
}
|
|
||||||
return autoHeight
|
|
||||||
},
|
|
||||||
fullScreenParentProps() {
|
|
||||||
let props = {
|
|
||||||
class: {
|
|
||||||
'full-screen-parent': true,
|
|
||||||
'full-screen': this.fullCoder,
|
|
||||||
'auto-height': this.isAutoHeight
|
|
||||||
},
|
|
||||||
style: {}
|
|
||||||
}
|
|
||||||
if (this.fullCoder) {
|
|
||||||
props.style['z-index'] = this.zIndex
|
|
||||||
}
|
|
||||||
if (!this.isAutoHeight) {
|
|
||||||
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
|
||||||
}
|
|
||||||
return props
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
fullCoder:{
|
|
||||||
handler(value) {
|
|
||||||
if(value){
|
|
||||||
this.iconType="fullscreen-exit"
|
|
||||||
}else{
|
|
||||||
this.iconType="fullscreen"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.init()
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
init(){
|
|
||||||
this.main();
|
|
||||||
},
|
|
||||||
main(){
|
|
||||||
let obj = document.getElementById(this.dynamicId);
|
|
||||||
const that = this;
|
|
||||||
let editor = CodeMirror.fromTextArea(obj,{
|
|
||||||
theme:'idea',
|
|
||||||
lineNumbers: this.lineNumbers,
|
|
||||||
lineWrapping: true,
|
|
||||||
mode: "javascript",
|
|
||||||
indentUnit: 1,
|
|
||||||
indentWithTabs: true,
|
|
||||||
styleActiveLine: true,
|
|
||||||
/* styleSelectedText: false, */
|
|
||||||
extraKeys: {
|
|
||||||
"F11": function(cm) {
|
|
||||||
that.fullCoder = !that.fullCoder
|
|
||||||
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
|
|
||||||
},
|
|
||||||
"Esc": function(cm) {
|
|
||||||
that.fullCoder = false
|
|
||||||
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
|
||||||
},
|
|
||||||
"Alt-/": function(cm) {
|
|
||||||
let a = cm.getValue()+""
|
|
||||||
console.log('a',a)
|
|
||||||
cm.showHint();
|
|
||||||
},
|
|
||||||
"Tab": (cm) => {
|
|
||||||
if (cm.somethingSelected()) {
|
|
||||||
cm.indentSelection('add');
|
|
||||||
} else {
|
|
||||||
//cm.indentLine(cm.getCursor().line, "add");
|
|
||||||
//走两格 第三格输入
|
|
||||||
cm.replaceSelection(Array(3).join(" "), "end", "+input");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shift-Tab": (cm) => {
|
|
||||||
if (cm.somethingSelected()) {
|
|
||||||
cm.indentSelection('subtract');
|
|
||||||
} else {
|
|
||||||
// cm.indentLine(cm.getCursor().line, "subtract");
|
|
||||||
const cursor = cm.getCursor();
|
|
||||||
// 光标回退 indexUnit 字符
|
|
||||||
cm.setCursor({line: cursor.line, ch: cursor.ch - 4});
|
|
||||||
}
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.coder = editor
|
|
||||||
this.addEvent();
|
|
||||||
this.setCoderValue();
|
|
||||||
},
|
|
||||||
setCoderValue(){
|
|
||||||
if(this.value||this.code){
|
|
||||||
this.hasCode=true
|
|
||||||
this.setCodeContent(this.value || this.code)
|
|
||||||
}else{
|
|
||||||
this.coder.setValue('')
|
|
||||||
this.hasCode=false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getCodeContent(){
|
|
||||||
return this.code
|
|
||||||
},
|
|
||||||
setCodeContent(val){
|
|
||||||
setTimeout(()=>{
|
|
||||||
if(!val){
|
|
||||||
this.coder.setValue('')
|
|
||||||
}else{
|
|
||||||
this.coder.setValue(val)
|
|
||||||
}
|
|
||||||
},300)
|
|
||||||
},
|
|
||||||
addEvent(){
|
|
||||||
const that = this;
|
|
||||||
this.coder.on('cursorActivity',function(wl) {
|
|
||||||
let arr = wl.state.activeLines
|
|
||||||
if(arr && arr.length>0){
|
|
||||||
let text = arr[0].text
|
|
||||||
if(text.lastIndexOf('that.')>=0){
|
|
||||||
that.coder.showHint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.coder.on('change', (coder) => {
|
|
||||||
this.code = coder.getValue()
|
|
||||||
if(this.code){
|
|
||||||
this.hasCode=true
|
|
||||||
}else{
|
|
||||||
this.hasCode=false
|
|
||||||
}
|
|
||||||
if (this.$emit) {
|
|
||||||
this.$emit('input', this.code)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.coder.on('focus', () => {
|
|
||||||
this.hasCode=true
|
|
||||||
});
|
|
||||||
this.coder.on('blur', () => {
|
|
||||||
if(this.code){
|
|
||||||
this.hasCode=true
|
|
||||||
}else{
|
|
||||||
this.hasCode=false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
loadResource(src,type){
|
|
||||||
return new Promise((resolve,reject)=>{
|
|
||||||
load(src,type,(msg)=>{
|
|
||||||
if(!msg){
|
|
||||||
resolve();
|
|
||||||
}else{
|
|
||||||
reject(msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
nullTipClick(){
|
|
||||||
this.coder.focus()
|
|
||||||
},
|
|
||||||
fullToggle(){
|
|
||||||
this.fullCoder = !this.fullCoder
|
|
||||||
this.coder.setOption("fullScreen", this.fullCoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="less" >
|
|
||||||
.jeecg-editor-ty{
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.full-screen-icon {
|
|
||||||
opacity: 0;
|
|
||||||
color: black;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
line-height: 24px;
|
|
||||||
background-color: white;
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
right: 2px;
|
|
||||||
z-index: 9;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
.full-screen-icon {
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(255, 255, 255, 0.88);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.null-tip{
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
left: 36px;
|
|
||||||
z-index: 10;
|
|
||||||
font-size:16px;
|
|
||||||
color: #acaaaac9;
|
|
||||||
line-height: initial;
|
|
||||||
}
|
|
||||||
.null-tip-hidden{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.jeecg-editor-max{
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 999;
|
|
||||||
height: 100%;
|
|
||||||
width: 100% !important;
|
|
||||||
|
|
||||||
.CodeMirror{
|
|
||||||
position: inherit !important;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.full-screen-icon{
|
|
||||||
z-index:9999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
/**js编辑器关键词用于提示*/
|
|
||||||
const js_keyword = [
|
|
||||||
'that',
|
|
||||||
'getAction','postAction','deleteAction',
|
|
||||||
'beforeAdd','beforeEdit','beforeDelete','mounted','created','show'
|
|
||||||
]
|
|
||||||
|
|
||||||
/**js编辑器 方法名用于提示*/
|
|
||||||
const js_method = [
|
|
||||||
'.getSelectOptions','.changeOptions','.triggleChangeValues','.immediateEnhance ','.simpleDateFormat','.lodash'
|
|
||||||
]
|
|
||||||
|
|
||||||
/**sql编辑器 表名字段名用于提示*/
|
|
||||||
const sql_keyword = {
|
|
||||||
sys_user: ['USERNAME', 'REALNAME', 'ID','BIRTHDAY','AGE'],
|
|
||||||
demo: ['name', 'age', 'id', 'sex']
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
js_keyword,
|
|
||||||
js_method,
|
|
||||||
sql_keyword
|
|
||||||
}
|
|
||||||
@ -1,177 +0,0 @@
|
|||||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
||||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|
||||||
import { js_keyword, js_method } from './Resource'
|
|
||||||
(function(mod) {
|
|
||||||
mod(CodeMirror);
|
|
||||||
/*if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
||||||
mod(require("../../lib/codemirror"));
|
|
||||||
else if (typeof define == "function" && define.amd) // AMD
|
|
||||||
define(["../../lib/codemirror"], mod);
|
|
||||||
else // Plain browser env*/
|
|
||||||
|
|
||||||
})(function(CodeMirror) {
|
|
||||||
var Pos = CodeMirror.Pos;
|
|
||||||
|
|
||||||
function forEach(arr, f) {
|
|
||||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function arrayContains(arr, item) {
|
|
||||||
if (!Array.prototype.indexOf) {
|
|
||||||
var i = arr.length;
|
|
||||||
while (i--) {
|
|
||||||
if (arr[i] === item) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return arr.indexOf(item) != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function scriptHint(editor, keywords, getToken, options) {
|
|
||||||
// Find the token at the cursor
|
|
||||||
var cur = editor.getCursor(), token = getToken(editor, cur);
|
|
||||||
if (/\b(?:string|comment)\b/.test(token.type)) return;
|
|
||||||
var innerMode = CodeMirror.innerMode(editor.getMode(), token.state);
|
|
||||||
if (innerMode.mode.helperType === "json") return;
|
|
||||||
token.state = innerMode.state;
|
|
||||||
if('.' === token.string){
|
|
||||||
let arr = []
|
|
||||||
for(let k of js_method){
|
|
||||||
arr.push(k)
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
list: arr,
|
|
||||||
from: Pos(cur.line, token.start),
|
|
||||||
to: Pos(cur.line, token.end)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// If it's not a 'word-style' token, ignore the token.
|
|
||||||
if (!/^[\w$_]*$/.test(token.string)) {
|
|
||||||
token = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
|
||||||
type: token.string == "." ? "property" : null};
|
|
||||||
} else if (token.end > cur.ch) {
|
|
||||||
token.end = cur.ch;
|
|
||||||
token.string = token.string.slice(0, cur.ch - token.start);
|
|
||||||
}
|
|
||||||
|
|
||||||
var tprop = token;
|
|
||||||
// If it is a property, find out what it is a property of.
|
|
||||||
while (tprop.type == "property") {
|
|
||||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
|
||||||
if (tprop.string != ".") return;
|
|
||||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
|
||||||
if (!context) var context = [];
|
|
||||||
context.push(tprop);
|
|
||||||
}
|
|
||||||
return {list: getCompletions(token, context, keywords, options),
|
|
||||||
from: Pos(cur.line, token.start),
|
|
||||||
to: Pos(cur.line, token.end)};
|
|
||||||
}
|
|
||||||
|
|
||||||
function javascriptHint(editor, options) {
|
|
||||||
return scriptHint(editor, javascriptKeywords,
|
|
||||||
function (e, cur) {return e.getTokenAt(cur);},
|
|
||||||
options);
|
|
||||||
};
|
|
||||||
CodeMirror.registerHelper("hint", "javascript", javascriptHint);
|
|
||||||
|
|
||||||
function getCoffeeScriptToken(editor, cur) {
|
|
||||||
// This getToken, it is for coffeescript, imitates the behavior of
|
|
||||||
// getTokenAt method in javascript.js, that is, returning "property"
|
|
||||||
// type and treat "." as indepenent token.
|
|
||||||
var token = editor.getTokenAt(cur);
|
|
||||||
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
|
|
||||||
token.end = token.start;
|
|
||||||
token.string = '.';
|
|
||||||
token.type = "property";
|
|
||||||
}
|
|
||||||
else if (/^\.[\w$_]*$/.test(token.string)) {
|
|
||||||
token.type = "property";
|
|
||||||
token.start++;
|
|
||||||
token.string = token.string.replace(/\./, '');
|
|
||||||
}
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
function coffeescriptHint(editor, options) {
|
|
||||||
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
|
|
||||||
}
|
|
||||||
CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint);
|
|
||||||
|
|
||||||
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
|
|
||||||
"toUpperCase toLowerCase split concat match replace search").split(" ");
|
|
||||||
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
|
|
||||||
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
|
|
||||||
var funcProps = "prototype apply call bind".split(" ");
|
|
||||||
|
|
||||||
var javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends false finally for function " +
|
|
||||||
"if in import instanceof new null return super switch this throw true try typeof var void while with yield that").split(" ");
|
|
||||||
for(let jk of js_keyword){
|
|
||||||
javascriptKeywords.push(jk)
|
|
||||||
}
|
|
||||||
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
|
|
||||||
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
|
|
||||||
|
|
||||||
function forAllProps(obj, callback) {
|
|
||||||
if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) {
|
|
||||||
for (var name in obj) callback(name)
|
|
||||||
} else {
|
|
||||||
for (var o = obj; o; o = Object.getPrototypeOf(o))
|
|
||||||
Object.getOwnPropertyNames(o).forEach(callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCompletions(token, context, keywords, options) {
|
|
||||||
var found = [], start = token.string, global = options && options.globalScope || window;
|
|
||||||
function maybeAdd(str) {
|
|
||||||
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
|
|
||||||
}
|
|
||||||
function gatherCompletions(obj) {
|
|
||||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
|
||||||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
|
||||||
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
|
||||||
forAllProps(obj, maybeAdd)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context && context.length) {
|
|
||||||
// If this is a property, see if it belongs to some object we can
|
|
||||||
// find in the current environment.
|
|
||||||
var obj = context.pop(), base;
|
|
||||||
if (obj.type && obj.type.indexOf("variable") === 0) {
|
|
||||||
if (options && options.additionalContext)
|
|
||||||
base = options.additionalContext[obj.string];
|
|
||||||
if (!options || options.useGlobalScope !== false)
|
|
||||||
base = base || global[obj.string];
|
|
||||||
} else if (obj.type == "string") {
|
|
||||||
base = "";
|
|
||||||
} else if (obj.type == "atom") {
|
|
||||||
base = 1;
|
|
||||||
} else if (obj.type == "function") {
|
|
||||||
if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
|
|
||||||
(typeof global.jQuery == 'function'))
|
|
||||||
base = global.jQuery();
|
|
||||||
else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function'))
|
|
||||||
base = global._();
|
|
||||||
}
|
|
||||||
while (base != null && context.length)
|
|
||||||
base = base[context.pop().string];
|
|
||||||
if (base != null) gatherCompletions(base);
|
|
||||||
} else {
|
|
||||||
// If not, just look in the global object, any local scope, and optional additional-context
|
|
||||||
// (reading into JS mode internals to get at the local and global variables)
|
|
||||||
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
|
|
||||||
for (var c = token.state.context; c; c = c.prev)
|
|
||||||
for (var v = c.vars; v; v = v.next) maybeAdd(v.name)
|
|
||||||
for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
|
|
||||||
if (options && options.additionalContext != null)
|
|
||||||
for (var key in options.additionalContext)
|
|
||||||
maybeAdd(key);
|
|
||||||
if (!options || options.useGlobalScope !== false)
|
|
||||||
gatherCompletions(global);
|
|
||||||
forEach(keywords, maybeAdd);
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,305 +0,0 @@
|
|||||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
||||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|
||||||
|
|
||||||
(function(mod) {
|
|
||||||
/*if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
||||||
mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
|
|
||||||
else if (typeof define == "function" && define.amd) // AMD
|
|
||||||
define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
|
|
||||||
else */
|
|
||||||
// Plain browser env
|
|
||||||
mod(CodeMirror);
|
|
||||||
})(function(CodeMirror) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var tables;
|
|
||||||
var defaultTable;
|
|
||||||
var keywords;
|
|
||||||
var identifierQuote;
|
|
||||||
var CONS = {
|
|
||||||
QUERY_DIV: ";",
|
|
||||||
ALIAS_KEYWORD: "AS"
|
|
||||||
};
|
|
||||||
var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;
|
|
||||||
|
|
||||||
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
|
|
||||||
|
|
||||||
function getKeywords(editor) {
|
|
||||||
var mode = editor.doc.modeOption;
|
|
||||||
if (mode === "sql") mode = "text/x-sql";
|
|
||||||
return CodeMirror.resolveMode(mode).keywords;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getIdentifierQuote(editor) {
|
|
||||||
var mode = editor.doc.modeOption;
|
|
||||||
if (mode === "sql") mode = "text/x-sql";
|
|
||||||
return CodeMirror.resolveMode(mode).identifierQuote || "`";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getText(item) {
|
|
||||||
return typeof item == "string" ? item : item.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
function wrapTable(name, value) {
|
|
||||||
if (isArray(value)) value = {columns: value}
|
|
||||||
if (!value.text) value.text = name
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseTables(input) {
|
|
||||||
var result = {}
|
|
||||||
if (isArray(input)) {
|
|
||||||
for (var i = input.length - 1; i >= 0; i--) {
|
|
||||||
var item = input[i]
|
|
||||||
result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
|
|
||||||
}
|
|
||||||
} else if (input) {
|
|
||||||
for (var name in input)
|
|
||||||
result[name.toUpperCase()] = wrapTable(name, input[name])
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTable(name) {
|
|
||||||
return tables[name.toUpperCase()]
|
|
||||||
}
|
|
||||||
|
|
||||||
function shallowClone(object) {
|
|
||||||
var result = {};
|
|
||||||
for (var key in object) if (object.hasOwnProperty(key))
|
|
||||||
result[key] = object[key];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function match(string, word) {
|
|
||||||
var len = string.length;
|
|
||||||
var sub = getText(word).substr(0, len);
|
|
||||||
return string.toUpperCase() === sub.toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addMatches(result, search, wordlist, formatter) {
|
|
||||||
if (isArray(wordlist)) {
|
|
||||||
for (var i = 0; i < wordlist.length; i++)
|
|
||||||
if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
|
|
||||||
} else {
|
|
||||||
for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
|
|
||||||
var val = wordlist[word]
|
|
||||||
if (!val || val === true)
|
|
||||||
val = word
|
|
||||||
else
|
|
||||||
val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
|
|
||||||
if (match(search, val)) result.push(formatter(val))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanName(name) {
|
|
||||||
// Get rid name from identifierQuote and preceding dot(.)
|
|
||||||
if (name.charAt(0) == ".") {
|
|
||||||
name = name.substr(1);
|
|
||||||
}
|
|
||||||
// replace doublicated identifierQuotes with single identifierQuotes
|
|
||||||
// and remove single identifierQuotes
|
|
||||||
var nameParts = name.split(identifierQuote+identifierQuote);
|
|
||||||
for (var i = 0; i < nameParts.length; i++)
|
|
||||||
nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), "");
|
|
||||||
return nameParts.join(identifierQuote);
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertIdentifierQuotes(name) {
|
|
||||||
var nameParts = getText(name).split(".");
|
|
||||||
for (var i = 0; i < nameParts.length; i++)
|
|
||||||
nameParts[i] = identifierQuote +
|
|
||||||
// doublicate identifierQuotes
|
|
||||||
nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) +
|
|
||||||
identifierQuote;
|
|
||||||
var escaped = nameParts.join(".");
|
|
||||||
if (typeof name == "string") return escaped;
|
|
||||||
name = shallowClone(name);
|
|
||||||
name.text = escaped;
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
function nameCompletion(cur, token, result, editor) {
|
|
||||||
// Try to complete table, column names and return start position of completion
|
|
||||||
var useIdentifierQuotes = false;
|
|
||||||
var nameParts = [];
|
|
||||||
var start = token.start;
|
|
||||||
var cont = true;
|
|
||||||
while (cont) {
|
|
||||||
cont = (token.string.charAt(0) == ".");
|
|
||||||
useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote);
|
|
||||||
|
|
||||||
start = token.start;
|
|
||||||
nameParts.unshift(cleanName(token.string));
|
|
||||||
|
|
||||||
token = editor.getTokenAt(Pos(cur.line, token.start));
|
|
||||||
if (token.string == ".") {
|
|
||||||
cont = true;
|
|
||||||
token = editor.getTokenAt(Pos(cur.line, token.start));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to complete table names
|
|
||||||
var string = nameParts.join(".");
|
|
||||||
addMatches(result, string, tables, function(w) {
|
|
||||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Try to complete columns from defaultTable
|
|
||||||
addMatches(result, string, defaultTable, function(w) {
|
|
||||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Try to complete columns
|
|
||||||
string = nameParts.pop();
|
|
||||||
var table = nameParts.join(".");
|
|
||||||
|
|
||||||
var alias = false;
|
|
||||||
var aliasTable = table;
|
|
||||||
// Check if table is available. If not, find table by Alias
|
|
||||||
if (!getTable(table)) {
|
|
||||||
var oldTable = table;
|
|
||||||
table = findTableByAlias(table, editor);
|
|
||||||
if (table !== oldTable) alias = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var columns = getTable(table);
|
|
||||||
if (columns && columns.columns)
|
|
||||||
columns = columns.columns;
|
|
||||||
|
|
||||||
if (columns) {
|
|
||||||
addMatches(result, string, columns, function(w) {
|
|
||||||
var tableInsert = table;
|
|
||||||
if (alias == true) tableInsert = aliasTable;
|
|
||||||
if (typeof w == "string") {
|
|
||||||
w = tableInsert + "." + w;
|
|
||||||
} else {
|
|
||||||
w = shallowClone(w);
|
|
||||||
w.text = tableInsert + "." + w.text;
|
|
||||||
}
|
|
||||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
function eachWord(lineText, f) {
|
|
||||||
var words = lineText.split(/\s+/)
|
|
||||||
for (var i = 0; i < words.length; i++)
|
|
||||||
if (words[i]) f(words[i].replace(/[,;]/g, ''))
|
|
||||||
}
|
|
||||||
|
|
||||||
function findTableByAlias(alias, editor) {
|
|
||||||
var doc = editor.doc;
|
|
||||||
var fullQuery = doc.getValue();
|
|
||||||
var aliasUpperCase = alias.toUpperCase();
|
|
||||||
var previousWord = "";
|
|
||||||
var table = "";
|
|
||||||
var separator = [];
|
|
||||||
var validRange = {
|
|
||||||
start: Pos(0, 0),
|
|
||||||
end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
|
|
||||||
};
|
|
||||||
|
|
||||||
//add separator
|
|
||||||
var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
|
|
||||||
while(indexOfSeparator != -1) {
|
|
||||||
separator.push(doc.posFromIndex(indexOfSeparator));
|
|
||||||
indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
|
|
||||||
}
|
|
||||||
separator.unshift(Pos(0, 0));
|
|
||||||
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
|
|
||||||
|
|
||||||
//find valid range
|
|
||||||
var prevItem = null;
|
|
||||||
var current = editor.getCursor()
|
|
||||||
for (var i = 0; i < separator.length; i++) {
|
|
||||||
if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
|
|
||||||
validRange = {start: prevItem, end: separator[i]};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prevItem = separator[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validRange.start) {
|
|
||||||
var query = doc.getRange(validRange.start, validRange.end, false);
|
|
||||||
|
|
||||||
for (var i = 0; i < query.length; i++) {
|
|
||||||
var lineText = query[i];
|
|
||||||
eachWord(lineText, function(word) {
|
|
||||||
var wordUpperCase = word.toUpperCase();
|
|
||||||
if (wordUpperCase === aliasUpperCase && getTable(previousWord))
|
|
||||||
table = previousWord;
|
|
||||||
if (wordUpperCase !== CONS.ALIAS_KEYWORD)
|
|
||||||
previousWord = word;
|
|
||||||
});
|
|
||||||
if (table) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return table;
|
|
||||||
}
|
|
||||||
|
|
||||||
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
|
|
||||||
tables = parseTables(options && options.tables)
|
|
||||||
var defaultTableName = options && options.defaultTable;
|
|
||||||
var disableKeywords = options && options.disableKeywords;
|
|
||||||
defaultTable = defaultTableName && getTable(defaultTableName);
|
|
||||||
keywords = getKeywords(editor);
|
|
||||||
identifierQuote = getIdentifierQuote(editor);
|
|
||||||
|
|
||||||
if (defaultTableName && !defaultTable)
|
|
||||||
defaultTable = findTableByAlias(defaultTableName, editor);
|
|
||||||
|
|
||||||
defaultTable = defaultTable || [];
|
|
||||||
|
|
||||||
if (defaultTable.columns)
|
|
||||||
defaultTable = defaultTable.columns;
|
|
||||||
|
|
||||||
var cur = editor.getCursor();
|
|
||||||
var result = [];
|
|
||||||
var token = editor.getTokenAt(cur), start, end, search;
|
|
||||||
if (token.end > cur.ch) {
|
|
||||||
token.end = cur.ch;
|
|
||||||
token.string = token.string.slice(0, cur.ch - token.start);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token.string.match(/^[.`"'\w@][\w$#]*$/g)) {
|
|
||||||
search = token.string;
|
|
||||||
start = token.start;
|
|
||||||
end = token.end;
|
|
||||||
} else {
|
|
||||||
start = end = cur.ch;
|
|
||||||
search = "";
|
|
||||||
}
|
|
||||||
if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) {
|
|
||||||
start = nameCompletion(cur, token, result, editor);
|
|
||||||
} else {
|
|
||||||
var objectOrClass = function(w, className) {
|
|
||||||
if (typeof w === "object") {
|
|
||||||
w.className = className;
|
|
||||||
} else {
|
|
||||||
w = { text: w, className: className };
|
|
||||||
}
|
|
||||||
return w;
|
|
||||||
};
|
|
||||||
addMatches(result, search, defaultTable, function(w) {
|
|
||||||
return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table");
|
|
||||||
});
|
|
||||||
addMatches(
|
|
||||||
result,
|
|
||||||
search,
|
|
||||||
tables, function(w) {
|
|
||||||
return objectOrClass(w, "CodeMirror-hint-table");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (!disableKeywords)
|
|
||||||
addMatches(result, search, keywords, function(w) {
|
|
||||||
return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
let callbacks = []
|
|
||||||
|
|
||||||
function loadSuccess(key) {
|
|
||||||
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144
|
|
||||||
// check is successfully downloaded script
|
|
||||||
return window[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
const load = (src, type, callback) => {
|
|
||||||
if(type=='link'){
|
|
||||||
|
|
||||||
loadStyle(src, callback)
|
|
||||||
}else{
|
|
||||||
let loadKey = ''
|
|
||||||
if(src.indexOf('tinymce')>=0){
|
|
||||||
loadKey = 'tinymce'
|
|
||||||
}else if(src.indexOf('codemirror')>=0){
|
|
||||||
loadKey = 'CodeMirror'
|
|
||||||
}
|
|
||||||
const scriptTag = document.getElementById(src)
|
|
||||||
//const cb = callback || function() {}
|
|
||||||
if (!scriptTag) {
|
|
||||||
const script = document.createElement('script')
|
|
||||||
script.src = src // src url for the third-party library being loaded.
|
|
||||||
script.id = src
|
|
||||||
script.onload=()=>callback()
|
|
||||||
script.onerror=()=>callback('加载失败:'+src)
|
|
||||||
document.body.appendChild(script)
|
|
||||||
//callbacks.push(cb)
|
|
||||||
// const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
|
|
||||||
// onEnd(script)
|
|
||||||
}else{
|
|
||||||
if (loadSuccess(loadKey)) {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scriptTag) {
|
|
||||||
/* else {
|
|
||||||
callbacks.push(cb)
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stdOnEnd(script) {
|
|
||||||
script['onload'] = function() {
|
|
||||||
// this.onload = null here is necessary
|
|
||||||
// because even IE9 works not like others
|
|
||||||
this.onerror = this.onload = null
|
|
||||||
for (const cb of callbacks) {
|
|
||||||
cb(null, script)
|
|
||||||
}
|
|
||||||
callbacks = null
|
|
||||||
}
|
|
||||||
script['onerror'] = function() {
|
|
||||||
this.onerror = this.onload = null
|
|
||||||
cb(new Error('Failed to load ' + src), script)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ieOnEnd(script) {
|
|
||||||
script.onreadystatechange = function() {
|
|
||||||
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
|
|
||||||
this.onreadystatechange = null
|
|
||||||
for (const cb of callbacks) {
|
|
||||||
cb(null, script) // there is no way to catch loading errors in IE8
|
|
||||||
}
|
|
||||||
callbacks = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadStyle(src, callback) {
|
|
||||||
const link = document.getElementById(src)
|
|
||||||
if (!link) {
|
|
||||||
const link = document.createElement('link')
|
|
||||||
link.setAttribute("rel", "stylesheet");
|
|
||||||
link.setAttribute("type", "text/css");
|
|
||||||
link.setAttribute("href", src);
|
|
||||||
link.id = src
|
|
||||||
let heads = document.getElementsByTagName("head")
|
|
||||||
if(heads.length){
|
|
||||||
heads[0].appendChild(link)
|
|
||||||
}else{
|
|
||||||
document.documentElement.appendChild(link)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default load
|
|
||||||
@ -26,11 +26,24 @@ import JSlider from './JSlider.vue'
|
|||||||
import JSwitch from './JSwitch.vue'
|
import JSwitch from './JSwitch.vue'
|
||||||
import JTime from './JTime.vue'
|
import JTime from './JTime.vue'
|
||||||
import JTreeTable from './JTreeTable.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'
|
||||||
|
//引入需要全局注册的js函数和变量
|
||||||
|
import { Modal, notification,message } from 'ant-design-vue'
|
||||||
|
import lodash_object from 'lodash'
|
||||||
|
import debounce from 'lodash/debounce'
|
||||||
|
import pick from 'lodash.pick'
|
||||||
|
import data from 'china-area-data'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(Vue) {
|
install(Vue) {
|
||||||
|
Vue.use(JModal)
|
||||||
Vue.component('JMarkdownEditor', JMarkdownEditor)
|
Vue.component('JMarkdownEditor', JMarkdownEditor)
|
||||||
Vue.component(JModal.name, JModal)
|
|
||||||
Vue.component('JPopupOnlReport', JPopupOnlReport)
|
Vue.component('JPopupOnlReport', JPopupOnlReport)
|
||||||
Vue.component('JFilePop', JFilePop)
|
Vue.component('JFilePop', JFilePop)
|
||||||
Vue.component('JInputPop', JInputPop)
|
Vue.component('JInputPop', JInputPop)
|
||||||
@ -57,5 +70,22 @@ export default {
|
|||||||
Vue.component('JTreeSelect', JTreeSelect)
|
Vue.component('JTreeSelect', JTreeSelect)
|
||||||
Vue.component('JTreeTable', JTreeTable)
|
Vue.component('JTreeTable', JTreeTable)
|
||||||
Vue.component('JUpload', JUpload)
|
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)
|
||||||
|
|
||||||
|
//注册全局js函数和变量
|
||||||
|
Vue.prototype.$Jnotification = notification
|
||||||
|
Vue.prototype.$Jmodal = Modal
|
||||||
|
Vue.prototype.$Jmessage = message
|
||||||
|
Vue.prototype.$Jlodash = lodash_object
|
||||||
|
Vue.prototype.$Jdebounce= debounce
|
||||||
|
Vue.prototype.$Jpick = pick
|
||||||
|
Vue.prototype.$Jpcaa = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -14,7 +14,6 @@
|
|||||||
</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,
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<a-icon type="close" @click="visible=false"/>
|
<a-icon type="close" @click="visible=false"/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<a-input :value="inputContent" :disabled="disabled" @change="handleInputChange">
|
<a-input :value="inputContent" :disabled="disabled" @change="handleInputChange" :placeholder="placeholder">
|
||||||
<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">
|
||||||
@ -53,6 +53,10 @@
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
placeholder:{
|
||||||
|
type:String,
|
||||||
|
required:false
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
@ -83,6 +87,10 @@
|
|||||||
this.$emit('change',this.inputContent)
|
this.$emit('change',this.inputContent)
|
||||||
},
|
},
|
||||||
pop(){
|
pop(){
|
||||||
|
// disabled 不弹窗
|
||||||
|
if (this.disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.visible=true
|
this.visible=true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.textarea.focus()
|
this.$refs.textarea.focus()
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -58,7 +58,7 @@
|
|||||||
:dataSource="table.dataSource"
|
:dataSource="table.dataSource"
|
||||||
:pagination="table.pagination"
|
:pagination="table.pagination"
|
||||||
:loading="table.loading"
|
:loading="table.loading"
|
||||||
:rowSelection="{fixed:true,selectedRowKeys: table.selectedRowKeys, onChange: handleChangeInTableSelect}"
|
:rowSelection="{type:rowSelectionType,fixed:true,selectedRowKeys: table.selectedRowKeys, onChange: handleChangeInTableSelect}"
|
||||||
@change="handleChangeInTable"
|
@change="handleChangeInTable"
|
||||||
style="min-height: 300px"
|
style="min-height: 300px"
|
||||||
:scroll="tableScroll"
|
:scroll="tableScroll"
|
||||||
@ -74,11 +74,12 @@
|
|||||||
import {filterObj} from '@/utils/util'
|
import {filterObj} from '@/utils/util'
|
||||||
import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
|
import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
|
||||||
import { httpGroupRequest } from '@/api/GroupRequest.js'
|
import { httpGroupRequest } from '@/api/GroupRequest.js'
|
||||||
|
import md5 from 'md5'
|
||||||
|
|
||||||
const MODAL_WIDTH = 1200;
|
const MODAL_WIDTH = 1200;
|
||||||
export default {
|
export default {
|
||||||
name: 'JPopupOnlReport',
|
name: 'JPopupOnlReport',
|
||||||
props: ['multi', 'code', 'groupId', 'param'],
|
props: ['multi', 'code', 'sorter', 'groupId', 'param'],
|
||||||
components:{
|
components:{
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
@ -121,9 +122,10 @@
|
|||||||
},
|
},
|
||||||
cgRpConfigId:"",
|
cgRpConfigId:"",
|
||||||
modalWidth:MODAL_WIDTH,
|
modalWidth:MODAL_WIDTH,
|
||||||
tableScroll:{x:MODAL_WIDTH-100},
|
tableScroll:{x:true},
|
||||||
dynamicParam:{}
|
dynamicParam:{},
|
||||||
|
// 排序字段,默认无排序
|
||||||
|
iSorter: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -136,15 +138,44 @@
|
|||||||
param:{
|
param:{
|
||||||
deep:true,
|
deep:true,
|
||||||
handler(){
|
handler(){
|
||||||
this.dynamicParamHandler()
|
// update--begin--autor:liusq-----date:20210706------for:JPopup组件在modal中使用报错#2729------
|
||||||
this.loadData();
|
if(this.visible){
|
||||||
|
this.dynamicParamHandler()
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
// update--begin--autor:liusq-----date:20210706------for:JPopup组件在modal中使用报错#2729------
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
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(){
|
||||||
return this.queryInfo && this.queryInfo.length>0
|
return this.queryInfo && this.queryInfo.length>0
|
||||||
}
|
},
|
||||||
|
// 行选择框类型,根据是否多选来控制显示为单选框还是多选框
|
||||||
|
rowSelectionType() {
|
||||||
|
return this.multi ? 'checkbox' : 'radio'
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
loadColumnsInfo(){
|
loadColumnsInfo(){
|
||||||
@ -167,9 +198,19 @@
|
|||||||
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()
|
||||||
|
} else {
|
||||||
|
this.$error({
|
||||||
|
title: '出错了',
|
||||||
|
content: (<p>Popup初始化失败,请检查你的配置或稍后重试!<br/>错误信息如下:{res.message}</p>),
|
||||||
|
onOk: () => this.close(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -253,7 +294,7 @@
|
|||||||
paramTarget['self_'+key] = this.dynamicParam[key]
|
paramTarget['self_'+key] = this.dynamicParam[key]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let param = Object.assign(paramTarget, this.queryParam, this.sorter);
|
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);
|
||||||
@ -288,8 +329,18 @@
|
|||||||
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()
|
||||||
@ -342,11 +393,20 @@
|
|||||||
combineRowKey(record){
|
combineRowKey(record){
|
||||||
let res = ''
|
let res = ''
|
||||||
Object.keys(record).forEach(key=>{
|
Object.keys(record).forEach(key=>{
|
||||||
res+=record[key]
|
//update-begin---author:liusq Date:20210203 for:pop选择器列主键问题 issues/I29P9Q------------
|
||||||
|
if(key=='id'){
|
||||||
|
res=record[key]+res
|
||||||
|
}else{
|
||||||
|
res+=record[key]
|
||||||
|
}
|
||||||
|
//update-end---author:liusq Date:20210203 for:pop选择器列主键问题 issues/I29P9Q------------
|
||||||
})
|
})
|
||||||
if(res.length>50){
|
// update-begin---author:taoyan Date:20211025 for:jpopup 表格key重复BUG /issues/3121
|
||||||
|
res = md5(res)
|
||||||
|
/*if(res.length>50){
|
||||||
res = res.substring(0,50)
|
res = res.substring(0,50)
|
||||||
}
|
}*/
|
||||||
|
// update-end---author:taoyan Date:20211025 for:jpopup 表格key重复BUG /issues/3121
|
||||||
return res
|
return res
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -371,6 +431,11 @@
|
|||||||
this.table.selectionRows.splice(rowKey_index,1);
|
this.table.selectionRows.splice(rowKey_index,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 判断是否允许多选,如果不允许多选,就只存储最后一个选中的行
|
||||||
|
if (!this.multi && this.table.selectedRowKeys.length > 1) {
|
||||||
|
this.table.selectionRows = [this.table.selectionRows.pop()]
|
||||||
|
this.table.selectedRowKeys = [this.table.selectedRowKeys.pop()]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,8 +62,9 @@
|
|||||||
import { getAction } from '@/api/manage'
|
import { getAction } from '@/api/manage'
|
||||||
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 { pushIfNotExist } from '@/utils/util'
|
||||||
import JSelectBizQueryItem from './JSelectBizQueryItem'
|
import JSelectBizQueryItem from './JSelectBizQueryItem'
|
||||||
|
import {cloneDeep} from 'lodash'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectBizComponentModal',
|
name: 'JSelectBizComponentModal',
|
||||||
@ -177,11 +178,24 @@
|
|||||||
computed: {
|
computed: {
|
||||||
// 表头
|
// 表头
|
||||||
innerColumns() {
|
innerColumns() {
|
||||||
let columns = cloneObject(this.columns)
|
let columns = cloneDeep(this.columns)
|
||||||
columns.forEach(column => {
|
columns.forEach(column => {
|
||||||
// 给所有的列加上过长裁剪
|
// 给所有的列加上过长裁剪
|
||||||
if (this.ellipsisLength !== -1) {
|
if (this.ellipsisLength !== -1) {
|
||||||
column.customRender = (text) => this.renderEllipsis(text)
|
// JSelectBizComponent columns 建议开放customRender等方法类配置
|
||||||
|
// https://github.com/jeecgboot/jeecg-boot/issues/3203
|
||||||
|
let myCustomRender = column.customRender
|
||||||
|
column.customRender = (text, record, index) => {
|
||||||
|
let value = text
|
||||||
|
if (typeof myCustomRender === 'function') {
|
||||||
|
// noinspection JSVoidFunctionReturnValueUsed
|
||||||
|
value = myCustomRender(text, record, index)
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return this.renderEllipsis(value)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return columns
|
return columns
|
||||||
@ -192,7 +206,7 @@
|
|||||||
deep: true,
|
deep: true,
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(val) {
|
handler(val) {
|
||||||
this.innerValue = cloneObject(val)
|
this.innerValue = cloneDeep(val)
|
||||||
this.selectedRowKeys = []
|
this.selectedRowKeys = []
|
||||||
this.valueWatchHandler(val)
|
this.valueWatchHandler(val)
|
||||||
this.queryOptionsByValue(val)
|
this.queryOptionsByValue(val)
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="components-input-demo-presuffix">
|
<div class="components-input-demo-presuffix">
|
||||||
<!---->
|
<!---->
|
||||||
<a-input @click="openModal" placeholder="请点击选择部门" v-model="departNames" readOnly :disabled="disabled">
|
<a-input @click="openModal" placeholder="请点击选择部门" v-model="textVals" readOnly :disabled="disabled">
|
||||||
<a-icon slot="prefix" type="cluster" title="部门选择控件"/>
|
<a-icon slot="prefix" type="cluster" title="部门选择控件"/>
|
||||||
<a-icon v-if="departIds" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
|
<a-icon v-if="storeVals" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
|
||||||
</a-input>
|
</a-input>
|
||||||
|
|
||||||
<j-select-depart-modal
|
<j-select-depart-modal
|
||||||
@ -11,7 +11,10 @@
|
|||||||
:modal-width="modalWidth"
|
:modal-width="modalWidth"
|
||||||
:multi="multi"
|
:multi="multi"
|
||||||
:rootOpened="rootOpened"
|
:rootOpened="rootOpened"
|
||||||
:depart-id="departIds"
|
:depart-id="value"
|
||||||
|
:store="storeField"
|
||||||
|
:text="textField"
|
||||||
|
:treeOpera="treeOpera"
|
||||||
@ok="handleOK"
|
@ok="handleOK"
|
||||||
@initComp="initComp"/>
|
@initComp="initComp"/>
|
||||||
</div>
|
</div>
|
||||||
@ -19,6 +22,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import JSelectDepartModal from './modal/JSelectDepartModal'
|
import JSelectDepartModal from './modal/JSelectDepartModal'
|
||||||
|
import { underLinetoHump } from '@/components/_util/StringUtil'
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectDepart',
|
name: 'JSelectDepart',
|
||||||
components:{
|
components:{
|
||||||
@ -52,59 +56,101 @@
|
|||||||
// 自定义返回字段,默认返回 id
|
// 自定义返回字段,默认返回 id
|
||||||
customReturnField: {
|
customReturnField: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'id'
|
default: ''
|
||||||
|
},
|
||||||
|
backDepart: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
// 存储字段 [key field]
|
||||||
|
store: {
|
||||||
|
type: String,
|
||||||
|
default: 'id',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
// 显示字段 [label field]
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: 'departName',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
treeOpera: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: false
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
visible:false,
|
visible:false,
|
||||||
confirmLoading:false,
|
confirmLoading:false,
|
||||||
departNames:"",
|
storeVals: '', //[key values]
|
||||||
departIds:''
|
textVals: '' //[label values]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
storeField(){
|
||||||
|
let field = this.customReturnField
|
||||||
|
if(!field){
|
||||||
|
field = this.store;
|
||||||
|
}
|
||||||
|
return underLinetoHump(field)
|
||||||
|
},
|
||||||
|
textField(){
|
||||||
|
return underLinetoHump(this.text)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted(){
|
mounted(){
|
||||||
this.departIds = this.value
|
this.storeVals = this.value
|
||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
value(val){
|
value(val){
|
||||||
//update-begin-author:wangshuai date:20201124 for:组件 JSelectDepart.vue不是默认id时新内容编辑问题 gitee I247X2
|
this.storeVals = val
|
||||||
// if (this.customReturnField === 'id') {
|
|
||||||
this.departIds = val
|
|
||||||
// }
|
|
||||||
//update-end-author:wangshuai date:20201124 for:组件 JSelectDepart.vue不是默认id时新内容编辑问题 gitee I247X2
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
initComp(departNames){
|
initComp(textVals){
|
||||||
this.departNames = departNames
|
this.textVals = textVals
|
||||||
//update-begin-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
|
},
|
||||||
//TODO 当返回字段为部门名称时会有问题,因为部门名称不唯一
|
//返回选中的部门信息
|
||||||
//返回字段不为id时,根据返回字段获取id
|
backDeparInfo(){
|
||||||
if(this.customReturnField !== 'id' && this.value){
|
if(this.backDepart===true){
|
||||||
const dataList = this.$refs.innerDepartSelectModal.dataList;
|
//LOWCOD-2147 【用户管理】选择部门和上级以后,负责部门没有数据可选 (陶炎改造自定义返回字段导致)
|
||||||
console.log('this.value',this.value)
|
if(this.storeVals && this.storeVals.length>0){
|
||||||
this.departIds = this.value.split(',').map(item => {
|
let arr1 = this.storeVals.split(',')
|
||||||
const data = dataList.filter(d=>d[this.customReturnField] === item)
|
let arr2 = this.textVals.split(',')
|
||||||
return data.length > 0 ? data[0].id : ''
|
let info = []
|
||||||
}).join(',')
|
for(let i=0;i<arr1.length;i++){
|
||||||
|
info.push({
|
||||||
|
value: arr1[i],
|
||||||
|
text: arr2[i]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.$emit('back', info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//update-end-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
|
|
||||||
},
|
},
|
||||||
openModal(){
|
openModal(){
|
||||||
this.$refs.innerDepartSelectModal.show()
|
this.$refs.innerDepartSelectModal.show()
|
||||||
},
|
},
|
||||||
handleOK(rows, idstr) {
|
handleOK(rows) {
|
||||||
let value = ''
|
|
||||||
if (!rows && rows.length <= 0) {
|
if (!rows && rows.length <= 0) {
|
||||||
this.departNames = ''
|
this.textVals = ''
|
||||||
this.departIds = ''
|
this.storeVals = ''
|
||||||
} else {
|
} else {
|
||||||
value = rows.map(row => row[this.customReturnField]).join(',')
|
let arr1 = []
|
||||||
this.departNames = rows.map(row => row['departName']).join(',')
|
let arr2 = []
|
||||||
this.departIds = idstr
|
for(let dep of rows){
|
||||||
|
arr1.push(dep[this.storeField])
|
||||||
|
arr2.push(dep[this.textField])
|
||||||
|
}
|
||||||
|
this.storeVals = arr1.join(',')
|
||||||
|
this.textVals = arr2.join(',')
|
||||||
}
|
}
|
||||||
this.$emit("change", value)
|
this.$emit("change", this.storeVals)
|
||||||
|
this.backDeparInfo()
|
||||||
},
|
},
|
||||||
getDepartNames(){
|
getDepartNames(){
|
||||||
return this.departNames
|
return this.departNames
|
||||||
|
|||||||
@ -1,19 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<a-input-search
|
<a-input-search
|
||||||
v-model="userNames"
|
v-model="textVals"
|
||||||
placeholder="请先选择用户"
|
placeholder="请先选择用户"
|
||||||
readOnly
|
readOnly
|
||||||
unselectable="on"
|
unselectable="on"
|
||||||
@search="onSearchDepUser">
|
@search="onSearchDepUser">
|
||||||
<a-button slot="enterButton" :disabled="disabled">选择用户</a-button>
|
<a-button slot="enterButton" :disabled="disabled">选择用户</a-button>
|
||||||
</a-input-search>
|
</a-input-search>
|
||||||
<j-select-user-by-dep-modal ref="selectModal" :modal-width="modalWidth" :multi="multi" @ok="selectOK" :user-ids="value" @initComp="initComp"/>
|
<j-select-user-by-dep-modal
|
||||||
|
ref="selectModal"
|
||||||
|
:modal-width="modalWidth"
|
||||||
|
:multi="multi"
|
||||||
|
@ok="selectOK"
|
||||||
|
:user-ids="value"
|
||||||
|
:store="storeField"
|
||||||
|
:text="textField"
|
||||||
|
@initComp="initComp"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import JSelectUserByDepModal from './modal/JSelectUserByDepModal'
|
import JSelectUserByDepModal from './modal/JSelectUserByDepModal'
|
||||||
|
import { underLinetoHump } from '@/components/_util/StringUtil'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectUserByDep',
|
name: 'JSelectUserByDep',
|
||||||
@ -38,19 +47,48 @@
|
|||||||
default: true,
|
default: true,
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
backUser: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
// 存储字段 [key field]
|
||||||
|
store: {
|
||||||
|
type: String,
|
||||||
|
default: 'username',
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
// 显示字段 [label field]
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: 'realname',
|
||||||
|
required: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
userIds: "",
|
storeVals: '', //[key values]
|
||||||
userNames: ""
|
textVals: '' //[label values]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
storeField(){
|
||||||
|
let field = this.customReturnField
|
||||||
|
if(!field){
|
||||||
|
field = this.store;
|
||||||
|
}
|
||||||
|
return underLinetoHump(field)
|
||||||
|
},
|
||||||
|
textField(){
|
||||||
|
return underLinetoHump(this.text)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.userIds = this.value
|
this.storeVals = this.value
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value(val) {
|
value(val) {
|
||||||
this.userIds = val
|
this.storeVals = val
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
@ -58,27 +96,45 @@
|
|||||||
event: 'change'
|
event: 'change'
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initComp(userNames) {
|
initComp(textVals) {
|
||||||
this.userNames = userNames
|
this.textVals = textVals
|
||||||
|
},
|
||||||
|
//返回选中的用户信息
|
||||||
|
backDeparInfo(){
|
||||||
|
if(this.backUser===true){
|
||||||
|
if(this.storeVals && this.storeVals.length>0){
|
||||||
|
let arr1 = this.storeVals.split(',')
|
||||||
|
let arr2 = this.textVals.split(',')
|
||||||
|
let info = []
|
||||||
|
for(let i=0;i<arr1.length;i++){
|
||||||
|
info.push({
|
||||||
|
value: arr1[i],
|
||||||
|
text: arr2[i]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.$emit('back', info)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onSearchDepUser() {
|
onSearchDepUser() {
|
||||||
this.$refs.selectModal.showModal()
|
this.$refs.selectModal.showModal()
|
||||||
},
|
},
|
||||||
selectOK(rows, idstr) {
|
selectOK(rows) {
|
||||||
console.log("当前选中用户", rows)
|
console.log("当前选中用户", rows)
|
||||||
console.log("当前选中用户ID", idstr)
|
|
||||||
if (!rows) {
|
if (!rows) {
|
||||||
this.userNames = ''
|
this.storeVals = ''
|
||||||
this.userIds = ''
|
this.textVals = ''
|
||||||
} else {
|
} else {
|
||||||
let temp = ''
|
let temp1 = []
|
||||||
|
let temp2 = []
|
||||||
for (let item of rows) {
|
for (let item of rows) {
|
||||||
temp += ',' + item.realname
|
temp1.push(item[this.storeField])
|
||||||
|
temp2.push(item[this.textField])
|
||||||
}
|
}
|
||||||
this.userNames = temp.substring(1)
|
this.storeVals = temp1.join(',')
|
||||||
this.userIds = idstr
|
this.textVals = temp2.join(',')
|
||||||
}
|
}
|
||||||
this.$emit("change", this.userIds)
|
this.$emit("change", this.storeVals)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,15 +6,19 @@
|
|||||||
:confirmLoading="confirmLoading"
|
:confirmLoading="confirmLoading"
|
||||||
@ok="handleSubmit"
|
@ok="handleSubmit"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
|
@update:fullscreen="isFullscreen"
|
||||||
|
wrapClassName="j-depart-select-modal"
|
||||||
switchFullscreen
|
switchFullscreen
|
||||||
cancelText="关闭">
|
cancelText="关闭">
|
||||||
<a-spin tip="Loading..." :spinning="false">
|
<a-spin tip="Loading..." :spinning="false">
|
||||||
<a-input-search style="margin-bottom: 1px" placeholder="请输入部门名称按回车进行搜索" @search="onSearch" />
|
<a-input-search v-model="searchValue" style="margin-bottom: 1px" placeholder="请输入部门名称按回车进行搜索" />
|
||||||
|
<a-empty v-if="filterTreeData.length===0"></a-empty>
|
||||||
<a-tree
|
<a-tree
|
||||||
|
v-else
|
||||||
checkable
|
checkable
|
||||||
class="my-dept-select-tree"
|
:class="treeScreenClass"
|
||||||
:treeData="treeData"
|
:treeData="filterTreeData"
|
||||||
:checkStrictly="true"
|
:checkStrictly="checkStrictly"
|
||||||
@check="onCheck"
|
@check="onCheck"
|
||||||
@select="onSelect"
|
@select="onSelect"
|
||||||
@expand="onExpand"
|
@expand="onExpand"
|
||||||
@ -22,17 +26,24 @@
|
|||||||
:expandedKeys="expandedKeys"
|
:expandedKeys="expandedKeys"
|
||||||
:checkedKeys="checkedKeys">
|
:checkedKeys="checkedKeys">
|
||||||
|
|
||||||
<template slot="title" slot-scope="{title}">
|
|
||||||
<span v-if="title.indexOf(searchValue) > -1">
|
|
||||||
{{title.substr(0, title.indexOf(searchValue))}}
|
|
||||||
<span style="color: #f50">{{searchValue}}</span>
|
|
||||||
{{title.substr(title.indexOf(searchValue) + searchValue.length)}}
|
|
||||||
</span>
|
|
||||||
<span v-else>{{title}}</span>
|
|
||||||
</template>
|
|
||||||
</a-tree>
|
</a-tree>
|
||||||
|
|
||||||
</a-spin>
|
</a-spin>
|
||||||
|
<!--底部父子关联操作和确认取消按钮-->
|
||||||
|
<template slot="footer" v-if="treeOpera && multi">
|
||||||
|
<div class="drawer-bootom-button">
|
||||||
|
<a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
|
||||||
|
<a-menu slot="overlay">
|
||||||
|
<a-menu-item key="1" @click="switchCheckStrictly(1)">父子关联</a-menu-item>
|
||||||
|
<a-menu-item key="2" @click="switchCheckStrictly(2)">取消关联</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
<a-button>
|
||||||
|
树操作 <a-icon type="up" />
|
||||||
|
</a-button>
|
||||||
|
</a-dropdown>
|
||||||
|
<a-button @click="handleCancel" type="primary" style="margin-right: 0.8rem">关闭</a-button>
|
||||||
|
<a-button @click="handleSubmit" type="primary" >确认</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</j-modal>
|
</j-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -40,7 +51,7 @@
|
|||||||
import { queryDepartTreeList } from '@/api/api'
|
import { queryDepartTreeList } from '@/api/api'
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectDepartModal',
|
name: 'JSelectDepartModal',
|
||||||
props:['modalWidth','multi','rootOpened','departId'],
|
props:['modalWidth','multi','rootOpened','departId', 'store', 'text','treeOpera'],
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
visible:false,
|
visible:false,
|
||||||
@ -51,7 +62,9 @@
|
|||||||
dataList:[],
|
dataList:[],
|
||||||
checkedKeys:[],
|
checkedKeys:[],
|
||||||
checkedRows:[],
|
checkedRows:[],
|
||||||
searchValue:""
|
searchValue:"",
|
||||||
|
checkStrictly: true,
|
||||||
|
fullscreen:false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
@ -63,15 +76,30 @@
|
|||||||
},
|
},
|
||||||
visible: {
|
visible: {
|
||||||
handler() {
|
handler() {
|
||||||
if (this.departId) {
|
this.initDepartComponent(true)
|
||||||
this.checkedKeys = this.departId.split(",");
|
|
||||||
// console.log('this.departId', this.departId)
|
|
||||||
} else {
|
|
||||||
this.checkedKeys = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed:{
|
||||||
|
treeScreenClass() {
|
||||||
|
return {
|
||||||
|
'my-dept-select-tree': true,
|
||||||
|
'fullscreen': this.fullscreen,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filterTreeData(){
|
||||||
|
if(!this.searchValue){
|
||||||
|
return this.treeData
|
||||||
|
}
|
||||||
|
let filter = []
|
||||||
|
this.dataList.forEach((item) => {
|
||||||
|
if (item.title.includes(this.searchValue)) {
|
||||||
|
filter.push(Object.assign({}, item, {children: null, isLeaf: true}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return filter
|
||||||
|
},
|
||||||
|
},
|
||||||
methods:{
|
methods:{
|
||||||
show(){
|
show(){
|
||||||
this.visible=true
|
this.visible=true
|
||||||
@ -79,6 +107,7 @@
|
|||||||
this.checkedKeys=[]
|
this.checkedKeys=[]
|
||||||
},
|
},
|
||||||
loadDepart(){
|
loadDepart(){
|
||||||
|
// 这个方法是找到所有的部门信息
|
||||||
queryDepartTreeList().then(res=>{
|
queryDepartTreeList().then(res=>{
|
||||||
if(res.success){
|
if(res.success){
|
||||||
let arr = [...res.result]
|
let arr = [...res.result]
|
||||||
@ -91,20 +120,23 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
initDepartComponent(){
|
initDepartComponent(flag){
|
||||||
let names = ''
|
let arr = []
|
||||||
|
//该方法两个地方用 1.visible改变事件重新设置选中项 2.组件编辑页面回显
|
||||||
|
let fieldName = flag==true?'key':this.text
|
||||||
if(this.departId){
|
if(this.departId){
|
||||||
let currDepartId = this.departId
|
let arr2 = this.departId.split(',')
|
||||||
for(let item of this.dataList){
|
for(let item of this.dataList){
|
||||||
if(currDepartId.indexOf(item.key)>=0){
|
if(arr2.indexOf(item[this.store])>=0){
|
||||||
names+=","+item.title
|
arr.push(item[fieldName])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(names){
|
|
||||||
names = names.substring(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.$emit("initComp",names)
|
if(flag==true){
|
||||||
|
this.checkedKeys = [...arr]
|
||||||
|
}else{
|
||||||
|
this.$emit("initComp", arr.join(','))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
reWriterWithSlot(arr){
|
reWriterWithSlot(arr){
|
||||||
for(let item of arr){
|
for(let item of arr){
|
||||||
@ -128,8 +160,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.expandedKeys=[...keys]
|
this.expandedKeys=[...keys]
|
||||||
|
//全部keys
|
||||||
|
//this.allTreeKeys = [...keys]
|
||||||
}else{
|
}else{
|
||||||
this.expandedKeys=[]
|
this.expandedKeys=[]
|
||||||
|
//this.allTreeKeys = []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onCheck (checkedKeys,info) {
|
onCheck (checkedKeys,info) {
|
||||||
@ -138,25 +173,32 @@
|
|||||||
this.checkedKeys = [...arr]
|
this.checkedKeys = [...arr]
|
||||||
this.checkedRows = (this.checkedKeys.length === 0) ? [] : [info.node.dataRef]
|
this.checkedRows = (this.checkedKeys.length === 0) ? [] : [info.node.dataRef]
|
||||||
}else{
|
}else{
|
||||||
this.checkedKeys = checkedKeys.checked
|
if(this.checkStrictly){
|
||||||
|
this.checkedKeys = checkedKeys.checked
|
||||||
|
}else{
|
||||||
|
this.checkedKeys = checkedKeys
|
||||||
|
}
|
||||||
this.checkedRows = this.getCheckedRows(this.checkedKeys)
|
this.checkedRows = this.getCheckedRows(this.checkedKeys)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSelect(selectedKeys,info) {
|
onSelect(selectedKeys,info) {
|
||||||
let keys = []
|
//取消关联的情况下才走onSelect的逻辑
|
||||||
keys.push(selectedKeys[0])
|
if(this.checkStrictly){
|
||||||
if(!this.checkedKeys || this.checkedKeys.length===0 || !this.multi){
|
let keys = []
|
||||||
this.checkedKeys = [...keys]
|
keys.push(selectedKeys[0])
|
||||||
this.checkedRows=[info.node.dataRef]
|
if(!this.checkedKeys || this.checkedKeys.length===0 || !this.multi){
|
||||||
}else{
|
this.checkedKeys = [...keys]
|
||||||
let currKey = info.node.dataRef.key
|
this.checkedRows=[info.node.dataRef]
|
||||||
if(this.checkedKeys.indexOf(currKey)>=0){
|
|
||||||
this.checkedKeys = this.checkedKeys.filter(item=> item !==currKey)
|
|
||||||
}else{
|
}else{
|
||||||
this.checkedKeys.push(...keys)
|
let currKey = info.node.dataRef.key
|
||||||
|
if(this.checkedKeys.indexOf(currKey)>=0){
|
||||||
|
this.checkedKeys = this.checkedKeys.filter(item=> item !==currKey)
|
||||||
|
}else{
|
||||||
|
this.checkedKeys.push(...keys)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
this.checkedRows = this.getCheckedRows(this.checkedKeys)
|
||||||
}
|
}
|
||||||
this.checkedRows = this.getCheckedRows(this.checkedKeys)
|
|
||||||
},
|
},
|
||||||
onExpand (expandedKeys) {
|
onExpand (expandedKeys) {
|
||||||
this.expandedKeys = expandedKeys
|
this.expandedKeys = expandedKeys
|
||||||
@ -166,7 +208,9 @@
|
|||||||
if(!this.checkedKeys || this.checkedKeys.length==0){
|
if(!this.checkedKeys || this.checkedKeys.length==0){
|
||||||
this.$emit("ok",'')
|
this.$emit("ok",'')
|
||||||
}else{
|
}else{
|
||||||
this.$emit("ok",this.checkedRows,this.checkedKeys.join(","))
|
let checkRow = this.getCheckedRows(this.checkedKeys)
|
||||||
|
let keyStr = this.checkedKeys.join(",")
|
||||||
|
this.$emit("ok", checkRow, keyStr)
|
||||||
}
|
}
|
||||||
this.handleClear()
|
this.handleClear()
|
||||||
},
|
},
|
||||||
@ -190,22 +234,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parentKey
|
return parentKey
|
||||||
},
|
|
||||||
onSearch(value){
|
|
||||||
const expandedKeys = this.dataList.map((item) => {
|
|
||||||
if (item.title.indexOf(value) > -1) {
|
|
||||||
return this.getParentKey(item.key,this.treeData)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}).filter((item, i, self) => item && self.indexOf(item) === i)
|
|
||||||
|
|
||||||
Object.assign(this, {
|
|
||||||
expandedKeys,
|
|
||||||
searchValue: value,
|
|
||||||
autoExpandParent: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
// 根据 checkedKeys 获取 rows
|
// 根据 checkedKeys 获取 rows
|
||||||
getCheckedRows(checkedKeys) {
|
getCheckedRows(checkedKeys) {
|
||||||
@ -232,6 +260,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rows
|
return rows
|
||||||
|
},
|
||||||
|
switchCheckStrictly (v) {
|
||||||
|
if(v==1){
|
||||||
|
this.checkStrictly = false
|
||||||
|
}else if(v==2){
|
||||||
|
this.checkStrictly = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isFullscreen(val){
|
||||||
|
this.fullscreen=val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,8 +279,22 @@
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
// 限制部门选择树高度,避免部门太多时点击确定不便
|
// 限制部门选择树高度,避免部门太多时点击确定不便
|
||||||
.my-dept-select-tree{
|
.my-dept-select-tree{
|
||||||
height: 350px;
|
height:350px;
|
||||||
|
|
||||||
|
&.fullscreen{
|
||||||
|
height: calc(100vh - 250px);
|
||||||
|
}
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
.drawer-bootom-button {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid #e8e8e8;
|
||||||
|
padding: 10px 16px;
|
||||||
|
text-align: right;
|
||||||
|
left: 0;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0 0 2px 2px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -4,6 +4,7 @@
|
|||||||
:visible="visible"
|
:visible="visible"
|
||||||
:title="title"
|
:title="title"
|
||||||
switchFullscreen
|
switchFullscreen
|
||||||
|
wrapClassName="j-user-select-modal"
|
||||||
@ok="handleSubmit"
|
@ok="handleSubmit"
|
||||||
@cancel="close"
|
@cancel="close"
|
||||||
style="top:50px"
|
style="top:50px"
|
||||||
@ -20,21 +21,30 @@
|
|||||||
:dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
|
:dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
|
||||||
:treeData="departTree"
|
:treeData="departTree"
|
||||||
:expandAction="false"
|
:expandAction="false"
|
||||||
:expandedKeys.sync="expandedKeys"
|
|
||||||
@select="onDepSelect"
|
@select="onDepSelect"
|
||||||
|
:load-data="onLoadDepartment"
|
||||||
/>
|
/>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :md="18" :sm="24">
|
<a-col :md="18" :sm="24">
|
||||||
<a-card :bordered="false">
|
<a-card :bordered="false">
|
||||||
用户账号:
|
<a-form-model>
|
||||||
<a-input-search
|
<a-form-model-item label="用户账号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||||
:style="{width:'150px',marginBottom:'15px'}"
|
<a-row type="flex" :gutter="8">
|
||||||
placeholder="请输入账号"
|
<a-col :span="18">
|
||||||
v-model="queryParam.username"
|
<a-input-search
|
||||||
@search="onSearch"
|
:style="{width:'100%'}"
|
||||||
></a-input-search>
|
placeholder="请输入账号"
|
||||||
<a-button @click="searchReset(1)" style="margin-left: 20px" icon="redo">重置</a-button>
|
v-model="queryParam.username"
|
||||||
|
@search="onSearch"
|
||||||
|
></a-input-search>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-button @click="searchReset(1)" icon="redo">重置</a-button>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form-model-item>
|
||||||
|
</a-form-model>
|
||||||
<!--用户列表-->
|
<!--用户列表-->
|
||||||
<a-table
|
<a-table
|
||||||
ref="table"
|
ref="table"
|
||||||
@ -55,13 +65,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {filterObj} from '@/utils/util'
|
import { pushIfNotExist, filterObj } from '@/utils/util'
|
||||||
import {queryDepartTreeList, getUserList, queryUserByDepId} from '@/api/api'
|
import {queryDepartTreeList, getUserList, queryUserByDepId, queryDepartTreeSync} from '@/api/api'
|
||||||
|
import { getAction } from '@/api/manage'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'JSelectUserByDepModal',
|
name: 'JSelectUserByDepModal',
|
||||||
components: {},
|
components: {},
|
||||||
props: ['modalWidth', 'multi', 'userIds'],
|
props: ['modalWidth', 'multi', 'userIds', 'store', 'text'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
queryParam: {
|
queryParam: {
|
||||||
@ -105,6 +116,7 @@
|
|||||||
],
|
],
|
||||||
scrollTrigger: {},
|
scrollTrigger: {},
|
||||||
dataSource: [],
|
dataSource: [],
|
||||||
|
selectionRows: [],
|
||||||
selectedRowKeys: [],
|
selectedRowKeys: [],
|
||||||
selectUserRows: [],
|
selectUserRows: [],
|
||||||
selectUserIds: [],
|
selectUserIds: [],
|
||||||
@ -130,6 +142,14 @@
|
|||||||
form: this.$form.createForm(this),
|
form: this.$form.createForm(this),
|
||||||
loading: false,
|
loading: false,
|
||||||
expandedKeys: [],
|
expandedKeys: [],
|
||||||
|
labelCol: {
|
||||||
|
xs: { span: 24 },
|
||||||
|
sm: { span: 4 },
|
||||||
|
},
|
||||||
|
wrapperCol: {
|
||||||
|
xs: { span: 24 },
|
||||||
|
sm: { span: 10 },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -156,45 +176,43 @@
|
|||||||
if (this.userIds) {
|
if (this.userIds) {
|
||||||
// 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确
|
// 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确
|
||||||
let values = this.userIds.split(',') + ','
|
let values = this.userIds.split(',') + ','
|
||||||
getUserList({
|
let param = {[this.store]: values}
|
||||||
username: values,
|
getAction('/sys/user/getMultiUser', param).then((list)=>{
|
||||||
pageNo: 1,
|
this.selectionRows = []
|
||||||
pageSize: values.length
|
let selectedRowKeys = []
|
||||||
}).then((res) => {
|
let textArray = []
|
||||||
if (res.success) {
|
if(list && list.length>0){
|
||||||
let selectedRowKeys = []
|
for(let user of list){
|
||||||
let realNames = []
|
textArray.push(user[this.text])
|
||||||
res.result.records.forEach(user => {
|
|
||||||
realNames.push(user['realname'])
|
|
||||||
selectedRowKeys.push(user['id'])
|
selectedRowKeys.push(user['id'])
|
||||||
})
|
this.selectionRows.push(user)
|
||||||
this.selectedRowKeys = selectedRowKeys
|
}
|
||||||
this.$emit('initComp', realNames.join(','))
|
|
||||||
}
|
}
|
||||||
|
this.selectedRowKeys = selectedRowKeys
|
||||||
|
this.$emit('initComp', textArray.join(','))
|
||||||
})
|
})
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// JSelectUserByDep组件bug issues/I16634
|
// JSelectUserByDep组件bug issues/I16634
|
||||||
this.$emit('initComp', '')
|
this.$emit('initComp', '')
|
||||||
|
// 前端用户选择单选无法置空的问题 #2610
|
||||||
|
this.selectedRowKeys = []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async loadData(arg) {
|
async loadData(arg) {
|
||||||
if (arg === 1) {
|
if (arg === 1) {
|
||||||
this.ipagination.current = 1;
|
this.ipagination.current = 1;
|
||||||
}
|
}
|
||||||
if (this.selectedDepIds && this.selectedDepIds.length > 0) {
|
let params = this.getQueryParams()//查询条件
|
||||||
await this.initQueryUserByDepId(this.selectedDepIds)
|
this.loading = true
|
||||||
} else {
|
getAction('/sys/user/queryUserComponentData', params).then(res=>{
|
||||||
this.loading = true
|
if (res.success) {
|
||||||
let params = this.getQueryParams()//查询条件
|
this.dataSource = res.result.records
|
||||||
await getUserList(params).then((res) => {
|
this.ipagination.total = res.result.total
|
||||||
if (res.success) {
|
}
|
||||||
this.dataSource = res.result.records
|
}).finally(() => {
|
||||||
this.ipagination.total = res.result.total
|
this.loading = false
|
||||||
}
|
})
|
||||||
}).finally(() => {
|
|
||||||
this.loading = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
// 触发屏幕自适应
|
// 触发屏幕自适应
|
||||||
resetScreenSize() {
|
resetScreenSize() {
|
||||||
@ -217,6 +235,7 @@
|
|||||||
param.field = this.getQueryField();
|
param.field = this.getQueryField();
|
||||||
param.pageNo = this.ipagination.current;
|
param.pageNo = this.ipagination.current;
|
||||||
param.pageSize = this.ipagination.pageSize;
|
param.pageSize = this.ipagination.pageSize;
|
||||||
|
param.departId = this.selectedDepIds.join(',')
|
||||||
return filterObj(param);
|
return filterObj(param);
|
||||||
},
|
},
|
||||||
getQueryField() {
|
getQueryField() {
|
||||||
@ -228,13 +247,13 @@
|
|||||||
},
|
},
|
||||||
searchReset(num) {
|
searchReset(num) {
|
||||||
let that = this;
|
let that = this;
|
||||||
|
that.selectedRowKeys = [];
|
||||||
|
that.selectUserIds = [];
|
||||||
|
that.selectedDepIds = [];
|
||||||
if (num !== 0) {
|
if (num !== 0) {
|
||||||
that.queryParam = {};
|
that.queryParam = {};
|
||||||
that.loadData(1);
|
that.loadData(1);
|
||||||
}
|
}
|
||||||
that.selectedRowKeys = [];
|
|
||||||
that.selectUserIds = [];
|
|
||||||
that.selectedDepIds = [];
|
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
this.searchReset(0);
|
this.searchReset(0);
|
||||||
@ -252,35 +271,32 @@
|
|||||||
handleSubmit() {
|
handleSubmit() {
|
||||||
let that = this;
|
let that = this;
|
||||||
this.getSelectUserRows();
|
this.getSelectUserRows();
|
||||||
that.$emit('ok', that.selectUserRows, that.selectUserIds);
|
that.$emit('ok', that.selectUserRows);
|
||||||
that.searchReset(0)
|
that.searchReset(0)
|
||||||
that.close();
|
that.close();
|
||||||
},
|
},
|
||||||
//获取选择用户信息
|
//获取选择用户信息
|
||||||
getSelectUserRows(rowId) {
|
getSelectUserRows() {
|
||||||
let dataSource = this.dataSource;
|
this.selectUserRows = []
|
||||||
let userIds = "";
|
for (let row of this.selectionRows) {
|
||||||
this.selectUserRows = [];
|
if (this.selectedRowKeys.includes(row.id)) {
|
||||||
for (let i = 0, len = dataSource.length; i < len; i++) {
|
this.selectUserRows.push(row)
|
||||||
if (this.selectedRowKeys.includes(dataSource[i].id)) {
|
|
||||||
this.selectUserRows.push(dataSource[i]);
|
|
||||||
userIds = userIds + "," + dataSource[i].username
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.selectUserIds = userIds.substring(1);
|
this.selectUserIds = this.selectUserRows.map(row => row.username).join(',')
|
||||||
},
|
},
|
||||||
// 点击树节点,筛选出对应的用户
|
// 点击树节点,筛选出对应的用户
|
||||||
onDepSelect(selectedDepIds) {
|
onDepSelect(selectedDepIds) {
|
||||||
if (selectedDepIds[0] != null) {
|
if (selectedDepIds[0] != null) {
|
||||||
this.initQueryUserByDepId(selectedDepIds); // 调用方法根据选选择的id查询用户信息
|
|
||||||
if (this.selectedDepIds[0] !== selectedDepIds[0]) {
|
if (this.selectedDepIds[0] !== selectedDepIds[0]) {
|
||||||
this.selectedDepIds = [selectedDepIds[0]];
|
this.selectedDepIds = [selectedDepIds[0]];
|
||||||
}
|
}
|
||||||
|
this.loadData(1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSelectChange(selectedRowKeys, selectionRows) {
|
onSelectChange(selectedRowKeys, selectionRows) {
|
||||||
this.selectedRowKeys = selectedRowKeys;
|
this.selectedRowKeys = selectedRowKeys;
|
||||||
this.selectionRows = selectionRows;
|
selectionRows.forEach(row => pushIfNotExist(this.selectionRows, row, 'id'))
|
||||||
},
|
},
|
||||||
onSearch() {
|
onSearch() {
|
||||||
this.loadData(1);
|
this.loadData(1);
|
||||||
@ -298,14 +314,35 @@
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
queryDepartTree() {
|
queryDepartTree() {
|
||||||
queryDepartTreeList().then((res) => {
|
//update-begin-author:taoyan date:20211202 for: 异步加载部门树 https://github.com/jeecgboot/jeecg-boot/issues/3196
|
||||||
|
this.expandedKeys = []
|
||||||
|
this.departTree = []
|
||||||
|
queryDepartTreeSync().then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.departTree = res.result;
|
for (let i = 0; i < res.result.length; i++) {
|
||||||
// 默认展开父节点
|
let temp = res.result[i]
|
||||||
this.expandedKeys = this.departTree.map(item => item.id)
|
this.departTree.push(temp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
onLoadDepartment(treeNode){
|
||||||
|
return new Promise(resolve => {
|
||||||
|
queryDepartTreeSync({pid:treeNode.dataRef.id}).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
//判断chidlren是否为空,并修改isLeaf属性值
|
||||||
|
if(res.result.length == 0){
|
||||||
|
treeNode.dataRef['isLeaf']=true
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
treeNode.dataRef['children']= res.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//update-end-author:taoyan date:20211202 for: 异步加载部门树 https://github.com/jeecgboot/jeecg-boot/issues/3196
|
||||||
modalFormOk() {
|
modalFormOk() {
|
||||||
this.loadData();
|
this.loadData();
|
||||||
}
|
}
|
||||||
@ -326,4 +363,4 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color .3s;
|
transition: color .3s;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -0,0 +1,214 @@
|
|||||||
|
<template>
|
||||||
|
<span v-if="syncToApp || syncToLocal">
|
||||||
|
<j-third-app-dropdown v-if="enabledTypes.wechatEnterprise" type="wechatEnterprise" name="企微" v-bind="bindAttrs" v-on="bindEvents"/>
|
||||||
|
<j-third-app-dropdown v-if="enabledTypes.dingtalk" type="dingtalk" name="钉钉" v-bind="bindAttrs" v-on="bindEvents"/>
|
||||||
|
</span>
|
||||||
|
<span v-else>未设置任何同步方向</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getAction } from '@/api/manage'
|
||||||
|
import { cloneObject } from '@/utils/util'
|
||||||
|
import JThirdAppDropdown from './JThirdAppDropdown'
|
||||||
|
|
||||||
|
const backEndUrl = {
|
||||||
|
// 获取启用的第三方App
|
||||||
|
getEnabledType: '/sys/thirdApp/getEnabledType',
|
||||||
|
// 企业微信
|
||||||
|
wechatEnterprise: {
|
||||||
|
user: '/sys/thirdApp/sync/wechatEnterprise/user',
|
||||||
|
depart: '/sys/thirdApp/sync/wechatEnterprise/depart',
|
||||||
|
},
|
||||||
|
// 钉钉
|
||||||
|
dingtalk: {
|
||||||
|
user: '/sys/thirdApp/sync/dingtalk/user',
|
||||||
|
depart: '/sys/thirdApp/sync/dingtalk/depart',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JThirdAppButton',
|
||||||
|
components: {JThirdAppDropdown},
|
||||||
|
props: {
|
||||||
|
// 同步类型,可以是 user、depart
|
||||||
|
bizType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
// 是否允许同步到第三方APP
|
||||||
|
syncToApp: Boolean,
|
||||||
|
// 是否允许第三方APP同步到本地
|
||||||
|
syncToLocal: Boolean,
|
||||||
|
// 选择的行
|
||||||
|
selectedRowKeys: Array,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
enabledTypes: {},
|
||||||
|
attrs: {
|
||||||
|
dingtalk: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
bindAttrs() {
|
||||||
|
return {
|
||||||
|
syncToApp: this.syncToApp,
|
||||||
|
syncToLocal: this.syncToLocal
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bindEvents() {
|
||||||
|
return {
|
||||||
|
'to-app': this.onToApp,
|
||||||
|
'to-local': this.onToLocal,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadEnabledTypes()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleMenuClick() {
|
||||||
|
console.log(arguments)
|
||||||
|
},
|
||||||
|
onToApp(e) {
|
||||||
|
this.doSync(e.type, '/toApp')
|
||||||
|
},
|
||||||
|
onToLocal(e) {
|
||||||
|
this.doSync(e.type, '/toLocal')
|
||||||
|
},
|
||||||
|
// 获取启用的第三方App
|
||||||
|
async loadEnabledTypes() {
|
||||||
|
this.enabledTypes = await loadEnabledTypes()
|
||||||
|
},
|
||||||
|
// 开始同步第三方App
|
||||||
|
doSync(type, direction) {
|
||||||
|
let urls = backEndUrl[type]
|
||||||
|
if (!(urls && urls[this.bizType])) {
|
||||||
|
console.warn('配置出错')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let url = urls[this.bizType] + direction
|
||||||
|
|
||||||
|
let selectedRowKeys = this.selectedRowKeys
|
||||||
|
let content = '确定要开始同步全部数据吗?可能花费较长时间!'
|
||||||
|
if (Array.isArray(selectedRowKeys) && selectedRowKeys.length > 0) {
|
||||||
|
content = `确定要开始同步这 ${selectedRowKeys.length} 项吗?`
|
||||||
|
} else {
|
||||||
|
selectedRowKeys = []
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let model = this.$confirm({
|
||||||
|
title: '同步',
|
||||||
|
content,
|
||||||
|
onOk: () => {
|
||||||
|
model.update({
|
||||||
|
keyboard: false,
|
||||||
|
okText: '同步中…',
|
||||||
|
cancelButtonProps: {props: {disabled: true}}
|
||||||
|
})
|
||||||
|
return getAction(url, {
|
||||||
|
ids: selectedRowKeys.join(',')
|
||||||
|
}).then(res => {
|
||||||
|
let options = null
|
||||||
|
if (res.result) {
|
||||||
|
options = {
|
||||||
|
width: 600,
|
||||||
|
title: res.message,
|
||||||
|
content: (h) => {
|
||||||
|
let nodes
|
||||||
|
let successInfo = [
|
||||||
|
`成功信息如下:`,
|
||||||
|
this.renderTextarea(h, res.result.successInfo.map((v, i) => `${i + 1}. ${v}`).join('\n')),
|
||||||
|
]
|
||||||
|
if (res.success) {
|
||||||
|
nodes = [
|
||||||
|
...successInfo,
|
||||||
|
h('br'),
|
||||||
|
`无失败信息!`,
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
nodes = [
|
||||||
|
`失败信息如下:`,
|
||||||
|
this.renderTextarea(h, res.result.failInfo.map((v, i) => `${i + 1}. ${v}`).join('\n')),
|
||||||
|
h('br'),
|
||||||
|
...successInfo,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res.success) {
|
||||||
|
if (options != null) {
|
||||||
|
this.$success(options)
|
||||||
|
} else {
|
||||||
|
this.$message.success(res.message)
|
||||||
|
}
|
||||||
|
this.$emit('sync-ok')
|
||||||
|
} else {
|
||||||
|
if (options != null) {
|
||||||
|
this.$warning(options)
|
||||||
|
} else {
|
||||||
|
this.$message.warning(res.message)
|
||||||
|
}
|
||||||
|
this.$emit('sync-error')
|
||||||
|
}
|
||||||
|
}).catch(() => model.destroy()).finally(() => {
|
||||||
|
resolve()
|
||||||
|
this.$emit('sync-finally', {
|
||||||
|
type,
|
||||||
|
direction,
|
||||||
|
isToApp: direction === '/toApp',
|
||||||
|
isToLocal: direction === '/toLocal',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
resolve()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
renderTextarea(h, value) {
|
||||||
|
return h('a-textarea', {
|
||||||
|
props: {
|
||||||
|
value: value,
|
||||||
|
readOnly: true,
|
||||||
|
autosize: {minRows: 5, maxRows: 10},
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
// 关闭textarea的自动换行,使其可以左右滚动
|
||||||
|
whiteSpace: 'pre',
|
||||||
|
overflow: 'auto',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启用了哪些第三方App(在此缓存)
|
||||||
|
let enabledTypes = null
|
||||||
|
|
||||||
|
// 获取启用的第三方App
|
||||||
|
export async function loadEnabledTypes() {
|
||||||
|
// 获取缓存
|
||||||
|
if (enabledTypes != null) {
|
||||||
|
return cloneObject(enabledTypes)
|
||||||
|
} else {
|
||||||
|
let {success, result} = await getAction(backEndUrl.getEnabledType)
|
||||||
|
if (success) {
|
||||||
|
// 在此缓存
|
||||||
|
enabledTypes = cloneObject(result)
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
console.warn('getEnabledType查询失败:', res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<a-dropdown v-if="syncToApp && syncToLocal">
|
||||||
|
<a-button type="primary" icon="sync">同步{{name}}</a-button>
|
||||||
|
<a-menu slot="overlay" @click="handleMenuClick">
|
||||||
|
<a-menu-item v-if="syncToApp" key="to-app">同步到{{name}}</a-menu-item>
|
||||||
|
<a-menu-item v-if="syncToLocal" key="to-local">同步到本地</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</a-dropdown>
|
||||||
|
<a-button v-else-if="syncToApp" type="primary" icon="sync" @click="handleMenuClick({key:'to-app'})">同步{{name}}</a-button>
|
||||||
|
<a-button v-else type="primary" icon="sync" @click="handleMenuClick({key:'to-local'})">同步{{name}}到本地</a-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
/* JThirdAppButton 的子组件,不可单独使用 */
|
||||||
|
export default {
|
||||||
|
name: 'JThirdAppDropdown',
|
||||||
|
props: {
|
||||||
|
type: String,
|
||||||
|
name: String,
|
||||||
|
syncToApp: Boolean,
|
||||||
|
syncToLocal: Boolean,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleMenuClick(event) {
|
||||||
|
this.$emit(event.key, {type: this.type})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -38,16 +38,20 @@
|
|||||||
//url = "http://www.baidu.com"
|
//url = "http://www.baidu.com"
|
||||||
console.log("------url------"+url)
|
console.log("------url------"+url)
|
||||||
if (url !== null && url !== undefined) {
|
if (url !== null && url !== undefined) {
|
||||||
this.url = url;
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//url支持通过 ${token}方式传递当前登录TOKEN
|
||||||
|
let tokenStr = "${token}";
|
||||||
|
if(url.indexOf(tokenStr)!=-1) {
|
||||||
|
let token = Vue.ls.get(ACCESS_TOKEN);
|
||||||
|
this.url = url.replace(tokenStr, token);
|
||||||
|
} else {
|
||||||
|
this.url = url
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/*update_begin author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
|
/*update_begin author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
|
||||||
if(this.$route.meta.internalOrExternal != undefined && this.$route.meta.internalOrExternal==true){
|
if(this.$route.meta.internalOrExternal != undefined && this.$route.meta.internalOrExternal==true){
|
||||||
this.closeCurrent();
|
this.closeCurrent();
|
||||||
//外部url加入token
|
|
||||||
let tokenStr = "${token}";
|
|
||||||
if(url.indexOf(tokenStr)!=-1){
|
|
||||||
let token = Vue.ls.get(ACCESS_TOKEN);
|
|
||||||
this.url = url.replace(tokenStr,token);
|
|
||||||
}
|
|
||||||
window.open(this.url);
|
window.open(this.url);
|
||||||
}
|
}
|
||||||
/*update_end author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
|
/*update_end author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
|
||||||
|
|||||||
@ -19,15 +19,18 @@
|
|||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
<div style="margin: 12px 12px 0;">
|
<div style="margin: 12px 12px 0;">
|
||||||
<transition name="page-toggle">
|
<!-- update-begin-author:taoyan date:20201221 for:此处删掉transition标签 不知道为什么加上后 页面路由切换的时候即1及菜单切到2及菜单的时候 两个菜单页面会同时出现300-500秒左右 -->
|
||||||
<keep-alive v-if="multipage">
|
<keep-alive v-if="multipage">
|
||||||
<router-view v-if="reloadFlag"/>
|
<router-view v-if="reloadFlag"/>
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<router-view v-if="reloadFlag"/>
|
<router-view v-if="reloadFlag"/>
|
||||||
</template>
|
</template>
|
||||||
</transition>
|
<!-- update-end-author:taoyan date:20201221 for:此处删掉transition标签 不知道为什么加上后 页面路由切换的时候即1及菜单切到2及菜单的时候 两个菜单页面会同时出现300-500秒左右 -->
|
||||||
</div>
|
</div>
|
||||||
|
<!-- update-begin-author:zyf date:20211129 for:qiankun 挂载子应用盒子 -->
|
||||||
|
<div id="content" class="app-view-box"></div>
|
||||||
|
<!-- update-end-author:zyf date:20211129 for: qiankun 挂载子应用盒子-->
|
||||||
</global-layout>
|
</global-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -36,9 +39,11 @@
|
|||||||
import Contextmenu from '@/components/menu/Contextmenu'
|
import Contextmenu from '@/components/menu/Contextmenu'
|
||||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||||
import { triggerWindowResizeEvent } from '@/utils/util'
|
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||||
const indexKey = '/dashboard/analysis'
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { CACHE_INCLUDED_ROUTES } from "@/store/mutation-types"
|
import { CACHE_INCLUDED_ROUTES } from '@/store/mutation-types'
|
||||||
|
import registerApps from "@/qiankun";
|
||||||
|
|
||||||
|
const indexKey = '/dashboard/analysis'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TabLayout',
|
name: 'TabLayout',
|
||||||
@ -86,18 +91,19 @@
|
|||||||
// 复制一个route对象出来,不能影响原route
|
// 复制一个route对象出来,不能影响原route
|
||||||
let currentRoute = Object.assign({}, this.$route)
|
let currentRoute = Object.assign({}, this.$route)
|
||||||
currentRoute.meta = Object.assign({}, currentRoute.meta)
|
currentRoute.meta = Object.assign({}, currentRoute.meta)
|
||||||
// update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
|
||||||
let storeKey = 'route:title:' + currentRoute.fullPath
|
|
||||||
let routeTitle = this.$ls.get(storeKey)
|
|
||||||
if (routeTitle) {
|
|
||||||
currentRoute.meta.title = routeTitle
|
|
||||||
}
|
|
||||||
// update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
|
||||||
this.pageList.push(currentRoute)
|
this.pageList.push(currentRoute)
|
||||||
this.linkList.push(currentRoute.fullPath)
|
this.linkList.push(currentRoute.fullPath)
|
||||||
this.activePage = currentRoute.fullPath
|
this.activePage = currentRoute.fullPath
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
if (process.env.VUE_APP_QIANKUN == 'true') {
|
||||||
|
//update-begin-author:zyf date:20211129 for:qiankun 注册子应用
|
||||||
|
if (!window.qiankunStarted) {
|
||||||
|
window.qiankunStarted = true;
|
||||||
|
registerApps();
|
||||||
|
}
|
||||||
|
//update-end-author:zyf date:20211129 for:qiankun 注册子应用
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route': function(newRoute) {
|
'$route': function(newRoute) {
|
||||||
@ -171,7 +177,7 @@
|
|||||||
|
|
||||||
// update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
|
// update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
|
||||||
changeTitle(title) {
|
changeTitle(title) {
|
||||||
let projectTitle = "Jeecg-Boot 企业级快速开发平台"
|
let projectTitle = "Jeecg-Boot 企业级低代码平台"
|
||||||
// 首页特殊处理
|
// 首页特殊处理
|
||||||
if (this.$route.path === indexKey) {
|
if (this.$route.path === indexKey) {
|
||||||
document.title = projectTitle
|
document.title = projectTitle
|
||||||
@ -186,7 +192,12 @@
|
|||||||
},
|
},
|
||||||
tabCallBack() {
|
tabCallBack() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
triggerWindowResizeEvent()
|
//update-begin-author:taoyan date: 20201211 for:【新版】online报错 JT-100
|
||||||
|
setTimeout(()=>{
|
||||||
|
//省市区组件里面给window绑定了个resize事件 导致切换页面的时候触发了他的resize,但是切换页面,省市区组件还没被销毁前就触发了该事件,导致控制台报错,加个延迟
|
||||||
|
triggerWindowResizeEvent()
|
||||||
|
},20)
|
||||||
|
//update-end-author:taoyan date: 20201211 for:【新版】online报错 JT-100
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
editPage(key, action) {
|
editPage(key, action) {
|
||||||
@ -220,10 +231,20 @@
|
|||||||
cacheRouterArray.splice(cacheRouterArray.findIndex(item => item === componentName), 1)
|
cacheRouterArray.splice(cacheRouterArray.findIndex(item => item === componentName), 1)
|
||||||
Vue.ls.set(CACHE_INCLUDED_ROUTES, cacheRouterArray)
|
Vue.ls.set(CACHE_INCLUDED_ROUTES, cacheRouterArray)
|
||||||
}
|
}
|
||||||
|
this.emitPageClosed(removeRoute[0])
|
||||||
}
|
}
|
||||||
//update-end--Author:scott Date:20201015 for:路由缓存问题,关闭了tab页时再打开就不刷新 #842
|
//update-end--Author:scott Date:20201015 for:路由缓存问题,关闭了tab页时再打开就不刷新 #842
|
||||||
|
|
||||||
},
|
},
|
||||||
|
// 触发 page-closed (页面关闭)全局事件
|
||||||
|
emitPageClosed(closedRoute) {
|
||||||
|
this.$root.$emit('page-closed', {
|
||||||
|
closedRoute,
|
||||||
|
pageList: this.pageList,
|
||||||
|
linkList: this.linkList,
|
||||||
|
activePage: this.activePage
|
||||||
|
})
|
||||||
|
},
|
||||||
onContextmenu(e) {
|
onContextmenu(e) {
|
||||||
const pagekey = this.getPageKey(e.target)
|
const pagekey = this.getPageKey(e.target)
|
||||||
if (pagekey !== null) {
|
if (pagekey !== null) {
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="desc">
|
<div class="desc">
|
||||||
Jeecg Boot 是中国最具影响力的 企业级 快速开发平台
|
Jeecg Boot 是中国最具影响力的 企业级 低代码平台
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user