Commit 92144cb12cd6c6ded273ab1a437585084511249f

Authored by zhangdaihao
1 parent 2a8cd2d0

Jeecg-Boot V2.0版本 正式发布

Showing 820 changed files with 87569 additions and 21965 deletions

Too many changes to show.

To preserve performance only 43 of 820 files are displayed.

README.md
1 Jeecg-Boot 快速开发平台(前后端分离版本) 1 Jeecg-Boot 快速开发平台(前后端分离版本)
2 =============== 2 ===============
3 3
4 -当前最新版本: 1.1(发布日期:20190415 4 +当前最新版本: 2.0.0(发布日期:20190520
5 5
6 项目介绍: 6 项目介绍:
7 ----------------------------------- 7 -----------------------------------
@@ -52,11 +52,11 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 @@ -52,11 +52,11 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤
52 ----------------------------------- 52 -----------------------------------
53 53
54 #### 后端 54 #### 后端
55 -- 基础框架:Spring Boot 2.0.3.RELEASE 55 +- 基础框架:Spring Boot 2.1.3.RELEASE
56 56
57 - 持久层框架:Mybatis-plus_3.0.6 57 - 持久层框架:Mybatis-plus_3.0.6
58 58
59 -- 安全框架:Apache Shiro 1.4.0-RC2,Jwt_3.4.1 59 +- 安全框架:Apache Shiro 1.4.0,Jwt_3.7.0
60 60
61 - 数据库连接池:阿里巴巴Druid 1.1.10 61 - 数据库连接池:阿里巴巴Druid 1.1.10
62 62
@@ -89,7 +89,7 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 @@ -89,7 +89,7 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤
89 89
90 - 依赖管理:Maven 90 - 依赖管理:Maven
91 91
92 -- 数据库:MySQL5.0 & Oracle 11g 92 +- 数据库:MySQL5.0 & Oracle 11g & Sqlserver2005
93 93
94 - 缓存:Redis 94 - 缓存:Redis
95 95
@@ -120,6 +120,7 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 @@ -120,6 +120,7 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤
120 │ ├─角色管理 120 │ ├─角色管理
121 │ ├─菜单管理 121 │ ├─菜单管理
122 │ ├─权限设置(支持按钮权限、数据权限) 122 │ ├─权限设置(支持按钮权限、数据权限)
  123 +│ ├─表单权限(控制字段禁用、隐藏)
123 │ ├─部门管理 124 │ ├─部门管理
124 │ └─字典管理 125 │ └─字典管理
125 ├─智能化功能 126 ├─智能化功能
@@ -130,11 +131,11 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 @@ -130,11 +131,11 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤
130 │ ├─高级查询器(弹窗自动组合查询条件) 131 │ ├─高级查询器(弹窗自动组合查询条件)
131 │ ├─Excel导入导出工具集成(支持单表,一对多 导入导出) 132 │ ├─Excel导入导出工具集成(支持单表,一对多 导入导出)
132 │ ├─平台移动自适应支持 133 │ ├─平台移动自适应支持
133 -├─Online在线开发  
134 -│ ├─Online在线表单(暂未开源)  
135 -│ ├─Online在线图表(暂未开源) 134 +├─Online在线开发(暂未开源)
  135 +│ ├─Online在线表单
  136 +│ ├─Online在线图表
  137 +│ ├─Online图表模板配置
136 │ ├─Online在线报表 138 │ ├─Online在线报表
137 -│ ├─消息中心(支持短信、邮件、微信推送等等)  
138 ├─系统监控 139 ├─系统监控
139 │ ├─性能扫描监控 140 │ ├─性能扫描监控
140 │ │ ├─监控 Redis 141 │ │ ├─监控 Redis
@@ -142,9 +143,11 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 @@ -142,9 +143,11 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤
142 │ │ ├─jvm 143 │ │ ├─jvm
143 │ │ ├─服务器信息 144 │ │ ├─服务器信息
144 │ │ ├─请求追踪 145 │ │ ├─请求追踪
  146 +│ │ ├─磁盘监控
145 │ ├─定时任务 147 │ ├─定时任务
146 │ ├─系统日志 148 │ ├─系统日志
147 -│ ├─数据日志(记录数据变更情况,可进行版本对比查看数据变更记录) 149 +│ ├─消息中心(支持短信、邮件、微信推送等等)
  150 +│ ├─数据日志(记录数据快照,可对比快照,查看数据变更情况)
148 │ ├─系统通知 151 │ ├─系统通知
149 │ ├─SQL监控 152 │ ├─SQL监控
150 │ ├─swagger-ui(在线接口文档) 153 │ ├─swagger-ui(在线接口文档)
@@ -166,9 +169,14 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 @@ -166,9 +169,14 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤
166 │ └─一对多TAB例子 169 │ └─一对多TAB例子
167 │ └─内嵌table例子 170 │ └─内嵌table例子
168 │ └─常用选择组件 171 │ └─常用选择组件
169 -│ └─一对多JEditable 172 +│ └─异步树table
170 │ └─接口模拟测试 173 │ └─接口模拟测试
171 │ └─一对多JEditable 174 │ └─一对多JEditable
  175 +│ └─图片拖拽排序
  176 +│ └─图片翻页
  177 +│ └─图片预览
  178 +│ └─PDF预览
  179 +│ └─分屏功能
172 │─封装通用组件 180 │─封装通用组件
173 │ ├─行编辑表格JEditableTable 181 │ ├─行编辑表格JEditableTable
174 │ └─省略显示组件 182 │ └─省略显示组件
@@ -177,7 +185,15 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 @@ -177,7 +185,15 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤
177 │ └─通用选择用户组件 185 │ └─通用选择用户组件
178 │ └─通过组织机构选择用户组件 186 │ └─通过组织机构选择用户组件
179 │ └─报表组件封装 187 │ └─报表组件封装
180 -│ └─等等组件 188 +│ └─字典组件
  189 +│ └─下拉多选组件
  190 +│ └─选人组件
  191 +│ └─选部门组件
  192 +│ └─通过部门选人组件
  193 +│ └─封装曲线、柱状图、饼状图、折线图等等报表的组件(经过封装,使用简单)
  194 +│ └─在线code编辑器
  195 +│ └─上传文件组件
  196 +│ └─等等
181 │─更多页面模板 197 │─更多页面模板
182 │ ├─各种高级表单 198 │ ├─各种高级表单
183 │ ├─各种列表效果 199 │ ├─各种列表效果
@@ -242,7 +258,7 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 @@ -242,7 +258,7 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤
242 - jdk8 258 - jdk8
243 - mysql 259 - mysql
244 - redis 260 - redis
245 -- 数据库脚步:jeecg-boot\docs\jeecg-boot_1.1.0-20190415.sql 261 +- 数据库脚步:jeecg-boot\docs\jeecg-boot-mysql.sql
246 - 默认登录账号: admin/123456 262 - 默认登录账号: admin/123456
247 263
248 264
V2.0 版本升级日志.txt 0 → 100644
  1 +版本更新日志
  2 +
  3 +1.java项目结构重构,采用maven多模块module构建
  4 +2.数据库兼容专项改造工作,支持mysql、oracle、SqlServer提供了对应脚本
  5 +3.表单权限实现(可控制字段隐藏、字段禁用)
  6 +4.数据权限完善(实现组织机构自动注入逻辑、用户拥有多部门采用选择部门登录机制 等等)
  7 +5.完善加强行编辑表格控件 JEditableTable
  8 +6.完善导出导入逻辑,采用shiro权限控制,解决获取不到登录人问题
  9 +7.封装JTreeTable组件,异步加载树列表
  10 +8.完善打印组件,支持canvas报表自适应打印
  11 +9.登陆增加验证码
  12 +10.封装共通组件:用户选择控件、部门选择组件、选择多用户排序组件等
  13 +11.消息模板支持富文本编辑器
  14 +12.添加菜单默认路由类型,智能补数据功能的bug修复
  15 +13.字典标签支持disabled属性、支持radio类型
  16 +14.监控页面重构
  17 +15.新增磁盘监控功能
  18 +16.新增在线pdf预览功能
  19 +17.新增分屏功能
  20 +18.解决用户管理新增上传图片无法修改图片的问题
  21 +19.代码生成器模板功能完善,追加注解自动生成swaagerUI接口文档
  22 +20.集成boostrap风格swaggerUI在线文档
  23 +21.重构在线定时任务,启动bug解决
  24 +22.springboot版本升级2.1.3
  25 +23.重构获取用户菜单和权限方法,通过token获取,接口更安全
  26 +24.online导入导出(一对多)完善
  27 +25.类注释不规范修改
  28 +26.升级autopoi版本,解决发布后导入路径问题
  29 +27.新增我的部门管理功能
  30 +28.首页菜单优化,支持单独滚动,上方菜单模式支持IE
  31 +29.图片预览插件
  32 +30.图片翻页功能
  33 +31.图片拖拽排序示例
  34 +32.常用组件各种封装和示例代码
  35 +33.多选checkbox组件封装
  36 +34.提供数据快照功能,记录单据每次变更内容
  37 +35.图形报表封装组件完善,提供对应的示例和文档
  38 +36.封装JCodeEditor组件,在线编码编辑器
  39 +37.封装下拉多选组件
  40 +
  41 +Issues解决清单:
  42 +
  43 +https://github.com/zhangdaiscott/jeecg-boot/issues/104
  44 +https://github.com/zhangdaiscott/jeecg-boot/issues/97
  45 +https://github.com/zhangdaiscott/jeecg-boot/issues/90
  46 +https://github.com/zhangdaiscott/jeecg-boot/issues/89
  47 +https://github.com/zhangdaiscott/jeecg-boot/issues/87
  48 +https://github.com/zhangdaiscott/jeecg-boot/issues/82
  49 +https://github.com/zhangdaiscott/jeecg-boot/issues/81
  50 +https://github.com/zhangdaiscott/jeecg-boot/issues/79
  51 +https://github.com/zhangdaiscott/jeecg-boot/issues/77
  52 +https://github.com/zhangdaiscott/jeecg-boot/issues/73
  53 +https://github.com/zhangdaiscott/jeecg-boot/issues/70
  54 +https://github.com/zhangdaiscott/jeecg-boot/issues/65
  55 +https://github.com/zhangdaiscott/jeecg-boot/issues/61
  56 +https://github.com/zhangdaiscott/jeecg-boot/issues/38
  57 +
  58 +
  59 +
  60 +
  61 +v1.1升级到v2.0 升级不兼容问题
  62 +
  63 + 1. 混入js更名
  64 + src/mixins/JEditableTableOneToManyMixin.js --rename--> JEditableTableMixin.js
  65 + 修改方案: 全文搜索JEditableTableOneToManyMixin替换为JEditableTableMixin
  66 +
  67 +
  68 + 2.excel导入逻辑
  69 + 需要设置headers参数,因为导入导出都加了shiro控制
  70 + 给<a-upload 标签加上 :headers="tokenHeader"
  71 + 3.excel导出逻辑,需要制定导出文件名字
  72 + handleExportXls('导出excel名字')
  73 +
  74 + 4. 样式冲突问题
  75 + 全文搜索ant-layout-content删除下面一段代码
  76 +
  77 + .ant-layout-content {
  78 + margin: 12px 16px 0 !important;
  79 + }
  80 +
  81 + 5.所有页面样式没有scoped的加上
  82 + <style scoped>
0 \ No newline at end of file 83 \ No newline at end of file
ant-design-jeecg-vue/.eslintignore 0 → 100644
  1 +/src
0 \ No newline at end of file 2 \ No newline at end of file
ant-design-jeecg-vue/LICENSE
1 MIT License 1 MIT License
2 2
3 -Copyright (c) 2019 jeecg-boot 3 +Copyright (c) 2019 DaiHao Zhang
4 4
5 Permission is hereby granted, free of charge, to any person obtaining a copy 5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal 6 of this software and associated documentation files (the "Software"), to deal
ant-design-jeecg-vue/README.md
1 Ant Design Jeecg Vue 1 Ant Design Jeecg Vue
2 ==== 2 ====
3 3
4 -当前最新版本: 1.1.0(发布日期:20190415 4 +当前最新版本: 2.0.0(发布日期:20190518
5 5
6 Overview 6 Overview
7 ---- 7 ----
ant-design-jeecg-vue/package.json
1 { 1 {
2 "name": "vue-antd-jeecg", 2 "name": "vue-antd-jeecg",
3 - "version": "1.1.0", 3 + "version": "2.0.0",
4 "private": true, 4 "private": true,
5 "scripts": { 5 "scripts": {
6 "serve": "vue-cli-service serve --open", 6 "serve": "vue-cli-service serve --open",
@@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
15 "ant-design-vue": "^1.3.1", 15 "ant-design-vue": "^1.3.1",
16 "apexcharts": "^3.6.5", 16 "apexcharts": "^3.6.5",
17 "axios": "^0.18.0", 17 "axios": "^0.18.0",
  18 + "clipboard": "^2.0.4",
  19 + "codemirror": "^5.46.0",
18 "dayjs": "^1.8.0", 20 "dayjs": "^1.8.0",
19 "enquire.js": "^2.1.6", 21 "enquire.js": "^2.1.6",
20 "js-cookie": "^2.2.0", 22 "js-cookie": "^2.2.0",
@@ -29,10 +31,14 @@ @@ -29,10 +31,14 @@
29 "vue-class-component": "^6.0.0", 31 "vue-class-component": "^6.0.0",
30 "vue-cropper": "^0.4.8", 32 "vue-cropper": "^0.4.8",
31 "vue-i18n": "^8.7.0", 33 "vue-i18n": "^8.7.0",
  34 + "vue-loader": "^15.7.0",
32 "vue-ls": "^3.2.0", 35 "vue-ls": "^3.2.0",
33 - "vue-print-nb-jeecg": "^1.0.5", 36 + "vue-photo-preview": "^1.1.3",
  37 + "vue-print-nb-jeecg": "^1.0.7",
34 "vue-property-decorator": "^7.3.0", 38 "vue-property-decorator": "^7.3.0",
35 "vue-router": "^3.0.1", 39 "vue-router": "^3.0.1",
  40 + "vue-splitpane": "^1.0.4",
  41 + "vuedraggable": "^2.20.0",
36 "vuex": "^3.0.1", 42 "vuex": "^3.0.1",
37 "vuex-class": "^0.3.1" 43 "vuex-class": "^0.3.1"
38 }, 44 },
ant-design-jeecg-vue/public/index.html
@@ -224,6 +224,7 @@ @@ -224,6 +224,7 @@
224 window._CONFIG = {}; 224 window._CONFIG = {};
225 window._CONFIG['domianURL'] = 'http://localhost:8080/jeecg-boot'; 225 window._CONFIG['domianURL'] = 'http://localhost:8080/jeecg-boot';
226 window._CONFIG['imgDomainURL'] = 'http://localhost:8080/jeecg-boot/sys/common/view'; 226 window._CONFIG['imgDomainURL'] = 'http://localhost:8080/jeecg-boot/sys/common/view';
  227 + window._CONFIG['pdfDomainURL'] = 'http://localhost:8080/jeecg-boot/sys/common/pdf/pdfPreviewIframe';
227 </script> 228 </script>
228 </head> 229 </head>
229 230
ant-design-jeecg-vue/src/api/api.js
@@ -5,7 +5,6 @@ import { getAction,deleteAction,putAction,postAction} from &#39;@/api/manage&#39; @@ -5,7 +5,6 @@ import { getAction,deleteAction,putAction,postAction} from &#39;@/api/manage&#39;
5 ////图片预览请求地址 5 ////图片预览请求地址
6 // const imgView = "http://localhost:8080/jeecg-boot/sys/common/view/"; 6 // const imgView = "http://localhost:8080/jeecg-boot/sys/common/view/";
7 7
8 -  
9 //角色管理 8 //角色管理
10 const addRole = (params)=>postAction("/sys/role/add",params); 9 const addRole = (params)=>postAction("/sys/role/add",params);
11 const editRole = (params)=>putAction("/sys/role/edit",params); 10 const editRole = (params)=>putAction("/sys/role/edit",params);
@@ -39,7 +38,8 @@ const queryTreeListForRole = (params)=&gt;getAction(&quot;/sys/role/queryTreeList&quot;,param @@ -39,7 +38,8 @@ const queryTreeListForRole = (params)=&gt;getAction(&quot;/sys/role/queryTreeList&quot;,param
39 const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params); 38 const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params);
40 const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params); 39 const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params);
41 const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params); 40 const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params);
42 -const queryPermissionsByUser = (params)=>getAction("/sys/permission/queryByUser",params); 41 +//const queryPermissionsByUser = (params)=>getAction("/sys/permission/queryByUser",params);
  42 +const queryPermissionsByUser = (params)=>getAction("/sys/permission/getUserPermissionByToken",params);
43 const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params); 43 const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params);
44 const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params); 44 const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params);
45 const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params); 45 const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params);
@@ -130,7 +130,7 @@ export { @@ -130,7 +130,7 @@ export {
130 queryUserByDepId, 130 queryUserByDepId,
131 queryUserRoleMap, 131 queryUserRoleMap,
132 duplicateCheck, 132 duplicateCheck,
133 - queryTreeListForRole 133 + queryTreeListForRole,
134 } 134 }
135 135
136 136
ant-design-jeecg-vue/src/assets/less/common.css renamed to ant-design-jeecg-vue/src/assets/less/common.less
1 1
2 -/*列表上方操作按钮*/ 2 +/*列表上方操作按钮区域*/
3 .ant-card-body .table-operator { 3 .ant-card-body .table-operator {
4 margin-bottom: 18px; 4 margin-bottom: 18px;
5 } 5 }
6 - 6 +/** Button按钮间距 */
  7 +.table-operator .ant-btn {
  8 + margin-right: 6px
  9 +}
7 /*列表td的padding设置 可以控制列表大小*/ 10 /*列表td的padding设置 可以控制列表大小*/
8 .ant-table-tbody .ant-table-row td { 11 .ant-table-tbody .ant-table-row td {
9 padding-top: 15px; 12 padding-top: 15px;
@@ -26,4 +29,14 @@ @@ -26,4 +29,14 @@
26 height: 90% !important; 29 height: 90% !important;
27 overflow-y: hidden 30 overflow-y: hidden
28 } 31 }
29 - 32 +/*列表中有图片的加这个样式 参考用户管理*/
  33 +.anty-img-wrap {
  34 + height: 25px;
  35 + position: relative;
  36 +}
  37 +.anty-img-wrap > img {
  38 + max-height: 100%;
  39 +}
  40 +/*列表中范围查询样式*/
  41 +.query-group-cust{width: calc(50% - 10px)}
  42 +.query-group-split-cust:before{content:"~";width: 20px;display: inline-block;text-align: center}
ant-design-jeecg-vue/src/assets/pdf4.jpg 0 → 100644

49.8 KB

ant-design-jeecg-vue/src/components/bpm/DynamicComponent.vue 0 → 100644
  1 +
  2 +<template>
  3 + <component ref="compModel" :is="comp" :formData="formData" v-if="comp" @ok="callBackOk" @close="callBackClose"></component>
  4 +</template>
  5 +<script>
  6 + export default {
  7 + name: 'DynamicComponent',
  8 + data () {
  9 + return {
  10 + compName: this.path
  11 + }
  12 + },
  13 + computed: {
  14 + comp: function () {
  15 + return () => import(`@/views/${this.compName}.vue`)
  16 + }
  17 + },
  18 + props: ['path','formData'],
  19 + methods: {
  20 + add () {
  21 + this.$refs.compModel.add();
  22 + },
  23 + callBackClose () {
  24 + this.$emit('close');
  25 + },
  26 + handleOk () {
  27 + this.$refs.compModel.handleOk();
  28 + },
  29 + callBackOk(){
  30 + this.$emit('ok');
  31 + this.close();
  32 + },
  33 + }
  34 + }
  35 +</script>
0 \ No newline at end of file 36 \ No newline at end of file
ant-design-jeecg-vue/src/components/bpm/FormCommonModal.vue 0 → 100644
  1 +<template>
  2 + <a-modal
  3 + :title="title"
  4 + :width="width"
  5 + :visible="visible"
  6 + :confirmLoading="confirmLoading"
  7 + @ok="handleOk"
  8 + @cancel="handleCancel"
  9 + destroyOnClose
  10 + cancelText="关闭">
  11 + <a-spin :spinning="confirmLoading">
  12 + <dynamic-component ref="dynamiclink" :path="path" :formData="formData" @ok="callBackOk" @close="callBackClose"></dynamic-component>
  13 + </a-spin>
  14 + </a-modal>
  15 +</template>
  16 +
  17 +<script>
  18 +
  19 + import DynamicComponent from "./DynamicComponent";
  20 +
  21 + export default {
  22 + name: "FormCommonModal",
  23 + props: ['path'],
  24 + components: {
  25 + DynamicComponent
  26 + },
  27 + data () {
  28 + return {
  29 + title:"操作",
  30 + width:"80%",
  31 + visible: false,
  32 + confirmLoading: false,
  33 + formData:{},
  34 + }
  35 + },
  36 + created () {
  37 + },
  38 + methods: {
  39 + add () {
  40 + this.formData =[];
  41 + this.title = "新增";
  42 + this.visible = true;
  43 + this.$refs.dynamiclink.add();
  44 + },
  45 + edit (record) {
  46 + var data = {
  47 + dataId:record.id,
  48 + }
  49 + this.formData = data;
  50 + this.visible = true;
  51 + },
  52 + callBackClose () {
  53 + this.$emit('close');
  54 + this.visible = false;
  55 + },
  56 + handleOk () {
  57 + this.$refs.dynamiclink.handleOk();
  58 + },
  59 + callBackOk(){
  60 + this.$emit('ok');
  61 + this.callBackClose();
  62 + },
  63 + handleCancel () {
  64 + this.callBackClose()
  65 + },
  66 + }
  67 + }
  68 +</script>
  69 +
  70 +<style scoped>
  71 +
  72 +</style>
