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 | 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 | 52 | ----------------------------------- |
53 | 53 | |
54 | 54 | #### 后端 |
55 | -- 基础框架:Spring Boot 2.0.3.RELEASE | |
55 | +- 基础框架:Spring Boot 2.1.3.RELEASE | |
56 | 56 | |
57 | 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 | 61 | - 数据库连接池:阿里巴巴Druid 1.1.10 |
62 | 62 | |
... | ... | @@ -89,7 +89,7 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 |
89 | 89 | |
90 | 90 | - 依赖管理:Maven |
91 | 91 | |
92 | -- 数据库:MySQL5.0 & Oracle 11g | |
92 | +- 数据库:MySQL5.0 & Oracle 11g & Sqlserver2005 | |
93 | 93 | |
94 | 94 | - 缓存:Redis |
95 | 95 | |
... | ... | @@ -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 | 131 | │ ├─高级查询器(弹窗自动组合查询条件) |
131 | 132 | │ ├─Excel导入导出工具集成(支持单表,一对多 导入导出) |
132 | 133 | │ ├─平台移动自适应支持 |
133 | -├─Online在线开发 | |
134 | -│ ├─Online在线表单(暂未开源) | |
135 | -│ ├─Online在线图表(暂未开源) | |
134 | +├─Online在线开发(暂未开源) | |
135 | +│ ├─Online在线表单 | |
136 | +│ ├─Online在线图表 | |
137 | +│ ├─Online图表模板配置 | |
136 | 138 | │ ├─Online在线报表 |
137 | -│ ├─消息中心(支持短信、邮件、微信推送等等) | |
138 | 139 | ├─系统监控 |
139 | 140 | │ ├─性能扫描监控 |
140 | 141 | │ │ ├─监控 Redis |
... | ... | @@ -142,9 +143,11 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 |
142 | 143 | │ │ ├─jvm |
143 | 144 | │ │ ├─服务器信息 |
144 | 145 | │ │ ├─请求追踪 |
146 | +│ │ ├─磁盘监控 | |
145 | 147 | │ ├─定时任务 |
146 | 148 | │ ├─系统日志 |
147 | -│ ├─数据日志(记录数据变更情况,可进行版本对比查看数据变更记录) | |
149 | +│ ├─消息中心(支持短信、邮件、微信推送等等) | |
150 | +│ ├─数据日志(记录数据快照,可对比快照,查看数据变更情况) | |
148 | 151 | │ ├─系统通知 |
149 | 152 | │ ├─SQL监控 |
150 | 153 | │ ├─swagger-ui(在线接口文档) |
... | ... | @@ -166,9 +169,14 @@ Jeecg-Boot快速开发平台,可以应用在任何J2EE项目的开发中,尤 |
166 | 169 | │ └─一对多TAB例子 |
167 | 170 | │ └─内嵌table例子 |
168 | 171 | │ └─常用选择组件 |
169 | -│ └─一对多JEditable | |
172 | +│ └─异步树table | |
170 | 173 | │ └─接口模拟测试 |
171 | 174 | │ └─一对多JEditable |
175 | +│ └─图片拖拽排序 | |
176 | +│ └─图片翻页 | |
177 | +│ └─图片预览 | |
178 | +│ └─PDF预览 | |
179 | +│ └─分屏功能 | |
172 | 180 | │─封装通用组件 |
173 | 181 | │ ├─行编辑表格JEditableTable |
174 | 182 | │ └─省略显示组件 |
... | ... | @@ -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 | 258 | - jdk8 |
243 | 259 | - mysql |
244 | 260 | - redis |
245 | -- 数据库脚步:jeecg-boot\docs\jeecg-boot_1.1.0-20190415.sql | |
261 | +- 数据库脚步:jeecg-boot\docs\jeecg-boot-mysql.sql | |
246 | 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 | 83 | \ No newline at end of file |
... | ... |
ant-design-jeecg-vue/.eslintignore
0 → 100644
ant-design-jeecg-vue/LICENSE
ant-design-jeecg-vue/README.md
ant-design-jeecg-vue/package.json
1 | 1 | { |
2 | 2 | "name": "vue-antd-jeecg", |
3 | - "version": "1.1.0", | |
3 | + "version": "2.0.0", | |
4 | 4 | "private": true, |
5 | 5 | "scripts": { |
6 | 6 | "serve": "vue-cli-service serve --open", |
... | ... | @@ -15,6 +15,8 @@ |
15 | 15 | "ant-design-vue": "^1.3.1", |
16 | 16 | "apexcharts": "^3.6.5", |
17 | 17 | "axios": "^0.18.0", |
18 | + "clipboard": "^2.0.4", | |
19 | + "codemirror": "^5.46.0", | |
18 | 20 | "dayjs": "^1.8.0", |
19 | 21 | "enquire.js": "^2.1.6", |
20 | 22 | "js-cookie": "^2.2.0", |
... | ... | @@ -29,10 +31,14 @@ |
29 | 31 | "vue-class-component": "^6.0.0", |
30 | 32 | "vue-cropper": "^0.4.8", |
31 | 33 | "vue-i18n": "^8.7.0", |
34 | + "vue-loader": "^15.7.0", | |
32 | 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 | 38 | "vue-property-decorator": "^7.3.0", |
35 | 39 | "vue-router": "^3.0.1", |
40 | + "vue-splitpane": "^1.0.4", | |
41 | + "vuedraggable": "^2.20.0", | |
36 | 42 | "vuex": "^3.0.1", |
37 | 43 | "vuex-class": "^0.3.1" |
38 | 44 | }, |
... | ... |
ant-design-jeecg-vue/public/index.html
... | ... | @@ -224,6 +224,7 @@ |
224 | 224 | window._CONFIG = {}; |
225 | 225 | window._CONFIG['domianURL'] = 'http://localhost:8080/jeecg-boot'; |
226 | 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 | 228 | </script> |
228 | 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 | 5 | ////图片预览请求地址 |
6 | 6 | // const imgView = "http://localhost:8080/jeecg-boot/sys/common/view/"; |
7 | 7 | |
8 | - | |
9 | 8 | //角色管理 |
10 | 9 | const addRole = (params)=>postAction("/sys/role/add",params); |
11 | 10 | const editRole = (params)=>putAction("/sys/role/edit",params); |
... | ... | @@ -39,7 +38,8 @@ const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",param |
39 | 38 | const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params); |
40 | 39 | const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params); |
41 | 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 | 43 | const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params); |
44 | 44 | const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params); |
45 | 45 | const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params); |
... | ... | @@ -130,7 +130,7 @@ export { |
130 | 130 | queryUserByDepId, |
131 | 131 | queryUserRoleMap, |
132 | 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 | 3 | .ant-card-body .table-operator { |
4 | 4 | margin-bottom: 18px; |
5 | 5 | } |
6 | - | |
6 | +/** Button按钮间距 */ | |
7 | +.table-operator .ant-btn { | |
8 | + margin-right: 6px | |
9 | +} | |
7 | 10 | /*列表td的padding设置 可以控制列表大小*/ |
8 | 11 | .ant-table-tbody .ant-table-row td { |
9 | 12 | padding-top: 15px; |
... | ... | @@ -26,4 +29,14 @@ |
26 | 29 | height: 90% !important; |
27 | 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 | 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 | 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 | 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 | 137 | \ No newline at end of file |
... | ... |
ant-design-jeecg-vue/src/components/chart/AreaChartTy.vue
1 | 1 | <template> |
2 | - <div :style="{ padding: '0 0 32px 32px' }"> | |
2 | + <div :style="{ padding: '0' }"> | |
3 | 3 | <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4> |
4 | 4 | |
5 | 5 | <v-chart ref="chart" :forceFit="true" :height="height" :data="dataSource" :scale="scale"> |
6 | - <v-tooltip/> | |
6 | + <v-tooltip :shared="false"/> | |
7 | 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 | 10 | </v-chart> |
11 | 11 | |
12 | 12 | </div> |
... | ... | @@ -38,6 +38,16 @@ |
38 | 38 | type: String, |
39 | 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 | 52 | height: { |
43 | 53 | type: Number, |
... | ... | @@ -47,13 +57,23 @@ |
47 | 57 | lineSize: { |
48 | 58 | type: Number, |
49 | 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 | 72 | computed: { |
53 | 73 | scale() { |
54 | 74 | return [ |
55 | 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 | 1 | <template> |
2 | 2 | <div :style="{ padding: '0 0 32px 32px' }"> |
3 | 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 | 5 | <v-tooltip/> |
6 | 6 | <v-axis/> |
7 | 7 | <v-bar position="x*y"/> |
... | ... | @@ -19,6 +19,10 @@ |
19 | 19 | type: Array, |
20 | 20 | required: true |
21 | 21 | }, |
22 | + yaxisText: { | |
23 | + type: String, | |
24 | + default: 'y' | |
25 | + }, | |
22 | 26 | title: { |
23 | 27 | type: String, |
24 | 28 | default: '' |
... | ... | @@ -31,6 +35,14 @@ |
31 | 35 | data() { |
32 | 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 | 46 | mounted() { |
35 | 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 | 58 | \ No newline at end of file |
... | ... |
ant-design-jeecg-vue/src/components/chart/BarMultid.vue
1 | 1 | <template> |
2 | 2 | <div :style="{ padding: '0 0 32px 32px' }"> |
3 | 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 | 5 | <v-tooltip /> |
6 | 6 | <v-axis /> |
7 | 7 | <v-legend /> |
... | ... | @@ -13,11 +13,6 @@ |
13 | 13 | <script> |
14 | 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 | 16 | export default { |
22 | 17 | name: 'BarMultid', |
23 | 18 | props: { |
... | ... | @@ -26,12 +21,15 @@ |
26 | 21 | default: '' |
27 | 22 | }, |
28 | 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 | 30 | fields:{ |
33 | - type:Array, | |
34 | - default:()=>[] | |
31 | + type: Array, | |
32 | + default: () => ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.'] | |
35 | 33 | }, |
36 | 34 | height: { |
37 | 35 | type: Number, |
... | ... | @@ -40,35 +38,28 @@ |
40 | 38 | }, |
41 | 39 | data() { |
42 | 40 | return { |
43 | - data:"", | |
44 | 41 | adjust: [{ |
45 | 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 | 50 | dv.transform({ |
66 | 51 | type: 'fold', |
67 | - fields:(!this.fields||this.fields.length==0)?fieldsConst:this.fields, | |
52 | + fields: this.fields, | |
68 | 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 | 1 | <template> |
2 | 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 | 4 | <v-coord type="polar" :startAngle="-202.5" :endAngle="22.5" :radius="0.75"></v-coord> |
5 | 5 | <v-axis |
6 | 6 | dataKey="value" |
... | ... | @@ -45,7 +45,7 @@ |
45 | 45 | </template> |
46 | 46 | |
47 | 47 | <script> |
48 | - import {registerShape} from 'viser-vue'; | |
48 | + import { registerShape } from 'viser-vue'; | |
49 | 49 | |
50 | 50 | registerShape('point', 'pointer', { |
51 | 51 | draw(cfg, container) { |
... | ... | @@ -87,67 +87,64 @@ |
87 | 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 | 94 | export default { |
95 | - name: "DashChartDemo", | |
96 | - props: { | |
97 | - value: { | |
95 | + name:"DashChartDemo", | |
96 | + props:{ | |
97 | + datasource:{ | |
98 | 98 | type: Number, |
99 | - default: 6.7 | |
99 | + default:7 | |
100 | 100 | }, |
101 | 101 | title: { |
102 | 102 | type: String, |
103 | 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 | 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 | 129 | this.abcd = 70 |
134 | 130 | } |
135 | 131 | }, |
136 | - getHtmlGuideHtml() { | |
132 | + getHtmlGuideHtml(){ | |
137 | 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 | 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 | 142 | data() { |
147 | 143 | return { |
148 | - data: [], | |
144 | + chartData:[], | |
145 | + height: 400, | |
149 | 146 | scale: scale, |
150 | - abcd: 70, | |
147 | + abcd:70, | |
151 | 148 | axisLabel: { |
152 | 149 | offset: -16, |
153 | 150 | textStyle: { |
... | ... |
ant-design-jeecg-vue/src/components/chart/LineChartMultid.vue
1 | 1 | <template> |
2 | 2 | <div :style="{ padding: '0 0 32px 32px' }"> |
3 | 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 | 10 | </v-chart> |
11 | 11 | </div> |
12 | 12 | </template> |
... | ... | @@ -14,23 +14,6 @@ |
14 | 14 | <script> |
15 | 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 | 17 | export default { |
35 | 18 | name: 'LineChartMultid', |
36 | 19 | props: { |
... | ... | @@ -38,58 +21,52 @@ |
38 | 21 | type: String, |
39 | 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 | 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 | 50 | data() { |
55 | 51 | return { |
56 | - data:"", | |
57 | 52 | scale: [{ |
58 | 53 | dataKey: 'x', |
59 | 54 | min: 0, |
60 | 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 | 63 | dv.transform({ |
86 | 64 | type: 'fold', |
87 | 65 | fields: this.fields, |
88 | 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 | 11 | <script> |
12 | 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 | 14 | export default { |
29 | 15 | props: { |
30 | 16 | title: { |
... | ... | @@ -37,37 +23,22 @@ |
37 | 23 | }, |
38 | 24 | dataSource: { |
39 | 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 | 35 | data() { |
68 | 36 | return { |
69 | - data: '', | |
70 | - scale, | |
37 | + scale: [{ | |
38 | + dataKey: 'percent', | |
39 | + min: 0, | |
40 | + formatter: '.0%' | |
41 | + }], | |
71 | 42 | pieStyle: { |
72 | 43 | stroke: '#fff', |
73 | 44 | lineWidth: 1 |
... | ... | @@ -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 | 67 | </script> |
84 | 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 | 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 | 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 | 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 | 13 | </a-select> |
6 | 14 | </template> |
7 | 15 | |
... | ... | @@ -14,15 +22,23 @@ |
14 | 22 | dictCode: String, |
15 | 23 | placeholder: String, |
16 | 24 | triggerChange: Boolean, |
17 | - value: String,// 1.接收一个 value prop | |
25 | + disabled: Boolean, | |
26 | + value: String, | |
27 | + type: String | |
18 | 28 | }, |
19 | 29 | data() { |
20 | 30 | return { |
21 | 31 | dictOptions: [], |
32 | + tagType:"" | |
22 | 33 | } |
23 | 34 | }, |
24 | 35 | created() { |
25 | 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 | 43 | this.initDictData(); |
28 | 44 | }, |
... | ... | @@ -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 | 62 | console.log(val); |
41 | 63 | if(this.triggerChange){ |
42 | 64 | this.$emit('change', val); |
43 | 65 | }else{ |
44 | 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 | 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 | 410 | \ No newline at end of file |
... | ... |
ant-design-jeecg-vue/src/components/jeecg/JDate.vue
... | ... | @@ -6,6 +6,7 @@ |
6 | 6 | :value="momVal" |
7 | 7 | :showTime="showTime" |
8 | 8 | :format="dateFormat" |
9 | + :getCalendarContainer="getCalendarContainer" | |
9 | 10 | /> |
10 | 11 | </template> |
11 | 12 | <script> |
... | ... | @@ -41,6 +42,10 @@ |
41 | 42 | type: Boolean, |
42 | 43 | required: false, |
43 | 44 | default: false |
45 | + }, | |
46 | + getCalendarContainer: { | |
47 | + type: Function, | |
48 | + default: () => document.body | |
44 | 49 | } |
45 | 50 | }, |
46 | 51 | data () { |
... | ... |
ant-design-jeecg-vue/src/components/jeecg/JEditableTable.vue
1 | 1 | <!-- JEditableTable --> |
2 | -<!-- @version 1.3 --> | |
2 | +<!-- @version 1.4 --> | |
3 | 3 | <!-- @author sjlei --> |
4 | 4 | <template> |
5 | 5 | <a-spin :spinning="loading"> |
... | ... | @@ -23,8 +23,8 @@ |
23 | 23 | |
24 | 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 | 28 | <!-- 左侧固定td --> |
29 | 29 | <div v-if="rowSelection" class="td td-cb" :style="style.tdLeft"> |
30 | 30 | <!--:indeterminate="true"--> |
... | ... | @@ -49,162 +49,232 @@ |
49 | 49 | </template> |
50 | 50 | </div> |
51 | 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 | 82 | <a-checkbox |
123 | - :key="i" | |
124 | 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 | 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 | 112 | :id="id" |
147 | - :key="i" | |
148 | 113 | v-bind="buildProps(row,col)" |
149 | - style="width: 100%;" | |
150 | - :value="selectValues[id]" | |
114 | + :data-input-number="col.type === formTypes.inputNumber" | |
151 | 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 | 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 | 263 | </div> |
195 | - </div> | |
196 | - <!-- -- tr end -- --> | |
264 | + <!-- -- tr end -- --> | |
197 | 265 | |
198 | - </template> | |
266 | + </template> | |
199 | 267 | |
200 | 268 | |
269 | + </div> | |
201 | 270 | </div> |
202 | 271 | </div> |
203 | 272 | </a-spin> |
204 | 273 | </template> |
205 | 274 | |
206 | 275 | <script> |
207 | - | |
276 | + import Vue from 'vue' | |
277 | + import { ACCESS_TOKEN } from '@/store/mutation-types' | |
208 | 278 | import { FormTypes, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil' |
209 | 279 | import { cloneObject, randomString } from '@/utils/util' |
210 | 280 | import JDate from '@/components/jeecg/JDate' |
... | ... | @@ -270,7 +340,8 @@ |
270 | 340 | }, |
271 | 341 | // 存储各个div的style |
272 | 342 | style: { |
273 | - tbody: { left: '0px', 'max-height': '400px' }, | |
343 | + // 'max-height': '400px' | |
344 | + tbody: { left: '0px' }, | |
274 | 345 | // 左侧固定td的style |
275 | 346 | tdLeft: { 'min-width': '4%', 'max-width': '45px' } |
276 | 347 | }, |
... | ... | @@ -288,6 +359,8 @@ |
288 | 359 | checkboxValues: {}, |
289 | 360 | // 绑定 jdate 的值 |
290 | 361 | jdateValues: {}, |
362 | + // file 信息 | |
363 | + uploadValues: {}, | |
291 | 364 | // 绑定左侧选择框已选择的id |
292 | 365 | selectedRowIds: [], |
293 | 366 | // 存储被删除行的id |
... | ... | @@ -331,7 +404,8 @@ |
331 | 404 | }, |
332 | 405 | tbodyStyle() { |
333 | 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 | 409 | return style |
336 | 410 | }, |
337 | 411 | showClearSelectButton() { |
... | ... | @@ -340,6 +414,30 @@ |
340 | 414 | if (this.disabledRows.hasOwnProperty(key)) count++ |
341 | 415 | } |
342 | 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 | 469 | } |
372 | 470 | |
373 | 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 | 491 | } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) { |
377 | 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 | 501 | } else { |
380 | 502 | value[column.key] = sourceValue |
381 | 503 | } |
... | ... | @@ -430,8 +552,22 @@ |
430 | 552 | vm.syncScrollBar(event.target.scrollLeft) |
431 | 553 | } |
432 | 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 | 567 | vm.recalcTrHiddenItem(event.target.scrollTop) |
568 | + | |
434 | 569 | } |
570 | + | |
435 | 571 | }, |
436 | 572 | methods: { |
437 | 573 | |
... | ... | @@ -455,15 +591,16 @@ |
455 | 591 | |
456 | 592 | /** 同步滚动条状态 */ |
457 | 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 | 598 | resetScrollTop(top) { |
599 | + let { scrollView } = this.$refs | |
463 | 600 | if (top != null && typeof top === 'number') { |
464 | - this.el.tbody.scrollTop = top | |
601 | + scrollView.scrollTop = top | |
465 | 602 | } else { |
466 | - this.el.tbody.scrollTop = this.scrollTop | |
603 | + scrollView.scrollTop = this.scrollTop | |
467 | 604 | } |
468 | 605 | }, |
469 | 606 | /** 重新计算需要隐藏或显示的tr */ |
... | ... | @@ -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 | 629 | /** push 一条数据 */ |
485 | 630 | push(record, update = true, rows) { |
486 | 631 | if (!(rows instanceof Array)) { |
487 | 632 | rows = cloneObject(this.rows) || [] |
488 | 633 | } |
489 | 634 | |
490 | - | |
491 | 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 | 640 | if (record.id.indexOf(this.caseId) === -1) { |
496 | 641 | record.id = this.caseId + record.id |
... | ... | @@ -524,11 +669,18 @@ |
524 | 669 | if (selected !== 0 && !selected) { |
525 | 670 | selected = undefined |
526 | 671 | } |
672 | + // 判断多选 | |
673 | + if (typeof selected === 'string' && (column.props || {})['mode'] === 'multiple') { | |
674 | + selected = selected.split(',') | |
675 | + } | |
527 | 676 | selectValues[inputId] = recordHasValue ? record[key] : selected |
528 | 677 | |
529 | 678 | } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) { |
530 | 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 | 684 | } else { |
533 | 685 | value[key] = recordHasValue ? record[key] : '' |
534 | 686 | } |
... | ... | @@ -568,10 +720,12 @@ |
568 | 720 | }, |
569 | 721 | /** 添加一行 */ |
570 | 722 | add(num = 1, forceScrollToBottom = false) { |
571 | - let timestamp = new Date().getTime() | |
723 | + // let timestamp = new Date().getTime() | |
572 | 724 | let rows = this.rows |
725 | + let row | |
573 | 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 | 729 | rows = this.push(row, false, rows) |
576 | 730 | } |
577 | 731 | this.rows = rows |
... | ... | @@ -579,6 +733,15 @@ |
579 | 733 | this.$nextTick(() => { |
580 | 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 | 746 | let tbody = this.el.tbody |
584 | 747 | let offsetHeight = tbody.offsetHeight |
... | ... | @@ -592,8 +755,6 @@ |
592 | 755 | this.$nextTick(() => { |
593 | 756 | tbody.scrollTop = tbody.scrollHeight |
594 | 757 | }) |
595 | - // 触发add事件 | |
596 | - this.$emit('added') | |
597 | 758 | }, |
598 | 759 | /** 删除被选中的行 */ |
599 | 760 | removeSelectedRows() { |
... | ... | @@ -607,7 +768,7 @@ |
607 | 768 | if (typeof id === 'string') { |
608 | 769 | ids = [id] |
609 | 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 | 777 | // 找到每个id对应的真实index并删除 |
617 | 778 | const findAndDelete = (arr) => { |
618 | 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 | 781 | arr.splice(i, 1) |
621 | 782 | return true |
622 | 783 | } |
... | ... | @@ -624,24 +785,52 @@ |
624 | 785 | } |
625 | 786 | // 找到rows对应的index,并删除 |
626 | 787 | if (findAndDelete(rows)) { |
788 | + // 找到values对应的index,并删除 | |
789 | + findAndDelete(this.inputValues) | |
627 | 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 | 795 | this.rows = rows |
634 | 796 | this.$emit('deleted', this.getDeleteIds()) |
797 | + this.$nextTick(() => { | |
798 | + // 更新formValues | |
799 | + this.updateFormValues() | |
800 | + }) | |
635 | 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 | 811 | let error = 0 |
641 | - let valueArray = cloneObject(this.inputValues) | |
812 | + let inputValues = cloneObject(this.inputValues) | |
642 | 813 | let tooltips = Object.assign({}, this.tooltips) |
643 | 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 | 834 | this.columns.forEach(column => { |
646 | 835 | let inputId = column.key + value.id |
647 | 836 | if (column.type === FormTypes.checkbox) { |
... | ... | @@ -653,46 +842,65 @@ |
653 | 842 | } |
654 | 843 | |
655 | 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 | 852 | } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) { |
659 | 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 | 861 | let results = this.validateOneInput(value[column.key], value, column, notPassedIds, false) |
665 | 862 | tooltips[inputId] = results[0] |
666 | 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 | 873 | tooltips[inputId].visible = false |
676 | 874 | notPassedIds = results[1] |
677 | 875 | } |
678 | 876 | }) |
679 | 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 | 883 | this.tooltips = tooltips |
683 | 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 | 895 | /** getValues的Promise版 */ |
687 | - getValuesPromise(validate = true) { | |
896 | + getValuesPromise(validate = true, rowIds) { | |
688 | 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 | 906 | /** 获取被删除项的id */ |
... | ... | @@ -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 | 932 | setValues(values) { |
715 | 933 | |
... | ... | @@ -722,8 +940,10 @@ |
722 | 940 | this.inputValues.forEach(value => { |
723 | 941 | // 在inputValues中找到了该字段 |
724 | 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 | 949 | let modelKey = `${newValueKey}${this.caseId}${rowKey}` |
... | ... | @@ -764,6 +984,7 @@ |
764 | 984 | // console.log(this.el.tbody.scrollTop, element.offsetTop) |
765 | 985 | // } |
766 | 986 | // }, |
987 | + | |
767 | 988 | /** 验证单个表单 */ |
768 | 989 | validateOneInput(value, row, column, notPassedIds, update = false) { |
769 | 990 | let tooltips = Object.assign({}, this.tooltips) |
... | ... | @@ -934,10 +1155,13 @@ |
934 | 1155 | /** input事件 */ |
935 | 1156 | handleInputCommono(target, index, row, column) { |
936 | 1157 | let { value, dataset, selectionStart } = target |
937 | - | |
1158 | + let type = FormTypes.input | |
1159 | + let change = true | |
938 | 1160 | if (`${dataset.inputNumber}` === 'true') { |
1161 | + type = FormTypes.inputNumber | |
939 | 1162 | let replace = value.replace(/[^0-9]/g, '') |
940 | 1163 | if (value !== replace) { |
1164 | + change = false | |
941 | 1165 | value = replace |
942 | 1166 | target.value = replace |
943 | 1167 | if (typeof selectionStart === 'number') { |
... | ... | @@ -950,19 +1174,51 @@ |
950 | 1174 | this.inputValues[index][column.key] = value |
951 | 1175 | // 做单个表单验证 |
952 | 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 | 1184 | let { id, checked } = event.target |
956 | 1185 | this.checkboxValues = this.bindValuesChange(checked, id, 'checkboxValues') |
1186 | + | |
1187 | + // 触发valueChange 事件 | |
1188 | + this.elemValueChange(FormTypes.checkbox, row, column, checked) | |
957 | 1189 | }, |
958 | 1190 | handleChangeSelectCommon(value, id, row, column) { |
959 | 1191 | this.selectValues = this.bindValuesChange(value, id, 'selectValues') |
960 | 1192 | // 做单个表单验证 |
961 | 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 | 1199 | this.jdateValues = this.bindValuesChange(value, id, 'jdateValues') |
965 | 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 | 1224 | bindValuesChange(value, id, key) { |
... | ... | @@ -979,6 +1235,29 @@ |
979 | 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 | 1261 | /* --- common function end --- */ |
983 | 1262 | |
984 | 1263 | /* --- 以下是辅助方法,多用于动态构造页面中的数据 --- */ |
... | ... | @@ -986,6 +1265,22 @@ |
986 | 1265 | /** 辅助方法:打印日志 */ |
987 | 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 | 1285 | replaceProps(col, value) { |
991 | 1286 | if (value && typeof value === 'string') { |
... | ... | @@ -1039,6 +1334,14 @@ |
1039 | 1334 | props['disabled'] = ((this.disabledRowIds || []).indexOf(row.id) !== -1) |
1040 | 1335 | } |
1041 | 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 | 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 | 1363 | @borderColor: #e8e8e8; |
1091 | 1364 | @border: 1px solid @borderColor; |
... | ... | @@ -1094,7 +1367,7 @@ |
1094 | 1367 | |
1095 | 1368 | .input-table { |
1096 | 1369 | max-width: 100%; |
1097 | - overflow-x: auto; | |
1370 | + overflow-x: hidden; | |
1098 | 1371 | overflow-y: hidden; |
1099 | 1372 | position: relative; |
1100 | 1373 | border: @border; |
... | ... | @@ -1106,6 +1379,8 @@ |
1106 | 1379 | } |
1107 | 1380 | |
1108 | 1381 | .td { |
1382 | + | |
1383 | + /*border-right: 1px solid red;*/ | |
1109 | 1384 | /*color: white;*/ |
1110 | 1385 | /*background-color: black;*/ |
1111 | 1386 | /*margin-right: @spacing !important;*/ |
... | ... | @@ -1129,9 +1404,22 @@ |
1129 | 1404 | |
1130 | 1405 | .thead { |
1131 | 1406 | overflow-y: scroll; |
1407 | + overflow-x: hidden; | |
1132 | 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 | 1421 | .td { |
1422 | + /*flex: 1;*/ | |
1135 | 1423 | padding: 8px @spacing; |
1136 | 1424 | justify-content: center; |
1137 | 1425 | } |
... | ... | @@ -1143,9 +1431,10 @@ |
1143 | 1431 | top: 0; |
1144 | 1432 | left: 0; |
1145 | 1433 | overflow-x: hidden; |
1146 | - overflow-y: scroll; | |
1434 | + overflow-y: hidden; | |
1147 | 1435 | min-height: 61px; |
1148 | - max-height: 400px; | |
1436 | + /*max-height: 400px;*/ | |
1437 | + min-width: 100%; | |
1149 | 1438 | |
1150 | 1439 | .tr-nodata { |
1151 | 1440 | color: #999; |
... | ... | @@ -1180,8 +1469,8 @@ |
1180 | 1469 | } |
1181 | 1470 | |
1182 | 1471 | .td { |
1472 | + /*flex: 1;*/ | |
1183 | 1473 | padding: 14px 0 14px @spacing; |
1184 | - | |
1185 | 1474 | justify-content: center; |
1186 | 1475 | |
1187 | 1476 | &:last-child { |
... | ... | @@ -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 | 1587 | </style> |
1249 | 1588 | \ No newline at end of file |
... | ... |
ant-design-jeecg-vue/src/components/jeecg/JEditor.vue
... | ... | @@ -30,6 +30,11 @@ |
30 | 30 | type: String, |
31 | 31 | required:false |
32 | 32 | }, |
33 | + triggerChange:{ | |
34 | + type: Boolean, | |
35 | + default: false, | |
36 | + required:false | |
37 | + }, | |
33 | 38 | disabled: { |
34 | 39 | type: Boolean, |
35 | 40 | default: false |
... | ... | @@ -82,7 +87,13 @@ |
82 | 87 | }, |
83 | 88 | myValue(newValue) { |
84 | 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 | 164 | \ No newline at end of file |
... | ... |
ant-design-jeecg-vue/src/components/jeecg/JSelectMultiple.vue
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 | 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 | 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 | 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 | 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 | 283 | \ No newline at end of file |
... | ... |
ant-design-jeecg-vue/src/components/jeecg/README_JEditableTable.md
... | ... | @@ -15,16 +15,16 @@ |
15 | 15 | |
16 | 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 | 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 | 29 | #### 当 type=checkbox 时所需的参数 |
30 | 30 | |
... | ... | @@ -41,10 +41,25 @@ |
41 | 41 | |
42 | 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 | 64 | ### validateRules 配置规则 |
50 | 65 | |
... | ... | @@ -128,18 +143,53 @@ |
128 | 143 | |----------|----------|----|-----------------------------------------------------------------------------------------------| |
129 | 144 | | callback | function | ✔️ | 获取值的回调方法,会传入`error`和`values`两个参数。`error`:未通过验证的数量,当等于`0`时代表验证通过;`values`:获取的值(即使未通过验证该字段也有数据) | |
130 | 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 | 183 | ### getValuesPromise |
135 | 184 | |
136 | 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 | 194 | - `返回值:` Promise |
145 | 195 | |
... | ... | @@ -219,6 +269,8 @@ setValues([ |
219 | 269 | - `select` 显示选择器(下拉框) |
220 | 270 | - `date` 日期选择器 |
221 | 271 | - `datetime` 日期时间选择器 |
272 | +- `upload` 上传组件(文件域) | |
273 | +- `slot` 自定义插槽 | |
222 | 274 | |
223 | 275 | ### VALIDATE_NO_PASSED |
224 | 276 | |
... | ... | @@ -284,7 +336,7 @@ validateTables(cases).then((all) => { |
284 | 336 | ### 为什么使用了ATab组件后,切换选项卡会导致白屏或滚动条位置会归零? |
285 | 337 | |
286 | 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 | 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 | 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 | 506 | \ No newline at end of file |
... | ... |
ant-design-jeecg-vue/src/components/jeecgbiz/JSearchUserByDep.vue
... | ... | @@ -29,7 +29,7 @@ |
29 | 29 | 用户账号: |
30 | 30 | <a-input-search |
31 | 31 | :style="{width:'150px',marginBottom:'15px'}" |
32 | - placeholder="请输入用户名搜索" | |
32 | + placeholder="请输入用户账号" | |
33 | 33 | v-model="queryParam.username" |
34 | 34 | @search="onSearch" |
35 | 35 | ></a-input-search> |
... | ... | @@ -194,13 +194,13 @@ |
194 | 194 | }, |
195 | 195 | searchReset(num) { |
196 | 196 | let that = this; |
197 | + if(num !== 0){ | |
198 | + that.queryParam = {}; | |
199 | + that.loadData(1); | |
200 | + } | |
197 | 201 | that.selectedRowKeys = []; |
198 | 202 | that.userNameArr = []; |
199 | - that.queryParam = {}; | |
200 | 203 | that.selectedKeys = []; |
201 | - if(num !== 0){ | |
202 | - that.loadData(); | |
203 | - } | |
204 | 204 | }, |
205 | 205 | close() { |
206 | 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 | 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 | 10 | cancelText="关闭"> |
11 | 11 | <a-row :gutter="18"> |
12 | 12 | <a-col :span="16"> |
13 | - <a-card title="选择人员" :bordered=true> | |
13 | + <a-card title="选择人员" :bordered="true"> | |
14 | 14 | <!-- 查询区域 --> |
15 | 15 | <div class="table-page-search-wrapper"> |
16 | 16 | <a-form layout="inline"> |
... | ... | @@ -51,7 +51,7 @@ |
51 | 51 | </a-card> |
52 | 52 | </a-col> |
53 | 53 | <a-col :span="8"> |
54 | - <a-card title="用户选择" :bordered=true> | |
54 | + <a-card title="用户选择" :bordered="true"> | |
55 | 55 | <!-- table区域-begin --> |
56 | 56 | <div> |
57 | 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 | 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 | 0 | \ No newline at end of file |