Commit 92144cb12cd6c6ded273ab1a437585084511249f
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
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
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 '@/api/manage' | @@ -5,7 +5,6 @@ import { getAction,deleteAction,putAction,postAction} from '@/api/manage' | ||
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)=>getAction("/sys/role/queryTreeList",param | @@ -39,7 +38,8 @@ const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",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 '@/components/chart/Bar' | @@ -35,6 +35,45 @@ import Bar from '@/components/chart/Bar' | ||
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
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) => { | @@ -284,7 +336,7 @@ validateTables(cases).then((all) => { | ||
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) => { | @@ -393,4 +449,57 @@ this.$refs.editableTable.getValues((error, values) => { | ||
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 |