0 \ No newline at end of file 73 \ No newline at end of file
ant-design-jeecg-vue/src/components/bpm/ProcNodeInfoModel.vue 0 → 100644
  1 +<template>
  2 + <a-modal
  3 + :title="title"
  4 + :width="280"
  5 + :visible="visible"
  6 + :confirmLoading="confirmLoading"
  7 + :bodyStyle ="bodyStyle"
  8 + :mask = "false"
  9 + destroyOnClose
  10 + :footer="null"
  11 + @cancel="handleCancel"
  12 + cancelText="关闭">
  13 +
  14 + <a-spin :spinning="confirmLoading">
  15 + <div style="height: 300px;overflow: hidden;overflow-y: auto;overflow-x: auto;">
  16 + <template v-for="(item, key, index) in nodeInfos">
  17 + <table class="gridtable">
  18 + <tbody>
  19 + <tr>
  20 + <th width="90">任务名称</th>
  21 + <td width="150">{{ item.taskName}}</td>
  22 + </tr>
  23 + <tr>
  24 + <th width="90">执行人</th>
  25 + <td width="150">{{ item.taskAssigneeId}}</td>
  26 + </tr>
  27 + <tr>
  28 + <th width="90">开始时间</th>
  29 + <td width="150">{{ item.taskBeginTime }}</td>
  30 + </tr>
  31 + <tr>
  32 + <th width="90">结束时间</th>
  33 + <td width="150">{{ item.taskEndTime }}</td>
  34 + </tr>
  35 + <tr>
  36 + <th width="90">耗时</th>
  37 + <td width="150">{{ item.durationStr }}</td>
  38 + </tr>
  39 + <tr>
  40 + <th width="90">意见</th>
  41 + <td width="150">{{ item.remarks }}</td>
  42 + </tr>
  43 + </tbody>
  44 + </table>
  45 + </template>
  46 + </div>
  47 + </a-spin>
  48 + </a-modal>
  49 +</template>
  50 +
  51 +<script>
  52 + import { httpAction } from '@/api/manage'
  53 + import pick from 'lodash.pick'
  54 +
  55 + export default {
  56 + name: "ProcNodeInfoModel",
  57 + data () {
  58 + return {
  59 + title:"任务审批详情",
  60 + visible: false,
  61 + bodyStyle:{
  62 + padding: "0",
  63 + },
  64 + confirmLoading: false,
  65 + validatorRules:{
  66 + },
  67 + nodeInfos:[],
  68 + }
  69 + },
  70 + created () {
  71 + },
  72 + methods: {
  73 + showInfo(record,taskId) {
  74 + this.nodeInfos = [];
  75 + for (var item of record) {
  76 + if(item.taskId == taskId){
  77 + this.nodeInfos.push(item);
  78 + }
  79 + }
  80 + this.visible = true;
  81 + },
  82 + close() {
  83 + this.nodeInfos = [];
  84 + this.visible = false;
  85 + },
  86 + handleCancel () {
  87 + this.nodeInfos = [];
  88 + this.visible = false;
  89 + },
  90 +
  91 + }
  92 + }
  93 +</script>
  94 +
  95 +<style scoped>
  96 + table.gridtable {
  97 + margin: 0 auto;
  98 + margin-top: 10px;
  99 + font-family: verdana,arial,sans-serif;
  100 + font-size:12px;
  101 + color:#333333;
  102 + border-width: 1px;
  103 + border-color: #ddd;
  104 + border-collapse: collapse;
  105 + }
  106 + table.gridtable th {
  107 + border-width: 1px;
  108 + padding: 8px;
  109 + border-style: solid;
  110 + border-color: #ddd;
  111 + background-color: #eee;
  112 + }
  113 + table.gridtable td {
  114 + border-width: 1px;
  115 + padding: 8px;
  116 + border-style: solid;
  117 + border-color: #ddd;
  118 + background-color: #ffffff;
  119 + }
  120 +</style>
0 \ No newline at end of file 121 \ No newline at end of file
ant-design-jeecg-vue/src/components/bpm/ProcessInstPicModal.vue 0 → 100644
  1 +<template>
  2 + <a-modal
  3 + :title="title"
  4 + :width="900"
  5 + :visible="visible"
  6 + :confirmLoading="confirmLoading"
  7 + @cancel="handleCancel"
  8 + :bodyStyle="bodyStyle"
  9 + style="top: 50px;"
  10 + destroyOnClose
  11 + :footer="null"
  12 + cancelText="关闭">
  13 +
  14 + <a-spin :spinning="confirmLoading">
  15 + <img :src="picUrl" alt="流程图" usemap="#planetmap"/>
  16 + <map name="planetmap">
  17 + <template v-for="(item, key, index) in nodePositionInfo.positionList">
  18 + <area shape="rect" :coords="item.coords" title="Venus" @mouseover="showNodeInfo(nodePositionInfo.hisTasks,item.id)">
  19 + </template>
  20 + </map>
  21 + </a-spin>
  22 + <proc-node-info-model ref="nodeInfoModel"></proc-node-info-model>
  23 + </a-modal>
  24 +</template>
  25 +
  26 +<script>
  27 + import { getAction } from '@/api/manage'
  28 + import qs from 'qs';
  29 + import ProcNodeInfoModel from "./ProcNodeInfoModel.vue";
  30 +
  31 + export default {
  32 + components: {ProcNodeInfoModel},
  33 + name: "ProcessInstPicModal",
  34 + data () {
  35 + return {
  36 + title:"操作",
  37 + visible: false,
  38 + nodePositionInfo:{},
  39 + model: {},
  40 + labelCol: {
  41 + xs: { span: 24 },
  42 + sm: { span: 5 },
  43 + },
  44 + wrapperCol: {
  45 + xs: { span: 24 },
  46 + sm: { span: 16 },
  47 + },
  48 + bodyStyle:{
  49 + "overflow-y":"auto",
  50 + "overflow-x":"auto",
  51 + height:(window.innerHeight-280)+"px",
  52 + },
  53 + confirmLoading: false,
  54 + picUrl:"",
  55 + url: {
  56 + getProcessInfo: "/process/extActFlowData/getProcessInfo",
  57 + getNodePositionInfo:"/act/task/getNodePositionInfo",
  58 + },
  59 + }
  60 + },
  61 + created () {
  62 + },
  63 + methods: {
  64 + preview(flowCode,dataId){
  65 + this.visible = true;
  66 + var params = {
  67 + flowCode:flowCode,
  68 + dataId:dataId
  69 + };//查询条件
  70 + this.confirmLoading = true;
  71 + getAction(this.url.getProcessInfo,params).then((res)=>{
  72 + if(res.success){
  73 + var processInstanceId = res.result.processInstanceId;
  74 + this.picUrl = this.getResourceURL(processInstanceId);
  75 + this.getNodePositionInfoData(processInstanceId);
  76 + console.log("---流程图----",this.picUrl)
  77 + }else{
  78 + this.$message.warning(res.message);
  79 + }
  80 + }).catch(e => {
  81 + console.error(e)
  82 + }).then(() => {
  83 + this.confirmLoading = false;
  84 + })
  85 +
  86 +
  87 + },
  88 + close () {
  89 + this.$emit('close');
  90 + this.visible = false;
  91 + },
  92 + handleCancel () {
  93 + this.close()
  94 + },
  95 + // 获取静态资源访问地址
  96 + getResourceURL(processInstanceId) {
  97 + var params = qs.stringify({
  98 + //'token': Cookies.get('token'),
  99 + '_t': Date.parse(new Date())/1000,
  100 + 'processInstanceId': processInstanceId
  101 + })
  102 + return `${window._CONFIG['domianURL']}/act/process/processPic?${params}`
  103 + },
  104 + // 获取静态资源访问地址
  105 + getResourceURL(processInstanceId) {
  106 + var params = qs.stringify({
  107 + //'token': Cookies.get('token'),
  108 + '_t': Date.parse(new Date())/1000,
  109 + 'processInstanceId': processInstanceId
  110 + })
  111 + return `${window._CONFIG['domianURL']}/act/process/processPic?${params}`
  112 + },
  113 +
  114 + // 查询坐标信息数据
  115 + getNodePositionInfoData(processInstanceId) {
  116 + var params = {processInstanceId:processInstanceId};//查询条件
  117 + getAction(this.url.getNodePositionInfo,params).then(res => {
  118 + if (res.success) {
  119 + this.nodePositionInfo = res.result
  120 + }
  121 + }).catch(e => {
  122 + console.error(e)
  123 + }).then(() => {
  124 + })
  125 + },
  126 + showNodeInfo(data,taskId){
  127 + this.$refs.nodeInfoModel.close();
  128 + this.$refs.nodeInfoModel.showInfo(data,taskId);
  129 + },
  130 + }
  131 + }
  132 +</script>
  133 +
  134 +<style scoped>
  135 +
  136 +</style>
0 \ No newline at end of file 137 \ No newline at end of file
ant-design-jeecg-vue/src/components/chart/AreaChartTy.vue
1 <template> 1 <template>
2 - <div :style="{ padding: '0 0 32px 32px' }"> 2 + <div :style="{ padding: '0' }">
3 <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4> 3 <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
4 4
5 <v-chart ref="chart" :forceFit="true" :height="height" :data="dataSource" :scale="scale"> 5 <v-chart ref="chart" :forceFit="true" :height="height" :data="dataSource" :scale="scale">
6 - <v-tooltip/> 6 + <v-tooltip :shared="false"/>
7 <v-axis/> 7 <v-axis/>
8 - <v-line position="x*y" :size="lineSize"/>  
9 - <v-area position="x*y"/> 8 + <v-line position="x*y" :size="lineSize" :color="lineColor"/>
  9 + <v-area position="x*y" :color="color"/>
10 </v-chart> 10 </v-chart>
11 11
12 </div> 12 </div>
@@ -38,6 +38,16 @@ @@ -38,6 +38,16 @@
38 type: String, 38 type: String,
39 default: 'y' 39 default: 'y'
40 }, 40 },
  41 + // Y轴最小值
  42 + min: {
  43 + type: Number,
  44 + default: 0
  45 + },
  46 + // Y轴最大值
  47 + max: {
  48 + type: Number,
  49 + default: null
  50 + },
41 // 图表高度 51 // 图表高度
42 height: { 52 height: {
43 type: Number, 53 type: Number,
@@ -47,13 +57,23 @@ @@ -47,13 +57,23 @@
47 lineSize: { 57 lineSize: {
48 type: Number, 58 type: Number,
49 default: 2 59 default: 2
  60 + },
  61 + // 面积的颜色
  62 + color: {
  63 + type: String,
  64 + default: ''
  65 + },
  66 + // 线的颜色
  67 + lineColor: {
  68 + type: String,
  69 + default: ''
50 } 70 }
51 }, 71 },
52 computed: { 72 computed: {
53 scale() { 73 scale() {
54 return [ 74 return [
55 { dataKey: 'x', title: this.x, alias: this.x }, 75 { dataKey: 'x', title: this.x, alias: this.x },
56 - { dataKey: 'y', title: this.y, alias: this.y } 76 + { dataKey: 'y', title: this.y, alias: this.y, min: this.min, max: this.max }
57 ] 77 ]
58 } 78 }
59 }, 79 },
ant-design-jeecg-vue/src/components/chart/Bar.vue
1 <template> 1 <template>
2 <div :style="{ padding: '0 0 32px 32px' }"> 2 <div :style="{ padding: '0 0 32px 32px' }">
3 <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4> 3 <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
4 - <v-chart :forceFit="true" :height="height" :data="dataSource" :padding="padding"> 4 + <v-chart :forceFit="true" :height="height" :data="dataSource" :scale="scale" :padding="padding">
5 <v-tooltip/> 5 <v-tooltip/>
6 <v-axis/> 6 <v-axis/>
7 <v-bar position="x*y"/> 7 <v-bar position="x*y"/>
@@ -19,6 +19,10 @@ @@ -19,6 +19,10 @@
19 type: Array, 19 type: Array,
20 required: true 20 required: true
21 }, 21 },
  22 + yaxisText: {
  23 + type: String,
  24 + default: 'y'
  25 + },
