Commit 92144cb12cd6c6ded273ab1a437585084511249f

Authored by zhangdaihao
1 parent 2a8cd2d0

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

Showing 820 changed files with 87569 additions and 21965 deletions

Too many changes to show.

To preserve performance only 43 of 820 files are displayed.

README.md
1 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
  1 +/src
0 2 \ No newline at end of file
... ...
ant-design-jeecg-vue/LICENSE
1 1 MIT License
2 2  
3   -Copyright (c) 2019 jeecg-boot
  3 +Copyright (c) 2019 DaiHao Zhang
4 4  
5 5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 6 of this software and associated documentation files (the "Software"), to deal
... ...
ant-design-jeecg-vue/README.md
1 1 Ant Design Jeecg Vue
2 2 ====
3 3  
4   -当前最新版本: 1.1.0(发布日期:20190415
  4 +当前最新版本: 2.0.0(发布日期:20190518
5 5  
6 6 Overview
7 7 ----
... ...
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 &#39;@/api/manage&#39;
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)=&gt;getAction(&quot;/sys/role/queryTreeList&quot;,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 &#39;@/components/chart/Bar&#39;
35 35 ]
36 36 ```
37 37  
  38 +##### 代码示例
  39 +
  40 +```html
  41 +<template>
  42 + <bar title="柱状图" :dataSource="dataSource" :height="420"/>
  43 +</template>
  44 +
  45 +<script>
  46 + import Bar from '@/components/chart/Bar'
  47 +
  48 + export default {
  49 + name: 'ChartDemo',
  50 + components: {
  51 + Bar
  52 + },
  53 + data() {
  54 + return {
  55 + dataSource: [
  56 + {
  57 + "x": "1月",
  58 + "y": 320
  59 + },
  60 + {
  61 + "x": "2月",
  62 + "y": 457
  63 + },
  64 + {
  65 + "x": "3月",
  66 + "y": 182
  67 + }
  68 + ]
  69 + }
  70 + }
  71 + }
  72 +</script>
  73 +
  74 +<style></style>
  75 +```
  76 +
38 77 ## 多列柱状图
39 78  
40 79 ##### 引用方式
... ...
ant-design-jeecg-vue/src/components/dict/JDictSelectTag.vue
1 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
... ... @@ -15,6 +15,7 @@
15 15 required: false,
16 16 default: false
17 17 },
  18 + /*label value*/
18 19 options:{
19 20 type: Array,
20 21 required: true
... ...
ant-design-jeecg-vue/src/components/jeecg/JCodeEditor.vue 0 → 100644
  1 +<template>
  2 + <div v-bind="fullScreenParentProps">
  3 + <a-icon v-if="fullScreen" class="full-screen-icon" type="fullscreen" @click="()=>fullCoder=!fullCoder"/>
  4 +
  5 + <div class="code-editor-cust full-screen-child">
  6 + <textarea ref="textarea"></textarea>
  7 + <span @click="nullTipClick" class="null-tip" :class="{'null-tip-hidden':hasCode}" :style="nullTipStyle">{{ placeholderShow }}</span>
  8 + <template v-if="languageChange">
  9 + <a-select v-model="mode" size="small" class="code-mode-select" @change="changeMode" placeholder="请选择主题">
  10 + <a-select-option
  11 + v-for="mode in modes"
  12 + :key="mode.value"
  13 + :value="mode.value">
  14 + {{ mode.label }}
  15 + </a-select-option>
  16 + </a-select>
  17 + </template>
  18 +
  19 + </div>
  20 + </div>
  21 +</template>
  22 +
  23 +<script type="text/ecmascript-6">
  24 + // 引入全局实例
  25 + import _CodeMirror from 'codemirror'
  26 +
  27 + // 核心样式
  28 + import 'codemirror/lib/codemirror.css'
  29 + // 引入主题后还需要在 options 中指定主题才会生效 darcula gruvbox-dark hopscotch monokai
  30 + import 'codemirror/theme/panda-syntax.css'
  31 + //提示css
  32 + import "codemirror/addon/hint/show-hint.css";
  33 +
  34 + // 需要引入具体的语法高亮库才会有对应的语法高亮效果
  35 + // codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库
  36 + // 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ,所以此处才把对应的 JS 提前引入
  37 + import 'codemirror/mode/javascript/javascript.js'
  38 + import 'codemirror/mode/css/css.js'
  39 + import 'codemirror/mode/xml/xml.js'
  40 + import 'codemirror/mode/clike/clike.js'
  41 + import 'codemirror/mode/markdown/markdown.js'
  42 + import 'codemirror/mode/python/python.js'
  43 + import 'codemirror/mode/r/r.js'
  44 + import 'codemirror/mode/shell/shell.js'
  45 + import 'codemirror/mode/sql/sql.js'
  46 + import 'codemirror/mode/swift/swift.js'
  47 + import 'codemirror/mode/vue/vue.js'
  48 +
  49 + // 尝试获取全局实例
  50 + const CodeMirror = window.CodeMirror || _CodeMirror
  51 +
  52 + export default {
  53 + name: 'JCodeEditor',
  54 + props: {
  55 + // 外部传入的内容,用于实现双向绑定
  56 + value: {
  57 + type: String,
  58 + default: ''
  59 + },
  60 + // 外部传入的语法类型
  61 + language: {
  62 + type: String,
  63 + default: null
  64 + },
  65 + languageChange:{
  66 + type: Boolean,
  67 + default:false,
  68 + required:false
  69 + },
  70 + placeholder: {
  71 + type: String,
  72 + default: null
  73 + },
  74 + // 显示行号
  75 + lineNumbers: {
  76 + type: Boolean,
  77 + default: true
  78 + },
  79 + // 是否显示全屏按钮
  80 + fullScreen: {
  81 + type: Boolean,
  82 + default: false
  83 + },
  84 + // 全屏以后的z-index
  85 + zIndex: {
  86 + type: [Number, String],
  87 + default: 999
  88 + }
  89 + },
  90 + data () {
  91 + return {
  92 + // 内部真实的内容
  93 + code: '',
  94 + hasCode:false,
  95 + // 默认的语法类型
  96 + mode: 'javascript',
  97 + // 编辑器实例
  98 + coder: null,
  99 + // 默认配置
  100 + options: {
  101 + // 缩进格式
  102 + tabSize: 2,
  103 + // 主题,对应主题库 JS 需要提前引入
  104 + theme: 'panda-syntax',
  105 + line: true,
  106 + // extraKeys: {'Ctrl': 'autocomplete'},//自定义快捷键
  107 + hintOptions: {
  108 + tables: {
  109 + users: ['name', 'score', 'birthDate'],
  110 + countries: ['name', 'population', 'size']
  111 + }
  112 + },
  113 + },
  114 + // 支持切换的语法高亮类型,对应 JS 已经提前引入
  115 + // 使用的是 MIME-TYPE ,不过作为前缀的 text/ 在后面指定时写死了
  116 + modes: [{
  117 + value: 'css',
  118 + label: 'CSS'
  119 + }, {
  120 + value: 'javascript',
  121 + label: 'Javascript'
  122 + }, {
  123 + value: 'html',
  124 + label: 'XML/HTML'
  125 + }, {
  126 + value: 'x-java',
  127 + label: 'Java'
  128 + }, {
  129 + value: 'x-objectivec',
  130 + label: 'Objective-C'
  131 + }, {
  132 + value: 'x-python',
  133 + label: 'Python'
  134 + }, {
  135 + value: 'x-rsrc',
  136 + label: 'R'
  137 + }, {
  138 + value: 'x-sh',
  139 + label: 'Shell'
  140 + }, {
  141 + value: 'x-sql',
  142 + label: 'SQL'
  143 + }, {
  144 + value: 'x-swift',
  145 + label: 'Swift'
  146 + }, {
  147 + value: 'x-vue',
  148 + label: 'Vue'
  149 + }, {
  150 + value: 'markdown',
  151 + label: 'Markdown'
  152 + }],
  153 + // code 编辑器 是否全屏
  154 + fullCoder: false
  155 + }
  156 + },
  157 + watch: {
  158 + // value: {
  159 + // immediate: false,
  160 + // handler(value) {
  161 + // this._getCoder().then(() => {
  162 + // this.coder.setValue(value)
  163 + // })
  164 + // }
  165 + // },
  166 + language: {
  167 + immediate: true,
  168 + handler(language) {
  169 + this._getCoder().then(() => {
  170 + // 尝试从父容器获取语法类型
  171 + if (language) {
  172 + // 获取具体的语法类型对象
  173 + let modeObj = this._getLanguage(language)
  174 +
  175 + // 判断父容器传入的语法是否被支持
  176 + if (modeObj) {
  177 + this.mode = modeObj.label
  178 + this.coder.setOption('mode', `text/${modeObj.value}`)
  179 + }
  180 + }
  181 + })
  182 + }
  183 + }
  184 + },
  185 + computed: {
  186 + placeholderShow() {
  187 + if (this.placeholder == null) {
  188 + return `请在此输入${this.language}代码`
  189 + } else {
  190 + return this.placeholder
  191 + }
  192 + },
  193 + nullTipStyle(){
  194 + if (this.lineNumbers) {
  195 + return { left: '36px' }
  196 + } else {
  197 + return { left: '12px' }
  198 + }
  199 + },
  200 + // coder 配置
  201 + coderOptions() {
  202 + return {
  203 + tabSize: this.options.tabSize,
  204 + theme: this.options.theme,
  205 + lineNumbers: this.lineNumbers,
  206 + line: true,
  207 + hintOptions: this.options.hintOptions
  208 + }
  209 + },
  210 + fullScreenParentProps(){
  211 + let props = {
  212 + class: ['full-screen-parent', this.fullCoder ? 'full-screen' : ''],
  213 + style: {}
  214 + }
  215 + if (this.fullCoder) {
  216 + props.style['z-index'] = this.zIndex
  217 + }
  218 + return props
  219 + }
  220 + },
  221 + mounted () {
  222 + // 初始化
  223 + this._initialize()
  224 + },
  225 + methods: {
  226 + // 初始化
  227 + _initialize () {
  228 + // 初始化编辑器实例,传入需要被实例化的文本域对象和默认配置
  229 + this.coder = CodeMirror.fromTextArea(this.$refs.textarea, this.coderOptions)
  230 + // 编辑器赋值
  231 + this.coder.setValue(this.value || this.code)
  232 + if(this.value||this.code){
  233 + this.hasCode=true
  234 + }else{
  235 + this.hasCode=false
  236 + }
  237 + // 支持双向绑定
  238 + this.coder.on('change', (coder) => {
  239 + this.code = coder.getValue()
  240 + if(this.code){
  241 + this.hasCode=true
  242 + }else{
  243 + this.hasCode=false
  244 + }
  245 + if (this.$emit) {
  246 + this.$emit('input', this.code)
  247 + }
  248 + })
  249 + this.coder.on('focus', () => {
  250 + this.hasCode=true
  251 + })
  252 + this.coder.on('blur', () => {
  253 + if(this.code){
  254 + this.hasCode=true
  255 + }else{
  256 + this.hasCode=false
  257 + }
  258 + })
  259 +
  260 + /* this.coder.on('cursorActivity',()=>{
  261 + this.coder.showHint()
  262 + })*/
  263 +
  264 + },
  265 + getCodeContent(){
  266 + return this.code
  267 + },
  268 + setCodeContent(val){
  269 + this.coder.setValue(val)
  270 + },
  271 + // 获取当前语法类型
  272 + _getLanguage (language) {
  273 + // 在支持的语法类型列表中寻找传入的语法类型
  274 + return this.modes.find((mode) => {
  275 + // 所有的值都忽略大小写,方便比较
  276 + let currentLanguage = language.toLowerCase()
  277 + let currentLabel = mode.label.toLowerCase()
  278 + let currentValue = mode.value.toLowerCase()
  279 +
  280 + // 由于真实值可能不规范,例如 java 的真实值是 x-java ,所以讲 value 和 label 同时和传入语法进行比较
  281 + return currentLabel === currentLanguage || currentValue === currentLanguage
  282 + })
  283 + },
  284 + _getCoder() {
  285 + let _this = this
  286 + return new Promise((resolve) => {
  287 + (function get() {
  288 + if (_this.coder) {
  289 + resolve(_this.coder)
  290 + } else {
  291 + setTimeout(get, 10)
  292 + }
  293 + })()
  294 + })
  295 + },
  296 + // 更改模式
  297 + changeMode (val) {
  298 + // 修改编辑器的语法配置
  299 + this.coder.setOption('mode', `text/${val}`)
  300 +
  301 + // 获取修改后的语法
  302 + let label = this._getLanguage(val).label.toLowerCase()
  303 +
  304 + // 允许父容器通过以下函数监听当前的语法值
  305 + this.$emit('language-change', label)
  306 + },
  307 + nullTipClick(){
  308 + this.coder.focus()
  309 + }
  310 + }
  311 + }
  312 +</script>
  313 +
  314 +<style lang="less">
  315 + .code-editor-cust{
  316 + flex-grow:1;
  317 + display:flex;
  318 + position:relative;
  319 + height:100%;
  320 + .CodeMirror{
  321 + flex-grow:1;
  322 + z-index:1;
  323 + .CodeMirror-code{
  324 + line-height:19px;
  325 + }
  326 +
  327 + }
  328 + .code-mode-select{
  329 + position:absolute;
  330 + z-index:2;
  331 + right:10px;
  332 + top:10px;
  333 + max-width:130px;
  334 + }
  335 + .CodeMirror{
  336 + height: auto;
  337 + min-height:100%;
  338 + }
  339 + .null-tip{
  340 + position: absolute;
  341 + top: 4px;
  342 + left: 36px;
  343 + z-index: 10;
  344 + color: #ffffffc9;
  345 + line-height: initial;
  346 + }
  347 + .null-tip-hidden{
  348 + display: none;
  349 + }
  350 + }
  351 +
  352 + /* 全屏样式 */
  353 + .full-screen-parent {
  354 + position: relative;
  355 +
  356 + .full-screen-icon {
  357 + opacity: 0;
  358 + color: black;
  359 + width: 20px;
  360 + height: 20px;
  361 + line-height: 24px;
  362 + background-color: white;
  363 + position: absolute;
  364 + top: 2px;
  365 + right: 2px;
  366 + z-index: 9;
  367 + cursor: pointer;
  368 + transition: opacity 0.3s;
  369 + }
  370 +
  371 + &:hover {
  372 + .full-screen-icon {
  373 + opacity: 1;
  374 +
  375 + &:hover {
  376 + background-color: rgba(255, 255, 255, 0.88);
  377 + }
  378 + }
  379 + }
  380 +
  381 + &.full-screen {
  382 + position: fixed;
  383 + top: 10px;
  384 + left: 10px;
  385 + width: calc(100% - 20px);
  386 + height: calc(100% - 20px);
  387 + padding: 10px;
  388 + background-color: #f5f5f5;
  389 +
  390 + .full-screen-icon {
  391 + top: 12px;
  392 + right: 12px;
  393 + }
  394 + .full-screen-child {
  395 + height: 100%;
  396 + max-height: 100%;
  397 + min-height: 100%;
  398 + }
  399 + }
  400 +
  401 + .full-screen-child {
  402 + min-height: 120px;
  403 + max-height: 320px;
  404 + }
  405 +
  406 + }
  407 +
  408 +
  409 +</style>
0 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
... ... @@ -4,7 +4,7 @@
4 4 v-for="(item,index) in options"
5 5 :key="index"
6 6 :value="item.value">
7   - {{ item.text }}
  7 + {{ item.text || item.label }}
8 8 </a-select-option>
9 9 </a-select>
10 10 </template>
... ...
ant-design-jeecg-vue/src/components/jeecg/JSlider.vue 0 → 100644
  1 +<template>
  2 + <div class="drag" ref="dragDiv">
  3 + <div class="drag_bg"></div>
  4 + <div class="drag_text">{{confirmWords}}</div>
  5 + <div ref="moveDiv" @mousedown="mousedownFn($event)" :class="{'handler_ok_bg':confirmSuccess}" class="handler handler_bg" style="border: 0.5px solid #fff;height: 34px;position: absolute;top: 0px;left: 0px;"></div>
  6 + </div>
  7 +</template>
  8 +
  9 +<script>
  10 + export default {
  11 + name:"JSlider",
  12 + data(){
  13 + return {
  14 + beginClientX:0, /*距离屏幕左端距离*/
  15 + mouseMoveStata:false, /*触发拖动状态 判断*/
  16 + maxwidth:'', /*拖动最大宽度,依据滑块宽度算出来的*/
  17 + confirmWords:'拖动滑块验证', /*滑块文字*/
  18 + confirmSuccess:false /*验证成功判断*/
  19 + }
  20 + },
  21 + methods: {
  22 + isSuccess(){
  23 + return this.confirmSuccess
  24 + },
  25 + mousedownFn:function (e) {
  26 + if(!this.confirmSuccess){
  27 + e.preventDefault && e.preventDefault(); //阻止文字选中等 浏览器默认事件
  28 + this.mouseMoveStata = true;
  29 + this.beginClientX = e.clientX;
  30 + }
  31 + }, //mousedoen 事件
  32 + successFunction(){
  33 + this.confirmSuccess = true
  34 + this.confirmWords = '验证通过';
  35 + if(window.addEventListener){
  36 + document.getElementsByTagName('html')[0].removeEventListener('mousemove',this.mouseMoveFn);
  37 + document.getElementsByTagName('html')[0].removeEventListener('mouseup',this.moseUpFn);
  38 + }else {
  39 + document.getElementsByTagName('html')[0].removeEventListener('mouseup',()=>{});
  40 + }
  41 + document.getElementsByClassName('drag_text')[0].style.color = '#fff'
  42 + document.getElementsByClassName('handler')[0].style.left = this.maxwidth + 'px';
  43 + document.getElementsByClassName('drag_bg')[0].style.width = this.maxwidth + 'px';
  44 +
  45 + this.$emit("onSuccess",true)
  46 + }, //验证成功函数
  47 + mouseMoveFn(e){
  48 + if(this.mouseMoveStata){
  49 + let width = e.clientX - this.beginClientX;
  50 + if(width>0 && width<=this.maxwidth){
  51 + document.getElementsByClassName('handler')[0].style.left = width + 'px';
  52 + document.getElementsByClassName('drag_bg')[0].style.width = width + 'px';
  53 + }else if(width>this.maxwidth){
  54 + this.successFunction();
  55 + }
  56 + }
  57 + }, //mousemove事件
  58 + moseUpFn(e){
  59 + this.mouseMoveStata = false;
  60 + var width = e.clientX - this.beginClientX;
  61 + if(width<this.maxwidth){
  62 + document.getElementsByClassName('handler')[0].style.left = 0 + 'px';
  63 + document.getElementsByClassName('drag_bg')[0].style.width = 0 + 'px';
  64 + }
  65 + } //mouseup事件
  66 + },
  67 + mounted(){
  68 + this.maxwidth = this.$refs.dragDiv.clientWidth - this.$refs.moveDiv.clientWidth;
  69 + document.getElementsByTagName('html')[0].addEventListener('mousemove',this.mouseMoveFn);
  70 + document.getElementsByTagName('html')[0].addEventListener('mouseup',this.moseUpFn)
  71 + }
  72 + }
  73 +</script>
  74 +
  75 +<style scoped>
  76 + .drag{
  77 + position: relative;
  78 + background-color: #e8e8e8;
  79 + width: 100%;
  80 + height: 34px;
  81 + line-height: 34px;
  82 + text-align: center;
  83 + }
  84 + .handler{
  85 + width: 40px;
  86 + height: 32px;
  87 + border: 1px solid #ccc;
  88 + cursor: move;
  89 + }
  90 + .handler_bg{
  91 + background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==") no-repeat center;
  92 + }
  93 + .handler_ok_bg{
  94 + background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==") no-repeat center;
  95 + }
  96 + .drag_bg{
  97 + background-color: #7ac23c;
  98 + height: 34px;
  99 + width: 0px;
  100 + }
  101 + .drag_text{
  102 + position: absolute;
  103 + top: 0px;
  104 + width: 100%;text-align: center;
  105 + -moz-user-select: none;
  106 + -webkit-user-select: none;
  107 + user-select: none;
  108 + -o-user-select:none;
  109 + -ms-user-select:none;
  110 + }
  111 +</style>
0 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) =&gt; {
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) =&gt; {
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