22 title: { 26 title: {
23 type: String, 27 type: String,
24 default: '' 28 default: ''
@@ -31,6 +35,14 @@ @@ -31,6 +35,14 @@
31 data() { 35 data() {
32 return { padding: ['auto', 'auto', '40', '50'] } 36 return { padding: ['auto', 'auto', '40', '50'] }
33 }, 37 },
  38 + computed: {
  39 + scale() {
  40 + return [{
  41 + dataKey: 'y',
  42 + alias: this.yaxisText
  43 + }]
  44 + }
  45 + },
34 mounted() { 46 mounted() {
35 triggerWindowResizeEvent() 47 triggerWindowResizeEvent()
36 } 48 }
ant-design-jeecg-vue/src/components/chart/BarAndLine.vue 0 → 100644
  1 +<template>
  2 + <div :style="{ padding: '0 0 32px 32px' }">
  3 + <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
  4 + <v-chart :forceFit="true" :height="height" :data="data" :scale="scale">
  5 + <v-tooltip/>
  6 + <v-legend/>
  7 + <v-axis/>
  8 + <v-bar position="type*bar"/>
  9 + <v-line position="type*line" color="#2fc25b" :size="3"/>
  10 + </v-chart>
  11 + </div>
  12 +</template>
  13 +
  14 +<script>
  15 +
  16 + export default {
  17 + name: 'BarMultid',
  18 + props: {
  19 + title: {
  20 + type: String,
  21 + default: ''
  22 + },
  23 + dataSource: {
  24 + type: Array,
  25 + default: () => [
  26 + { type: '10:10', bar: 2, line: 2 },
  27 + { type: '10:15', bar: 6, line: 3 },
  28 + { type: '10:20', bar: 2, line: 5 },
  29 + { type: '10:25', bar: 9, line: 1 },
  30 + { type: '10:30', bar: 2, line: 3 },
  31 + { type: '10:35', bar: 2, line: 1 },
  32 + { type: '10:40', bar: 1, line: 2 }
  33 + ]
  34 + },
  35 + height: {
  36 + type: Number,
  37 + default: 400
  38 + }
  39 + },
  40 + data() {
  41 + return {
  42 + scale: [{
  43 + dataKey: 'bar',
  44 + min: 0
  45 + }, {
  46 + dataKey: 'line',
  47 + min: 0
  48 + }]
  49 + }
  50 + },
  51 + computed: {
  52 + data() {
  53 + return this.dataSource
  54 + }
  55 + }
  56 + }
  57 +</script>
0 \ No newline at end of file 58 \ No newline at end of file
ant-design-jeecg-vue/src/components/chart/BarMultid.vue
1 <template> 1 <template>
2 <div :style="{ padding: '0 0 32px 32px' }"> 2 <div :style="{ padding: '0 0 32px 32px' }">
3 <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4> 3 <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
4 - <v-chart :forceFit="true" :height="height" :data="data" :padding="['auto', 'auto', '40', '50']"> 4 + <v-chart :forceFit="true" :height="height" :data="data">
5 <v-tooltip /> 5 <v-tooltip />
6 <v-axis /> 6 <v-axis />
7 <v-legend /> 7 <v-legend />
@@ -13,11 +13,6 @@ @@ -13,11 +13,6 @@
13 <script> 13 <script>
14 import { DataSet } from '@antv/data-set' 14 import { DataSet } from '@antv/data-set'
15 15
16 - const sourceDataConst = [  
17 - { type: 'Jeecg', 'Jan.': 18.9, 'Feb.': 28.8, 'Mar.': 39.3, 'Apr.': 81.4, 'May': 47, 'Jun.': 20.3, 'Jul.': 24, 'Aug.': 35.6 },  
18 - { type: 'Jeebt', 'Jan.': 12.4, 'Feb.': 23.2, 'Mar.': 34.5, 'Apr.': 99.7, 'May': 52.6, 'Jun.': 35.5, 'Jul.': 37.4, 'Aug.': 42.4 }  
19 - ];  
20 - const fieldsConst = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.'];  
21 export default { 16 export default {
22 name: 'BarMultid', 17 name: 'BarMultid',
23 props: { 18 props: {
@@ -26,12 +21,15 @@ @@ -26,12 +21,15 @@
26 default: '' 21 default: ''
27 }, 22 },
28 dataSource:{ 23 dataSource:{
29 - type:Array,  
30 - default:()=>[] 24 + type: Array,
  25 + default: () => [
  26 + { type: 'Jeecg', 'Jan.': 18.9, 'Feb.': 28.8, 'Mar.': 39.3, 'Apr.': 81.4, 'May': 47, 'Jun.': 20.3, 'Jul.': 24, 'Aug.': 35.6 },
  27 + { type: 'Jeebt', 'Jan.': 12.4, 'Feb.': 23.2, 'Mar.': 34.5, 'Apr.': 99.7, 'May': 52.6, 'Jun.': 35.5, 'Jul.': 37.4, 'Aug.': 42.4 }
  28 + ]
31 }, 29 },
32 fields:{ 30 fields:{
33 - type:Array,  
34 - default:()=>[] 31 + type: Array,
  32 + default: () => ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.']
35 }, 33 },
36 height: { 34 height: {
37 type: Number, 35 type: Number,
@@ -40,35 +38,28 @@ @@ -40,35 +38,28 @@
40 }, 38 },
41 data() { 39 data() {
42 return { 40 return {
43 - data:"",  
44 adjust: [{ 41 adjust: [{
45 type: 'dodge', 42 type: 'dodge',
46 - marginRatio: 1 / 32,  
47 - }],  
48 - };  
49 - },  
50 - watch: {  
51 - 'dataSource': function () {  
52 - this.drawChart(); 43 + marginRatio: 1 / 32
  44 + }]
53 } 45 }
54 }, 46 },
55 - mounted(){  
56 - this.drawChart()  
57 - },  
58 - methods:{  
59 - drawChart(){  
60 - let temp = sourceDataConst;  
61 - if(this.dataSource && this.dataSource.length>0){  
62 - temp = this.dataSource  
63 - }  
64 - const dv = new DataSet.View().source(temp); 47 + computed: {
  48 + data() {
  49 + const dv = new DataSet.View().source(this.dataSource)
65 dv.transform({ 50 dv.transform({
66 type: 'fold', 51 type: 'fold',
67 - fields:(!this.fields||this.fields.length==0)?fieldsConst:this.fields, 52 + fields: this.fields,
68 key: 'x', 53 key: 'x',
69 - value: 'y',  
70 - });  
71 - this.data=dv.rows; 54 + value: 'y'
  55 + })
  56 +
  57 + // bar 使用不了 - 和 / 所以替换下
  58 + return dv.rows.map(row => {
  59 + row.x = row.x.replace(/[-/]/g, '_')
  60 + return row
  61 + })
  62 +
72 } 63 }
73 } 64 }
74 } 65 }
ant-design-jeecg-vue/src/components/chart/DashChartDemo.vue
1 <template> 1 <template>
2 <div :style="{ padding: '0 0 32px 32px' }"> 2 <div :style="{ padding: '0 0 32px 32px' }">
3 - <v-chart :forceFit="true" :height="height" :data="data" :scale="scale"> 3 + <v-chart :forceFit="true" :height="350" :data="chartData" :scale="scale">
4 <v-coord type="polar" :startAngle="-202.5" :endAngle="22.5" :radius="0.75"></v-coord> 4 <v-coord type="polar" :startAngle="-202.5" :endAngle="22.5" :radius="0.75"></v-coord>
5 <v-axis 5 <v-axis
6 dataKey="value" 6 dataKey="value"
@@ -45,7 +45,7 @@ @@ -45,7 +45,7 @@
45 </template> 45 </template>
46 46
47 <script> 47 <script>
48 - import {registerShape} from 'viser-vue'; 48 + import { registerShape } from 'viser-vue';
49 49
50 registerShape('point', 'pointer', { 50 registerShape('point', 'pointer', {
51 draw(cfg, container) { 51 draw(cfg, container) {
@@ -87,67 +87,64 @@ @@ -87,67 +87,64 @@
87 nice: false, 87 nice: false,
88 }]; 88 }];
89 89
90 - const sourceData = [  
91 - {value: 6.7}, 90 + const data = [
  91 + { value: 7.0 },
92 ]; 92 ];
93 93
94 export default { 94 export default {
95 - name: "DashChartDemo",  
96 - props: {  
97 - value: { 95 + name:"DashChartDemo",
  96 + props:{
  97 + datasource:{
98 type: Number, 98 type: Number,
99 - default: 6.7 99 + default:7
100 }, 100 },
101 title: { 101 title: {
102 type: String, 102 type: String,
103 default: '' 103 default: ''
104 - },  
105 - height: {  
106 - type: Number,  
107 - default: 254  
108 } 104 }
109 }, 105 },
110 - created() {  
111 - if (!this.value) {  
112 - this.data = sourceData;  
113 - } else {  
114 - this.data = [  
115 - {value: this.value}, 106 + created(){
  107 + if(!this.datasource){
  108 + this.chartData = data;
  109 + }else{
  110 + this.chartData = [
  111 + { value: this.datasource },
116 ]; 112 ];
117 } 113 }
118 - this.getData() 114 + this.getChartData()
119 }, 115 },
120 watch: { 116 watch: {
121 - 'value': function (val) {  
122 - this.data = [  
123 - {value: val}, 117 + 'datasource': function (val) {
  118 + this.chartData = [
  119 + { value: val},
124 ]; 120 ];
125 - this.getData(); 121 + this.getChartData();
126 } 122 }
127 }, 123 },
128 - methods: {  
129 - getData() {  
130 - if (this.data && this.data.length > 0) {  
131 - this.abcd = this.data[0].value * 10  
132 - } else { 124 + methods:{
  125 + getChartData(){
  126 + if(this.chartData && this.chartData.length>0){
  127 + this.abcd = this.chartData[0].value * 10
  128 + }else{
133 this.abcd = 70 129 this.abcd = 70
134 } 130 }
135 }, 131 },
136 - getHtmlGuideHtml() { 132 + getHtmlGuideHtml(){
137 return '<div style="width: 300px;text-align: center;">\n' + 133 return '<div style="width: 300px;text-align: center;">\n' +
138 - '<p style="font-size: 14px;color: #545454;margin: 0;">' + this.title + '</p>\n' +  
139 - '<p style="font-size: 36px;color: #545454;margin: 0;">' + this.abcd + '%</p>\n' + 134 + '<p style="font-size: 14px;color: #545454;margin: 0;">'+this.title+'</p>\n' +
  135 + '<p style="font-size: 36px;color: #545454;margin: 0;">'+this.abcd+'%</p>\n' +
140 '</div>' 136 '</div>'
141 }, 137 },
142 - getArcGuide2End() {  
143 - return [this.data[0].value, 0.945] 138 + getArcGuide2End(){
  139 + return [this.chartData[0].value, 0.945]
144 } 140 }
145 }, 141 },
146 data() { 142 data() {
147 return { 143 return {
148 - data: [], 144 + chartData:[],
  145 + height: 400,
149 scale: scale, 146 scale: scale,
150 - abcd: 70, 147 + abcd:70,
151 axisLabel: { 148 axisLabel: {
152 offset: -16, 149 offset: -16,
153 textStyle: { 150 textStyle: {
ant-design-jeecg-vue/src/components/chart/LineChartMultid.vue
1 <template> 1 <template>
2 <div :style="{ padding: '0 0 32px 32px' }"> 2 <div :style="{ padding: '0 0 32px 32px' }">
3 <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4> 3 <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
4 - <v-chart :force-fit="true" :height="height" :data="data" :scale="scale" :padding="['auto', 'auto', '40', '50']">  
5 - <v-tooltip />  
6 - <v-axis />  
7 - <v-legend />  
8 - <v-line position="type*y" color="x" />  
9 - <v-point position="type*y" color="x" :size="4" :v-style="style" :shape="'circle'" /> 4 + <v-chart :force-fit="true" :height="height" :data="data" :scale="scale">
  5 + <v-tooltip/>
  6 + <v-axis/>
  7 + <v-legend/>
  8 + <v-line position="type*y" color="x"/>
  9 + <v-point position="type*y" color="x" :size="4" :v-style="style" :shape="'circle'"/>
10 </v-chart> 10 </v-chart>
11 </div> 11 </div>
12 </template> 12 </template>
@@ -14,23 +14,6 @@ @@ -14,23 +14,6 @@
14 <script> 14 <script>
15 import { DataSet } from '@antv/data-set' 15 import { DataSet } from '@antv/data-set'
16 16
17 - const sourceDataConst = [  
18 - { type: 'Jan', jeecg: 7.0, jeebt: 3.9 },  
19 - { type: 'Feb', jeecg: 6.9, jeebt: 4.2 },  
20 - { type: 'Mar', jeecg: 9.5, jeebt: 5.7 },  
21 - { type: 'Apr', jeecg: 14.5, jeebt: 8.5 },  
22 - { type: 'May', jeecg: 18.4, jeebt: 11.9 },  
23 - { type: 'Jun', jeecg: 21.5, jeebt: 15.2 },  
24 - { type: 'Jul', jeecg: 25.2, jeebt: 17.0 },  
25 - { type: 'Aug', jeecg: 26.5, jeebt: 16.6 },  
26 - { type: 'Sep', jeecg: 23.3, jeebt: 14.2 },  
27 - { type: 'Oct', jeecg: 18.3, jeebt: 10.3 },  
28 - { type: 'Nov', jeecg: 13.9, jeebt: 6.6 },  
29 - { type: 'Dec', jeecg: 9.6, jeebt: 4.8 }  
30 - ];  
31 -  
32 -  
33 -  
34 export default { 17 export default {
35 name: 'LineChartMultid', 18 name: 'LineChartMultid',
36 props: { 19 props: {
@@ -38,58 +21,52 @@ @@ -38,58 +21,52 @@
38 type: String, 21 type: String,
39 default: '' 22 default: ''
40 }, 23 },
41 - dataSource:{  
42 - type:Array,  
43 - default:()=>[] 24 + dataSource: {
  25 + type: Array,
  26 + default: () => [
  27 + { type: 'Jan', jeecg: 7.0, jeebt: 3.9 },
  28 + { type: 'Feb', jeecg: 6.9, jeebt: 4.2 },
  29 + { type: 'Mar', jeecg: 9.5, jeebt: 5.7 },
  30 + { type: 'Apr', jeecg: 14.5, jeebt: 8.5 },
  31 + { type: 'May', jeecg: 18.4, jeebt: 11.9 },
  32 + { type: 'Jun', jeecg: 21.5, jeebt: 15.2 },
  33 + { type: 'Jul', jeecg: 25.2, jeebt: 17.0 },
  34 + { type: 'Aug', jeecg: 26.5, jeebt: 16.6 },
  35 + { type: 'Sep', jeecg: 23.3, jeebt: 14.2 },
  36 + { type: 'Oct', jeecg: 18.3, jeebt: 10.3 },
  37 + { type: 'Nov', jeecg: 13.9, jeebt: 6.6 },
  38 + { type: 'Dec', jeecg: 9.6, jeebt: 4.8 }
  39 + ]
44 }, 40 },
45 - fields:{  
46 - type:Array, 41 + fields: {
  42 + type: Array,
47 default: () => ['jeecg', 'jeebt'] 43 default: () => ['jeecg', 'jeebt']
48 }, 44 },
49 - height:{  
50 - type:Number,  
51 - default:254 45 + height: {
  46 + type: Number,
  47 + default: 254
52 } 48 }
53 }, 49 },
54 data() { 50 data() {
55 return { 51 return {
56 - data:"",  
57 scale: [{ 52 scale: [{
58 dataKey: 'x', 53 dataKey: 'x',
59 min: 0, 54 min: 0,
60 max: 1 55 max: 1
61 }], 56 }],
62 - style: { stroke: '#fff', lineWidth: 1 },  
63 - };  
64 - },  
65 - watch: {  
66 - 'dataSource': function () {  
67 - this.drawChart(); 57 + style: { stroke: '#fff', lineWidth: 1 }
68 } 58 }
69 }, 59 },
70 - mounted(){  
71 - this.drawChart()  
72 - },  
73 - methods:{  
74 - drawChart(){  
75 - let temp = sourceDataConst;  
76 - if (this.dataSource && this.dataSource.length > 0) {  
77 - temp = this.dataSource.map(item => {  
78 - // 为了防止直接修改源数据导致报错  
79 - let obj = Object.assign({}, item)  
80 - obj.type = obj.x  
81 - return obj  
82 - })  
83 - }  
84 - const dv = new DataSet.View().source(temp); 60 + computed: {
  61 + data() {
  62 + const dv = new DataSet.View().source(this.dataSource)
85 dv.transform({ 63 dv.transform({
86 type: 'fold', 64 type: 'fold',
87 fields: this.fields, 65 fields: this.fields,
88 key: 'x', 66 key: 'x',
89 - value: 'y',  
90 - });  
91 -  
92 - this.data=dv.rows; 67 + value: 'y'
  68 + })
  69 + return dv.rows
93 } 70 }
94 } 71 }
95 } 72 }
ant-design-jeecg-vue/src/components/chart/Pie.vue
@@ -11,20 +11,6 @@ @@ -11,20 +11,6 @@
11 <script> 11 <script>
12 const DataSet = require('@antv/data-set') 12 const DataSet = require('@antv/data-set')
13 13
14 - const sourceData = [  
15 - { item: '事例一', percent: 40 },  
16 - { item: '事例二', percent: 21 },  
17 - { item: '事例三', percent: 17 },  
18 - { item: '事例四', percent: 13 },  
19 - { item: '事例五', percent: 9 }  
20 - ]  
21 -  
22 - const scale = [{  
23 - dataKey: 'percent',  
24 - min: 0,  
25 - formatter: '.0%'  
26 - }]  
27 -  
28 export default { 14 export default {
29 props: { 15 props: {
30 title: { 16 title: {
@@ -37,37 +23,22 @@ @@ -37,37 +23,22 @@
37 }, 23 },
38 dataSource: { 24 dataSource: {
39 type: Array, 25 type: Array,
40 - default: () => []  
41 - }  
42 - },  
43 - created() {  
44 - this.change()  
45 - },  
46 - watch: {  
47 - 'dataSource': function() {  
48 - this.change()  
49 - }  
50 - },  
51 - methods: {  
52 - change() {  
53 - if (this.dataSource.length === 0) {  
54 - this.data = sourceData  
55 - } else {  
56 - const dv = new DataSet.View().source(this.dataSource)  
57 - dv.transform({  
58 - type: 'percent',  
59 - field: 'count',  
60 - dimension: 'item',  
61 - as: 'percent'  
62 - })  
63 - this.data = dv.rows  
64 - } 26 + default: () => [
  27 + { item: '示例一', count: 40 },
  28 + { item: '示例二', count: 21 },
  29 + { item: '示例三', count: 17 },
  30 + { item: '示例四', count: 13 },
  31 + { item: '示例五', count: 9 }
  32 + ]
65 } 33 }
66 }, 34 },
67 data() { 35 data() {
68 return { 36 return {
69 - data: '',  
70 - scale, 37 + scale: [{
  38 + dataKey: 'percent',
  39 + min: 0,
  40 + formatter: '.0%'
  41 + }],
71 pieStyle: { 42 pieStyle: {
72 stroke: '#fff', 43 stroke: '#fff',
73 lineWidth: 1 44 lineWidth: 1
@@ -78,6 +49,19 @@ @@ -78,6 +49,19 @@
78 } 49 }
79 }] 50 }]
80 } 51 }
  52 + },
  53 + computed: {
  54 + data() {
  55 + let dv = new DataSet.View().source(this.dataSource)
  56 + // 计算数据百分比
  57 + dv.transform({
  58 + type: 'percent',
  59 + field: 'count',
  60 + dimension: 'item',
  61 + as: 'percent'
  62 + })
  63 + return dv.rows
  64 + }
81 } 65 }
82 } 66 }
83 </script> 67 </script>
84 \ No newline at end of file 68 \ No newline at end of file
ant-design-jeecg-vue/src/components/chart/README.md
@@ -35,6 +35,45 @@ import Bar from &#39;@/components/chart/Bar&#39; @@ -35,6 +35,45 @@ import Bar from &#39;@/components/chart/Bar&#39;
35 ] 35 ]
36 ``` 36 ```
37 37
  38 +##### 代码示例
  39 +
  40 +```html
  41 +<template>
  42 + <bar title="柱状图" :dataSource="dataSource" :height="420"/>
  43 +</template>
  44 +
  45 +<script>
  46 + import Bar from '@/components/chart/Bar'
  47 +
  48 + export default {
  49 + name: 'ChartDemo',
  50 + components: {
  51 + Bar
  52 + },
  53 + data() {
  54 + return {
  55 + dataSource: [
  56 + {
  57 + "x": "1月",
  58 + "y": 320
  59 + },
  60 + {
  61 + "x": "2月",
  62 + "y": 457
  63 + },
  64 + {
  65 + "x": "3月",
  66 + "y": 182
  67 + }
  68 + ]
  69 + }
  70 + }
  71 + }
  72 +</script>
  73 +
  74 +<style></style>
  75 +```
  76 +
38 ## 多列柱状图 77 ## 多列柱状图
39 78
40 ##### 引用方式 79 ##### 引用方式
ant-design-jeecg-vue/src/components/dict/JDictSelectTag.vue
1 <template> 1 <template>
2 - <a-select :placeholder="placeholder" :value="value" @change="handleInput"> 2 + <a-radio-group v-if="tagType=='radio'" @change="handleInput" :value="value" :disabled="disabled">
  3 + <a-radio v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio>
  4 + </a-radio-group>
  5 +
  6 + <a-select v-else-if="tagType=='select'" :placeholder="placeholder" :disabled="disabled" :value="value" @change="handleInput">
3 <a-select-option value="">请选择</a-select-option> 7 <a-select-option value="">请选择</a-select-option>
4 - <a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-select-option> 8 + <a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">
  9 + <span style="display: inline-block;width: 100%" :title=" item.text || item.label ">
  10 + {{ item.text || item.label }}
  11 + </span>
  12 + </a-select-option>
5 </a-select> 13 </a-select>
6 </template> 14 </template>
7 15
@@ -14,15 +22,23 @@ @@ -14,15 +22,23 @@
14 dictCode: String, 22 dictCode: String,
15 placeholder: String, 23 placeholder: String,
16 triggerChange: Boolean, 24 triggerChange: Boolean,
17 - value: String,// 1.接收一个 value prop 25 + disabled: Boolean,
  26 + value: String,
  27 + type: String
18 }, 28 },
19 data() { 29 data() {
20 return { 30 return {
21 dictOptions: [], 31 dictOptions: [],
  32 + tagType:""
22 } 33 }
23 }, 34 },
24 created() { 35 created() {
25 console.log(this.dictCode); 36 console.log(this.dictCode);
  37 + if(!this.type || this.type==="list"){
  38 + this.tagType = "select"
  39 + }else{
  40 + this.tagType = this.type
  41 + }
26 //获取字典数据 42 //获取字典数据
27 this.initDictData(); 43 this.initDictData();
28 }, 44 },
@@ -36,13 +52,25 @@ @@ -36,13 +52,25 @@
36 } 52 }
37 }) 53 })
38 }, 54 },
39 - handleInput(val) { 55 + handleInput(e) {
  56 + let val;
  57 + if(this.tagType=="radio"){
  58 + val = e.target.value
  59 + }else{
  60 + val = e
  61 + }
40 console.log(val); 62 console.log(val);
41 if(this.triggerChange){ 63 if(this.triggerChange){
42 this.$emit('change', val); 64 this.$emit('change', val);
43 }else{ 65 }else{
44 this.$emit('input', val); 66 this.$emit('input', val);
45 } 67 }
  68 + },
  69 + setCurrentDictOptions(dictOptions){
  70 + this.dictOptions = dictOptions
  71 + },
  72 + getCurrentDictOptions(){
  73 + return this.dictOptions
46 } 74 }
47 } 75 }
48 } 76 }
ant-design-jeecg-vue/src/components/dict/JMultiSelectTag.vue 0 → 100644
  1 +<template>
  2 + <a-checkbox-group v-if="tagType=='checkbox'" @change="onChange" :value="arrayValue" :disabled="disabled">
  3 + <a-checkbox v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text || item.label }}</a-checkbox>
  4 + </a-checkbox-group>
  5 +
  6 + <a-select
  7 + v-else-if="tagType=='select'"
  8 + :value="arrayValue"
  9 + @change="onChange"
  10 + :disabled="disabled"
  11 + mode="multiple"
  12 + :placeholder="placeholder">
  13 + <a-select-option
  14 + v-for="(item,index) in dictOptions"
  15 + :key="index"
  16 + :value="item.value">
  17 + <span style="display: inline-block;width: 100%" :title=" item.text || item.label ">
  18 + {{ item.text || item.label }}
  19 + </span>
  20 + </a-select-option>
  21 + </a-select>
  22 +
  23 +</template>
  24 +
  25 +<script>
  26 + import {ajaxGetDictItems} from '@/api/api'
  27 + export default {
  28 + name: 'JMultiSelectTag',
  29 + props: {
  30 + dictCode: String,
  31 + placeholder: String,
  32 + triggerChange: Boolean,
  33 + disabled: Boolean,
  34 + value: String,
  35 + type: String,
  36 + options:Array
  37 + },
  38 + data() {
  39 + return {
  40 + dictOptions: [],
  41 + tagType:"",
  42 + arrayValue:!this.value?[]:this.value.split(",")
  43 + }
  44 + },
  45 + created() {
  46 + if(!this.type || this.type==="list_multi"){
  47 + this.tagType = "select"
  48 + }else{
  49 + this.tagType = this.type
  50 + }
  51 + //获取字典数据
  52 + this.initDictData();
  53 + },
  54 + watch:{
  55 + value (val) {
  56 + if(!val){
  57 + this.arrayValue = []
  58 + }else{
  59 + this.arrayValue = this.value.split(",")
  60 + }
  61 + }
  62 + },
  63 + methods: {
  64 + initDictData() {
  65 + if(this.options && this.options.length>0){
  66 + this.dictOptions = [...this.options]
  67 + }else{
  68 + //根据字典Code, 初始化字典数组
  69 + ajaxGetDictItems(this.dictCode, null).then((res) => {
  70 + if (res.success) {
  71 + this.dictOptions = res.result;
  72 + }
  73 + })
  74 + }
  75 +
  76 + },
  77 + onChange (selectedValue) {
  78 + if(this.triggerChange){
  79 + this.$emit('change', selectedValue.join(","));
  80 + }else{
  81 + this.$emit('input', selectedValue.join(","));
  82 + }
  83 + },
  84 + setCurrentDictOptions(dictOptions){
  85 + this.dictOptions = dictOptions
  86 + },
  87 + getCurrentDictOptions(){
  88 + return this.dictOptions
  89 + }
  90 + }
  91 + }
  92 +</script>
ant-design-jeecg-vue/src/components/dict/JSearchSelectTag.vue 0 → 100644
  1 +<template>
  2 +
  3 + <a-select
  4 + v-if="async"
  5 + showSearch
  6 + labelInValue
  7 + @search="loadData"
  8 + :placeholder="placeholder"
  9 + v-model="selectedAsyncValue"
  10 + style="width: 100%"
  11 + :filterOption="false"
  12 + @change="handleAsyncChange"
  13 + :notFoundContent="loading ? undefined : null"
  14 + >
  15 + <a-spin v-if="loading" slot="notFoundContent" size="small"/>
  16 + <a-select-option v-for="d in options" :key="d.value" :value="d.value">{{ d.text }}</a-select-option>
  17 + </a-select>
  18 +
  19 + <a-select
  20 + v-else
  21 + showSearch
  22 + :placeholder="placeholder"
  23 + optionFilterProp="children"
  24 + style="width: 100%"
  25 + @change="handleChange"
  26 + :filterOption="filterOption"
  27 + v-model="selectedValue"
  28 + :notFoundContent="loading ? undefined : null">
  29 + <a-spin v-if="loading" slot="notFoundContent" size="small"/>
  30 + <a-select-option v-for="d in options" :key="d.value" :value="d.value">{{ d.text }}</a-select-option>
  31 + </a-select>
  32 +
  33 +</template>
  34 +
  35 +<script>
  36 + import { ajaxGetDictItems } from '@/api/api'
  37 + import debounce from 'lodash/debounce';
  38 + import { getAction } from '../../api/manage'
  39 +
  40 + export default {
  41 + name: 'JSearchSelectTag',
  42 + props:{
  43 + triggerChange: Boolean,
  44 + disabled: Boolean,
  45 + value: String,
  46 + dictCode: String,
  47 + dictOptions: Array,
  48 + async: Boolean,
  49 + placeholder:{
  50 + type:String,
  51 + default:"请选择",
  52 + required:false
  53 + }
  54 + },
  55 + data(){
  56 + this.loadData = debounce(this.loadData, 800);//消抖
  57 + this.lastLoad = 0;
  58 + return {
  59 + loading:false,
  60 + selectedValue:[],
  61 + selectedAsyncValue:[],
  62 + options: [],
  63 + }
  64 + },
  65 + created(){
  66 + this.initDictData();
  67 + },
  68 + watch:{
  69 + "value":{
  70 + immediate:true,
  71 + handler(val){
  72 + if(!val){
  73 + this.selectedValue=[]
  74 + this.selectedAsyncValue=[]
  75 + }else{
  76 + this.initSelectValue()
  77 + }
  78 + }
  79 + }
  80 + },
  81 + methods:{
  82 + initSelectValue(){
  83 + if(this.async){
  84 + if(!this.selectedAsyncValue || !this.selectedAsyncValue.key || this.selectedAsyncValue.key!=this.value){
  85 + console.log("这才请求后台")
  86 + getAction(`/sys/dict/loadDictItem/${this.dictCode}`,{key:this.value}).then(res=>{
  87 + if(res.success){
  88 + let obj = {
  89 + key:this.value,
  90 + label:res.result
  91 + }
  92 + this.selectedAsyncValue = {...obj}
  93 + }
  94 + })
  95 + }
  96 + }else{
  97 + this.selectedValue = this.value
  98 + }
  99 + },
  100 + loadData(value){
  101 + console.log("数据加载",value)
  102 + this.lastLoad +=1
  103 + const currentLoad = this.lastLoad
  104 + this.options = []
  105 + this.loading=true
  106 + // 字典code格式:table,text,code
  107 + getAction(`/sys/dict/loadDict/${this.dictCode}`,{keyword:value}).then(res=>{
  108 + this.loading=false
  109 + if(res.success){
  110 + if(currentLoad!=this.lastLoad){
  111 + return
  112 + }
  113 + this.options = res.result
  114 + console.log("我是第一个",res)
  115 + }else{
  116 + this.$message.warning(res.message)
  117 + }
  118 +
  119 + })
  120 +
  121 + },
  122 + initDictData(){
  123 + if(!this.async){
  124 + //如果字典项集合有数据
  125 + if(this.dictOptions && this.dictOptions.length>0){
  126 + this.options = [...this.dictOptions]
  127 + }else{
  128 + //根据字典Code, 初始化字典数组
  129 + ajaxGetDictItems(this.dictCode, null).then((res) => {
  130 + if (res.success) {
  131 + this.options = res.result;
  132 + }
  133 + })
  134 + }
  135 + }
  136 + },
  137 + filterOption(input, option) {
  138 + return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
  139 + },
  140 + handleChange (selectedValue) {
  141 + console.log("selectedValue",selectedValue)
  142 + this.selectedValue = selectedValue
  143 + this.callback()
  144 + },
  145 + handleAsyncChange(selectedObj){
  146 + this.selectedAsyncValue = selectedObj
  147 + this.selectedValue = selectedObj.key
  148 + this.callback()
  149 + },
  150 + callback(){
  151 + if(this.triggerChange){
  152 + this.$emit('change', this.selectedValue);
  153 + }else{
  154 + this.$emit('input', this.selectedValue);
  155 + }
  156 + },
  157 + setCurrentDictOptions(dictOptions){
  158 + this.options = dictOptions
  159 + },
  160 + getCurrentDictOptions(){
  161 + return this.options
  162 + }
  163 +
  164 + }
  165 + }
  166 +</script>
  167 +
  168 +<style scoped>
  169 +
  170 +</style>
0 \ No newline at end of file 171 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecg/JCheckbox.vue
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 required: false, 15 required: false,
16 default: false 16 default: false
17 }, 17 },
  18 + /*label value*/
18 options:{ 19 options:{
19 type: Array, 20 type: Array,
20 required: true 21 required: true
ant-design-jeecg-vue/src/components/jeecg/JCodeEditor.vue 0 → 100644
  1 +<template>
  2 + <div v-bind="fullScreenParentProps">
  3 + <a-icon v-if="fullScreen" class="full-screen-icon" type="fullscreen" @click="()=>fullCoder=!fullCoder"/>
  4 +
  5 + <div class="code-editor-cust full-screen-child">
  6 + <textarea ref="textarea"></textarea>
  7 + <span @click="nullTipClick" class="null-tip" :class="{'null-tip-hidden':hasCode}" :style="nullTipStyle">{{ placeholderShow }}</span>
  8 + <template v-if="languageChange">
  9 + <a-select v-model="mode" size="small" class="code-mode-select" @change="changeMode" placeholder="请选择主题">
  10 + <a-select-option
  11 + v-for="mode in modes"
  12 + :key="mode.value"
  13 + :value="mode.value">
  14 + {{ mode.label }}
  15 + </a-select-option>
  16 + </a-select>
  17 + </template>
  18 +
  19 + </div>
  20 + </div>
  21 +</template>
  22 +
  23 +<script type="text/ecmascript-6">
  24 + // 引入全局实例
  25 + import _CodeMirror from 'codemirror'
  26 +
  27 + // 核心样式
  28 + import 'codemirror/lib/codemirror.css'
  29 + // 引入主题后还需要在 options 中指定主题才会生效 darcula gruvbox-dark hopscotch monokai
  30 + import 'codemirror/theme/panda-syntax.css'
  31 + //提示css
  32 + import "codemirror/addon/hint/show-hint.css";
  33 +
  34 + // 需要引入具体的语法高亮库才会有对应的语法高亮效果
  35 + // codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库
  36 + // 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ,所以此处才把对应的 JS 提前引入
  37 + import 'codemirror/mode/javascript/javascript.js'
  38 + import 'codemirror/mode/css/css.js'
  39 + import 'codemirror/mode/xml/xml.js'
  40 + import 'codemirror/mode/clike/clike.js'
  41 + import 'codemirror/mode/markdown/markdown.js'
  42 + import 'codemirror/mode/python/python.js'
  43 + import 'codemirror/mode/r/r.js'
  44 + import 'codemirror/mode/shell/shell.js'
  45 + import 'codemirror/mode/sql/sql.js'
  46 + import 'codemirror/mode/swift/swift.js'
  47 + import 'codemirror/mode/vue/vue.js'
  48 +
  49 + // 尝试获取全局实例
  50 + const CodeMirror = window.CodeMirror || _CodeMirror
  51 +
  52 + export default {
  53 + name: 'JCodeEditor',
  54 + props: {
  55 + // 外部传入的内容,用于实现双向绑定
  56 + value: {
  57 + type: String,
  58 + default: ''
  59 + },
  60 + // 外部传入的语法类型
  61 + language: {
  62 + type: String,
  63 + default: null
  64 + },
  65 + languageChange:{
  66 + type: Boolean,
  67 + default:false,
  68 + required:false
  69 + },
  70 + placeholder: {
  71 + type: String,
  72 + default: null
  73 + },
  74 + // 显示行号
  75 + lineNumbers: {
  76 + type: Boolean,
  77 + default: true
  78 + },
  79 + // 是否显示全屏按钮
  80 + fullScreen: {
  81 + type: Boolean,
  82 + default: false
  83 + },
  84 + // 全屏以后的z-index
  85 + zIndex: {
  86 + type: [Number, String],
  87 + default: 999
  88 + }
  89 + },
  90 + data () {
  91 + return {
  92 + // 内部真实的内容
  93 + code: '',
  94 + hasCode:false,
  95 + // 默认的语法类型
  96 + mode: 'javascript',
  97 + // 编辑器实例
  98 + coder: null,
  99 + // 默认配置
  100 + options: {
  101 + // 缩进格式
  102 + tabSize: 2,
  103 + // 主题,对应主题库 JS 需要提前引入
  104 + theme: 'panda-syntax',
  105 + line: true,
  106 + // extraKeys: {'Ctrl': 'autocomplete'},//自定义快捷键
  107 + hintOptions: {
  108 + tables: {
  109 + users: ['name', 'score', 'birthDate'],
  110 + countries: ['name', 'population', 'size']
  111 + }
  112 + },
  113 + },
  114 + // 支持切换的语法高亮类型,对应 JS 已经提前引入
  115 + // 使用的是 MIME-TYPE ,不过作为前缀的 text/ 在后面指定时写死了
  116 + modes: [{
  117 + value: 'css',
  118 + label: 'CSS'
  119 + }, {
  120 + value: 'javascript',
  121 + label: 'Javascript'
  122 + }, {
  123 + value: 'html',
  124 + label: 'XML/HTML'
  125 + }, {
  126 + value: 'x-java',
  127 + label: 'Java'
  128 + }, {
  129 + value: 'x-objectivec',
  130 + label: 'Objective-C'
  131 + }, {
  132 + value: 'x-python',
  133 + label: 'Python'
  134 + }, {
  135 + value: 'x-rsrc',
  136 + label: 'R'
  137 + }, {
  138 + value: 'x-sh',
  139 + label: 'Shell'
  140 + }, {
  141 + value: 'x-sql',
  142 + label: 'SQL'
  143 + }, {
  144 + value: 'x-swift',
  145 + label: 'Swift'
  146 + }, {
  147 + value: 'x-vue',
  148 + label: 'Vue'
  149 + }, {
  150 + value: 'markdown',
  151 + label: 'Markdown'
  152 + }],
  153 + // code 编辑器 是否全屏
  154 + fullCoder: false
  155 + }
  156 + },
  157 + watch: {
  158 + // value: {
  159 + // immediate: false,
  160 + // handler(value) {
  161 + // this._getCoder().then(() => {
  162 + // this.coder.setValue(value)
  163 + // })
  164 + // }
  165 + // },
  166 + language: {
  167 + immediate: true,
  168 + handler(language) {
  169 + this._getCoder().then(() => {
  170 + // 尝试从父容器获取语法类型
  171 + if (language) {
  172 + // 获取具体的语法类型对象
  173 + let modeObj = this._getLanguage(language)
  174 +
  175 + // 判断父容器传入的语法是否被支持
  176 + if (modeObj) {
  177 + this.mode = modeObj.label
  178 + this.coder.setOption('mode', `text/${modeObj.value}`)
  179 + }
  180 + }
  181 + })
  182 + }
  183 + }
  184 + },
  185 + computed: {
  186 + placeholderShow() {
  187 + if (this.placeholder == null) {
  188 + return `请在此输入${this.language}代码`
  189 + } else {
  190 + return this.placeholder
  191 + }
  192 + },
  193 + nullTipStyle(){
  194 + if (this.lineNumbers) {
  195 + return { left: '36px' }
  196 + } else {
  197 + return { left: '12px' }
  198 + }
  199 + },
  200 + // coder 配置
  201 + coderOptions() {
  202 + return {
  203 + tabSize: this.options.tabSize,
  204 + theme: this.options.theme,
  205 + lineNumbers: this.lineNumbers,
  206 + line: true,
  207 + hintOptions: this.options.hintOptions
  208 + }
  209 + },
  210 + fullScreenParentProps(){
  211 + let props = {
  212 + class: ['full-screen-parent', this.fullCoder ? 'full-screen' : ''],
  213 + style: {}
  214 + }
  215 + if (this.fullCoder) {
  216 + props.style['z-index'] = this.zIndex
  217 + }
  218 + return props
  219 + }
  220 + },
  221 + mounted () {
  222 + // 初始化
  223 + this._initialize()
  224 + },
  225 + methods: {
  226 + // 初始化
  227 + _initialize () {
  228 + // 初始化编辑器实例,传入需要被实例化的文本域对象和默认配置
  229 + this.coder = CodeMirror.fromTextArea(this.$refs.textarea, this.coderOptions)
  230 + // 编辑器赋值
  231 + this.coder.setValue(this.value || this.code)
  232 + if(this.value||this.code){
  233 + this.hasCode=true
  234 + }else{
  235 + this.hasCode=false
  236 + }
  237 + // 支持双向绑定
  238 + this.coder.on('change', (coder) => {
  239 + this.code = coder.getValue()
  240 + if(this.code){
  241 + this.hasCode=true
  242 + }else{
  243 + this.hasCode=false
  244 + }
  245 + if (this.$emit) {
  246 + this.$emit('input', this.code)
  247 + }
  248 + })
  249 + this.coder.on('focus', () => {
  250 + this.hasCode=true
  251 + })
  252 + this.coder.on('blur', () => {
  253 + if(this.code){
  254 + this.hasCode=true
  255 + }else{
  256 + this.hasCode=false
  257 + }
  258 + })
  259 +
  260 + /* this.coder.on('cursorActivity',()=>{
  261 + this.coder.showHint()
  262 + })*/
  263 +
  264 + },
  265 + getCodeContent(){
  266 + return this.code
  267 + },
  268 + setCodeContent(val){
  269 + this.coder.setValue(val)
  270 + },
  271 + // 获取当前语法类型
  272 + _getLanguage (language) {
  273 + // 在支持的语法类型列表中寻找传入的语法类型
  274 + return this.modes.find((mode) => {
  275 + // 所有的值都忽略大小写,方便比较
  276 + let currentLanguage = language.toLowerCase()
  277 + let currentLabel = mode.label.toLowerCase()
  278 + let currentValue = mode.value.toLowerCase()
  279 +
  280 + // 由于真实值可能不规范,例如 java 的真实值是 x-java ,所以讲 value 和 label 同时和传入语法进行比较
  281 + return currentLabel === currentLanguage || currentValue === currentLanguage
  282 + })
  283 + },
  284 + _getCoder() {
  285 + let _this = this
  286 + return new Promise((resolve) => {
  287 + (function get() {
  288 + if (_this.coder) {
  289 + resolve(_this.coder)
  290 + } else {
  291 + setTimeout(get, 10)
  292 + }
  293 + })()
  294 + })
  295 + },
  296 + // 更改模式
  297 + changeMode (val) {
  298 + // 修改编辑器的语法配置
  299 + this.coder.setOption('mode', `text/${val}`)
  300 +
  301 + // 获取修改后的语法
  302 + let label = this._getLanguage(val).label.toLowerCase()
  303 +
  304 + // 允许父容器通过以下函数监听当前的语法值
  305 + this.$emit('language-change', label)
  306 + },
  307 + nullTipClick(){
  308 + this.coder.focus()
  309 + }
  310 + }
  311 + }
  312 +</script>
  313 +
  314 +<style lang="less">
  315 + .code-editor-cust{
  316 + flex-grow:1;
  317 + display:flex;
  318 + position:relative;
  319 + height:100%;
  320 + .CodeMirror{
  321 + flex-grow:1;
  322 + z-index:1;
  323 + .CodeMirror-code{
  324 + line-height:19px;
  325 + }
  326 +
  327 + }
  328 + .code-mode-select{
  329 + position:absolute;
  330 + z-index:2;
  331 + right:10px;
  332 + top:10px;
  333 + max-width:130px;
  334 + }
  335 + .CodeMirror{
  336 + height: auto;
  337 + min-height:100%;
  338 + }
  339 + .null-tip{
  340 + position: absolute;
  341 + top: 4px;
  342 + left: 36px;
  343 + z-index: 10;
  344 + color: #ffffffc9;
  345 + line-height: initial;
  346 + }
  347 + .null-tip-hidden{
  348 + display: none;
  349 + }
  350 + }
  351 +
  352 + /* 全屏样式 */
  353 + .full-screen-parent {
  354 + position: relative;
  355 +
  356 + .full-screen-icon {
  357 + opacity: 0;
  358 + color: black;
  359 + width: 20px;
  360 + height: 20px;
  361 + line-height: 24px;
  362 + background-color: white;
  363 + position: absolute;
  364 + top: 2px;
  365 + right: 2px;
  366 + z-index: 9;
  367 + cursor: pointer;
  368 + transition: opacity 0.3s;
  369 + }
  370 +
  371 + &:hover {
  372 + .full-screen-icon {
  373 + opacity: 1;
  374 +
  375 + &:hover {
  376 + background-color: rgba(255, 255, 255, 0.88);
  377 + }
  378 + }
  379 + }
  380 +
  381 + &.full-screen {
  382 + position: fixed;
  383 + top: 10px;
  384 + left: 10px;
  385 + width: calc(100% - 20px);
  386 + height: calc(100% - 20px);
  387 + padding: 10px;
  388 + background-color: #f5f5f5;
  389 +
  390 + .full-screen-icon {
  391 + top: 12px;
  392 + right: 12px;
  393 + }
  394 + .full-screen-child {
  395 + height: 100%;
  396 + max-height: 100%;
  397 + min-height: 100%;
  398 + }
  399 + }
  400 +
  401 + .full-screen-child {
  402 + min-height: 120px;
  403 + max-height: 320px;
  404 + }
  405 +
  406 + }
  407 +
  408 +
  409 +</style>
0 \ No newline at end of file 410 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecg/JDate.vue
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 :value="momVal" 6 :value="momVal"
7 :showTime="showTime" 7 :showTime="showTime"
8 :format="dateFormat" 8 :format="dateFormat"
  9 + :getCalendarContainer="getCalendarContainer"
9 /> 10 />
10 </template> 11 </template>
11 <script> 12 <script>
@@ -41,6 +42,10 @@ @@ -41,6 +42,10 @@
41 type: Boolean, 42 type: Boolean,
42 required: false, 43 required: false,
43 default: false 44 default: false
  45 + },
  46 + getCalendarContainer: {
  47 + type: Function,
  48 + default: () => document.body
44 } 49 }
45 }, 50 },
46 data () { 51 data () {
ant-design-jeecg-vue/src/components/jeecg/JEditableTable.vue
1 <!-- JEditableTable --> 1 <!-- JEditableTable -->
2 -<!-- @version 1.3 --> 2 +<!-- @version 1.4 -->
3 <!-- @author sjlei --> 3 <!-- @author sjlei -->
4 <template> 4 <template>
5 <a-spin :spinning="loading"> 5 <a-spin :spinning="loading">
@@ -23,8 +23,8 @@ @@ -23,8 +23,8 @@
23 23
24 <div :id="`${caseId}inputTable`" class="input-table"> 24 <div :id="`${caseId}inputTable`" class="input-table">
25 <!-- 渲染表头 --> 25 <!-- 渲染表头 -->
26 - <div class="thead">  
27 - <div class="tr"> 26 + <div class="thead" ref="thead">
  27 + <div class="tr" :style="{width: this.realTrWidth}">
28 <!-- 左侧固定td --> 28 <!-- 左侧固定td -->
29 <div v-if="rowSelection" class="td td-cb" :style="style.tdLeft"> 29 <div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
30 <!--:indeterminate="true"--> 30 <!--:indeterminate="true"-->
@@ -49,162 +49,232 @@ @@ -49,162 +49,232 @@
49 </template> 49 </template>
50 </div> 50 </div>
51 </div> 51 </div>
52 - <!-- 渲染主体 body -->  
53 - <div :id="`${caseId}tbody`" class="tbody" :style="tbodyStyle">  
54 - <!-- 扩展高度 -->  
55 - <div class="tr-expand" :style="`height:${getExpandHeight}px; z-index:${loading?'11':'9'};`"></div>  
56 - <!-- 无数据时显示 -->  
57 - <div v-if="rows.length===0" class="tr-nodata">  
58 - <span>暂无数据</span>  
59 - </div>  
60 - <!-- 动态生成tr -->  
61 - <template v-for="(row,rowIndex) in rows">  
62 - <!-- tr 只加载可见的和预加载的总共十条数据 -->  
63 - <div  
64 - v-if="  
65 - rowIndex >= parseInt(`${(scrollTop-rowHeight) / rowHeight}`) &&  
66 - (parseInt(`${scrollTop / rowHeight}`) + 9) > rowIndex  
67 - "  
68 - :id="`${caseId}tbody-tr-${rowIndex}`"  
69 - :data-idx="rowIndex"  
70 - class="tr"  
71 - :class="selectedRowIds.indexOf(row.id) !== -1 ? 'tr-checked' : ''"  
72 - :style="buildTrStyle(rowIndex)"  
73 - :key="row.id">  
74 - <!-- 左侧固定td -->  
75 - <div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">  
76 - <!-- 此 v-for 只是为了拼接 id 字符串 -->  
77 - <template v-for="(id,i) in [`${row.id}`]">  
78 - <a-checkbox  
79 - :id="id"  
80 - :key="i"  
81 - :checked="selectedRowIds.indexOf(id) !== -1"  
82 - @change="handleChangeLeftCheckbox"/>  
83 - </template>  
84 - </div>  
85 - <div v-if="rowNumber" class="td td-num" :style="style.tdLeft">  
86 - <span>{{ rowIndex+1 }}</span>  
87 - </div>  
88 - <!-- 右侧动态生成td -->  
89 - <div  
90 - class="td"  
91 - v-for="col in columns"  
92 - :key="col.key"  
93 - :style="buildTdStyle(col)">  
94 -  
95 - <!-- 此 v-for 只是为了拼接 id 字符串 -->  
96 - <template v-for="(id,i) in [`${col.key}${row.id}`]">  
97 -  
98 - <!-- native input -->  
99 - <label :key="i" v-if="col.type === formTypes.input || col.type === formTypes.inputNumber">  
100 - <a-tooltip  
101 - :id="id"  
102 - placement="top"  
103 - :title="(tooltips[id] || {}).title"  
104 - :visible="(tooltips[id] || {}).visible || false"  
105 - :autoAdjustOverflow="true">  
106 -  
107 - <input  
108 - :id="id"  
109 - v-bind="buildProps(row,col)"  
110 52
111 - :data-input-number="col.type === formTypes.inputNumber"  
112 - :placeholder="replaceProps(col, col.placeholder)"  
113 - @input="(e)=>{handleInputCommono(e.target,rowIndex,row,col)}"  
114 - @mouseover="()=>{handleMouseoverCommono(row,col)}"  
115 - @mouseout="()=>{handleMouseoutCommono(row,col)}"/> 53 + <div class="scroll-view" ref="scrollView" :style="{'max-height':maxHeight+'px'}">
116 54
117 - </a-tooltip>  
118 55
119 - </label>  
120 - <!-- checkbox -->  
121 - <template v-else-if="col.type === formTypes.checkbox"> 56 + <!-- 渲染主体 body -->
  57 + <div :id="`${caseId}tbody`" class="tbody" :style="tbodyStyle">
  58 + <!-- 扩展高度 -->
  59 + <div class="tr-expand" :style="`height:${getExpandHeight}px; z-index:${loading?'11':'9'};`"></div>
  60 + <!-- 无数据时显示 -->
  61 + <div v-if="rows.length===0" class="tr-nodata">
  62 + <span>暂无数据</span>
  63 + </div>
  64 + <!-- 动态生成tr -->
  65 + <template v-for="(row,rowIndex) in rows">
  66 + <!-- tr 只加载可见的和预加载的总共十条数据 -->
  67 + <div
  68 + v-if="
  69 + rowIndex >= parseInt(`${(scrollTop-rowHeight) / rowHeight}`) &&
  70 + (parseInt(`${scrollTop / rowHeight}`) + 9) > rowIndex
  71 + "
  72 + :id="`${caseId}tbody-tr-${rowIndex}`"
  73 + :data-idx="rowIndex"
  74 + class="tr"
  75 + :class="selectedRowIds.indexOf(row.id) !== -1 ? 'tr-checked' : ''"
  76 + :style="buildTrStyle(rowIndex)"
  77 + :key="row.id">
  78 + <!-- 左侧固定td -->
  79 + <div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
  80 + <!-- 此 v-for 只是为了拼接 id 字符串 -->
  81 + <template v-for="(id,i) in [`${row.id}`]">
122 <a-checkbox 82 <a-checkbox
123 - :key="i"  
124 :id="id" 83 :id="id"
125 - v-bind="buildProps(row,col)"  
126 - :checked="checkboxValues[id]"  
127 - @change="handleChangeCheckboxCommon"  
128 - />  
129 - </template>  
130 - <!-- select -->  
131 - <template v-else-if="col.type === formTypes.select">  
132 - <!-- select 真身 -->  
133 - <a-tooltip  
134 :key="i" 84 :key="i"
135 - :id="id"  
136 - placement="top"  
137 - :title="(tooltips[id] || {}).title"  
138 - :visible="(tooltips[id] || {}).visible || false"  
139 - :autoAdjustOverflow="true">  
140 -  
141 - <span  
142 - @mouseover="()=>{handleMouseoverCommono(row,col)}"  
143 - @mouseout="()=>{handleMouseoutCommono(row,col)}"> 85 + :checked="selectedRowIds.indexOf(id) !== -1"
  86 + @change="handleChangeLeftCheckbox"/>
  87 + </template>
  88 + </div>
  89 + <div v-if="rowNumber" class="td td-num" :style="style.tdLeft">
  90 + <span>{{ rowIndex+1 }}</span>
  91 + </div>
  92 + <!-- 右侧动态生成td -->
  93 + <div
  94 + class="td"
  95 + v-for="col in columns"
  96 + :key="col.key"
  97 + :style="buildTdStyle(col)">
  98 +
  99 + <!-- 此 v-for 只是为了拼接 id 字符串 -->
  100 + <template v-for="(id,i) in [`${col.key}${row.id}`]">
  101 +
  102 + <!-- native input -->
  103 + <label :key="i" v-if="col.type === formTypes.input || col.type === formTypes.inputNumber">
  104 + <a-tooltip
  105 + :id="id"
  106 + placement="top"
  107 + :title="(tooltips[id] || {}).title"
  108 + :visible="(tooltips[id] || {}).visible || false"
  109 + :autoAdjustOverflow="true">
144 110
145 - <a-select 111 + <input
146 :id="id" 112 :id="id"
147 - :key="i"  
148 v-bind="buildProps(row,col)" 113 v-bind="buildProps(row,col)"
149 - style="width: 100%;"  
150 - :value="selectValues[id]" 114 + :data-input-number="col.type === formTypes.inputNumber"
151 :placeholder="replaceProps(col, col.placeholder)" 115 :placeholder="replaceProps(col, col.placeholder)"
152 - @change="(v)=>handleChangeSelectCommon(v,id,row,col)"> 116 + @input="(e)=>{handleInputCommono(e.target,rowIndex,row,col)}"
  117 + @mouseover="()=>{handleMouseoverCommono(row,col)}"
  118 + @mouseout="()=>{handleMouseoutCommono(row,col)}"/>
  119 +
  120 + </a-tooltip>
153 121
154 - <template v-for="(opt,optKey) in col.options">  
155 - <a-select-option :value="opt.value" :key="optKey">{{ opt.title }}</a-select-option> 122 + </label>
  123 + <!-- checkbox -->
  124 + <template v-else-if="col.type === formTypes.checkbox">
  125 + <a-checkbox
  126 + :key="i"
  127 + :id="id"
  128 + v-bind="buildProps(row,col)"
  129 + :checked="checkboxValues[id]"
  130 + @change="(e)=>handleChangeCheckboxCommon(e,row,col)"
  131 + />
  132 + </template>
  133 + <!-- select -->
  134 + <template v-else-if="col.type === formTypes.select">
  135 + <!-- select 真身 -->
  136 + <a-tooltip
  137 + :key="i"
  138 + :id="id"
  139 + placement="top"
  140 + :title="(tooltips[id] || {}).title"
  141 + :visible="(tooltips[id] || {}).visible || false"
  142 + :autoAdjustOverflow="true">
  143 +
  144 + <span
  145 + @mouseover="()=>{handleMouseoverCommono(row,col)}"
  146 + @mouseout="()=>{handleMouseoutCommono(row,col)}">
  147 +
  148 + <a-select
  149 + :id="id"
  150 + :key="i"
  151 + v-bind="buildProps(row,col)"
  152 + style="width: 100%;"
  153 + :value="selectValues[id]"
  154 + :options="col.options"
  155 + :getPopupContainer="getParentContainer"
  156 + :placeholder="replaceProps(col, col.placeholder)"
  157 + @change="(v)=>handleChangeSelectCommon(v,id,row,col)">
  158 +
  159 + <!--<template v-for="(opt,optKey) in col.options">-->
  160 + <!--<a-select-option :value="opt.value" :key="optKey">{{ opt.title }}</a-select-option>-->
  161 + <!--</template>-->
  162 + </a-select>
  163 + </span>
  164 + </a-tooltip>
  165 + </template>
  166 + <!-- date -->
  167 + <template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime">
  168 + <a-tooltip
  169 + :key="i"
  170 + :id="id"
  171 + placement="top"
  172 + :title="(tooltips[id] || {}).title"
  173 + :visible="(tooltips[id] || {}).visible || false"
  174 + :autoAdjustOverflow="true">
  175 +
  176 + <span
  177 + @mouseover="()=>{handleMouseoverCommono(row,col)}"
  178 + @mouseout="()=>{handleMouseoutCommono(row,col)}">
  179 +
  180 + <j-date
  181 + :id="id"
  182 + :key="i"
  183 + v-bind="buildProps(row,col)"
  184 + style="width: 100%;"
  185 + :value="jdateValues[id]"
  186 + :getCalendarContainer="getParentContainer"
  187 + :placeholder="replaceProps(col, col.placeholder)"
  188 + :trigger-change="true"
  189 + :showTime="col.type === formTypes.datetime"
  190 + :dateFormat="col.type === formTypes.date? 'YYYY-MM-DD':'YYYY-MM-DD HH:mm:ss'"
  191 + @change="(v)=>handleChangeJDateCommon(v,id,row,col,col.type === formTypes.datetime)"/>
  192 +
  193 + </span>
  194 + </a-tooltip>
  195 + </template>
  196 +
  197 + <div v-else-if="col.type === formTypes.upload" :key="i">
  198 + <template v-if="uploadValues[id] != null" v-for="(file,fileKey) of [(uploadValues[id]||{})]">
  199 + <a-input
  200 + :key="fileKey"
  201 + :readOnly="true"
  202 + :value="file.name"
  203 + >
  204 +
  205 + <template slot="addonBefore" style="width: 30px">
  206 + <a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
  207 + <a-icon type="loading"/>
  208 + </a-tooltip>
  209 + <a-tooltip v-else-if="file.status==='done'" title="上传完成">
  210 + <a-icon type="check-circle" style="color:#00DB00;"/>
  211 + </a-tooltip>
  212 + <a-tooltip v-else title="上传失败">
  213 + <a-icon type="exclamation-circle" style="color:red;"/>
  214 + </a-tooltip>
156 </template> 215 </template>
157 - </a-select>  
158 - </span>  
159 - </a-tooltip>  
160 - </template>  
161 - <!-- date -->  
162 - <template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime">  
163 - <a-tooltip  
164 - :key="i"  
165 - :id="id"  
166 - placement="top"  
167 - :title="(tooltips[id] || {}).title"  
168 - :visible="(tooltips[id] || {}).visible || false"  
169 - :autoAdjustOverflow="true">  
170 216
171 - <span  
172 - @mouseover="()=>{handleMouseoverCommono(row,col)}"  
173 - @mouseout="()=>{handleMouseoutCommono(row,col)}"> 217 + <template slot="addonAfter" style="width: 30px">
  218 + <a-tooltip title="删除并重新上传">
  219 + <a-icon
  220 + v-if="file.status!=='uploading'"
  221 + type="close-circle"
  222 + style="cursor: pointer;"
  223 + @click="()=>handleClickDelFile(id)"/>
  224 + </a-tooltip>
  225 + </template>
174 226
175 - <j-date  
176 - :id="id"  
177 - :key="i"  
178 - v-bind="buildProps(row,col)"  
179 - style="width: 100%;"  
180 - :value="jdateValues[id]"  
181 - :placeholder="replaceProps(col, col.placeholder)"  
182 - :trigger-change="true"  
183 - :showTime="col.type === formTypes.datetime"  
184 - :dateFormat="col.type === formTypes.date? 'YYYY-MM-DD':'YYYY-MM-DD HH:mm:ss'"  
185 - @change="(v)=>handleChangeJDateCommon(v,id,row,col)"/> 227 + </a-input>
  228 + </template>
186 229
187 - </span>  
188 - </a-tooltip>  
189 - </template> 230 + <div :hidden="uploadValues[id] != null">
190 231
191 - <!-- else (normal) -->  
192 - <span v-else :key="i">{{ col.defaultValue }}</span>  
193 - </template> 232 + <a-upload
  233 + name="file"
  234 + :data="{'isup':1}"
  235 + :multiple="false"
  236 + :action="col.action"
  237 + :headers="uploadGetHeaders(row,col)"
  238 + :showUploadList="false"
  239 + v-bind="buildProps(row,col)"
  240 + @change="(v)=>handleChangeUpload(v,id,row,col)"
  241 + >
  242 + <a-button icon="upload">{{ col.placeholder }}</a-button>
  243 + </a-upload>
  244 + </div>
  245 +
  246 + </div>
  247 +
  248 + <div v-else-if="col.type === formTypes.slot" :key="i">
  249 + <slot
  250 + :name="col.slotName || col.key"
  251 + :text="inputValues[rowIndex][col.key]"
  252 + :column="col"
  253 + :rowId="removeCaseId(row.id)"
  254 + :getValue="()=>_getValueForSlot(row.id)"
  255 + :target="getVM()"
  256 + />
  257 + </div>
  258 +
  259 + <!-- else (normal) -->
  260 + <span v-else :key="i">{{ inputValues[rowIndex][col.key] }}</span>
  261 + </template>
  262 + </div>
194 </div> 263 </div>
195 - </div>  
196 - <!-- -- tr end -- --> 264 + <!-- -- tr end -- -->
197 265
198 - </template> 266 + </template>
199 267
200 268
  269 + </div>
201 </div> 270 </div>
202 </div> 271 </div>
203 </a-spin> 272 </a-spin>
204 </template> 273 </template>
205 274
206 <script> 275 <script>
207 - 276 + import Vue from 'vue'
  277 + import { ACCESS_TOKEN } from '@/store/mutation-types'
208 import { FormTypes, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil' 278 import { FormTypes, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil'
209 import { cloneObject, randomString } from '@/utils/util' 279 import { cloneObject, randomString } from '@/utils/util'
210 import JDate from '@/components/jeecg/JDate' 280 import JDate from '@/components/jeecg/JDate'
@@ -270,7 +340,8 @@ @@ -270,7 +340,8 @@
270 }, 340 },
271 // 存储各个div的style 341 // 存储各个div的style
272 style: { 342 style: {
273 - tbody: { left: '0px', 'max-height': '400px' }, 343 + // 'max-height': '400px'
  344 + tbody: { left: '0px' },
274 // 左侧固定td的style 345 // 左侧固定td的style
275 tdLeft: { 'min-width': '4%', 'max-width': '45px' } 346 tdLeft: { 'min-width': '4%', 'max-width': '45px' }
276 }, 347 },
@@ -288,6 +359,8 @@ @@ -288,6 +359,8 @@
288 checkboxValues: {}, 359 checkboxValues: {},
289 // 绑定 jdate 的值 360 // 绑定 jdate 的值
290 jdateValues: {}, 361 jdateValues: {},
  362 + // file 信息
  363 + uploadValues: {},
291 // 绑定左侧选择框已选择的id 364 // 绑定左侧选择框已选择的id
292 selectedRowIds: [], 365 selectedRowIds: [],
293 // 存储被删除行的id 366 // 存储被删除行的id
@@ -331,7 +404,8 @@ @@ -331,7 +404,8 @@
331 }, 404 },
332 tbodyStyle() { 405 tbodyStyle() {
333 let style = Object.assign({}, this.style.tbody) 406 let style = Object.assign({}, this.style.tbody)
334 - style['max-height'] = `${this.maxHeight}px` 407 + // style['max-height'] = `${this.maxHeight}px`
  408 + style['width'] = this.realTrWidth
335 return style 409 return style
336 }, 410 },
337 showClearSelectButton() { 411 showClearSelectButton() {
@@ -340,6 +414,30 @@ @@ -340,6 +414,30 @@
340 if (this.disabledRows.hasOwnProperty(key)) count++ 414 if (this.disabledRows.hasOwnProperty(key)) count++
341 } 415 }
342 return count > 0 416 return count > 0
  417 + },
  418 + accessToken() {
  419 + return Vue.ls.get(ACCESS_TOKEN)
  420 + },
  421 + realTrWidth() {
  422 + let calcWidth = 'calc('
  423 + this.columns.forEach((column, i) => {
  424 + let { width } = column
  425 + if (typeof width === 'number') {
  426 + calcWidth += width + 'px'
  427 + } else if (typeof width === 'string') {
  428 + calcWidth += width
  429 + } else {
  430 + calcWidth += '120px'
  431 + }
  432 +
  433 + if (i < this.columns.length - 1) {
  434 + calcWidth += ' + '
  435 + }
  436 +
  437 + })
  438 + calcWidth += ')'
  439 + console.log('calcWidth: ', calcWidth)
  440 + return calcWidth
343 } 441 }
344 }, 442 },
345 // 侦听器 443 // 侦听器
@@ -371,11 +469,35 @@ @@ -371,11 +469,35 @@
371 } 469 }
372 470
373 } else if (column.type === FormTypes.select) { 471 } else if (column.type === FormTypes.select) {
374 - selectValues[inputId] = sourceValue ? sourceValue : undefined  
375 - 472 + if (sourceValue) {
  473 + // 判断是否是多选
  474 + selectValues[inputId] = (column.props || {})['mode'] === 'multiple' ? sourceValue.split(',') : sourceValue
  475 + } else {
  476 + selectValues[inputId] = undefined
  477 + }
  478 + // 兼容 旧版本 options
  479 + if (column.options instanceof Array) {
  480 + column.options = column.options.map(item => {
  481 + if (item) {
  482 + return {
  483 + text: item.text || item.title,
  484 + title: item.text || item.title,
  485 + value: item.value
  486 + }
  487 + }
  488 + return {}
  489 + })
  490 + }
376 } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) { 491 } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
377 jdateValues[inputId] = sourceValue 492 jdateValues[inputId] = sourceValue
378 493
  494 + } else if (column.type === FormTypes.slot) {
  495 + if (sourceValue !== 0 && !sourceValue) {
  496 + value[column.key] = column.defaultValue
  497 + } else {
  498 + value[column.key] = sourceValue
  499 + }
  500 +
379 } else { 501 } else {
380 value[column.key] = sourceValue 502 value[column.key] = sourceValue
381 } 503 }
@@ -430,8 +552,22 @@ @@ -430,8 +552,22 @@
430 vm.syncScrollBar(event.target.scrollLeft) 552 vm.syncScrollBar(event.target.scrollLeft)
431 } 553 }
432 this.el.tbody.onscroll = function(event) { 554 this.el.tbody.onscroll = function(event) {
  555 + // vm.recalcTrHiddenItem(event.target.scrollTop)
  556 + }
  557 +
  558 + let { thead, scrollView } = this.$refs
  559 + scrollView.onscroll = function(event) {
  560 +
  561 + // console.log(event.target.scrollTop, ' - ', event.target.scrollLeft)
  562 +
  563 + thead.scrollLeft = event.target.scrollLeft
  564 +
  565 + // vm.recalcTrHiddenItem(event.target.scrollTop)
  566 +
433 vm.recalcTrHiddenItem(event.target.scrollTop) 567 vm.recalcTrHiddenItem(event.target.scrollTop)
  568 +
434 } 569 }
  570 +
435 }, 571 },
436 methods: { 572 methods: {
437 573
@@ -455,15 +591,16 @@ @@ -455,15 +591,16 @@
455 591
456 /** 同步滚动条状态 */ 592 /** 同步滚动条状态 */
457 syncScrollBar(scrollLeft) { 593 syncScrollBar(scrollLeft) {
458 - this.style.tbody.left = `${scrollLeft}px`  
459 - this.el.tbody.scrollLeft = scrollLeft 594 + // this.style.tbody.left = `${scrollLeft}px`
  595 + // this.el.tbody.scrollLeft = scrollLeft
460 }, 596 },
461 /** 重置滚动条位置,参数留空则滚动到上次记录的位置 */ 597 /** 重置滚动条位置,参数留空则滚动到上次记录的位置 */
462 resetScrollTop(top) { 598 resetScrollTop(top) {
  599 + let { scrollView } = this.$refs
463 if (top != null && typeof top === 'number') { 600 if (top != null && typeof top === 'number') {
464 - this.el.tbody.scrollTop = top 601 + scrollView.scrollTop = top
465 } else { 602 } else {
466 - this.el.tbody.scrollTop = this.scrollTop 603 + scrollView.scrollTop = this.scrollTop
467 } 604 }
468 }, 605 },
469 /** 重新计算需要隐藏或显示的tr */ 606 /** 重新计算需要隐藏或显示的tr */
@@ -481,16 +618,24 @@ @@ -481,16 +618,24 @@
481 }) 618 })
482 } 619 }
483 }, 620 },
  621 + /** 生成id */
  622 + generateId(rows) {
  623 + if (!(rows instanceof Array)) {
  624 + rows = this.rows || []
  625 + }
  626 + let timestamp = new Date().getTime()
  627 + return `${this.caseId}${timestamp}${rows.length}`
  628 + },
484 /** push 一条数据 */ 629 /** push 一条数据 */
485 push(record, update = true, rows) { 630 push(record, update = true, rows) {
486 if (!(rows instanceof Array)) { 631 if (!(rows instanceof Array)) {
487 rows = cloneObject(this.rows) || [] 632 rows = cloneObject(this.rows) || []
488 } 633 }
489 634
490 -  
491 if (record.id == null) { 635 if (record.id == null) {
492 - let timestamp = new Date().getTime()  
493 - record.id = `${this.caseId}${timestamp}${rows.length}` 636 + record.id = this.generateId(rows)
  637 + // let timestamp = new Date().getTime()
  638 + // record.id = `${this.caseId}${timestamp}${rows.length}`
494 } 639 }
495 if (record.id.indexOf(this.caseId) === -1) { 640 if (record.id.indexOf(this.caseId) === -1) {
496 record.id = this.caseId + record.id 641 record.id = this.caseId + record.id
@@ -524,11 +669,18 @@ @@ -524,11 +669,18 @@
524 if (selected !== 0 && !selected) { 669 if (selected !== 0 && !selected) {
525 selected = undefined 670 selected = undefined
526 } 671 }
  672 + // 判断多选
  673 + if (typeof selected === 'string' && (column.props || {})['mode'] === 'multiple') {
  674 + selected = selected.split(',')
  675 + }
527 selectValues[inputId] = recordHasValue ? record[key] : selected 676 selectValues[inputId] = recordHasValue ? record[key] : selected
528 677
529 } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) { 678 } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
530 jdateValues[inputId] = recordHasValue ? record[key] : column.defaultValue 679 jdateValues[inputId] = recordHasValue ? record[key] : column.defaultValue
531 680
  681 + } else if (column.type === FormTypes.slot) {
  682 + value[key] = recordHasValue ? record[key] : (column.defaultValue || '')
  683 +
532 } else { 684 } else {
533 value[key] = recordHasValue ? record[key] : '' 685 value[key] = recordHasValue ? record[key] : ''
534 } 686 }
@@ -568,10 +720,12 @@ @@ -568,10 +720,12 @@
568 }, 720 },
569 /** 添加一行 */ 721 /** 添加一行 */
570 add(num = 1, forceScrollToBottom = false) { 722 add(num = 1, forceScrollToBottom = false) {
571 - let timestamp = new Date().getTime() 723 + // let timestamp = new Date().getTime()
572 let rows = this.rows 724 let rows = this.rows
  725 + let row
573 for (let i = 0; i < num; i++) { 726 for (let i = 0; i < num; i++) {
574 - let row = { id: `${this.caseId}${timestamp}${rows.length}` } 727 + // row = { id: `${this.caseId}${timestamp}${rows.length}` }
  728 + row = { id: this.generateId(rows) }
575 rows = this.push(row, false, rows) 729 rows = this.push(row, false, rows)
576 } 730 }
577 this.rows = rows 731 this.rows = rows
@@ -579,6 +733,15 @@ @@ -579,6 +733,15 @@
579 this.$nextTick(() => { 733 this.$nextTick(() => {
580 this.updateFormValues() 734 this.updateFormValues()
581 }) 735 })
  736 + // 触发add事件
  737 + this.$emit('added', {
  738 + row: (() => {
  739 + let r = Object.assign({}, row)
  740 + r.id = this.removeCaseId(r.id)
  741 + return r
  742 + })(),
  743 + target: this
  744 + })
582 // 设置滚动条位置 745 // 设置滚动条位置
583 let tbody = this.el.tbody 746 let tbody = this.el.tbody
584 let offsetHeight = tbody.offsetHeight 747 let offsetHeight = tbody.offsetHeight
@@ -592,8 +755,6 @@ @@ -592,8 +755,6 @@
592 this.$nextTick(() => { 755 this.$nextTick(() => {
593 tbody.scrollTop = tbody.scrollHeight 756 tbody.scrollTop = tbody.scrollHeight
594 }) 757 })
595 - // 触发add事件  
596 - this.$emit('added')  
597 }, 758 },
598 /** 删除被选中的行 */ 759 /** 删除被选中的行 */
599 removeSelectedRows() { 760 removeSelectedRows() {
@@ -607,7 +768,7 @@ @@ -607,7 +768,7 @@
607 if (typeof id === 'string') { 768 if (typeof id === 'string') {
608 ids = [id] 769 ids = [id]
609 } else { 770 } else {
610 - throw `InputTable.removeRows() 函数需要的参数可以是string或Array类型,但提供的却是${typeof id}` 771 + throw `JEditableTable.removeRows() 函数需要的参数可以是string或Array类型,但提供的却是${typeof id}`
611 } 772 }
612 } 773 }
613 774
@@ -616,7 +777,7 @@ @@ -616,7 +777,7 @@
616 // 找到每个id对应的真实index并删除 777 // 找到每个id对应的真实index并删除
617 const findAndDelete = (arr) => { 778 const findAndDelete = (arr) => {
618 for (let i = 0; i < arr.length; i++) { 779 for (let i = 0; i < arr.length; i++) {
619 - if (arr[i].id === removeId) { 780 + if (arr[i].id === removeId || arr[i].id === this.caseId + removeId) {
620 arr.splice(i, 1) 781 arr.splice(i, 1)
621 return true 782 return true
622 } 783 }
@@ -624,24 +785,52 @@ @@ -624,24 +785,52 @@
624 } 785 }
625 // 找到rows对应的index,并删除 786 // 找到rows对应的index,并删除
626 if (findAndDelete(rows)) { 787 if (findAndDelete(rows)) {
  788 + // 找到values对应的index,并删除
  789 + findAndDelete(this.inputValues)
627 // 将caseId去除 790 // 将caseId去除
628 - this.deleteIds.push(removeId.split(this.caseId)[1]) 791 + let id = this.removeCaseId(removeId)
  792 + this.deleteIds.push(id)
629 } 793 }
630 - // 找到values对应的index,并删除  
631 - findAndDelete(this.inputValues)  
632 }) 794 })
633 this.rows = rows 795 this.rows = rows
634 this.$emit('deleted', this.getDeleteIds()) 796 this.$emit('deleted', this.getDeleteIds())
  797 + this.$nextTick(() => {
  798 + // 更新formValues
  799 + this.updateFormValues()
  800 + })
635 return true 801 return true
636 }, 802 },
637 803
638 - /** 获取表格表单里的值 */  
639 - getValues(callback, validate = true) { 804 + /** 获取表格表单里的值(同步版) */
  805 + getValuesSync(options = {}) {
  806 + let { validate, rowIds } = options
  807 + if (typeof validate !== 'boolean') validate = true
  808 + if (!(rowIds instanceof Array)) rowIds = null
  809 + // console.log('options:', { validate, rowIds })
  810 +
640 let error = 0 811 let error = 0
641 - let valueArray = cloneObject(this.inputValues) 812 + let inputValues = cloneObject(this.inputValues)
642 let tooltips = Object.assign({}, this.tooltips) 813 let tooltips = Object.assign({}, this.tooltips)
643 let notPassedIds = cloneObject(this.notPassedIds) 814 let notPassedIds = cloneObject(this.notPassedIds)
644 - valueArray.forEach(value => { 815 + // 用于存储合并后的值
  816 + let values = []
  817 + // 遍历inputValues来获取每行的值
  818 + for (let value of inputValues) {
  819 + let rowIdsFlag = false
  820 + // 如果带有rowIds,那么就只存这几行的数据
  821 + if (rowIds == null) {
  822 + rowIdsFlag = true
  823 + } else {
  824 + for (let rowId of rowIds) {
  825 + if (rowId === value.id || `${this.caseId}${rowId}` === value.id) {
  826 + rowIdsFlag = true
  827 + break
  828 + }
  829 + }
  830 + }
  831 +
  832 + if (!rowIdsFlag) continue
  833 +
645 this.columns.forEach(column => { 834 this.columns.forEach(column => {
646 let inputId = column.key + value.id 835 let inputId = column.key + value.id
647 if (column.type === FormTypes.checkbox) { 836 if (column.type === FormTypes.checkbox) {
@@ -653,46 +842,65 @@ @@ -653,46 +842,65 @@
653 } 842 }
654 843
655 } else if (column.type === FormTypes.select) { 844 } else if (column.type === FormTypes.select) {
656 - value[column.key] = this.selectValues[inputId] 845 + let selected = this.selectValues[inputId]
  846 + if (selected instanceof Array) {
  847 + value[column.key] = cloneObject(selected)
  848 + } else {
  849 + value[column.key] = selected
  850 + }
657 851
658 } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) { 852 } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
659 value[column.key] = this.jdateValues[inputId] 853 value[column.key] = this.jdateValues[inputId]
660 854
  855 + } else if (column.type === FormTypes.upload) {
  856 + value[column.key] = cloneObject(this.uploadValues[inputId] || null)
  857 +
661 } 858 }
662 // 检查表单验证 859 // 检查表单验证
663 - if (validate) { 860 + if (validate === true) {
664 let results = this.validateOneInput(value[column.key], value, column, notPassedIds, false) 861 let results = this.validateOneInput(value[column.key], value, column, notPassedIds, false)
665 tooltips[inputId] = results[0] 862 tooltips[inputId] = results[0]
666 if (tooltips[inputId].visible) { 863 if (tooltips[inputId].visible) {
667 - if (error++ === 0) {  
668 - // let element = document.getElementById(inputId)  
669 - // while (element.className !== 'tr') {  
670 - // element = element.parentElement  
671 - // }  
672 - // this.jumpToId(inputId, element)  
673 - } 864 + error++
  865 + // if (error++ === 0) {
  866 + // let element = document.getElementById(inputId)
  867 + // while (element.className !== 'tr') {
  868 + // element = element.parentElement
  869 + // }
  870 + // this.jumpToId(inputId, element)
  871 + // }
674 } 872 }
675 tooltips[inputId].visible = false 873 tooltips[inputId].visible = false
676 notPassedIds = results[1] 874 notPassedIds = results[1]
677 } 875 }
678 }) 876 })
679 // 将caseId去除 877 // 将caseId去除
680 - value.id = value.id.split(this.caseId)[1]  
681 - }) 878 + value.id = this.removeCaseId(value.id)
  879 + values.push(value)
  880 +
  881 + }
  882 +
682 this.tooltips = tooltips 883 this.tooltips = tooltips
683 this.notPassedIds = notPassedIds 884 this.notPassedIds = notPassedIds
684 - if (typeof callback === 'function') callback(error, valueArray) 885 + return { error, values }
  886 + },
  887 +
  888 + /** 获取表格表单里的值 */
  889 + getValues(callback, validate = true, rowIds) {
  890 + let result = this.getValuesSync({ validate, rowIds })
  891 + if (typeof callback === 'function') {
  892 + callback(result.error, result.values)
  893 + }
685 }, 894 },
686 /** getValues的Promise版 */ 895 /** getValues的Promise版 */
687 - getValuesPromise(validate = true) { 896 + getValuesPromise(validate = true, rowIds) {
688 return new Promise((resolve, reject) => { 897 return new Promise((resolve, reject) => {
689 - this.getValues((error, values) => {  
690 - if (error === 0) {  
691 - resolve(values)  
692 - } else {  
693 - reject(VALIDATE_NO_PASSED)  
694 - }  
695 - }, validate) 898 + let { error, values } = this.getValuesSync({ validate, rowIds })
  899 + if (error === 0) {
  900 + resolve(values)
  901 + } else {
  902 + reject(VALIDATE_NO_PASSED)
  903 + }
696 }) 904 })
697 }, 905 },
698 /** 获取被删除项的id */ 906 /** 获取被删除项的id */
@@ -710,6 +918,16 @@ @@ -710,6 +918,16 @@
710 }) 918 })
711 }) 919 })
712 }, 920 },
  921 + /** Sync 获取所有的数据,包括values、deleteIds */
  922 + getAllSync(validate, rowIds) {
  923 + let result = this.getValuesSync({ validate, rowIds })
  924 + result.deleteIds = this.getDeleteIds()
  925 + return result
  926 + },
  927 + // slot 获取值
  928 + _getValueForSlot(rowId) {
  929 + return this.getValuesSync({ rowIds: [rowId] }).values[0]
  930 + },
713 /** 设置某行某列的值 */ 931 /** 设置某行某列的值 */
714 setValues(values) { 932 setValues(values) {
715 933
@@ -722,8 +940,10 @@ @@ -722,8 +940,10 @@
722 this.inputValues.forEach(value => { 940 this.inputValues.forEach(value => {
723 // 在inputValues中找到了该字段 941 // 在inputValues中找到了该字段
724 if (`${this.caseId}${rowKey}` === value.id) { 942 if (`${this.caseId}${rowKey}` === value.id) {
725 - edited = true  
726 - value[newValueKey] = newValue 943 + if (value.hasOwnProperty(newValueKey)) {
  944 + edited = true
  945 + value[newValueKey] = newValue
  946 + }
727 } 947 }
728 }) 948 })
729 let modelKey = `${newValueKey}${this.caseId}${rowKey}` 949 let modelKey = `${newValueKey}${this.caseId}${rowKey}`
@@ -764,6 +984,7 @@ @@ -764,6 +984,7 @@
764 // console.log(this.el.tbody.scrollTop, element.offsetTop) 984 // console.log(this.el.tbody.scrollTop, element.offsetTop)
765 // } 985 // }
766 // }, 986 // },
  987 +
767 /** 验证单个表单 */ 988 /** 验证单个表单 */
768 validateOneInput(value, row, column, notPassedIds, update = false) { 989 validateOneInput(value, row, column, notPassedIds, update = false) {
769 let tooltips = Object.assign({}, this.tooltips) 990 let tooltips = Object.assign({}, this.tooltips)
@@ -934,10 +1155,13 @@ @@ -934,10 +1155,13 @@
934 /** input事件 */ 1155 /** input事件 */
935 handleInputCommono(target, index, row, column) { 1156 handleInputCommono(target, index, row, column) {
936 let { value, dataset, selectionStart } = target 1157 let { value, dataset, selectionStart } = target
937 - 1158 + let type = FormTypes.input
  1159 + let change = true
938 if (`${dataset.inputNumber}` === 'true') { 1160 if (`${dataset.inputNumber}` === 'true') {
  1161 + type = FormTypes.inputNumber
939 let replace = value.replace(/[^0-9]/g, '') 1162 let replace = value.replace(/[^0-9]/g, '')
940 if (value !== replace) { 1163 if (value !== replace) {
  1164 + change = false
941 value = replace 1165 value = replace
942 target.value = replace 1166 target.value = replace
943 if (typeof selectionStart === 'number') { 1167 if (typeof selectionStart === 'number') {
@@ -950,19 +1174,51 @@ @@ -950,19 +1174,51 @@
950 this.inputValues[index][column.key] = value 1174 this.inputValues[index][column.key] = value
951 // 做单个表单验证 1175 // 做单个表单验证
952 this.validateOneInput(value, row, column, this.notPassedIds, true) 1176 this.validateOneInput(value, row, column, this.notPassedIds, true)
  1177 +
  1178 + // 触发valueChange 事件
  1179 + if (change) {
  1180 + this.elemValueChange(type, row, column, value)
  1181 + }
953 }, 1182 },
954 - handleChangeCheckboxCommon(event) { 1183 + handleChangeCheckboxCommon(event, row, column) {
955 let { id, checked } = event.target 1184 let { id, checked } = event.target
956 this.checkboxValues = this.bindValuesChange(checked, id, 'checkboxValues') 1185 this.checkboxValues = this.bindValuesChange(checked, id, 'checkboxValues')
  1186 +
  1187 + // 触发valueChange 事件
  1188 + this.elemValueChange(FormTypes.checkbox, row, column, checked)
957 }, 1189 },
958 handleChangeSelectCommon(value, id, row, column) { 1190 handleChangeSelectCommon(value, id, row, column) {
959 this.selectValues = this.bindValuesChange(value, id, 'selectValues') 1191 this.selectValues = this.bindValuesChange(value, id, 'selectValues')
960 // 做单个表单验证 1192 // 做单个表单验证
961 this.validateOneInput(value, row, column, this.notPassedIds, true) 1193 this.validateOneInput(value, row, column, this.notPassedIds, true)
  1194 +
  1195 + // 触发valueChange 事件
  1196 + this.elemValueChange(FormTypes.select, row, column, value)
962 }, 1197 },
963 - handleChangeJDateCommon(value, id, row, column) { 1198 + handleChangeJDateCommon(value, id, row, column, showTime) {
964 this.jdateValues = this.bindValuesChange(value, id, 'jdateValues') 1199 this.jdateValues = this.bindValuesChange(value, id, 'jdateValues')
965 this.validateOneInput(value, row, column, this.notPassedIds, true) 1200 this.validateOneInput(value, row, column, this.notPassedIds, true)
  1201 +
  1202 + // 触发valueChange 事件
  1203 + if (showTime) {
  1204 + this.elemValueChange(FormTypes.datetime, row, column, value)
  1205 + } else {
  1206 + this.elemValueChange(FormTypes.date, row, column, value)
  1207 + }
  1208 + },
  1209 + handleChangeUpload(info, id, row, column) {
  1210 + let { file } = info
  1211 + let value = {
  1212 + name: file.name,
  1213 + type: file.type,
  1214 + size: file.size,
  1215 + status: file.status,
  1216 + percent: file.percent
  1217 + }
  1218 + if (column.responseName && file.response) {
  1219 + value['responseName'] = file.response[column.responseName]
  1220 + }
  1221 + this.uploadValues = this.bindValuesChange(value, id, 'uploadValues')
966 }, 1222 },
967 /** 记录用到数据绑定的组件的值 */ 1223 /** 记录用到数据绑定的组件的值 */
968 bindValuesChange(value, id, key) { 1224 bindValuesChange(value, id, key) {
@@ -979,6 +1235,29 @@ @@ -979,6 +1235,29 @@
979 this.tooltips = tooltips 1235 this.tooltips = tooltips
980 }, 1236 },
981 1237
  1238 + /** value 触发valueChange事件 */
  1239 + elemValueChange(type, rowSource, columnSource, value) {
  1240 + let column = Object.assign({}, columnSource)
  1241 + // 将caseId去除
  1242 + let row = Object.assign({}, rowSource)
  1243 + row.id = this.removeCaseId(row.id)
  1244 + // 获取整行的数据
  1245 + let { values } = this.getValuesSync({ validate: false, rowIds: [row.id] })
  1246 + if (values.length > 0) {
  1247 + Object.assign(row, values[0])
  1248 + }
  1249 + this.$emit('valueChange', { type, row, column, value, target: this })
  1250 + },
  1251 +
  1252 + /** 将caseId去除 */
  1253 + removeCaseId(id) {
  1254 + return id.split(this.caseId)[1]
  1255 + },
  1256 +
  1257 + handleClickDelFile(id) {
  1258 + this.uploadValues[id] = null
  1259 + },
  1260 +
982 /* --- common function end --- */ 1261 /* --- common function end --- */
983 1262
984 /* --- 以下是辅助方法,多用于动态构造页面中的数据 --- */ 1263 /* --- 以下是辅助方法,多用于动态构造页面中的数据 --- */
@@ -986,6 +1265,22 @@ @@ -986,6 +1265,22 @@
986 /** 辅助方法:打印日志 */ 1265 /** 辅助方法:打印日志 */
987 log: console.log, 1266 log: console.log,
988 1267
  1268 + getVM() {
  1269 + return this
  1270 + },
  1271 +
  1272 + /** 辅助方法:指定a-select 和 j-data 的父容器 */
  1273 + getParentContainer(node) {
  1274 + if (this.$el && this.$el.nodeType !== 8) {
  1275 + return this.$el
  1276 + }
  1277 + let doc = document.getElementById(this.caseId + 'inputTable')
  1278 + if (doc != null) {
  1279 + return doc
  1280 + }
  1281 + return node.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode
  1282 + },
  1283 +
989 /** 辅助方法:替换${...}变量 */ 1284 /** 辅助方法:替换${...}变量 */
990 replaceProps(col, value) { 1285 replaceProps(col, value) {
991 if (value && typeof value === 'string') { 1286 if (value && typeof value === 'string') {
@@ -1039,6 +1334,14 @@ @@ -1039,6 +1334,14 @@
1039 props['disabled'] = ((this.disabledRowIds || []).indexOf(row.id) !== -1) 1334 props['disabled'] = ((this.disabledRowIds || []).indexOf(row.id) !== -1)
1040 } 1335 }
1041 return props 1336 return props
  1337 + },
  1338 + /** upload 辅助方法:获取 headers */
  1339 + uploadGetHeaders(row, column) {
  1340 + let headers = {}
  1341 + if (column.token === true) {
  1342 + headers['X-Access-Token'] = this.accessToken
  1343 + }
  1344 + return headers
1042 } 1345 }
1043 1346
1044 } 1347 }
@@ -1056,36 +1359,6 @@ @@ -1056,36 +1359,6 @@
1056 1359
1057 } 1360 }
1058 1361
1059 - @scrollBarSize: 12px;  
1060 -  
1061 - /* 定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/  
1062 - ::-webkit-scrollbar {  
1063 - width: @scrollBarSize;  
1064 - height: @scrollBarSize;  
1065 - background-color: transparent;  
1066 - }  
1067 -  
1068 - /* 定义滚动条轨道 */  
1069 - ::-webkit-scrollbar-track {  
1070 - background-color: #f0f0f0;  
1071 - }  
1072 -  
1073 - /* 定义滑块 */  
1074 - ::-webkit-scrollbar-thumb {  
1075 - border-radius: @scrollBarSize;  
1076 - background-color: #eee;  
1077 - box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);  
1078 -  
1079 - &:hover {  
1080 - background-color: #bbb;  
1081 - }  
1082 -  
1083 - &:active {  
1084 - background-color: #888;  
1085 - }  
1086 -  
1087 - }  
1088 -  
1089 /* 设定边框参数 */ 1362 /* 设定边框参数 */
1090 @borderColor: #e8e8e8; 1363 @borderColor: #e8e8e8;
1091 @border: 1px solid @borderColor; 1364 @border: 1px solid @borderColor;
@@ -1094,7 +1367,7 @@ @@ -1094,7 +1367,7 @@
1094 1367
1095 .input-table { 1368 .input-table {
1096 max-width: 100%; 1369 max-width: 100%;
1097 - overflow-x: auto; 1370 + overflow-x: hidden;
1098 overflow-y: hidden; 1371 overflow-y: hidden;
1099 position: relative; 1372 position: relative;
1100 border: @border; 1373 border: @border;
@@ -1106,6 +1379,8 @@ @@ -1106,6 +1379,8 @@
1106 } 1379 }
1107 1380
1108 .td { 1381 .td {
  1382 +
  1383 + /*border-right: 1px solid red;*/
1109 /*color: white;*/ 1384 /*color: white;*/
1110 /*background-color: black;*/ 1385 /*background-color: black;*/
1111 /*margin-right: @spacing !important;*/ 1386 /*margin-right: @spacing !important;*/
@@ -1129,9 +1404,22 @@ @@ -1129,9 +1404,22 @@
1129 1404
1130 .thead { 1405 .thead {
1131 overflow-y: scroll; 1406 overflow-y: scroll;
  1407 + overflow-x: hidden;
1132 border-bottom: @border; 1408 border-bottom: @border;
1133 1409
  1410 + /** 隐藏thead的滑块 */
  1411 + &::-webkit-scrollbar-thumb {
  1412 + box-shadow: none !important;
  1413 + background-color: transparent !important;
  1414 + }
  1415 +
  1416 + .tr {
  1417 + min-width: 100%;
  1418 + overflow-y: scroll;
  1419 + }
  1420 +
1134 .td { 1421 .td {
  1422 + /*flex: 1;*/
1135 padding: 8px @spacing; 1423 padding: 8px @spacing;
1136 justify-content: center; 1424 justify-content: center;
1137 } 1425 }
@@ -1143,9 +1431,10 @@ @@ -1143,9 +1431,10 @@
1143 top: 0; 1431 top: 0;
1144 left: 0; 1432 left: 0;
1145 overflow-x: hidden; 1433 overflow-x: hidden;
1146 - overflow-y: scroll; 1434 + overflow-y: hidden;
1147 min-height: 61px; 1435 min-height: 61px;
1148 - max-height: 400px; 1436 + /*max-height: 400px;*/
  1437 + min-width: 100%;
1149 1438
1150 .tr-nodata { 1439 .tr-nodata {
1151 color: #999; 1440 color: #999;
@@ -1180,8 +1469,8 @@ @@ -1180,8 +1469,8 @@
1180 } 1469 }
1181 1470
1182 .td { 1471 .td {
  1472 + /*flex: 1;*/
1183 padding: 14px 0 14px @spacing; 1473 padding: 14px 0 14px @spacing;
1184 -  
1185 justify-content: center; 1474 justify-content: center;
1186 1475
1187 &:last-child { 1476 &:last-child {
@@ -1243,6 +1532,56 @@ @@ -1243,6 +1532,56 @@
1243 1532
1244 } 1533 }
1245 1534
  1535 + .scroll-view {
  1536 + overflow: auto;
  1537 + overflow-y: scroll;
  1538 + }
  1539 +
  1540 + .thead, .thead .tr, .scroll-view {
  1541 + @scrollBarSize: 6px;
  1542 + /* 定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
  1543 + &::-webkit-scrollbar {
  1544 + width: @scrollBarSize;
  1545 + height: @scrollBarSize;
  1546 + background-color: transparent;
  1547 + }
  1548 + /* 定义滚动条轨道 */
  1549 + &::-webkit-scrollbar-track {
  1550 + background-color: #f0f0f0;
  1551 + }
  1552 + /* 定义滑块 */
  1553 + &::-webkit-scrollbar-thumb {
  1554 + background-color: #eee;
  1555 + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
  1556 +
  1557 + &:hover {
  1558 + background-color: #bbb;
  1559 + }
  1560 +
  1561 + &:active {
  1562 + background-color: #888;
  1563 + }
  1564 + }
  1565 +
  1566 + }
  1567 +
  1568 + .thead .tr {
  1569 +
  1570 + &::-webkit-scrollbar-track {
  1571 + background-color: transparent;
  1572 + }
  1573 +
  1574 + /* IE模式下隐藏 */
  1575 + -ms-overflow-style: none;
  1576 + -ms-scroll-chaining: chained;
  1577 + -ms-content-zooming: zoom;
  1578 + -ms-scroll-rails: none;
  1579 + -ms-content-zoom-limit-min: 100%;
  1580 + -ms-content-zoom-limit-max: 500%;
  1581 + -ms-scroll-snap-type: proximity;
  1582 + -ms-scroll-snap-points-x: snapList(100%, 200%, 300%, 400%, 500%);
  1583 + }
  1584 +
1246 } 1585 }
1247 1586
1248 </style> 1587 </style>
1249 \ No newline at end of file 1588 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecg/JEditor.vue
@@ -30,6 +30,11 @@ @@ -30,6 +30,11 @@
30 type: String, 30 type: String,
31 required:false 31 required:false
32 }, 32 },
  33 + triggerChange:{
  34 + type: Boolean,
  35 + default: false,
  36 + required:false
  37 + },
33 disabled: { 38 disabled: {
34 type: Boolean, 39 type: Boolean,
35 default: false 40 default: false
@@ -82,7 +87,13 @@ @@ -82,7 +87,13 @@
82 }, 87 },
83 myValue(newValue) { 88 myValue(newValue) {
84 console.log(newValue) 89 console.log(newValue)
85 - this.$emit('input', newValue) 90 + if(this.triggerChange){
  91 + console.log(1)
  92 + this.$emit('change', newValue)
  93 + }else{
  94 + console.log(2)
  95 + this.$emit('input', newValue)
  96 + }
86 } 97 }
87 } 98 }
88 } 99 }
ant-design-jeecg-vue/src/components/jeecg/JGraphicCode.vue 0 → 100644
  1 +<template>
  2 + <div class="gc-canvas" @click="reloadPic">
  3 + <canvas id="gc-canvas" :width="contentWidth" :height="contentHeight"></canvas>
  4 + </div>
  5 +</template>
  6 +
  7 +<script>
  8 + export default {
  9 + name: 'JGraphicCode',
  10 + props: {
  11 + length:{
  12 + type: Number,
  13 + default: 4
  14 + },
  15 + fontSizeMin: {
  16 + type: Number,
  17 + default: 20
  18 + },
  19 + fontSizeMax: {
  20 + type: Number,
  21 + default: 45
  22 + },
  23 + backgroundColorMin: {
  24 + type: Number,
  25 + default: 180
  26 + },
  27 + backgroundColorMax: {
  28 + type: Number,
  29 + default: 240
  30 + },
  31 + colorMin: {
  32 + type: Number,
  33 + default: 50
  34 + },
  35 + colorMax: {
  36 + type: Number,
  37 + default: 160
  38 + },
  39 + lineColorMin: {
  40 + type: Number,
  41 + default: 40
  42 + },
  43 + lineColorMax: {
  44 + type: Number,
  45 + default: 180
  46 + },
  47 + dotColorMin: {
  48 + type: Number,
  49 + default: 0
  50 + },
  51 + dotColorMax: {
  52 + type: Number,
  53 + default: 255
  54 + },
  55 + contentWidth: {
  56 + type: Number,
  57 + default:136
  58 + },
  59 + contentHeight: {
  60 + type: Number,
  61 + default: 38
  62 + }
  63 + },
  64 + methods: {
  65 + // 生成一个随机数
  66 + randomNum (min, max) {
  67 + return Math.floor(Math.random() * (max - min) + min)
  68 + },
  69 + // 生成一个随机的颜色
  70 + randomColor (min, max) {
  71 + let r = this.randomNum(min, max)
  72 + let g = this.randomNum(min, max)
  73 + let b = this.randomNum(min, max)
  74 + return 'rgb(' + r + ',' + g + ',' + b + ')'
  75 + },
  76 + drawPic () {
  77 + this.randomCode()
  78 + let canvas = document.getElementById('gc-canvas')
  79 + let ctx = canvas.getContext('2d')
  80 + ctx.textBaseline = 'bottom'
  81 + // 绘制背景
  82 + ctx.fillStyle = this.randomColor(this.backgroundColorMin, this.backgroundColorMax)
  83 + ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
  84 + // 绘制文字
  85 + for (let i = 0; i < this.code.length; i++) {
  86 + this.drawText(ctx, this.code[i], i)
  87 + }
  88 + this.drawLine(ctx)
  89 + this.drawDot(ctx)
  90 + this.$emit("success",this.code)
  91 + },
  92 + drawText (ctx, txt, i) {
  93 + ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
  94 + let fontSize = this.randomNum(this.fontSizeMin, this.fontSizeMax)
  95 + ctx.font = fontSize + 'px SimHei'
  96 + let padding = 10;
  97 + let offset = (this.contentWidth-40)/(this.code.length-1)
  98 + let x=padding;
  99 + if(i>0){
  100 + x = padding+(i*offset)
  101 + }
  102 + //let x = (i + 1) * (this.contentWidth / (this.code.length + 1))
  103 + let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
  104 + if(fontSize>40){
  105 + y=40
  106 + }
  107 + var deg = this.randomNum(-10,10)
  108 + // 修改坐标原点和旋转角度
  109 + ctx.translate(x, y)
  110 + ctx.rotate(deg * Math.PI / 180)
  111 + ctx.fillText(txt, 0, 0)
  112 + // 恢复坐标原点和旋转角度
  113 + ctx.rotate(-deg * Math.PI / 180)
  114 + ctx.translate(-x, -y)
  115 + },
  116 + drawLine (ctx) {
  117 + // 绘制干扰线
  118 + for (let i = 0; i <1; i++) {
  119 + ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
  120 + ctx.beginPath()
  121 + ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
  122 + ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
  123 + ctx.stroke()
  124 + }
  125 + },
  126 + drawDot (ctx) {
  127 + // 绘制干扰点
  128 + for (let i = 0; i < 100; i++) {
  129 + ctx.fillStyle = this.randomColor(0, 255)
  130 + ctx.beginPath()
  131 + ctx.arc(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight), 1, 0, 2 * Math.PI)
  132 + ctx.fill()
  133 + }
  134 + },
  135 + reloadPic(){
  136 + this.drawPic()
  137 + },
  138 + randomCode(){
  139 + let random = ''
  140 + //去掉了I l i o O
  141 + let str = "QWERTYUPLKJHGFDSAZXCVBNMqwertyupkjhgfdsazxcvbnm1234567890"
  142 + for(let i = 0; i < this.length; i++) {
  143 + let index = Math.floor(Math.random()*57);
  144 + random += str[index];
  145 + }
  146 + this.code = random
  147 + }
  148 + },
  149 + mounted () {
  150 + this.drawPic()
  151 + },
  152 + data(){
  153 + return {
  154 + code:""
  155 + }
  156 + }
  157 +
  158 + }
  159 +</script>
  160 +
  161 +<style scoped>
  162 +
  163 +</style>
0 \ No newline at end of file 164 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecg/JSelectMultiple.vue
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 v-for="(item,index) in options" 4 v-for="(item,index) in options"
5 :key="index" 5 :key="index"
6 :value="item.value"> 6 :value="item.value">
7 - {{ item.text }} 7 + {{ item.text || item.label }}
8 </a-select-option> 8 </a-select-option>
9 </a-select> 9 </a-select>
10 </template> 10 </template>
ant-design-jeecg-vue/src/components/jeecg/JSlider.vue 0 → 100644
  1 +<template>
  2 + <div class="drag" ref="dragDiv">
  3 + <div class="drag_bg"></div>
  4 + <div class="drag_text">{{confirmWords}}</div>
  5 + <div ref="moveDiv" @mousedown="mousedownFn($event)" :class="{'handler_ok_bg':confirmSuccess}" class="handler handler_bg" style="border: 0.5px solid #fff;height: 34px;position: absolute;top: 0px;left: 0px;"></div>
  6 + </div>
  7 +</template>
  8 +
  9 +<script>
  10 + export default {
  11 + name:"JSlider",
  12 + data(){
  13 + return {
  14 + beginClientX:0, /*距离屏幕左端距离*/
  15 + mouseMoveStata:false, /*触发拖动状态 判断*/
  16 + maxwidth:'', /*拖动最大宽度,依据滑块宽度算出来的*/
  17 + confirmWords:'拖动滑块验证', /*滑块文字*/
  18 + confirmSuccess:false /*验证成功判断*/
  19 + }
  20 + },
  21 + methods: {
  22 + isSuccess(){
  23 + return this.confirmSuccess
  24 + },
  25 + mousedownFn:function (e) {
  26 + if(!this.confirmSuccess){
  27 + e.preventDefault && e.preventDefault(); //阻止文字选中等 浏览器默认事件
  28 + this.mouseMoveStata = true;
  29 + this.beginClientX = e.clientX;
  30 + }
  31 + }, //mousedoen 事件
  32 + successFunction(){
  33 + this.confirmSuccess = true
  34 + this.confirmWords = '验证通过';
  35 + if(window.addEventListener){
  36 + document.getElementsByTagName('html')[0].removeEventListener('mousemove',this.mouseMoveFn);
  37 + document.getElementsByTagName('html')[0].removeEventListener('mouseup',this.moseUpFn);
  38 + }else {
  39 + document.getElementsByTagName('html')[0].removeEventListener('mouseup',()=>{});
  40 + }
  41 + document.getElementsByClassName('drag_text')[0].style.color = '#fff'
  42 + document.getElementsByClassName('handler')[0].style.left = this.maxwidth + 'px';
  43 + document.getElementsByClassName('drag_bg')[0].style.width = this.maxwidth + 'px';
  44 +
  45 + this.$emit("onSuccess",true)
  46 + }, //验证成功函数
  47 + mouseMoveFn(e){
  48 + if(this.mouseMoveStata){
  49 + let width = e.clientX - this.beginClientX;
  50 + if(width>0 && width<=this.maxwidth){
  51 + document.getElementsByClassName('handler')[0].style.left = width + 'px';
  52 + document.getElementsByClassName('drag_bg')[0].style.width = width + 'px';
  53 + }else if(width>this.maxwidth){
  54 + this.successFunction();
  55 + }
  56 + }
  57 + }, //mousemove事件
  58 + moseUpFn(e){
  59 + this.mouseMoveStata = false;
  60 + var width = e.clientX - this.beginClientX;
  61 + if(width<this.maxwidth){
  62 + document.getElementsByClassName('handler')[0].style.left = 0 + 'px';
  63 + document.getElementsByClassName('drag_bg')[0].style.width = 0 + 'px';
  64 + }
  65 + } //mouseup事件
  66 + },
  67 + mounted(){
  68 + this.maxwidth = this.$refs.dragDiv.clientWidth - this.$refs.moveDiv.clientWidth;
  69 + document.getElementsByTagName('html')[0].addEventListener('mousemove',this.mouseMoveFn);
  70 + document.getElementsByTagName('html')[0].addEventListener('mouseup',this.moseUpFn)
  71 + }
  72 + }
  73 +</script>
  74 +
  75 +<style scoped>
  76 + .drag{
  77 + position: relative;
  78 + background-color: #e8e8e8;
  79 + width: 100%;
  80 + height: 34px;
  81 + line-height: 34px;
  82 + text-align: center;
  83 + }
  84 + .handler{
  85 + width: 40px;
  86 + height: 32px;
  87 + border: 1px solid #ccc;
  88 + cursor: move;
  89 + }
  90 + .handler_bg{
  91 + background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==") no-repeat center;
  92 + }
  93 + .handler_ok_bg{
  94 + background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==") no-repeat center;
  95 + }
  96 + .drag_bg{
  97 + background-color: #7ac23c;
  98 + height: 34px;
  99 + width: 0px;
  100 + }
  101 + .drag_text{
  102 + position: absolute;
  103 + top: 0px;
  104 + width: 100%;text-align: center;
  105 + -moz-user-select: none;
  106 + -webkit-user-select: none;
  107 + user-select: none;
  108 + -o-user-select:none;
  109 + -ms-user-select:none;
  110 + }
  111 +</style>
0 \ No newline at end of file 112 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecg/JTreeTable.vue 0 → 100644
  1 +<template>
  2 + <a-table
  3 + :rowKey="rowKey"
  4 + :columns="columns"
  5 + :dataSource="dataSource"
  6 + v-bind="tableProps"
  7 + @expand="handleExpand"/>
  8 +</template>
  9 +
  10 +<script>
  11 + import { getAction } from '@/api/manage'
  12 +
  13 + export default {
  14 + name: 'JTreeTable',
  15 + props: {
  16 + rowKey: {
  17 + type: String,
  18 + default: 'id'
  19 + },
  20 + columns: {
  21 + type: Array,
  22 + required: true
  23 + },
  24 + url: {
  25 + type: String,
  26 + required: true
  27 + },
  28 + childrenUrl: {
  29 + type: String,
  30 + default: null
  31 + },
  32 + tableProps: {
  33 + type: Object,
  34 + default: () => {
  35 + }
  36 + }
  37 + },
  38 + data() {
  39 + return {
  40 + dataSource: []
  41 + }
  42 + },
  43 + computed: {
  44 + getChildrenUrl() {
  45 + if (this.childrenUrl) {
  46 + return this.childrenUrl
  47 + } else {
  48 + return this.url
  49 + }
  50 + }
  51 + },
  52 + created() {
  53 + this.loadData()
  54 + },
  55 + methods: {
  56 +
  57 + /** 加载数据*/
  58 + loadData(id = '0', first = true, url = this.url) {
  59 + return getAction(url, { id }).then(res => {
  60 + let dataSource = res.result.map(item => {
  61 + // 判断是否标记了带有子级
  62 + if (item.hasChildren === true) {
  63 + // 定义默认展开时显示的loading子级,实际子级数据只在展开时加载
  64 + let loadChild = { id: `${item.id}_loadChild`, name: 'loading...', isLoading: true }
  65 + item.children = [loadChild]
  66 + }
  67 + return item
  68 + })
  69 + if (first) {
  70 + this.dataSource = dataSource
  71 + }
  72 + return Promise.resolve(dataSource)
  73 + })
  74 + },
  75 +
  76 + /** 点击展开图标时触发 */
  77 + handleExpand(expanded, record) {
  78 + // 判断是否是展开状态
  79 + if (expanded) {
  80 + // 判断子级的首个项的标记是否是“正在加载中”,如果是就加载数据
  81 + if (record.children[0].isLoading === true) {
  82 + this.loadData(record.id, false, this.getChildrenUrl).then(dataSource => {
  83 + // 处理好的数据可直接赋值给children
  84 + record.children = dataSource
  85 + })
  86 + }
  87 + }
  88 + }
  89 +
  90 + }
  91 + }
  92 +</script>
  93 +
  94 +<style scoped>
  95 +
  96 +</style>
0 \ No newline at end of file 97 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecg/JUpload.vue 0 → 100644
  1 +<template>
  2 + <a-upload
  3 + name="file"
  4 + :multiple="true"
  5 + :action="uploadAction"
  6 + :headers="headers"
  7 + :data="{'isup':1,'bizPath':bizPath}"
  8 + :fileList="fileList"
  9 + :beforeUpload="beforeUpload"
  10 + @change="handleChange">
  11 + <a-button>
  12 + <a-icon type="upload" />{{ text }}
  13 + </a-button>
  14 + </a-upload>
  15 +</template>
  16 +
  17 +<script>
  18 +
  19 + import Vue from 'vue'
  20 + import { ACCESS_TOKEN } from "@/store/mutation-types"
  21 +
  22 + const FILE_TYPE_ALL = "all"
  23 + const FILE_TYPE_IMG = "image"
  24 + const FILE_TYPE_TXT = "file"
  25 + const uidGenerator=()=>{
  26 + return '-'+parseInt(Math.random()*10000+1,10);
  27 + }
  28 + const getFileName=(path)=>{
  29 + if(path.lastIndexOf("\\")>=0){
  30 + let reg=new RegExp("\\\\","g");
  31 + path = path.replace(reg,"/");
  32 + }
  33 + return path.substring(path.lastIndexOf("/")+1);
  34 + }
  35 + export default {
  36 + name: 'JUpload',
  37 + data(){
  38 + return {
  39 + uploadAction:window._CONFIG['domianURL']+"/sys/common/upload",
  40 + urlDownload:window._CONFIG['domianURL'] + "/sys/common/download/",
  41 + headers:{},
  42 + fileList: []
  43 + }
  44 + },
  45 + props:{
  46 + text:{
  47 + type:String,
  48 + required:false,
  49 + default:"点击上传"
  50 + },
  51 + fileType:{
  52 + type:String,
  53 + required:false,
  54 + default:FILE_TYPE_ALL
  55 + },
  56 + /*这个属性用于控制文件上传的业务路径*/
  57 + bizPath:{
  58 + type:String,
  59 + required:false,
  60 + default:"temp"
  61 + },
  62 + value:{
  63 + type:String,
  64 + required:false
  65 + },
  66 + triggerChange:{
  67 + type: Boolean,
  68 + required: false,
  69 + default: false
  70 + },
  71 + },
  72 + watch:{
  73 + value(val){
  74 + this.initFileList(val)
  75 + }
  76 + },
  77 + created(){
  78 + const token = Vue.ls.get(ACCESS_TOKEN);
  79 + this.headers = {"X-Access-Token":token}
  80 + },
  81 +
  82 + methods:{
  83 + initFileList(paths){
  84 + if(!paths || paths.length==0){
  85 + return [];
  86 + }
  87 + let fileList = [];
  88 + let arr = paths.split(",")
  89 + for(var a=0;a<arr.length;a++){
  90 + fileList.push({
  91 + uid:uidGenerator(),
  92 + name:getFileName(arr[a]),
  93 + status: 'done',
  94 + url: this.urlDownload+arr[a],
  95 + response:{
  96 + status:"history",
  97 + message:arr[a]
  98 + }
  99 + })
  100 + }
  101 + this.fileList = fileList
  102 + },
  103 + handlePathChange(){
  104 + let uploadFiles = this.fileList
  105 + let path = ''
  106 + if(!uploadFiles || uploadFiles.length==0){
  107 + path = ''
  108 + }
  109 + let arr = [];
  110 +
  111 + for(var a=0;a<uploadFiles.length;a++){
  112 + arr.push(uploadFiles[a].response.message)
  113 + }
  114 + if(arr.length>0){
  115 + path = arr.join(",")
  116 + }
  117 + if(this.triggerChange){
  118 + this.$emit('change', path);
  119 + }else{
  120 + this.$emit('input', path);
  121 + }
  122 + },
  123 + beforeUpload(file){
  124 + var fileType = file.type;
  125 + if(fileType===FILE_TYPE_IMG){
  126 + if(fileType.indexOf('image')<0){
  127 + this.$message.warning('请上传图片');
  128 + return false;
  129 + }
  130 + }else if(fileType===FILE_TYPE_TXT){
  131 + if(fileType.indexOf('image')>=0){
  132 + this.$message.warning('请上传文件');
  133 + return false;
  134 + }
  135 + }
  136 + //TODO 扩展功能验证文件大小
  137 + return true
  138 + },
  139 + handleChange(info) {
  140 + console.log("--文件列表改变--")
  141 + let fileList = info.fileList
  142 + if(info.file.status==='done'){
  143 + if(info.file.response.success){
  144 + fileList = fileList.map((file) => {
  145 + if (file.response) {
  146 + file.url = this.urlDownload+file.response.message;
  147 + }
  148 + return file;
  149 + });
  150 + }
  151 + this.$message.success(`${info.file.name} 上传成功!`);
  152 + }else if (info.file.status === 'error') {
  153 + this.$message.error(`${info.file.name} 上传失败.`);
  154 + }else if(info.file.status === 'removed'){
  155 + this.handleDelete(info.file)
  156 + }
  157 + this.fileList = fileList
  158 + if(info.file.status==='done' || info.file.status === 'removed'){
  159 + this.handlePathChange()
  160 + }
  161 + },
  162 + handleDelete(file){
  163 + //如有需要新增 删除逻辑
  164 + console.log(file)
  165 + },
  166 + }
  167 + }
  168 +</script>
  169 +
  170 +<style scoped>
  171 +
  172 +</style>
0 \ No newline at end of file 173 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecg/README.md
@@ -196,3 +196,87 @@ this.$refs.superQueryModal.show(); @@ -196,3 +196,87 @@ this.$refs.superQueryModal.show();
196 modaltoggleFlag:true, 196 modaltoggleFlag:true,
197 ``` 197 ```
198 198
  199 +# <a-select/> 下拉选项滚动错位的解决方法
  200 +
  201 +## 问题描述
  202 +
  203 +当使用了 `a-modal` 或其他带有滚动条的组件时,使用`a-select`组件并打开下拉框时滚动滚动条,就会导致错位的问题产生。
  204 +
  205 +## 解决方法
  206 +
  207 +大多数情况下,在 `a-select` 上添加一个 `getPopupContainer` 属性,值为`node => node.parentNode`即可解决。
  208 +但是如果遇到 `a-select` 标签层级过深的情况,可能仍然会显示异常,只需要多加几个`.parentNode` (例:node => node.parentNode.parentNode.parentNode)多尝试几次直到解决问题即可。
  209 +
  210 +### 代码示例
  211 +
  212 +```html
  213 +<a-select
  214 + placeholder="请选择展示模板"
  215 + :options="dicts.displayTemplate"
  216 + :getPopupContainer="node => node.parentNode"
  217 +/>
  218 +```
  219 +
  220 +# JAsyncTreeList 异步数列表组件使用说明
  221 +
  222 +## 引入组件
  223 +
  224 +```js
  225 +import JTreeTable from '@/components/jeecg/JTreeTable'
  226 +export default {
  227 + components: { JTreeTable }
  228 +}
  229 +```
  230 +
  231 +## 所需参数
  232 +
  233 +| 参数 | 类型 | 必填 | 说明 |
  234 +|-------------|--------|-----|------------------------------------------------------------|
  235 +| rowKey | String | 非必填 | 表格行 key 的取值,默认为"id" |
  236 +| columns | Array | 必填 | 表格列的配置描述,具体见Antd官方文档 |
  237 +| url | String | 必填 | 数据查询url |
  238 +| childrenUrl | String | 非必填 | 查询子级时的url,若不填则使用url参数查询子级 |
  239 +| tableProps | Object | 非必填 | 自定义给内部table绑定的props |
  240 +
  241 +## 代码示例
  242 +
  243 +```html
  244 +<template>
  245 + <a-card :bordered="false">
  246 + <j-tree-table :url="url" :columns="columns" :tableProps="tableProps"/>
  247 + </a-card>
  248 +</template>
  249 +
  250 +<script>
  251 + import JTreeTable from '@/components/jeecg/JTreeTable'
  252 +
  253 + export default {
  254 + name: 'AsyncTreeTable',
  255 + components: { JTreeTable },
  256 + data() {
  257 + return {
  258 + url: '/api/asynTreeList',
  259 + columns: [
  260 + { title: '菜单名称', dataIndex: 'name' },
  261 + { title: '组件', dataIndex: 'component' },
  262 + { title: '排序', dataIndex: 'orderNum' }
  263 + ],
  264 + selectedRowKeys: []
  265 + }
  266 + },
  267 + computed: {
  268 + tableProps() {
  269 + let _this = this
  270 + return {
  271 + // 列表项是否可选择
  272 + // 配置项见:https://vue.ant.design/components/table-cn/#rowSelection
  273 + rowSelection: {
  274 + selectedRowKeys: _this.selectedRowKeys,
  275 + onChange: (selectedRowKeys) => _this.selectedRowKeys = selectedRowKeys
  276 + }
  277 + }
  278 + }
  279 + }
  280 + }
  281 +</script>
  282 +```
199 \ No newline at end of file 283 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecg/README_JEditableTable.md
@@ -15,16 +15,16 @@ @@ -15,16 +15,16 @@
15 15
16 ### columns 参数详解 16 ### columns 参数详解
17 17
18 -| 参数 | 类型 | 必填 | 说明 |  
19 -|---------------|--------|----|----------------------------------------------------------------------|  
20 -| title | string | ✔️ | 表格列头显示的问题 |  
21 -| key | string | ✔️ | 列数据在数据项中对应的 key,必须是唯一的 |  
22 -| type | string | ✔️ | 表单的类型,可以通过`JEditableTableUtil.FormTypes`赋值 | 18 +| 参数 | 类型 | 必填 | 说明 |
  19 +|---------------|--------|----|---------------------------------------------------------------------------------|
  20 +| title | string | ✔️ | 表格列头显示的问题 |
  21 +| key | string | ✔️ | 列数据在数据项中对应的 key,必须是唯一的 |
  22 +| type | string | ✔️ | 表单的类型,可以通过`JEditableTableUtil.FormTypes`赋值 |
23 | width | string | | 列的宽度,可以是百分比,也可以是`px`或其他单位,建议设置为百分比,且每一列的宽度加起来不应超过100%,否则可能会不能达到预期的效果。留空会自动计算百分比 | 23 | width | string | | 列的宽度,可以是百分比,也可以是`px`或其他单位,建议设置为百分比,且每一列的宽度加起来不应超过100%,否则可能会不能达到预期的效果。留空会自动计算百分比 |
24 -| placeholder | string | | 表单预期值的提示信息,可以使用`${...}`变量替换文本(详见`${...} 变量使用方式`) |  
25 -| defaultValue | string | | 默认值,在新增一行时生效 |  
26 -| validateRules | array | | 表单验证规则,配置方式见[validateRules 配置规则](#validaterules-配置规则) |  
27 -| props | object | | 设置添加给表单元素的自定义属性,例如:`props:{title: 'show title'}` | 24 +| placeholder | string | | 表单预期值的提示信息,可以使用`${...}`变量替换文本(详见`${...} 变量使用方式`) |
  25 +| defaultValue | string | | 默认值,在新增一行时生效 |
  26 +| validateRules | array | | 表单验证规则,配置方式见[validateRules 配置规则](#validaterules-配置规则) |
  27 +| props | object | | 设置添加给表单元素的自定义属性,例如:`props:{title: 'show title'}` |
28 28
29 #### 当 type=checkbox 时所需的参数 29 #### 当 type=checkbox 时所需的参数
30 30
@@ -41,10 +41,25 @@ @@ -41,10 +41,25 @@
41 41
42 ##### options 所需参数 42 ##### options 所需参数
43 43
44 -| 参数 | 类型 | 必填 | 说明 |  
45 -|-------|--------|----|------|  
46 -| title | string | ✔️ | 显示标题 |  
47 -| value | string | ✔️ | 真实值 | 44 +| 参数 | 类型 | 必填 | 说明 |
  45 +|-----------|------------|----|-----------------------------------------------|
  46 +| text | string | ✔️ | 显示标题 |
  47 +| value | string | ✔️ | 真实值 |
  48 +| ~~title~~ | ~~string~~ | | ~~显示标题(已废弃,若同时填写了 title 和 text 那么优先使用 text)~~ |
  49 +
  50 +#### 当 type=upload 时所需的参数
  51 +
  52 +| 参数 | 类型 | 必填 | 说明 |
  53 +|--------------|---------|----|------------------------------------------------|
  54 +| action | string | ✔️ | 上传文件路径 |
  55 +| token | boolean | | 上传的时候是否传递token |
  56 +| responseName | string | ✔️ | 若要从上传成功后从response中取出返回的文件名,那么这里填后台返回的包含文件名的字段名 |
  57 +
  58 +#### 当 type=slot 时所需的参数
  59 +
  60 +| 参数 | 类型 | 必填 | 说明 |
  61 +|--------------|---------|----|------------------------------------------------|
  62 +| slot | string | ✔️ | slot的名称 |
48 63
49 ### validateRules 配置规则 64 ### validateRules 配置规则
50 65
@@ -128,18 +143,53 @@ @@ -128,18 +143,53 @@
128 |----------|----------|----|-----------------------------------------------------------------------------------------------| 143 |----------|----------|----|-----------------------------------------------------------------------------------------------|
129 | callback | function | ✔️ | 获取值的回调方法,会传入`error`和`values`两个参数。`error`:未通过验证的数量,当等于`0`时代表验证通过;`values`:获取的值(即使未通过验证该字段也有数据) | 144 | callback | function | ✔️ | 获取值的回调方法,会传入`error`和`values`两个参数。`error`:未通过验证的数量,当等于`0`时代表验证通过;`values`:获取的值(即使未通过验证该字段也有数据) |
130 | validate | boolean | | 是否进行表单验证,默认为`true`,设为`false`则代表忽略表单验证 | 145 | validate | boolean | | 是否进行表单验证,默认为`true`,设为`false`则代表忽略表单验证 |
  146 +| rowIds | array | | 默认返回所有行的数据,如果传入了`rowIds`,那么就会只返回与该`rowIds`相匹配的数据,如果没有匹配的数据,就会返回空数组 |
131 147
132 - `返回值:` 无 148 - `返回值:` 无
133 149
  150 +
  151 +### getValuesSync
  152 +
  153 +`getValues`的同步版,会直接将获取到的数据返回
  154 +
  155 +- `参数:`
  156 +
  157 +| 参数名 | 类型 | 必填 | 说明 |
  158 +|---------|--------|----|-------------|
  159 +| options | object | | 选项,详见下方所需参数 |
  160 +
  161 +- - `options` 所需参数
  162 +
  163 +| 参数名 | 类型 | 必填 | 说明 |
  164 +|----------|---------|----|--------------------------------------------------------------------|
  165 +| validate | boolean | | 是否进行表单验证,默认为`true`,设为`false`则代表忽略表单验证 |
  166 +| rowIds | array | | 默认返回所有行的数据,如果传入了`rowIds`,那么就会只返回与该`rowIds`相匹配的数据,如果没有匹配的数据,就会返回空数组 |
  167 +
  168 +- `返回值:` object
  169 + - `error` 未通过验证的数量,当等于`0`时代表验证通过
  170 + - `values` 获取的值(即使未通过验证该字段也有数据)
  171 +
  172 +- `使用示例`
  173 +
  174 +```js
  175 +let { error, values } = this.$refs.editableTable.getValuesSync({ validate: true, rowIds: ['rowId1', 'rowId2'] })
  176 +if (error === 0) {
  177 + console.log('表单验证通过,数据:', values);
  178 +} else {
  179 + console.log('未通过表单验证,数据:', values);
  180 +}
  181 +```
  182 +
134 ### getValuesPromise 183 ### getValuesPromise
135 184
136 `getValues`的promise版,会在`resolve`中传入获取到的值,会在`reject`中传入失败原因,例如`VALIDATE_NO_PASSED` 185 `getValues`的promise版,会在`resolve`中传入获取到的值,会在`reject`中传入失败原因,例如`VALIDATE_NO_PASSED`
137 186
138 - `参数:` 187 - `参数:`
139 188
140 -| 参数名 | 类型 | 必填 | 说明 |  
141 -|----------|---------|----|---------------------------|  
142 -| validate | boolean | | 同`getValues`的`validate`参数 | 189 +| 参数名 | 类型 | 必填 | 说明 |
  190 +|----------|---------|----|--------------------------------------------------------------------|
  191 +| validate | boolean | | 同`getValues`的`validate`参数 |
  192 +| rowIds | array | | 默认返回所有行的数据,如果传入了`rowIds`,那么就会只返回与该`rowIds`相匹配的数据,如果没有匹配的数据,就会返回空数组 |
143 193
144 - `返回值:` Promise 194 - `返回值:` Promise
145 195
@@ -219,6 +269,8 @@ setValues([ @@ -219,6 +269,8 @@ setValues([
219 - `select` 显示选择器(下拉框) 269 - `select` 显示选择器(下拉框)
220 - `date` 日期选择器 270 - `date` 日期选择器
221 - `datetime` 日期时间选择器 271 - `datetime` 日期时间选择器
  272 +- `upload` 上传组件(文件域)
  273 +- `slot` 自定义插槽
222 274
223 ### VALIDATE_NO_PASSED 275 ### VALIDATE_NO_PASSED
224 276
@@ -284,7 +336,7 @@ validateTables(cases).then((all) =&gt; { @@ -284,7 +336,7 @@ validateTables(cases).then((all) =&gt; {
284 ### 为什么使用了ATab组件后,切换选项卡会导致白屏或滚动条位置会归零? 336 ### 为什么使用了ATab组件后,切换选项卡会导致白屏或滚动条位置会归零?
285 337
286 在ATab组件中确实会导致滚动条位置归零,且不会触发`onscroll`方法,所以无法动态加载行,导致白屏的问题出现。 338 在ATab组件中确实会导致滚动条位置归零,且不会触发`onscroll`方法,所以无法动态加载行,导致白屏的问题出现。
287 -解决方法是在ATab组件的`onChange`事件触发时执行`resetScrollTop()`即可,但是需要注意的是:代码主动改变ATab的`activeKey`不会触发`onChange`事件,还需要你手动调用下 339 +解决方法是在ATab组件的`onChange`事件触发时执行实例提供的`resetScrollTop()`方法即可,但是需要注意的是:代码主动改变ATab的`activeKey`不会触发`onChange`事件,还需要你手动调用下。
288 340
289 - `示例` 341 - `示例`
290 342
@@ -322,7 +374,11 @@ methods: { @@ -322,7 +374,11 @@ methods: {
322 /*--- 忽略部分代码片段 ---*/ 374 /*--- 忽略部分代码片段 ---*/
323 ``` 375 ```
324 376
325 ----- 377 +### slot(自定义插槽)如何使用?
  378 +
  379 +代码示例请看:[示例四(slot)](#示例四(slot))
  380 +
  381 +----------------------------------------------------------------------------------------
326 382
327 ## 示例一 383 ## 示例一
328 384
@@ -393,4 +449,57 @@ this.$refs.editableTable.getValues((error, values) =&gt; { @@ -393,4 +449,57 @@ this.$refs.editableTable.getValues((error, values) =&gt; {
393 this.$message.error('验证未通过') 449 this.$message.error('验证未通过')
394 } 450 }
395 }) 451 })
  452 +```
  453 +
  454 +## 示例四(slot)
  455 +
  456 +```html
  457 +<template>
  458 + <j-editable-table :columns="columns" :dataSource="dataSource">
  459 + <!-- 定义插槽 -->
  460 + <!-- 这种定义插槽的写法是vue推荐的新版写法(https://cn.vuejs.org/v2/guide/components-slots.html#具名插槽),旧版已被废弃的写法不再支持 -->
  461 + <!-- 若webstorm这样写报错,请看这篇文章:https://blog.csdn.net/lxq_9532/article/details/81870651 -->
  462 + <template v-slot:action="props">
  463 + <a @click="handleDelete(props)">删除</a>
  464 + </template>
  465 + </j-editable-table>
  466 +</template>
  467 +<script>
  468 + import { FormTypes } from '@/utils/JEditableTableUtil'
  469 + import JEditableTable from '@/components/jeecg/JEditableTable'
  470 + export default {
  471 + components: { JEditableTable },
  472 + data() {
  473 + return {
  474 + columns: [
  475 + // ...
  476 + {
  477 + title: '操作',
  478 + key: 'action',
  479 + width: '8%',
  480 + type: FormTypes.slot, // 定义该列为 自定义插值列
  481 + slot: 'action' // slot 的名称,对应 v-slot 冒号后面和等号前面的内容
  482 + }
  483 + ]
  484 + }
  485 + },
  486 + methods: {
  487 + /* a 标签的点击事件,删除当前选中的行 */
  488 + handleDelete(props) {
  489 + // 参数解释
  490 + // props.text :当前值,可能是defaultValue定义的值,也可能是从dataSource中取出的值
  491 + // props.rowId :当前选中行的id,如果是新增行则是临时id
  492 + // props.column :当前操作的列
  493 + // props.getValue :这是一个function,执行后可以获取当前行的所有值(禁止在template中使用)
  494 + // 例:const value = props.getValue()
  495 + // props.target :触发当前事件的实例,可直接调用该实例内的方法(禁止在template中使用)
  496 + // 例:target.add()
  497 +
  498 + // 使用实例:删除当前操作的行
  499 + let { rowId, target } = props
  500 + target.removeRows(rowId)
  501 + }
  502 + }
  503 + }
  504 +</script>
396 ``` 505 ```
397 \ No newline at end of file 506 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecgbiz/JSearchUserByDep.vue
@@ -29,7 +29,7 @@ @@ -29,7 +29,7 @@
29 用户账号: 29 用户账号:
30 <a-input-search 30 <a-input-search
31 :style="{width:'150px',marginBottom:'15px'}" 31 :style="{width:'150px',marginBottom:'15px'}"
32 - placeholder="请输入用户名搜索" 32 + placeholder="请输入用户账号"
33 v-model="queryParam.username" 33 v-model="queryParam.username"
34 @search="onSearch" 34 @search="onSearch"
35 ></a-input-search> 35 ></a-input-search>
@@ -194,13 +194,13 @@ @@ -194,13 +194,13 @@
194 }, 194 },
195 searchReset(num) { 195 searchReset(num) {
196 let that = this; 196 let that = this;
  197 + if(num !== 0){
  198 + that.queryParam = {};
  199 + that.loadData(1);
  200 + }
197 that.selectedRowKeys = []; 201 that.selectedRowKeys = [];
198 that.userNameArr = []; 202 that.userNameArr = [];
199 - that.queryParam = {};  
200 that.selectedKeys = []; 203 that.selectedKeys = [];
201 - if(num !== 0){  
202 - that.loadData();  
203 - }  
204 }, 204 },
205 close() { 205 close() {
206 this.searchReset(0); 206 this.searchReset(0);
ant-design-jeecg-vue/src/components/jeecgbiz/JSelectDepart.vue 0 → 100644
  1 +<template>
  2 + <div class="components-input-demo-presuffix">
  3 + <!---->
  4 + <a-input @click="openModal" placeholder="请点击选择部门" v-model="departNames" readOnly :disabled="disabled">
  5 + <a-icon slot="prefix" type="cluster" title="部门选择控件"/>
  6 + <a-icon v-if="departIds" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
  7 + </a-input>
  8 +
  9 + <j-select-depart-modal
  10 + ref="innerDepartSelectModal"
  11 + :modal-width="modalWidth"
  12 + :multi="multi"
  13 + :rootOpened="rootOpened"
  14 + :depart-id="value"
  15 + @ok="handleOK"
  16 + @initComp="initComp"/>
  17 + </div>
  18 +</template>
  19 +
  20 +<script>
  21 + import JSelectDepartModal from './modal/JSelectDepartModal'
  22 + export default {
  23 + name: 'JSelectDepart',
  24 + components:{
  25 + JSelectDepartModal
  26 + },
  27 + props:{
  28 + modalWidth:{
  29 + type:Number,
  30 + default:500,
  31 + required:false
  32 + },
  33 + multi:{
  34 + type:Boolean,
  35 + default:false,
  36 + required:false
  37 + },
  38 + rootOpened:{
  39 + type:Boolean,
  40 + default:true,
  41 + required:false
  42 + },
  43 + value:{
  44 + type:String,
  45 + required:false
  46 + },
  47 + triggerChange:{
  48 + type: Boolean,
  49 + required: false,
  50 + default: false
  51 + },
  52 + disabled:{
  53 + type: Boolean,
  54 + required: false,
  55 + default: false
  56 + }
  57 + },
  58 + data(){
  59 + return {
  60 + visible:false,
  61 + confirmLoading:false,
  62 + departNames:"",
  63 + departIds:''
  64 + }
  65 + },
  66 + mounted(){
  67 + this.departIds = this.value
  68 + },
  69 + watch:{
  70 + value(val){
  71 + this.departIds = val
  72 + }
  73 + },
  74 + methods:{
  75 + initComp(departNames){
  76 + this.departNames = departNames
  77 + },
  78 + openModal(){
  79 + this.$refs.innerDepartSelectModal.show()
  80 + },
  81 + handleOK(rows,idstr){
  82 + console.log("当前选中部门",rows)
  83 + console.log("当前选中部门ID",idstr)
  84 + if(!rows){
  85 + this.departNames = ''
  86 + this.departIds=''
  87 + }else{
  88 + let temp = ''
  89 + for(let item of rows){
  90 + temp+=','+item.departName
  91 + }
  92 + this.departNames = temp.substring(1)
  93 + this.departIds=idstr
  94 + }
  95 +
  96 + if(this.triggerChange){
  97 + this.$emit("change",this.departIds)
  98 + }else{
  99 + this.$emit("input",this.departIds)
  100 + }
  101 + },
  102 + getDepartNames(){
  103 + return this.departNames
  104 + },
  105 + handleEmpty(){
  106 + this.handleOK('')
  107 + }
  108 + }
  109 + }
  110 +</script>
  111 +
  112 +<style scoped>
  113 + .components-input-demo-presuffix .anticon-close-circle {
  114 + cursor: pointer;
  115 + color: #ccc;
  116 + transition: color 0.3s;
  117 + font-size: 12px;
  118 + }
  119 + .components-input-demo-presuffix .anticon-close-circle:hover {
  120 + color: #f5222d;
  121 + }
  122 + .components-input-demo-presuffix .anticon-close-circle:active {
  123 + color: #666;
  124 + }
  125 +</style>
0 \ No newline at end of file 126 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecgbiz/JSelectMultiUser.vue 0 → 100644
  1 +<template>
  2 + <div style="width: 100%;">
  3 + <a-select
  4 + mode="multiple"
  5 + placeholder="Please select"
  6 + :value="nameList"
  7 + style="width: calc(100% - 178px);">
  8 + </a-select>
  9 + <span style="display: inline-block;width:170px;float: right;overflow: hidden;">
  10 + <a-button type="primary" @click="handleSelect" icon="search" style="width: 81px">选择</a-button>
  11 + <a-button type="primary" @click="selectReset" icon="reload" style="margin-left: 8px;width: 81px">清空</a-button>
  12 + </span>
  13 +
  14 + <!-- 选择多个用户支持排序 -->
  15 + <j-select-multi-user-modal ref="selectModal" @selectFinished="selectOK"/>
  16 + </div>
  17 +</template>
  18 +
  19 +<script>
  20 + import JSelectMultiUserModal from './modal/JSelectMultiUserModal'
  21 + export default {
  22 + name: 'JSelectMultiUser',
  23 + components:{ JSelectMultiUserModal },
  24 + props:{
  25 + value:{
  26 + type:String,
  27 + required:false
  28 + },
  29 + triggerChange:{
  30 + type: Boolean,
  31 + required: false,
  32 + default: false
  33 + }
  34 + },
  35 + data(){
  36 + return {
  37 + selectList: [],
  38 + }
  39 + },
  40 + computed: {
  41 + nameList: function () {
  42 + var names = [];
  43 + for (var a = 0; a < this.selectList.length; a++) {
  44 + names.push(this.selectList[a].name);
  45 + }
  46 + let nameStr = ''
  47 + if(names.length>0){
  48 + nameStr = names.join(",")
  49 + }
  50 + if(this.triggerChange){
  51 + this.$emit("change",nameStr)
  52 + }else{
  53 + this.$emit("input",nameStr)
  54 + }
  55 + return names;
  56 + }
  57 + },
  58 + methods:{
  59 + handleSelect: function () {
  60 + this.$refs.selectModal.add();
  61 + },
  62 + selectReset() {
  63 + this.selectList = [];
  64 + },
  65 + selectOK: function (data) {
  66 + this.selectList = data;
  67 + }
  68 + }
  69 + }
  70 +</script>
ant-design-jeecg-vue/src/components/jeecgbiz/SelectMultipleUserModal.vue renamed to ant-design-jeecg-vue/src/components/jeecgbiz/JSelectMultipleUser.vue
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 cancelText="关闭"> 10 cancelText="关闭">
11 <a-row :gutter="18"> 11 <a-row :gutter="18">
12 <a-col :span="16"> 12 <a-col :span="16">
13 - <a-card title="选择人员" :bordered=true> 13 + <a-card title="选择人员" :bordered="true">
14 <!-- 查询区域 --> 14 <!-- 查询区域 -->
15 <div class="table-page-search-wrapper"> 15 <div class="table-page-search-wrapper">
16 <a-form layout="inline"> 16 <a-form layout="inline">
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 </a-card> 51 </a-card>
52 </a-col> 52 </a-col>
53 <a-col :span="8"> 53 <a-col :span="8">
54 - <a-card title="用户选择" :bordered=true> 54 + <a-card title="用户选择" :bordered="true">
55 <!-- table区域-begin --> 55 <!-- table区域-begin -->
56 <div> 56 <div>
57 <a-table 57 <a-table
ant-design-jeecg-vue/src/components/jeecgbiz/JSelectUserByDep.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <a-input-search
  4 + v-model="selectedDepUsers"
  5 + placeholder="请先选择用户"
  6 + disabled
  7 + @search="onSearchDepUser">
  8 + <a-button slot="enterButton" :disabled="disabled">选择用户</a-button>
  9 + </a-input-search>
  10 + <j-select-user-by-dep-modal
  11 + ref="selectModal"
  12 + :modal-width="modalWidth"
  13 + @ok="onSearchDepUserCallBack" />
  14 + </div>
  15 +</template>
  16 +
  17 +<script>
  18 + import JSelectUserByDepModal from './modal/JSelectUserByDepModal'
  19 + export default {
  20 + name: 'JSelectUserByDep',
  21 + components: { JSelectUserByDepModal },
  22 + props:{
  23 + modalWidth:{
  24 + type:Number,
  25 + default:1250,
  26 + required:false
  27 + },
  28 + value:{
  29 + type:String,
  30 + required:false
  31 + },
  32 + triggerChange:{
  33 + type: Boolean,
  34 + required: false,
  35 + default: false
  36 + },
  37 + disabled:{
  38 + type: Boolean,
  39 + required: false,
  40 + default: false
  41 + }
  42 + },
  43 + data() {
  44 + return {
  45 + selectedDepUsers:"",
  46 + }
  47 + },
  48 + mounted(){
  49 + this.selectedDepUsers = this.value
  50 + },
  51 + watch:{
  52 + value(val){
  53 + this.selectedDepUsers = val
  54 + }
  55 + },
  56 + methods: {
  57 + //通过组织机构筛选选择用户
  58 + onSearchDepUser() {
  59 + this.$refs.selectModal.showModal()
  60 + this.onSearchDepUserCallBack('')
  61 + },
  62 + onSearchDepUserCallBack(selectedDepUsers) {
  63 + this.selectedDepUsers = selectedDepUsers
  64 + if(this.triggerChange){
  65 + this.$emit("change",selectedDepUsers)
  66 + }else{
  67 + this.$emit("input",selectedDepUsers)
  68 + }
  69 + }
  70 + }
  71 + }
  72 +</script>
  73 +
  74 +<style scoped>
  75 +
  76 +</style>
0 \ No newline at end of file 77 \ No newline at end of file
ant-design-jeecg-vue/src/components/jeecgbiz/SearchUserByDepModal.vue deleted
1 -<template>  
2 - <a-modal  
3 - :width="modalWidth"  
4 - :visible="visible"  
5 - :title="title"  
6 - @ok="handleSubmit"  
7 - @cancel="close"  
8 - cancelText="关闭"  
9 - style="margin-top: -70px"  
10 - wrapClassName="ant-modal-cust-warp"  
11 - >  
12 - <a-row :gutter="10" style="background-color: #ececec; padding: 10px; margin: -10px">  
13 - <a-col :md="6" :sm="24">  
14 - <a-card :bordered="false">  
15 - <!--组织机构-->  
16 - <a-directory-tree  
17 - selectable  
18 - :selectedKeys="selectedKeys"  
19 - :checkStrictly="true"  
20 - @select="this.onSelect"  
21 - :dropdownStyle="{maxHeight:'200px',overflow:'auto'}"  
22 - :treeData="departTree"  
23 - />  
24 - </a-card>  
25 - </a-col>  
26 - <a-col :md="18" :sm="24">  
27 - <a-card :bordered="false">  
28 - 用户账号:  
29 - <a-input-search  
30 - :style="{width:'150px',marginBottom:'15px'}"  
31 - placeholder=""  
32 - v-model="queryParam.username"  
33 - @search="onSearch"  
34 - />  
35 - <a-button @click="searchReset" style="margin-left: 10px" icon="redo">重置</a-button>  
36 - <!--用户列表-->  
37 - <a-table  
38 - ref="table"  
39 - :scroll="scrollTrigger"  
40 - size="middle"  
41 - rowKey="id"  
42 - :columns="columns"  
43 - :dataSource="dataSource"  
44 - :pagination="ipagination"  
45 - style="background-color: white"  
46 - :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"  
47 - @change="handleTableChange">  
48 - </a-table>  
49 - </a-card>  
50 - </a-col>  
51 - </a-row>  
52 - </a-modal>  
53 -</template>  
54 -  
55 -<script>  
56 - import { filterObj } from '@/utils/util'  
57 - import { queryDepartTreeList, getUserList, queryUserByDepId, queryUserRoleMap } from '@/api/api'  
58 -  
59 - export default {  
60 - name: 'SearchUserByDepModal',  
61 - components: {  
62 - },  
63 - data() {  
64 - return {  
65 - queryParam: {},  
66 - columns: [  
67 - {  
68 - title: '用户账号',  
69 - align: 'center',  
70 - dataIndex: 'username'  
71 - },  
72 - {  
73 - title: '真实姓名',  
74 - align: 'center',  
75 - dataIndex: 'realname'  
76 - },  
77 - {  
78 - title: '角色名称',  
79 - align: 'center',  
80 - dataIndex: 'roleName'  
81 - },  
82 - {  
83 - title: '性别',  
84 - align: 'center',  
85 - dataIndex: 'sex',  
86 - customRender: function(text) {  
87 - if (text === 1) {  
88 - return '男'  
89 - } else if (text === 2) {  
90 - return '女'  
91 - } else {  
92 - return text  
93 - }  
94 - }  
95 - },  
96 - {  
97 - title: '手机号码',  
98 - align: 'center',  
99 - dataIndex: 'phone'  
100 - },  
101 - {  
102 - title: '邮箱',  
103 - align: 'center',  
104 - dataIndex: 'email'  
105 - }  
106 - ],  
107 - scrollTrigger:{},  
108 - dataSource: [],  
109 - selectedKeys: [],  
110 - userNames: [],  
111 - departName: '',  
112 - userRolesMap: {},  
113 - title: '',  
114 - ipagination: {  
115 - current: 1,  
116 - pageSize: 10,  
117 - pageSizeOptions: ['10', '20', '30'],  
118 - showTotal: (total, range) => {  
119 - return range[0] + '-' + range[1] + ' 共' + total + '条'  
120 - },  
121 - showQuickJumper: true,  
122 - showSizeChanger: true,  
123 - total: 0  
124 - },  
125 - isorter: {  
126 - column: 'createTime',  
127 - order: 'desc'  
128 - },  
129 - selectedRowKeys: [],  
130 - selectedRows: [],  
131 - userData: [],  
132 - modalWidth: 1250,  
133 - departTree: [],  
134 - visible: false,  
135 - form: this.$form.createForm(this),  
136 - }  
137 - },  
138 - created() {  
139 - // 该方法触发屏幕自适应  
140 - this.resetScreenSize();  
141 - },  
142 - methods: {  
143 - loadData(arg) {  
144 - if (arg === 1) {  
145 - this.ipagination.current = 1;  
146 - }  
147 - let params = this.getQueryParams();//查询条件  
148 - getUserList(params).then((res) => {  
149 - if (res.success) {  
150 - this.dataSource = res.result.records;  
151 - this.assignRoleName(this.dataSource);  
152 - this.userData = res.result.records;  
153 - this.ipagination.total = res.result.total;  
154 - }  
155 - })  
156 - queryUserRoleMap().then((res) => {  
157 - if (res.success) {  
158 - this.userRolesMap = res.result;  
159 - }  
160 - })  
161 - },  
162 - // 触发屏幕自适应  
163 - resetScreenSize(){  
164 - let screenWidth = document.body.clientWidth;  
165 - if(screenWidth < 500){  
166 - this.scrollTrigger = {x : 800};  
167 - }else{  
168 - this.scrollTrigger = {};  
169 - }  
170 - },  
171 - showModal() {  
172 - this.visible = true;  
173 - this.assignRoleName(this.dataSource);  
174 - this.queryDepartTree();  
175 - this.form.resetFields();  
176 - this.loadData(1);  
177 - },  
178 - getQueryParams() {  
179 - let param = Object.assign({}, this.queryParam, this.isorter);  
180 - param.field = this.getQueryField();  
181 - param.pageNo = this.ipagination.current;  
182 - param.pageSize = this.ipagination.pageSize;  
183 - return filterObj(param);  
184 - },  
185 - getQueryField() {  
186 - let str = 'id,';  
187 - for (let a = 0; a < this.columns.length; a++) {  
188 - str += ',' + this.columns[a].dataIndex;  
189 - }  
190 - return str;  
191 - },  
192 - searchReset(num) {  
193 - let that = this;  
194 - if(num !== 0){  
195 - that.loadData(1);  
196 - }  
197 - that.selectedRowKeys = [];  
198 - that.userNames = [];  
199 - that.queryParam = {};  
200 - that.selectedKeys = [];  
201 - that.userNames = [];  
202 - },  
203 - close() {  
204 - this.$emit('close');  
205 - this.searchReset(0);  
206 - this.visible = false;  
207 - },  
208 - handleTableChange(pagination, filters, sorter) {  
209 - //TODO 筛选  
210 - if (Object.keys(sorter).length > 0) {  
211 - this.isorter.column = sorter.field;  
212 - this.isorter.order = 'ascend' === sorter.order ? 'asc' : 'desc';  
213 - }  
214 - this.ipagination = pagination;  
215 - this.loadData();  
216 - },  
217 - handleSubmit() {  
218 - const that = this;  
219 - for (let i = 0, len = this.selectedRowKeys.length; i < len; i++) {  
220 - this.getUserNames(this.selectedRowKeys[i]);  
221 - }  
222 - that.$emit('ok', that.userNames.join(','));  
223 - that.close();  
224 - },  
225 - // 遍历匹配,获取用户真实姓名  
226 - getUserNames(rowId) {  
227 - let dataSource = this.dataSource;  
228 - for (let i = 0, len = dataSource.length; i < len; i++) {  
229 - if (rowId === dataSource[i].id) {  
230 - this.userNames.push(dataSource[i].realname);  
231 - }  
232 - }  
233 - },  
234 - // 点击树节点,筛选出对应的用户  
235 - onSelect(selectedKeys) {  
236 - if (selectedKeys[0] != null) {  
237 - this.queryUser(selectedKeys) // 调用方法根据选选择的id查询用户信息  
238 - if (this.selectedKeys[0] !== selectedKeys[0]) {  
239 - this.selectedKeys = [selectedKeys[0]];  
240 - }  
241 - }  
242 - },  
243 - onSelectChange(selectedRowKeys, selectionRows) {  
244 - this.selectedRowKeys = selectedRowKeys;  
245 - this.selectionRows = selectionRows;  
246 - },  
247 - onSearch() {  
248 - this.loadData(1);  
249 - },  
250 - // 根据选择的id来查询用户信息  
251 - queryUser(selectedKeys) {  
252 - queryUserByDepId({ id: selectedKeys.toString() }).then((res) => {  
253 - if (res.success) {  
254 - this.ipagination.total = res.result.length;  
255 - this.dataSource = res.result;  
256 - this.assignRoleName(this.dataSource);  
257 - }  
258 - })  
259 - },  
260 - // 传入用户id,找到匹配的角色名称  
261 - queryUserRole(userId) {  
262 - let map = this.userRolesMap;  
263 - let roleName = [];  
264 - for (var key in map) {  
265 - if (userId === key) {  
266 - roleName.push(map[key]);  
267 - }  
268 - }  
269 - return roleName.join(',');  
270 - },  
271 - queryDepartTree() {  
272 - queryDepartTreeList().then((res) => {  
273 - if (res.success) {  
274 - this.departTree = res.result;  
275 - }  
276 - })  
277 - },  
278 - // 为角色名称赋值  
279 - assignRoleName(data) {  
280 - let userId = '';  
281 - let role = '';  
282 - for (let i = 0, length = data.length; i < length; i++) {  
283 - userId = this.dataSource[i].id;  
284 - role = this.queryUserRole(userId);  
285 - this.dataSource[i].roleName = role;  
286 - }  
287 - },  
288 - modalFormOk() {  
289 - this.loadData();  
290 - }  
291 - }  
292 - }  
293 -</script>  
294 -  
295 -<style scoped>  
296 - .ant-table-tbody .ant-table-row td {  
297 - padding-top: 10px;  
298 - padding-bottom: 10px;  
299 - }  
300 -  
301 - #components-layout-demo-custom-trigger .trigger {  
302 - font-size: 18px;  
303 - line-height: 64px;  
304 - padding: 0 24px;  
305 - cursor: pointer;  
306 - transition: color .3s;  
307 - }  
308 -</style>  
309 \ No newline at end of file 0 \ No newline at end of file