소스 검색

Jeecg-Boot 2.1.4 版本发布 | 重构较大,较多新功能

zhangdaiscott 5 년 전
부모
커밋
4a4f236772
100개의 변경된 파일8918개의 추가작업 그리고 9795개의 파일을 삭제
  1. 2 2
      ant-design-vue-jeecg/README.md
  2. 5 5
      ant-design-vue-jeecg/package.json
  3. 4 4
      ant-design-vue-jeecg/public/index.html
  4. 21 3
      ant-design-vue-jeecg/src/api/api.js
  5. 14 0
      ant-design-vue-jeecg/src/api/manage.js
  6. 1 1
      ant-design-vue-jeecg/src/assets/less/common.less
  7. 4 2
      ant-design-vue-jeecg/src/components/chart/BarAndLine.vue
  8. 51 39
      ant-design-vue-jeecg/src/components/chart/BarMultid.vue
  9. 3 1
      ant-design-vue-jeecg/src/components/chart/LineChartMultid.vue
  10. 4 1
      ant-design-vue-jeecg/src/components/chart/Pie.vue
  11. 10 0
      ant-design-vue-jeecg/src/components/chart/mixins/ChartMixins.js
  12. 9 4
      ant-design-vue-jeecg/src/components/dict/JDictSelectTag.vue
  13. 10 0
      ant-design-vue-jeecg/src/components/dict/JDictSelectUtil.js
  14. 343 215
      ant-design-vue-jeecg/src/components/jeecg/JEditableTable.vue
  15. 1 1
      ant-design-vue-jeecg/src/components/jeecg/JGraphicCode.vue
  16. 202 0
      ant-design-vue-jeecg/src/components/jeecg/JImageUpload.vue
  17. 15 2
      ant-design-vue-jeecg/src/components/jeecg/JImportModal.vue
  18. 209 0
      ant-design-vue-jeecg/src/components/jeecg/JModal/index.vue
  19. 16 9
      ant-design-vue-jeecg/src/components/jeecg/JSuperQuery.vue
  20. 67 9
      ant-design-vue-jeecg/src/components/jeecg/JUpload.vue
  21. 9 5
      ant-design-vue-jeecg/src/components/jeecg/index.js
  22. 59 37
      ant-design-vue-jeecg/src/components/jeecgbiz/modal/JSelectUserByDepModal.vue
  23. 1 1
      ant-design-vue-jeecg/src/components/jeecgbiz/modal/SelectUserListModal.vue
  24. 8 0
      ant-design-vue-jeecg/src/components/layouts/IframePageView.vue
  25. 62 12
      ant-design-vue-jeecg/src/components/layouts/TabLayout.vue
  26. 3 3
      ant-design-vue-jeecg/src/components/layouts/UserLayout.vue
  27. 1 1
      ant-design-vue-jeecg/src/components/page/GlobalFooter.vue
  28. 1 1
      ant-design-vue-jeecg/src/components/page/GlobalHeader.vue
  29. 12 0
      ant-design-vue-jeecg/src/components/page/GlobalLayout.vue
  30. 36 0
      ant-design-vue-jeecg/src/components/tools/DynamicNotice.vue
  31. 12 1
      ant-design-vue-jeecg/src/components/tools/HeaderNotice.vue
  32. 13 3
      ant-design-vue-jeecg/src/components/tools/ShowAnnouncement.vue
  33. 42 19
      ant-design-vue-jeecg/src/components/tools/UserMenu.vue
  34. 2 2
      ant-design-vue-jeecg/src/main.js
  35. 4 4
      ant-design-vue-jeecg/src/mixins/JeecgListMixin.js
  36. 78 0
      ant-design-vue-jeecg/src/mixins/OnlAutoListMixin.js
  37. 13 0
      ant-design-vue-jeecg/src/store/modules/user.js
  38. 28 26
      ant-design-vue-jeecg/src/utils/authFilter.js
  39. 1 1
      ant-design-vue-jeecg/src/utils/commonUploadFile.js
  40. 22 18
      ant-design-vue-jeecg/src/utils/hasPermission.js
  41. 8 1
      ant-design-vue-jeecg/src/utils/request.js
  42. 125 6
      ant-design-vue-jeecg/src/utils/util.js
  43. 1 1
      ant-design-vue-jeecg/src/views/account/center/Index.vue
  44. 7 7
      ant-design-vue-jeecg/src/views/dashboard/IndexChart.vue
  45. 1 1
      ant-design-vue-jeecg/src/views/dashboard/Workplace.vue
  46. 75 40
      ant-design-vue-jeecg/src/views/jeecg/SelectDemo.vue
  47. 8 6
      ant-design-vue-jeecg/src/views/jeecg/helloworld.vue
  48. 7 6
      ant-design-vue-jeecg/src/views/jeecg/modules/JeecgDemoModal.vue
  49. 1 1
      ant-design-vue-jeecg/src/views/jeecg/report/ArchivesStatisticst.vue
  50. 8 24
      ant-design-vue-jeecg/src/views/jeecg/tablist/form/JeecgOrderCustomerModal.vue
  51. 10 7
      ant-design-vue-jeecg/src/views/modules/online/cgform/OnlCgformCopyList.vue
  52. 31 16
      ant-design-vue-jeecg/src/views/modules/online/cgform/OnlCgformHeadList.vue
  53. 55 49
      ant-design-vue-jeecg/src/views/modules/online/cgform/auto/OnlCgformAutoList.vue
  54. 4 21
      ant-design-vue-jeecg/src/views/modules/online/cgform/auto/OnlCgformTreeList.vue
  55. 111 0
      ant-design-vue-jeecg/src/views/modules/online/cgform/auto/erp/OnlCgformErpList.vue
  56. 1 0
      ant-design-vue-jeecg/src/views/modules/online/cgform/util/TableUtils.js
  57. 33 7
      ant-design-vue-jeecg/src/views/modules/oss/OSSFileList.vue
  58. 89 79
      ant-design-vue-jeecg/src/views/system/DepartList.vue
  59. 27 6
      ant-design-vue-jeecg/src/views/system/DepartUserList.vue
  60. 13 1
      ant-design-vue-jeecg/src/views/system/DictList.vue
  61. 38 9
      ant-design-vue-jeecg/src/views/system/NewPermissionList.vue
  62. 10 3
      ant-design-vue-jeecg/src/views/system/PermissionList.vue
  63. 1 1
      ant-design-vue-jeecg/src/views/system/RoleList.vue
  64. 22 21
      ant-design-vue-jeecg/src/views/system/RoleUserList.vue
  65. 178 0
      ant-design-vue-jeecg/src/views/system/SysCheckRuleList.vue
  66. 194 0
      ant-design-vue-jeecg/src/views/system/SysDataSourceList.vue
  67. 11 1
      ant-design-vue-jeecg/src/views/system/UserAnnouncementList.vue
  68. 21 16
      ant-design-vue-jeecg/src/views/system/UserList.vue
  69. 14 13
      ant-design-vue-jeecg/src/views/system/modules/AddressListLeft.vue
  70. 26 13
      ant-design-vue-jeecg/src/views/system/modules/AddressListRight.vue
  71. 184 0
      ant-design-vue-jeecg/src/views/system/modules/DepartAuthModal.vue
  72. 116 0
      ant-design-vue-jeecg/src/views/system/modules/DepartDataruleModal.vue
  73. 217 0
      ant-design-vue-jeecg/src/views/system/modules/DeptRoleAuthModal.vue
  74. 122 0
      ant-design-vue-jeecg/src/views/system/modules/DeptRoleDataruleModal.vue
  75. 196 0
      ant-design-vue-jeecg/src/views/system/modules/DeptRoleInfo.vue
  76. 200 0
      ant-design-vue-jeecg/src/views/system/modules/DeptRoleUserModal.vue
  77. 55 15
      ant-design-vue-jeecg/src/views/system/modules/DeptUserInfo.vue
  78. 2 2
      ant-design-vue-jeecg/src/views/system/modules/PasswordModal.vue
  79. 7 7
      ant-design-vue-jeecg/src/views/system/modules/SelectUserListModal.vue
  80. 18 6
      ant-design-vue-jeecg/src/views/system/modules/SelectUserModal.vue
  81. 37 38
      ant-design-vue-jeecg/src/views/system/modules/SysAnnouncementModal.vue
  82. 379 0
      ant-design-vue-jeecg/src/views/system/modules/SysCheckRuleModal.vue
  83. 58 0
      ant-design-vue-jeecg/src/views/system/modules/SysCheckRuleTestModal.vue
  84. 227 0
      ant-design-vue-jeecg/src/views/system/modules/SysDataSourceModal.vue
  85. 162 0
      ant-design-vue-jeecg/src/views/system/modules/SysDepartRoleModal.vue
  86. 95 27
      ant-design-vue-jeecg/src/views/system/modules/UserModal.vue
  87. 191 0
      ant-design-vue-jeecg/src/views/system/modules/UserRecycleBinModal.vue
  88. 17 8
      ant-design-vue-jeecg/src/views/system/modules/UserRoleModal.vue
  89. 14 13
      ant-design-vue-jeecg/src/views/user/Alteration.vue
  90. 35 27
      ant-design-vue-jeecg/src/views/user/Login.vue
  91. 1 1
      ant-design-vue-jeecg/src/views/user/RegisterResult.vue
  92. 54 49
      ant-design-vue-jeecg/src/views/user/Step1.vue
  93. 119 111
      ant-design-vue-jeecg/src/views/user/Step2.vue
  94. 0 1
      ant-design-vue-jeecg/vue.config.js
  95. 3300 3202
      ant-design-vue-jeecg/yarn.lock
  96. 1 1
      jeecg-boot/Dockerfile
  97. 3 3
      jeecg-boot/README.md
  98. 580 417
      jeecg-boot/db/mysql-5.7.sql
  99. 0 5079
      jeecg-boot/db/oracle11g.sql
  100. 0 0
      jeecg-boot/db/sqlserver2017.sql

+ 2 - 2
ant-design-vue-jeecg/README.md

@@ -1,13 +1,13 @@
 Ant Design Jeecg Vue
 ====
 
-当前最新版本: 2.1.3(发布日期:20191226
+当前最新版本: 2.0.4(发布日期:20200224
 
 Overview
 ----
 
 基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Ant Design Pro  Vue 版
-Jeecg-boot 的前端UI框架,采用前后端分离框架,提供强大代码生成器的快速开发平台。
+Jeecg-boot 的前段UI框架,采用前后端分离方案,提供强大代码生成器的快速开发平台。
 前端页面代码和后端功能代码一键生成,不需要写任何代码,保持jeecg一贯的强大!!
 
 

+ 5 - 5
ant-design-vue-jeecg/package.json

@@ -1,6 +1,6 @@
 {
   "name": "vue-antd-jeecg",
-  "version": "2.1.3",
+  "version": "2.1.4",
   "private": true,
   "scripts": {
     "pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
@@ -10,7 +10,7 @@
   },
   "dependencies": {
     "@antv/data-set": "^0.10.2",
-    "@jeecg/antd-online-re": "2.1.3",
+    "@jeecg/antd-online-214": "^2.1.4",
     "@tinymce/tinymce-vue": "^2.0.0",
     "ant-design-vue": "^1.4.0",
     "apexcharts": "^3.6.5",
@@ -24,7 +24,7 @@
     "lodash.pick": "^4.4.0",
     "md5": "^2.2.1",
     "nprogress": "^0.2.0",
-    "tinymce": "^5.0.2",
+    "tinymce": "^5.1.4",
     "viser-vue": "^2.4.4",
     "vue": "^2.6.10",
     "vue-apexcharts": "^1.3.2",
@@ -51,12 +51,12 @@
     "babel-eslint": "^10.0.1",
     "eslint": "^5.16.0",
     "eslint-plugin-vue": "^5.1.0",
+    "html-webpack-plugin": "^4.0.0-beta.11",
     "less": "^3.9.0",
     "less-loader": "^4.1.0",
     "node-sass": "^4.11.0",
     "sass-loader": "^7.0.1",
-    "vue-template-compiler": "^2.6.10",
-    "html-webpack-plugin": "^4.0.0-beta.11"
+    "vue-template-compiler": "^2.6.10"
   },
   "eslintConfig": {
     "root": true,

+ 4 - 4
ant-design-vue-jeecg/public/index.html

@@ -5,9 +5,9 @@
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
-  <title>Jeecg-Boot 快速开发平台</title>
+  <title>Jeecg-Boot 企业级快速开发平台</title>
   <link rel="icon" href="<%= BASE_URL %>logo.png">
-  <script src="https://cdn.bootcss.com/babel-polyfill/7.6.0/polyfill.js"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.2.5/polyfill.js"></script>
   <style>
     html,
     body,
@@ -244,8 +244,8 @@
     window._CONFIG = {};
     window._CONFIG['domianURL'] = 'http://127.0.0.1:8080/jeecg-boot';
     window._CONFIG['casPrefixUrl'] = 'http://cas.example.org:8443/cas';
-    window._CONFIG['imgDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/view';
-    window._CONFIG['downloadUrl'] = window._CONFIG['domianURL'] + '/sys/common/download';
+    window._CONFIG['onlinePreviewDomainURL'] = 'http://fileview.jeecg.com/onlinePreview'
+    window._CONFIG['staticDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/static';
     window._CONFIG['pdfDomainURL'] =  window._CONFIG['domianURL'] + '/sys/common/pdf/pdfPreviewIframe';
   </script>
 </head>

+ 21 - 3
ant-design-vue-jeecg/src/api/api.js

@@ -25,7 +25,7 @@ const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
 //验证用户是否存在
 const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
 //改变密码
-const changPassword = (params)=>putAction("/sys/user/changPassword",params);
+const changePassword = (params)=>putAction("/sys/user/changePassword",params);
 
 //权限管理
 const addPermission= (params)=>postAction("/sys/permission/add",params);
@@ -34,6 +34,7 @@ const getPermissionList = (params)=>getAction("/sys/permission/list",params);
 /*update_begin author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
 const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
 const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
+const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
 /*update_end author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
 
 // const deletePermission = (params)=>deleteAction("/sys/permission/delete",params);
@@ -56,6 +57,14 @@ const queryParentName   = (params)=>getAction("/sys/sysDepart/queryParentName",p
 const searchByKeywords   = (params)=>getAction("/sys/sysDepart/searchBy",params);
 const deleteByDepartId   = (params)=>deleteAction("/sys/sysDepart/delete",params);
 
+//二级部门管理
+const queryDepartPermission = (params)=>getAction("/sys/permission/queryDepartPermission",params);
+const saveDepartPermission = (params)=>postAction("/sys/permission/saveDepartPermission",params);
+const queryTreeListForDeptRole = (params)=>getAction("/sys/sysDepartPermission/queryTreeListForDeptRole",params);
+const queryDeptRolePermission = (params)=>getAction("/sys/sysDepartPermission/queryDeptRolePermission",params);
+const saveDeptRolePermission = (params)=>postAction("/sys/sysDepartPermission/saveDeptRolePermission",params);
+const queryMyDepartTreeList = (params)=>getAction("/sys/sysDepart/queryMyDeptTreeList",params);
+
 //日志管理
 //const getLogList = (params)=>getAction("/sys/log/list",params);
 const deleteLog = (params)=>deleteAction("/sys/log/delete",params);
@@ -94,6 +103,7 @@ const queryUserRoleMap = (params)=>getAction("/sys/user/queryUserRoleMap",params
 const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
 // 加载分类字典
 const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params);
+const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
 
 export {
   // imgView,
@@ -108,7 +118,7 @@ export {
   queryall,
   frozenBatch,
   checkOnlyUser,
-  changPassword,
+  changePassword,
   getPermissionList,
   addPermission,
   editPermission,
@@ -142,7 +152,15 @@ export {
   queryTreeListForRole,
   getSystemMenuList,
   getSystemSubmenu,
-  loadCategoryData
+  getSystemSubmenuBatch,
+  loadCategoryData,
+  checkRuleByCode,
+  queryDepartPermission,
+  saveDepartPermission,
+  queryTreeListForDeptRole,
+  queryDeptRolePermission,
+  saveDeptRolePermission,
+  queryMyDepartTreeList
 }
 
 

+ 14 - 0
ant-design-vue-jeecg/src/api/manage.js

@@ -112,3 +112,17 @@ export function downFile(url,parameter){
   })
 }
 
+/**
+ * 获取文件访问路径
+ * @param avatar
+ * @param imgerver
+ * @param str
+ * @returns {*}
+ */
+export function getFileAccessHttpUrl(avatar,imgerver,subStr) {
+  if(avatar && avatar.indexOf(subStr) != -1 ){
+    return avatar;
+  }else{
+    return imgerver + "/" + avatar;
+  }
+}

+ 1 - 1
ant-design-vue-jeecg/src/assets/less/common.less

@@ -5,7 +5,7 @@
 }
 /** Button按钮间距 */
 .table-operator .ant-btn {
-  margin-right: 6px
+  margin: 8px 8px 0 0;
 }
 /*列表td的padding设置 可以控制列表大小*/
 .ant-table-tbody .ant-table-row td {

+ 4 - 2
ant-design-vue-jeecg/src/components/chart/BarAndLine.vue

@@ -1,7 +1,7 @@
 <template>
   <div :style="{ padding: '0 50px 32px 0' }">
     <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
-    <v-chart :forceFit="true" :height="height" :data="data" :scale="scale" :padding=" padding">
+    <v-chart :forceFit="true" :height="height" :data="data" :scale="scale" :padding=" padding" :onClick="handleClick">
       <v-tooltip/>
       <v-legend/>
       <v-axis/>
@@ -12,9 +12,11 @@
 </template>
 
 <script>
+  import { ChartEventMixins } from './mixins/ChartMixins'
 
   export default {
-    name: 'BarMultid',
+    name: 'BarAndLine',
+    mixins: [ChartEventMixins],
     props: {
       title: {
         type: String,

+ 51 - 39
ant-design-vue-jeecg/src/components/chart/BarMultid.vue

@@ -1,71 +1,83 @@
 <template>
   <div :style="{ padding: '0 0 32px 32px' }">
     <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
-    <v-chart :forceFit="true" :height="254" :data="chartData" :padding="['auto', 'auto', '40', '50']">
-      <v-tooltip />
-      <v-axis />
-      <v-legend />
-      <v-bar position="x*y" color="type" :adjust="adjust" />
+    <v-chart :data="data" :height="height" :force-fit="true" :onClick="handleClick">
+      <v-tooltip/>
+      <v-axis/>
+      <v-legend/>
+      <v-bar position="x*y" color="type" :adjust="adjust"/>
     </v-chart>
   </div>
 </template>
 
 <script>
   import { DataSet } from '@antv/data-set'
+  import { ChartEventMixins } from './mixins/ChartMixins'
 
-  const sourceDataConst = [
-    { type: 'Jeecg', 'Jan.': 18.9, 'Feb.': 28.8, 'Mar.': 39.3, 'Apr.': 81.4, 'May': 47, 'Jun.': 20.3, 'Jul.': 24, 'Aug.': 35.6 },
-    { 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 },
-  ];
-  const fieldsConst = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.'];
   export default {
     name: 'BarMultid',
+    mixins: [ChartEventMixins],
     props: {
       title: {
         type: String,
         default: ''
       },
-      sourceData:{
-        type:Array,
-        default:()=>[]
+      dataSource: {
+        type: Array,
+        default: () => [
+          { type: 'Jeecg', 'Jan.': 18.9, 'Feb.': 28.8, 'Mar.': 39.3, 'Apr.': 81.4, 'May': 47, 'Jun.': 20.3, 'Jul.': 24, 'Aug.': 35.6 },
+          { 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 }
+        ]
       },
-      fields:{
-        type:Array,
-        default:()=>[]
+      fields: {
+        type: Array,
+        default: () => ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.']
+      },
+      // 别名,需要的格式:[{field:'name',alias:'姓名'}, {field:'sex',alias:'性别'}]
+      aliases: {
+        type: Array,
+        default: () => []
+      },
+      height: {
+        type: Number,
+        default: 254
       }
     },
     data() {
       return {
-        chartData:"",
-        height: 400,
         adjust: [{
           type: 'dodge',
-          marginRatio: 1 / 32,
-        }],
-      };
-    },
-    watch: {
-      'sourceData': function () {
-        this.drawChart();
+          marginRatio: 1 / 32
+        }]
       }
     },
-    mounted(){
-      this.drawChart()
-    },
-    methods:{
-      drawChart(){
-        let temp = sourceDataConst;
-        if(this.sourceData && this.sourceData.length>0){
-          temp = this.sourceData
-        }
-        const dv = new DataSet.View().source(temp);
+    computed: {
+      data() {
+        const dv = new DataSet.View().source(this.dataSource)
         dv.transform({
           type: 'fold',
-          fields:(!this.fields||this.fields.length==0)?fieldsConst:this.fields,
+          fields: this.fields,
           key: 'x',
-          value: 'y',
-        });
-        this.chartData=dv.rows;
+          value: 'y'
+        })
+
+        // bar 使用不了 - 和 / 所以替换下
+        let rows = dv.rows.map(row => {
+          if (typeof row.x === 'string') {
+            row.x = row.x.replace(/[-/]/g, '_')
+          }
+          return row
+        })
+        // 替换别名
+        rows.forEach(row => {
+          for (let item of this.aliases) {
+            if (item.field === row.type) {
+              row.type = item.alias
+              break
+            }
+          }
+        })
+        return rows
       }
     }
   }

+ 3 - 1
ant-design-vue-jeecg/src/components/chart/LineChartMultid.vue

@@ -1,7 +1,7 @@
 <template>
   <div :style="{ padding: '0 0 32px 32px' }">
     <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
-    <v-chart :force-fit="true" :height="height" :data="data" :scale="scale">
+    <v-chart :force-fit="true" :height="height" :data="data" :scale="scale" :onClick="handleClick">
       <v-tooltip/>
       <v-axis/>
       <v-legend/>
@@ -13,9 +13,11 @@
 
 <script>
   import { DataSet } from '@antv/data-set'
+  import { ChartEventMixins } from './mixins/ChartMixins'
 
   export default {
     name: 'LineChartMultid',
+    mixins: [ChartEventMixins],
     props: {
       title: {
         type: String,

+ 4 - 1
ant-design-vue-jeecg/src/components/chart/Pie.vue

@@ -1,5 +1,5 @@
 <template>
-  <v-chart :forceFit="true" :height="height" :data="data" :scale="scale">
+  <v-chart :forceFit="true" :height="height" :data="data" :scale="scale" :onClick="handleClick">
     <v-tooltip :showTitle="false" dataKey="item*percent"/>
     <v-axis/>
     <v-legend dataKey="item"/>
@@ -10,8 +10,11 @@
 
 <script>
   const DataSet = require('@antv/data-set')
+  import { ChartEventMixins } from './mixins/ChartMixins'
 
   export default {
+    name: 'Pie',
+    mixins: [ChartEventMixins],
     props: {
       title: {
         type: String,

+ 10 - 0
ant-design-vue-jeecg/src/components/chart/mixins/ChartMixins.js

@@ -0,0 +1,10 @@
+export const ChartEventMixins = {
+  methods: {
+    handleClick(event, chart) {
+      this.handleEvent('click', event, chart)
+    },
+    handleEvent(eventName, event, chart) {
+      this.$emit(eventName, event, chart)
+    },
+  }
+}

+ 9 - 4
ant-design-vue-jeecg/src/components/dict/JDictSelectTag.vue

@@ -1,10 +1,10 @@
 <template>
-  <a-radio-group v-if="tagType=='radio'" @change="handleInput" :value="value" :disabled="disabled">
+  <a-radio-group v-if="tagType=='radio'" @change="handleInput" :value="getValueSting" :disabled="disabled">
     <a-radio v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio>
   </a-radio-group>
 
-  <a-select v-else-if="tagType=='select'" :getPopupContainer = "(target) => target.parentNode" :placeholder="placeholder" :disabled="disabled" :value="value" @change="handleInput">
-    <a-select-option value="">请选择</a-select-option>
+  <a-select v-else-if="tagType=='select'" :getPopupContainer = "(target) => target.parentNode" :placeholder="placeholder" :disabled="disabled" :value="getValueSting" @change="handleInput">
+    <a-select-option :value="undefined">请选择</a-select-option>
     <a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">
       <span style="display: inline-block;width: 100%" :title=" item.text || item.label ">
         {{ item.text || item.label }}
@@ -23,7 +23,7 @@
       placeholder: String,
       triggerChange: Boolean,
       disabled: Boolean,
-      value: String,
+      value: [String, Number],
       type: String
     },
     data() {
@@ -50,6 +50,11 @@
       //获取字典数据
       // this.initDictData();
     },
+    computed: {
+      getValueSting(){
+        return this.value ? this.value.toString() : null;
+      },
+    },
     methods: {
       initDictData() {
         //根据字典Code, 初始化字典数组

+ 10 - 0
ant-design-vue-jeecg/src/components/dict/JDictSelectUtil.js

@@ -47,10 +47,20 @@ export function filterDictText(dictOptions, text) {
  * @return String
  */
 export function filterMultiDictText(dictOptions, text) {
+  //js “!text” 认为0为空,所以做提前处理
+  if(text === 0 || text === '0'){
+    for (let dictItem of dictOptions) {
+      if (text == dictItem.value) {
+        return dictItem.text
+      }
+    }
+  }
+
   if(!text || !dictOptions || dictOptions.length==0){
     return ""
   }
   let re = "";
+  text = text.toString()
   let arr = text.split(",")
   dictOptions.forEach(function (option) {
     for(let i=0;i<arr.length;i++){

+ 343 - 215
ant-design-vue-jeecg/src/components/jeecg/JEditableTable.vue

@@ -32,6 +32,8 @@
       </a-col>
     </a-row>
 
+    <slot name="actionButtonAfter" :target="getVM()"/>
+
     <div :id="`${caseId}inputTable`" class="input-table">
       <!-- 渲染表头 -->
       <div class="thead" ref="thead">
@@ -142,7 +144,9 @@
                         placement="top"
                         :title="(tooltips[id] || {}).title"
                         :visible="(tooltips[id] || {}).visible || false"
-                        :autoAdjustOverflow="true">
+                        :autoAdjustOverflow="true"
+                        :getPopupContainer="getParentContainer"
+                      >
 
                         <input
                           :id="id"
@@ -175,7 +179,9 @@
                         placement="top"
                         :title="(tooltips[id] || {}).title"
                         :visible="(tooltips[id] || {}).visible || false"
-                        :autoAdjustOverflow="true">
+                        :autoAdjustOverflow="true"
+                        :getPopupContainer="getParentContainer"
+                      >
 
                       <span
                         @mouseover="()=>{handleMouseoverCommono(row,col)}"
@@ -211,7 +217,9 @@
                         placement="top"
                         :title="(tooltips[id] || {}).title"
                         :visible="(tooltips[id] || {}).visible || false"
-                        :autoAdjustOverflow="true">
+                        :autoAdjustOverflow="true"
+                        :getPopupContainer="getParentContainer"
+                      >
 
                       <span
                         @mouseover="()=>{handleMouseoverCommono(row,col)}"
@@ -278,19 +286,33 @@
                       </template>
 
                       <div :hidden="uploadValues[id] != null">
-
-                        <a-upload
-                          name="file"
-                          :data="{'isup':1}"
-                          :multiple="false"
-                          :action="col.action"
-                          :headers="uploadGetHeaders(row,col)"
-                          :showUploadList="false"
-                          v-bind="buildProps(row,col)"
-                          @change="(v)=>handleChangeUpload(v,id,row,col)"
+                        <a-tooltip
+                          :key="i"
+                          :id="id"
+                          placement="top"
+                          :title="(tooltips[id] || {}).title"
+                          :visible="(tooltips[id] || {}).visible || false"
+                          :autoAdjustOverflow="true"
+                          :getPopupContainer="getParentContainer"
                         >
-                          <a-button icon="upload">{{ col.placeholder }}</a-button>
-                        </a-upload>
+
+                          <span
+                            @mouseover="()=>{handleMouseoverCommono(row,col)}"
+                            @mouseout="()=>{handleMouseoutCommono(row,col)}">
+                            <a-upload
+                              name="file"
+                              :data="{'isup':1}"
+                              :multiple="false"
+                              :action="col.action"
+                              :headers="uploadGetHeaders(row,col)"
+                              :showUploadList="false"
+                              v-bind="buildProps(row,col)"
+                              @change="(v)=>handleChangeUpload(v,id,row,col)"
+                            >
+                              <a-button icon="upload">{{ col.placeholder }}</a-button>
+                            </a-upload>
+                          </span>
+                        </a-tooltip>
                       </div>
 
                     </div>
@@ -303,7 +325,10 @@
                         placement="top"
                         :title="(tooltips[id] || {}).title"
                         :visible="(tooltips[id] || {}).visible || false"
-                        :autoAdjustOverflow="true">
+                        :autoAdjustOverflow="true"
+                        :getPopupContainer="getParentContainer"
+                      >
+
                         <span
                           @mouseover="()=>{handleMouseoverCommono(row,col)}"
                           @mouseout="()=>{handleMouseoutCommono(row,col)}">
@@ -359,19 +384,33 @@
                       </template>
 
                       <div :hidden="uploadValues[id] != null">
-
-                        <a-upload
-                          name="file"
-                          :data="{'isup':1}"
-                          :multiple="false"
-                          :action="getUploadAction(col.action)"
-                          :headers="uploadGetHeaders(row,col)"
-                          :showUploadList="false"
-                          v-bind="buildProps(row,col)"
-                          @change="(v)=>handleChangeUpload(v,id,row,col)"
+                        <a-tooltip
+                          :key="i"
+                          :id="id"
+                          placement="top"
+                          :title="(tooltips[id] || {}).title"
+                          :visible="(tooltips[id] || {}).visible || false"
+                          :autoAdjustOverflow="true"
+                          :getPopupContainer="getParentContainer"
                         >
-                          <a-button icon="upload">{{ col.placeholder }}</a-button>
-                        </a-upload>
+
+                          <span
+                            @mouseover="()=>{handleMouseoverCommono(row,col)}"
+                            @mouseout="()=>{handleMouseoutCommono(row,col)}">
+                            <a-upload
+                              name="file"
+                              :data="{'isup':1}"
+                              :multiple="false"
+                              :action="getUploadAction(col.action)"
+                              :headers="uploadGetHeaders(row,col)"
+                              :showUploadList="false"
+                              v-bind="buildProps(row,col)"
+                              @change="(v)=>handleChangeUpload(v,id,row,col)"
+                            >
+                              <a-button icon="upload">{{ col.placeholder }}</a-button>
+                            </a-upload>
+                          </span>
+                        </a-tooltip>
                       </div>
 
                     </div>
@@ -406,19 +445,33 @@
                       </template>
 
                       <div :hidden="uploadValues[id] != null">
-
-                        <a-upload
-                          name="file"
-                          :data="{'isup':1}"
-                          :multiple="false"
-                          :action="getUploadAction(col.action)"
-                          :headers="uploadGetHeaders(row,col)"
-                          :showUploadList="false"
-                          v-bind="buildProps(row,col)"
-                          @change="(v)=>handleChangeUpload(v,id,row,col)"
+                        <a-tooltip
+                          :key="i"
+                          :id="id"
+                          placement="top"
+                          :title="(tooltips[id] || {}).title"
+                          :visible="(tooltips[id] || {}).visible || false"
+                          :autoAdjustOverflow="true"
+                          :getPopupContainer="getParentContainer"
                         >
-                          <a-button icon="upload">请上传图片</a-button>
-                        </a-upload>
+
+                          <span
+                            @mouseover="()=>{handleMouseoverCommono(row,col)}"
+                            @mouseout="()=>{handleMouseoutCommono(row,col)}">
+                            <a-upload
+                              name="file"
+                              :data="{'isup':1}"
+                              :multiple="false"
+                              :action="getUploadAction(col.action)"
+                              :headers="uploadGetHeaders(row,col)"
+                              :showUploadList="false"
+                              v-bind="buildProps(row,col)"
+                              @change="(v)=>handleChangeUpload(v,id,row,col)"
+                            >
+                              <a-button icon="upload">请上传图片</a-button>
+                            </a-upload>
+                          </span>
+                        </a-tooltip>
                       </div>
 
                     </div>
@@ -433,7 +486,10 @@
                         placement="top"
                         :title="(tooltips[id] || {}).title"
                         :visible="(tooltips[id] || {}).visible || false"
-                        :autoAdjustOverflow="true">
+                        :autoAdjustOverflow="true"
+                        :getPopupContainer="getParentContainer"
+                      >
+
                         <span
                           @mouseover="()=>{handleMouseoverCommono(row,col)}"
                           @mouseout="()=>{handleMouseoutCommono(row,col)}">
@@ -459,7 +515,9 @@
                         placement="top"
                         :title="(tooltips[id] || {}).title"
                         :visible="(tooltips[id] || {}).visible || false"
-                        :autoAdjustOverflow="true">
+                        :autoAdjustOverflow="true"
+                        :getPopupContainer="getParentContainer"
+                      >
 
                         <span
                           @mouseover="()=>{handleMouseoverCommono(row,col)}"
@@ -492,7 +550,9 @@
                         placement="top"
                         :title="(tooltips[id] || {}).title"
                         :visible="(tooltips[id] || {}).visible || false"
-                        :autoAdjustOverflow="true">
+                        :autoAdjustOverflow="true"
+                        :getPopupContainer="getParentContainer"
+                      >
 
                         <span
                           @mouseover="()=>{handleMouseoverCommono(row,col)}"
@@ -526,7 +586,9 @@
                         placement="top"
                         :title="(tooltips[id] || {}).title"
                         :visible="(tooltips[id] || {}).visible || false"
-                        :autoAdjustOverflow="true">
+                        :autoAdjustOverflow="true"
+                        :getPopupContainer="getParentContainer"
+                      >
 
                         <span
                           @mouseover="()=>{handleMouseoverCommono(row,col)}"
@@ -693,6 +755,7 @@
       }
     },
     created() {
+      this.inputValues = []
       // 当前显示的tr
       this.visibleTrEls = []
       this.disabledRowIds = (this.disabledRowIds || [])
@@ -771,149 +834,155 @@
       dataSource: {
         immediate: true,
         handler: function (newValue) {
-          this.initialize()
-
-          let rows = []
-          let checkboxValues = {}
-          let selectValues = {}
-          let jdateValues = {}
-          let slotValues = {}
-          let uploadValues = {}
-          let popupValues = {}
-          let radioValues = {}
-          let multiSelectValues = {}
-          let searchSelectValues = {}
-
-          // 禁用行的id
-          let disabledRowIds = (this.disabledRowIds || [])
-          newValue.forEach((data, newValueIndex) => {
-            // 判断源数据是否带有id
-            if (data.id == null || data.id === '') {
-              data.id = this.removeCaseId(this.generateId() + newValueIndex)
-            }
+          // 兼容IE
+          this.getElementPromise('tbody').then(() => {
+
+            this.initialize()
+
+            let rows = []
+            let checkboxValues = {}
+            let selectValues = {}
+            let jdateValues = {}
+            let slotValues = {}
+            let uploadValues = {}
+            let popupValues = {}
+            let radioValues = {}
+            let multiSelectValues = {}
+            let searchSelectValues = {}
+
+            // 禁用行的id
+            let disabledRowIds = (this.disabledRowIds || [])
+            newValue.forEach((data, newValueIndex) => {
+              // 判断源数据是否带有id
+              if (data.id == null || data.id === '') {
+                data.id = this.removeCaseId(this.generateId() + newValueIndex)
+              }
 
-            let value = { id: this.caseId + data.id }
-            let row = { id: value.id }
-            let disabled = false
-            this.columns.forEach(column => {
-              let inputId = column.key + value.id
-              let sourceValue = (data[column.key] == null ? '' : data[column.key]).toString()
-              if (column.type === FormTypes.checkbox) {
-
-                // 判断是否设定了customValue(自定义值)
-                if (column.customValue instanceof Array) {
-                  let customValue = (column.customValue[0] || '').toString()
-                  checkboxValues[inputId] = (sourceValue === customValue)
-                } else {
-                  checkboxValues[inputId] = sourceValue
-                }
+              let value = { id: this.caseId + data.id }
+              let row = { id: value.id }
+              let disabled = false
+              this.columns.forEach(column => {
+                let inputId = column.key + value.id
+                let sourceValue = (data[column.key] == null ? '' : data[column.key]).toString()
+                if (column.type === FormTypes.checkbox) {
+
+                  // 判断是否设定了customValue(自定义值)
+                  if (column.customValue instanceof Array) {
+                    let customValue = (column.customValue[0] || '').toString()
+                    checkboxValues[inputId] = (sourceValue === customValue)
+                  } else {
+                    checkboxValues[inputId] = sourceValue
+                  }
 
-              } else if (column.type === FormTypes.select) {
-                if (sourceValue) {
-                  // 判断是否是多选
-                  selectValues[inputId] = (column.props || {})['mode'] === 'multiple' ? sourceValue.split(',') : sourceValue
-                } else {
-                  selectValues[inputId] = undefined
-                }
+                } else if (column.type === FormTypes.select) {
+                  if (sourceValue) {
+                    // 判断是否是多选
+                    selectValues[inputId] = (column.props || {})['mode'] === 'multiple' ? sourceValue.split(',') : sourceValue
+                  } else {
+                    selectValues[inputId] = undefined
+                  }
 
-              } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
-                jdateValues[inputId] = sourceValue
+                } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
+                  jdateValues[inputId] = sourceValue
 
-              } else if (column.type === FormTypes.slot) {
-                if (sourceValue !== 0 && !sourceValue) {
-                  slotValues[inputId] = column.defaultValue
-                } else {
-                  slotValues[inputId] = sourceValue
-                }
+                } else if (column.type === FormTypes.slot) {
+                  if (sourceValue !== 0 && !sourceValue) {
+                    slotValues[inputId] = column.defaultValue
+                  } else {
+                    slotValues[inputId] = sourceValue
+                  }
 
-              } else if (column.type === FormTypes.popup) {
-                popupValues[inputId] = sourceValue
-              } else if (column.type === FormTypes.radio) {
-                radioValues[inputId] = sourceValue
-              } else if (column.type === FormTypes.sel_search) {
-                searchSelectValues[inputId] = sourceValue
-              } else if (column.type === FormTypes.list_multi) {
-                if (sourceValue.length > 0) {
-                  multiSelectValues[inputId] = sourceValue.split(',')
-                } else {
-                  multiSelectValues[inputId] = []
-                }
-              } else if (column.type === FormTypes.upload || column.type === FormTypes.file || column.type === FormTypes.image) {
-                if (sourceValue) {
-                  let fileName = sourceValue.substring(sourceValue.lastIndexOf('/') + 1)
-                  uploadValues[inputId] = {
-                    name: fileName,
-                    status: 'done',
-                    path: sourceValue
+                } else if (column.type === FormTypes.popup) {
+                  popupValues[inputId] = sourceValue
+                } else if (column.type === FormTypes.radio) {
+                  radioValues[inputId] = sourceValue
+                } else if (column.type === FormTypes.sel_search) {
+                  searchSelectValues[inputId] = sourceValue
+                } else if (column.type === FormTypes.list_multi) {
+                  if (sourceValue.length > 0) {
+                    multiSelectValues[inputId] = sourceValue.split(',')
+                  } else {
+                    multiSelectValues[inputId] = []
                   }
+                } else if (column.type === FormTypes.upload || column.type === FormTypes.file || column.type === FormTypes.image) {
+                  if (sourceValue) {
+                    let fileName = sourceValue.substring(sourceValue.lastIndexOf('/') + 1)
+                    uploadValues[inputId] = {
+                      name: fileName,
+                      status: 'done',
+                      path: sourceValue
+                    }
+                  }
+                } else {
+                  value[column.key] = sourceValue
                 }
-              } else {
-                value[column.key] = sourceValue
-              }
 
-              // 解析disabledRows
-              for (let columnKey in this.disabledRows) {
-                // 判断是否有该属性
-                if (this.disabledRows.hasOwnProperty(columnKey) && data.hasOwnProperty(columnKey)) {
-                  if (disabled !== true) {
-                    let temp = this.disabledRows[columnKey]
-                    // 禁用规则可以是一个数组
-                    if (temp instanceof Array) {
-                      disabled = temp.includes(data[columnKey])
-                    } else {
-                      disabled = (temp === data[columnKey])
-                    }
-                    if (disabled) {
-                      disabledRowIds.push(row.id)
+                // 解析disabledRows
+                for (let columnKey in this.disabledRows) {
+                  // 判断是否有该属性
+                  if (this.disabledRows.hasOwnProperty(columnKey) && data.hasOwnProperty(columnKey)) {
+                    if (disabled !== true) {
+                      let temp = this.disabledRows[columnKey]
+                      // 禁用规则可以是一个数组
+                      if (temp instanceof Array) {
+                        disabled = temp.includes(data[columnKey])
+                      } else {
+                        disabled = (temp === data[columnKey])
+                      }
+                      if (disabled) {
+                        disabledRowIds.push(row.id)
+                      }
                     }
                   }
                 }
-              }
+              })
+              this.inputValues.push(value)
+              rows.push(row)
+            })
+            this.disabledRowIds = disabledRowIds
+            this.checkboxValues = checkboxValues
+            this.selectValues = selectValues
+            this.jdateValues = jdateValues
+            this.slotValues = slotValues
+            this.rows = rows
+            this.uploadValues = uploadValues
+            this.popupValues = popupValues
+            this.radioValues = radioValues
+            this.multiSelectValues = multiSelectValues
+            this.searchSelectValues = searchSelectValues
+
+            // 更新form表单的值
+            this.$nextTick(() => {
+              this.updateFormValues()
             })
-            this.inputValues.push(value)
-            rows.push(row)
-          })
-          this.disabledRowIds = disabledRowIds
-          this.checkboxValues = checkboxValues
-          this.selectValues = selectValues
-          this.jdateValues = jdateValues
-          this.slotValues = slotValues
-          this.rows = rows
-          this.uploadValues = uploadValues
-          this.popupValues = popupValues
-          this.radioValues = radioValues
-          this.multiSelectValues = multiSelectValues
-          this.searchSelectValues = searchSelectValues
-
-          // 更新form表单的值
-          this.$nextTick(() => {
-            this.updateFormValues()
           })
-
         }
       },
       columns: {
         immediate: true,
         handler(columns) {
-          columns.forEach(column => {
-            if (column.type === FormTypes.select || column.type === FormTypes.list_multi || column.type === FormTypes.sel_search) {
-              // 兼容 旧版本 options
-              if (column.options instanceof Array) {
-                column.options = column.options.map(item => {
-                  if (item) {
-                    return {
-                      ...item,
-                      text: item.text || item.title,
-                      title: item.text || item.title
+          // 兼容IE
+          this.getElementPromise('tbody').then(() => {
+            columns.forEach(column => {
+              if (column.type === FormTypes.select || column.type === FormTypes.list_multi || column.type === FormTypes.sel_search) {
+                // 兼容 旧版本 options
+                if (column.options instanceof Array) {
+                  column.options = column.options.map(item => {
+                    if (item) {
+                      return {
+                        ...item,
+                        text: item.text || item.title,
+                        title: item.text || item.title
+                      }
                     }
-                  }
-                  return {}
-                })
-              }
-              if (column.dictCode) {
-                this._loadDictConcatToOptions(column)
+                    return {}
+                  })
+                }
+                if (column.dictCode) {
+                  this._loadDictConcatToOptions(column)
+                }
               }
-            }
+            })
           })
         }
       },
@@ -923,19 +992,12 @@
       }
     },
     mounted() {
-      // 获取document element对象
-      let elements = {};
-      ['inputTable', 'tbody'].forEach(id => {
-        elements[id] = document.getElementById(this.caseId + id)
-      })
-      this.el = elements
-
       let vm = this
       /** 监听滚动条事件 */
-      this.el.inputTable.onscroll = function (event) {
+      this.getElement('inputTable').onscroll = function (event) {
         vm.syncScrollBar(event.target.scrollLeft)
       }
-      this.el.tbody.onscroll = function (event) {
+      this.getElement('tbody').onscroll = function (event) {
         // vm.recalcTrHiddenItem(event.target.scrollTop)
       }
 
@@ -955,6 +1017,25 @@
     },
     methods: {
 
+      getElement(id, noCaseId = false) {
+        if (!this.el[id]) {
+          this.el[id] = document.getElementById((noCaseId ? '' : this.caseId) + id)
+        }
+        return this.el[id]
+      },
+
+      getElementPromise(id, noCaseId = false) {
+        return new Promise((resolve) => {
+          let timer = setInterval(() => {
+            let element = this.getElement(id, noCaseId)
+            if (element) {
+              clearInterval(timer)
+              resolve(element)
+            }
+          }, 10)
+        })
+      },
+
       /** 初始化列表 */
       initialize() {
         // inputValues:用来存储input表单的值
@@ -985,14 +1066,14 @@
         this.searchSelectValues = []
         this.scrollTop = 0
         this.$nextTick(() => {
-          this.el.tbody.scrollTop = 0
+          this.getElement('tbody').scrollTop = 0
         })
       },
 
       /** 同步滚动条状态 */
       syncScrollBar(scrollLeft) {
         // this.style.tbody.left = `${scrollLeft}px`
-        // this.el.tbody.scrollLeft = scrollLeft
+        // this.getElement('tbody').scrollLeft = scrollLeft
       },
       /** 重置滚动条位置,参数留空则滚动到上次记录的位置 */
       resetScrollTop(top) {
@@ -1157,7 +1238,7 @@
           target: this
         })
         // 设置滚动条位置
-        let tbody = this.el.tbody
+        let tbody = this.getElement('tbody')
         let offsetHeight = tbody.offsetHeight
         let realScrollTop = tbody.scrollTop + offsetHeight
         if (forceScrollToBottom === false) {
@@ -1245,13 +1326,14 @@
         return true
       },
 
-      /** 获取表格表单里的值(步版) */
-      getValuesSync(options = {}) {
+      /** 获取表格表单里的值(步版) */
+      getValuesAsync(options = {}, callback) {
         let { validate, rowIds } = options
         if (typeof validate !== 'boolean') validate = true
         if (!(rowIds instanceof Array)) rowIds = null
         // console.log('options:', { validate, rowIds })
 
+        let asyncCount = 0
         let error = 0
         let inputValues = cloneObject(this.inputValues)
         let tooltips = Object.assign({}, this.tooltips)
@@ -1314,7 +1396,7 @@
             } else if (column.type === FormTypes.sel_search) {
               value[column.key] = this.searchSelectValues[inputId]
             } else if (column.type === FormTypes.list_multi) {
-              if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length == 0) {
+              if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length === 0) {
                 value[column.key] = ''
               } else {
                 value[column.key] = this.multiSelectValues[inputId].join(',')
@@ -1326,20 +1408,27 @@
 
             // 检查表单验证
             if (validate === true) {
-              let results = this.validateOneInput(value[column.key], value, column, notPassedIds, false, 'getValues')
-              tooltips[inputId] = results[0]
-              if (tooltips[inputId].passed === false) {
-                error++
-                // if (error++ === 0) {
-                // let element = document.getElementById(inputId)
-                // while (element.className !== 'tr') {
-                //   element = element.parentElement
-                // }
-                // this.jumpToId(inputId, element)
-                // }
+              const handleValidateOneInput = (results) => {
+                tooltips[inputId] = results[0]
+                if (tooltips[inputId].passed === false) {
+                  error++
+                  // if (error++ === 0) {
+                  // let element = document.getElementById(inputId)
+                  // while (element.className !== 'tr') {
+                  //   element = element.parentElement
+                  // }
+                  // this.jumpToId(inputId, element)
+                  // }
+                }
+                tooltips[inputId].visible = false
+                notPassedIds = results[1]
               }
-              tooltips[inputId].visible = false
-              notPassedIds = results[1]
+              asyncCount++
+              let results = this.validateOneInputAsync(value[column.key], value, column, notPassedIds, false, 'getValues', (results) => {
+                handleValidateOneInput(results)
+                asyncCount--
+              })
+              handleValidateOneInput(results)
             }
           })
           // 将caseId去除
@@ -1352,25 +1441,42 @@
           this.tooltips = tooltips
           this.notPassedIds = notPassedIds
         }
+
+        const timer = setInterval(() => {
+          if (asyncCount === 0) {
+            clearInterval(timer)
+            if (typeof callback === 'function') {
+              callback({ error, values })
+            }
+          }
+        }, 50)
+
         return { error, values }
       },
 
+      /** 获取表格表单里的值(同步版) */
+      getValuesSync(options = {}) {
+        return this.getValuesAsync(options)
+      },
+
       /** 获取表格表单里的值 */
       getValues(callback, validate = true, rowIds) {
-        let result = this.getValuesSync({ validate, rowIds })
-        if (typeof callback === 'function') {
-          callback(result.error, result.values)
-        }
+        this.getValuesAsync({ validate, rowIds }, ({ error, values }) => {
+          if (typeof callback === 'function') {
+            callback(error, values)
+          }
+        })
       },
       /** getValues的Promise版 */
       getValuesPromise(validate = true, rowIds) {
         return new Promise((resolve, reject) => {
-          let { error, values } = this.getValuesSync({ validate, rowIds })
-          if (error === 0) {
-            resolve(values)
-          } else {
-            reject(VALIDATE_NO_PASSED)
-          }
+          this.getValuesAsync({ validate, rowIds }, ({ error, values }) => {
+            if (error === 0) {
+              resolve(values)
+            } else {
+              reject(VALIDATE_NO_PASSED)
+            }
+          })
         })
       },
       /** 获取被删除项的id */
@@ -1468,14 +1574,24 @@
       //     element = document.getElementById(id)
       //   }
       //   if (element != null) {
-      //     console.log(this.el.tbody.scrollTop, element.offsetTop)
-      //     this.el.tbody.scrollTop = element.offsetTop
-      //     console.log(this.el.tbody.scrollTop, element.offsetTop)
+      //     console.log(this.getElement('tbody').scrollTop, element.offsetTop)
+      //     this.getElement('tbody').scrollTop = element.offsetTop
+      //     console.log(this.getElement('tbody').scrollTop, element.offsetTop)
       //   }
       // },
 
-      /** 验证单个表单 */
-      validateOneInput(value, row, column, notPassedIds, update = false, validType = 'input') {
+      /**
+       * 验证单个表单,异步版
+       *
+       * @param value 校验的值
+       * @param row 校验的行
+       * @param column 校验的列
+       * @param notPassedIds 没有通过校验的 id
+       * @param update 是否更新到vue中
+       * @param validType 校验触发的方式(input、blur等)
+       * @param callback
+       */
+      validateOneInputAsync(value, row, column, notPassedIds, update = false, validType = 'input', callback) {
         let tooltips = Object.assign({}, this.tooltips)
         // let notPassedIds = cloneObject(this.notPassedIds)
         let inputId = column.key + row.id
@@ -1515,6 +1631,10 @@
             if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
               element = element.getElementsByTagName('input')[0]
             }
+            // upload 在 .ant-upload .ant-btn 上设置 border-color
+            if (column.type === FormTypes.upload || column.type === FormTypes.file || column.type === FormTypes.image) {
+              element = element.getElementsByClassName('ant-upload')[0].getElementsByClassName('ant-btn')[0]
+            }
             element.style.borderColor = borderColor
             element.style.boxShadow = boxShadow
             if (element.tagName === 'SPAN') {
@@ -1527,6 +1647,10 @@
             this.notPassedIds = notPassedIds
           }
 
+          if (typeof callback === 'function') {
+            callback([tooltips[inputId], notPassedIds])
+          }
+
         }
 
         if (typeof passed === 'function') {
@@ -1547,9 +1671,13 @@
           nextThen([passed, message])
         }
 
-
         return [tooltips[inputId], notPassedIds]
       },
+
+      /** 验证单个表单 */
+      validateOneInput(value, row, column, notPassedIds, update = false, validType = 'input') {
+        return this.validateOneInputAsync(value, row, column, notPassedIds, update, validType)
+      },
       /** 通过规则验证值是否正确 */
       validateValue(column, value) {
         let rules = column.validateRules
@@ -1620,7 +1748,7 @@
 
       /** 动态更新表单的值 */
       updateFormValues() {
-        let trs = this.el.tbody.getElementsByClassName('tr')
+        let trs = this.getElement('tbody').getElementsByClassName('tr')
         let trEls = []
         for (let tr of trs) {
           trEls.push(tr)
@@ -1959,7 +2087,7 @@
       handleClickDownloadFile(id) {
         let { path } = this.uploadValues[id] || {}
         if (path) {
-          let url = window._CONFIG['downloadUrl'] + '/' + path
+          let url = window._CONFIG['staticDomainURL'] + '/' + path
           window.open(url)
         }
       },
@@ -2130,7 +2258,7 @@
       getCellImageView(id) {
         let currUploadObj = this.uploadValues[id] || null
         if (currUploadObj && currUploadObj['path']) {
-          return window._CONFIG['domianURL'] + '/sys/common/view/' + currUploadObj['path']
+          return window._CONFIG['staticDomainURL'] + '/' + currUploadObj['path']
         } else {
           return ''
         }
@@ -2340,7 +2468,7 @@
 
       .td {
         /*flex: 1;*/
-        padding: 14px 0 14px @spacing;
+        padding: 14px @spacing 14px 0;
         justify-content: center;
 
         &:last-child {

+ 1 - 1
ant-design-vue-jeecg/src/components/jeecg/JGraphicCode.vue

@@ -150,7 +150,7 @@
               console.log("aaaaa",res)
               if(res.success){
                 this.checkKey = res.result.key
-                this.code = res.result.code
+                this.code = window.atob(res.result.code)
                 resolve();
               }else{
                 this.$message.error("生成验证码错误,请联系系统管理员")

+ 202 - 0
ant-design-vue-jeecg/src/components/jeecg/JImageUpload.vue

@@ -0,0 +1,202 @@
+<template>
+  <a-upload
+    name="file"
+    listType="picture-card"
+    :multiple="isMultiple"
+    :action="uploadAction"
+    :headers="headers"
+    :data="{biz:bizPath}"
+    :fileList="fileList"
+    :beforeUpload="beforeUpload"
+    :disabled="disabled"
+    :isMultiple="isMultiple"
+    :showUploadList="isMultiple"
+    @change="handleChange"
+    @preview="handlePreview">
+    <img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="height:104px;max-width:300px"/>
+    <div v-else >
+      <a-icon :type="uploadLoading ? 'loading' : 'plus'" />
+      <div class="ant-upload-text">{{ text }}</div>
+    </div>
+    <a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
+      <img alt="example" style="width: 100%" :src="previewImage"/>
+    </a-modal>
+  </a-upload>
+</template>
+
+<script>
+  import Vue from 'vue'
+  import { ACCESS_TOKEN } from "@/store/mutation-types"
+  import { getFileAccessHttpUrl } from '@/api/manage'
+
+  const uidGenerator=()=>{
+    return '-'+parseInt(Math.random()*10000+1,10);
+  }
+  const getFileName=(path)=>{
+    if(path.lastIndexOf("\\")>=0){
+      let reg=new RegExp("\\\\","g");
+      path = path.replace(reg,"/");
+    }
+    return path.substring(path.lastIndexOf("/")+1);
+  }
+  export default {
+    name: 'JImageUpload',
+    data(){
+      return {
+        uploadAction:window._CONFIG['domianURL']+"/sys/common/upload",
+        urlView:window._CONFIG['staticDomainURL'],
+        uploadLoading:false,
+        picUrl:false,
+        headers:{},
+        fileList: [],
+        previewImage:"",
+        previewVisible: false,
+      }
+    },
+    props:{
+      text:{
+        type:String,
+        required:false,
+        default:"上传"
+      },
+      /*这个属性用于控制文件上传的业务路径*/
+      bizPath:{
+        type:String,
+        required:false,
+        default:"temp"
+      },
+      value:{
+        type:[String,Array],
+        required:false
+      },
+      disabled:{
+        type:Boolean,
+        required:false,
+        default: false
+      },
+      isMultiple:{
+        type:Boolean,
+        required:false,
+        default: false
+      }
+    },
+    watch:{
+      value(val){
+        if (val instanceof Array) {
+          this.initFileList(val.join(','))
+        } else {
+          this.initFileList(val)
+        }
+      }
+    },
+    created(){
+      const token = Vue.ls.get(ACCESS_TOKEN);
+      this.headers = {"X-Access-Token":token}
+    },
+    methods:{
+      initFileList(paths){
+        if(!paths || paths.length==0){
+          this.fileList = [];
+          return;
+        }
+        this.picUrl = true;
+        let fileList = [];
+        let arr = paths.split(",")
+        for(var a=0;a<arr.length;a++){
+          let url = getFileAccessHttpUrl(arr[a],this.urlView,"http");
+          fileList.push({
+            uid: uidGenerator(),
+            name: getFileName(arr[a]),
+            status: 'done',
+            url: url,
+            response:{
+              status:"history",
+              message:arr[a]
+            }
+          })
+        }
+        this.fileList = fileList
+      },
+      beforeUpload: function(file){
+        var fileType = file.type;
+        if(fileType.indexOf('image')<0){
+          this.$message.warning('请上传图片');
+          return false;
+        }
+      },
+      handleChange(info) {
+        this.picUrl = false;
+        let fileList = info.fileList
+        if(info.file.status==='done'){
+          if(info.file.response.success){
+            this.picUrl = true;
+            fileList = fileList.map((file) => {
+              if (file.response) {
+                file.url = file.response.message;
+              }
+              return file;
+            });
+          }
+          //this.$message.success(`${info.file.name} 上传成功!`);
+        }else if (info.file.status === 'error') {
+          this.$message.error(`${info.file.name} 上传失败.`);
+        }else if(info.file.status === 'removed'){
+          this.handleDelete(info.file)
+        }
+        this.fileList = fileList
+        if(info.file.status==='done' || info.file.status === 'removed'){
+          this.handlePathChange()
+        }
+      },
+      // 预览
+      handlePreview (file) {
+        this.previewImage = file.url || file.thumbUrl
+        this.previewVisible = true
+      },
+      getAvatarView(){
+        if(this.fileList.length>0){
+          let url = this.fileList[0].url
+          return getFileAccessHttpUrl(url,this.urlView,"http")
+        }
+      },
+      handlePathChange(){
+        let uploadFiles = this.fileList
+        let path = ''
+        if(!uploadFiles || uploadFiles.length==0){
+          path = ''
+        }
+        let arr = [];
+        if(!this.isMultiple){
+          arr.push(uploadFiles[uploadFiles.length-1].response.message)
+        }else{
+          for(var a=0;a<uploadFiles.length;a++){
+            arr.push(uploadFiles[a].response.message)
+          }
+        }
+        if(arr.length>0){
+          path = arr.join(",")
+        }
+        this.$emit('change', path);
+      },
+      handleDelete(file){
+        //如有需要新增 删除逻辑
+        console.log(file)
+      },
+      handleCancel() {
+        this.close();
+        this.previewVisible = false;
+      },
+      close () {
+
+      },
+    },
+    model: {
+      prop: 'value',
+      event: 'change'
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 15 - 2
ant-design-vue-jeecg/src/components/jeecg/JImportModal.vue

@@ -42,6 +42,11 @@
         type: String,
         default: '',
         required: false
+      },
+      biz:{
+        type: String,
+        default: '',
+        required: false
       }
     },
     data(){
@@ -49,7 +54,8 @@
         visible:false,
         uploading:false,
         fileList:[],
-        uploadAction:''
+        uploadAction:'',
+        foreignKeys:''
       }
     },
     watch: {
@@ -67,10 +73,11 @@
       handleClose(){
         this.visible=false
       },
-      show(){
+      show(arg){
         this.fileList = []
         this.uploading = false
         this.visible = true
+        this.foreignKeys = arg;
       },
       handleRemove(file) {
         const index = this.fileList.indexOf(file);
@@ -85,6 +92,12 @@
       handleImport() {
         const { fileList } = this;
         const formData = new FormData();
+        if(this.biz){
+          formData.append('isSingleTableImport',this.biz);
+        }
+        if(this.foreignKeys && this.foreignKeys.length>0){
+          formData.append('foreignKeys',this.foreignKeys);
+        }
         fileList.forEach((file) => {
           formData.append('files[]', file);
         });

+ 209 - 0
ant-design-vue-jeecg/src/components/jeecg/JModal/index.vue

@@ -0,0 +1,209 @@
+<template>
+  <a-modal
+    ref="modal"
+    class="j-modal-box"
+    :class="{'fullscreen':innerFullscreen,'no-title':isNoTitle,'no-footer':isNoFooter,}"
+    :visible="visible"
+    v-bind="_attrs"
+    v-on="$listeners"
+    @ok="handleOk"
+    @cancel="handleCancel"
+  >
+
+    <slot></slot>
+
+    <template v-if="!isNoTitle" slot="title">
+      <a-row class="j-modal-title-row" type="flex">
+        <a-col class="left">
+          <slot name="title">{{ title }}</slot>
+        </a-col>
+        <a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
+          <a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
+        </a-col>
+      </a-row>
+    </template>
+
+    <!-- 处理 scopedSlots -->
+    <template v-for="slotName of scopedSlotsKeys" :slot="slotName">
+      <slot :name="slotName"></slot>
+    </template>
+
+    <!-- 处理 slots -->
+    <template v-for="slotName of slotsKeys" v-slot:[slotName]>
+      <slot :name="slotName"></slot>
+    </template>
+
+  </a-modal>
+</template>
+
+<script>
+  import ACol from 'ant-design-vue/es/grid/Col'
+
+  export default {
+    name: 'JModal',
+    components: { ACol },
+    props: {
+      title: String,
+      // 可使用 .sync 修饰符
+      visible: Boolean,
+      // 是否在弹出时禁止 body 滚动
+      lockScroll: {
+        type: Boolean,
+        default: true
+      },
+      // 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
+      fullscreen: {
+        type: Boolean,
+        default: true
+      },
+      // 是否允许切换全屏(允许后右上角会出现一个按钮)
+      switchFullscreen: {
+        type: Boolean,
+        default: false
+      },
+    },
+    data() {
+      return {
+        // 内部使用的 slots ,不再处理
+        usedSlots: ['title'],
+
+        // 缓存 body 的 overflow
+        bodyOverflowCache: '',
+        innerFullscreen: this.fullscreen,
+        fullscreenButtonIcon: 'fullscreen-exit',
+      }
+    },
+    computed: {
+      // 一些未处理的参数或特殊处理的参数绑定到 a-modal 上
+      _attrs() {
+        let attrs = { ...this.$attrs }
+        // 如果全屏就将宽度设为 100%
+        if (this.innerFullscreen) {
+          attrs['width'] = '100%'
+        }
+        return attrs
+      },
+      isNoTitle() {
+        return !this.title && !this.allSlotsKeys.includes('title')
+      },
+      isNoFooter() {
+        return this._attrs['footer'] === null
+      },
+      slotsKeys() {
+        return Object.keys(this.$slots).filter(key => !this.usedSlots.includes(key))
+      },
+      scopedSlotsKeys() {
+        return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
+      },
+      allSlotsKeys() {
+        return this.slotsKeys.concat(this.scopedSlotsKeys)
+      },
+      // 是否锁定body滚动
+      lockBodyScroll() {
+        return this.lockScroll || this.innerFullscreen
+      }
+    },
+    watch: {
+      visible() {
+        if (this.visible) {
+          this.innerFullscreen = this.fullscreen
+        }
+        if (this.lockBodyScroll) {
+          if (this.visible) {
+            this.bodyOverflowCache = document.body.style.overflow
+            document.body.style.overflow = 'hidden'
+          } else {
+            document.body.style.overflow = this.bodyOverflowCache
+          }
+        }
+      },
+      innerFullscreen(val) {
+        this.$emit('update:fullscreen', val)
+      },
+    },
+    methods: {
+
+      close() {
+        this.$emit('update:visible', false)
+      },
+
+      handleOk() {
+        this.close()
+      },
+      handleCancel() {
+        this.close()
+      },
+
+      toggleFullscreen() {
+        if (this.innerFullscreen) {
+          this.fullscreenButtonIcon = 'fullscreen'
+        } else {
+          this.fullscreenButtonIcon = 'fullscreen-exit'
+        }
+        this.innerFullscreen = !this.innerFullscreen
+      },
+
+    }
+  }
+</script>
+
+<style lang="scss">
+  .j-modal-box {
+
+    &.fullscreen {
+      top: 0;
+      left: 0;
+      padding: 0;
+
+      height: 100vh;
+
+      & .ant-modal-content {
+        height: 100vh;
+        border-radius: 0;
+
+        & .ant-modal-body {
+          /* title 和 footer 各占 55px */
+          height: calc(100% - 55px - 55px);
+          overflow: auto;
+        }
+      }
+
+      &.no-title, &.no-footer {
+        .ant-modal-body {
+          height: calc(100% - 55px);
+        }
+      }
+
+      &.no-title.no-footer {
+        .ant-modal-body {
+          height: 100%;
+        }
+      }
+
+    }
+
+    .j-modal-title-row {
+      .left {
+        width: calc(100% - 56px - 56px);
+      }
+
+      .right {
+        width: 56px;
+
+        .ant-modal-close {
+          right: 56px;
+          color: rgba(0, 0, 0, 0.45);
+
+          &:hover {
+            color: rgba(0, 0, 0, 0.75);
+          }
+
+        }
+      }
+    }
+
+    /deep/ {
+
+    }
+  }
+</style>

+ 16 - 9
ant-design-vue-jeecg/src/components/jeecg/JSuperQuery.vue

@@ -1,15 +1,22 @@
 <template>
 <div class="j-super-query-box">
 
-  <slot>
-    <a-tooltip v-if="superQueryFlag" title="已有高级查询条件生效">
-      <a-button type="primary" @click="visible=true">
-        <a-icon type="appstore" theme="twoTone" :spin="true"></a-icon>
-        <span>高级查询</span>
-      </a-button>
-    </a-tooltip>
-    <a-button v-else type="primary" icon="filter" @click="visible=true">高级查询</a-button>
-  </slot>
+  <div @click="visible=true">
+    <slot>
+      <a-tooltip v-if="superQueryFlag" :mouseLeaveDelay="0.2">
+        <template slot="title">
+          <span>已有高级查询条件生效</span>
+          <a-divider type="vertical"/>
+          <a @click="handleReset">清空</a>
+        </template>
+        <a-button type="primary">
+          <a-icon type="appstore" theme="twoTone" :spin="true"></a-icon>
+          <span>高级查询</span>
+        </a-button>
+      </a-tooltip>
+      <a-button v-else type="primary" icon="filter" @click="visible=true">高级查询</a-button>
+    </slot>
+  </div>
 
   <a-modal
     title="高级查询构造器"

+ 67 - 9
ant-design-vue-jeecg/src/components/jeecg/JUpload.vue

@@ -4,11 +4,12 @@
     :multiple="true"
     :action="uploadAction"
     :headers="headers"
-    :data="{'isup':1,'bizPath':bizPath}"
+    :data="{'biz':bizPath}"
     :fileList="fileList"
     :beforeUpload="beforeUpload"
     @change="handleChange"
-    :disabled="disabled">
+    :disabled="disabled"
+    :returnUrl="returnUrl">
     <a-button>
       <a-icon type="upload" />{{ text }}
     </a-button>
@@ -19,6 +20,7 @@
 
   import Vue from 'vue'
   import { ACCESS_TOKEN } from "@/store/mutation-types"
+  import { getFileAccessHttpUrl } from '@/api/manage';
 
   const FILE_TYPE_ALL = "all"
   const FILE_TYPE_IMG = "image"
@@ -38,9 +40,10 @@
     data(){
       return {
         uploadAction:window._CONFIG['domianURL']+"/sys/common/upload",
-        urlDownload:window._CONFIG['domianURL'] + "/sys/common/download/",
+        urlDownload:window._CONFIG['staticDomainURL'],
         headers:{},
-        fileList: []
+        fileList: [],
+        newFileList: [],
       }
     },
     props:{
@@ -77,11 +80,25 @@
         required: false,
         default: false
       },
+      /**
+       * update -- author:lvdandan -- date:20190219 -- for:Jupload组件增加是否返回url,
+       * true:仅返回url
+       * false:返回fileName filePath fileSize
+       */
+      returnUrl:{
+        type:Boolean,
+        required:false,
+        default: true
+      },
     },
     watch:{
       value(val){
         if (val instanceof Array) {
-          this.initFileList(val.join(','))
+          if(this.returnUrl){
+            this.initFileList(val.join(','))
+          }else{
+            this.initFileListArr(val);
+          }
         } else {
           this.initFileList(val)
         }
@@ -93,6 +110,26 @@
     },
 
     methods:{
+      initFileListArr(val){
+        if(!val || val.length==0){
+          this.fileList = [];
+          return;
+        }
+        let fileList = [];
+        for(var a=0;a<val.length;a++){
+          fileList.push({
+            uid:uidGenerator(),
+            name:val[a].fileName,
+            status: 'done',
+            url: val[a].filePath,
+            response:{
+              status:"history",
+              message:val[a].filePath
+            }
+          })
+        }
+        this.fileList = fileList
+      },
       initFileList(paths){
         if(!paths || paths.length==0){
           //return [];
@@ -104,11 +141,12 @@
         let fileList = [];
         let arr = paths.split(",")
         for(var a=0;a<arr.length;a++){
+          let url = getFileAccessHttpUrl(arr[a],this.urlDownload,"http");
           fileList.push({
             uid:uidGenerator(),
             name:getFileName(arr[a]),
             status: 'done',
-            url: this.urlDownload+arr[a],
+            url: url,
             response:{
               status:"history",
               message:arr[a]
@@ -156,12 +194,13 @@
           if(info.file.response.success){
             fileList = fileList.map((file) => {
               if (file.response) {
-                file.url = this.urlDownload+file.response.message;
+                let reUrl = file.response.message;
+                file.url = getFileAccessHttpUrl(reUrl,this.urlDownload,"http");
               }
               return file;
             });
           }
-          this.$message.success(`${info.file.name} 上传成功!`);
+          //this.$message.success(`${info.file.name} 上传成功!`);
         }else if (info.file.status === 'error') {
           this.$message.error(`${info.file.name} 上传失败.`);
         }else if(info.file.status === 'removed'){
@@ -169,7 +208,26 @@
         }
         this.fileList = fileList
         if(info.file.status==='done' || info.file.status === 'removed'){
-          this.handlePathChange()
+          //returnUrl为true时仅返回文件路径
+          if(this.returnUrl){
+            this.handlePathChange()
+          }else{
+            //returnUrl为false时返回文件名称、文件路径及文件大小
+            fileList = fileList.filter((file) => {
+              if (file.response) {
+                return file.response.success === true;
+              }
+              return false;
+            }).map((file) => {
+              var fileJson = {
+                fileName:file.name,
+                filePath:file.url,
+                fileSize:file.size
+              };
+              this.newFileList.push(fileJson);
+              this.$emit('change', this.newFileList);
+            });
+          }
         }
       },
       handleDelete(file){

+ 9 - 5
ant-design-vue-jeecg/src/components/jeecg/index.js

@@ -1,5 +1,9 @@
-import T from './JFormContainer.vue'
-let install = function (Vue) {
-  Vue.component('JFormContainer',T);
-}
-export default { install };
+import JModal from './JModal'
+import JFormContainer from './JFormContainer.vue'
+
+export default {
+  install(Vue) {
+    Vue.component('JFormContainer', JFormContainer)
+    Vue.component(JModal.name, JModal)
+  }
+}

+ 59 - 37
ant-design-vue-jeecg/src/components/jeecgbiz/modal/JSelectUserByDepModal.vue

@@ -17,9 +17,11 @@
             selectable
             :selectedKeys="selectedDepIds"
             :checkStrictly="true"
-            @select="onDepSelect"
             :dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
             :treeData="departTree"
+            :expandAction="false"
+            :expandedKeys.sync="expandedKeys"
+            @select="onDepSelect"
           />
         </a-card>
       </a-col>
@@ -28,7 +30,7 @@
           用户账号:
           <a-input-search
             :style="{width:'150px',marginBottom:'15px'}"
-            placeholder="请输入用户账号"
+            placeholder="请输入账号"
             v-model="queryParam.username"
             @search="onSearch"
           ></a-input-search>
@@ -43,6 +45,7 @@
             :dataSource="dataSource"
             :pagination="ipagination"
             :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange,type: getType}"
+            :loading="loading"
             @change="handleTableChange">
           </a-table>
         </a-card>
@@ -71,7 +74,7 @@
             dataIndex: 'username'
           },
           {
-            title: '真实姓名',
+            title: '用户姓名',
             align: 'center',
             dataIndex: 'realname'
           },
@@ -90,14 +93,14 @@
             }
           },
           {
-            title: '手机号码',
+            title: '手机',
             align: 'center',
             dataIndex: 'phone'
           },
           {
-            title: '邮箱',
+            title: '部门',
             align: 'center',
-            dataIndex: 'email'
+            dataIndex: 'orgCode'
           }
         ],
         scrollTrigger: {},
@@ -124,60 +127,74 @@
         selectedDepIds: [],
         departTree: [],
         visible: false,
-        form: this.$form.createForm(this)
+        form: this.$form.createForm(this),
+        loading: false,
+        expandedKeys: [],
       }
     },
     computed: {
       // 计算属性的 getter
       getType: function () {
-        console.log("multi: ", this.multi);
         return this.multi == true ? 'checkbox' : 'radio';
       }
     },
     watch: {
-      userIds() {
-        this.initUserNames()
-      }
+      userIds: {
+        immediate: true,
+        handler() {
+          this.initUserNames()
+        }
+      },
     },
     created() {
       // 该方法触发屏幕自适应
       this.resetScreenSize();
-      this.loadData().then((res) => {
-        this.initUserNames();
-      })
+      this.loadData()
     },
     methods: {
       initUserNames() {
-        let names = ''
-        console.log("props userIds: ", this.userIds)
         if (this.userIds) {
-          let currUserIds = this.userIds
-          let userIdsArr = currUserIds.split(',');
-          for (let item of this.dataSource) {
-            if (userIdsArr.includes(item.username)) {
-              names += "," + item.realname
+          // 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确
+          let values = this.userIds.split(',') + ','
+          getUserList({
+            username: values,
+            pageNo: 1,
+            pageSize: values.length
+          }).then((res) => {
+            if (res.success) {
+              let selectedRowKeys = []
+              let realNames = []
+              res.result.records.forEach(user => {
+                realNames.push(user['realname'])
+                selectedRowKeys.push(user['id'])
+              })
+              this.selectedRowKeys = selectedRowKeys
+              this.$emit('initComp', realNames.join(','))
             }
-          }
-          if (names) {
-            names = names.substring(1)
-          }
-          this.$emit("initComp", names)
-        }else{
+          })
+        } else {
           // JSelectUserByDep组件bug issues/I16634
-          this.$emit("initComp", "")
+          this.$emit('initComp', '')
         }
       },
       async loadData(arg) {
         if (arg === 1) {
           this.ipagination.current = 1;
         }
-        let params = this.getQueryParams();//查询条件
-        await getUserList(params).then((res) => {
-          if (res.success) {
-            this.dataSource = res.result.records;
-            this.ipagination.total = res.result.total;
-          }
-        })
+        if (this.selectedDepIds && this.selectedDepIds.length > 0) {
+          await this.initQueryUserByDepId(this.selectedDepIds)
+        } else {
+          this.loading = true
+          let params = this.getQueryParams()//查询条件
+          await getUserList(params).then((res) => {
+            if (res.success) {
+              this.dataSource = res.result.records
+              this.ipagination.total = res.result.total
+            }
+          }).finally(() => {
+            this.loading = false
+          })
+        }
       },
       // 触发屏幕自适应
       resetScreenSize() {
@@ -191,6 +208,7 @@
       showModal() {
         this.visible = true;
         this.queryDepartTree();
+        this.initUserNames()
         this.loadData();
         this.form.resetFields();
       },
@@ -234,7 +252,6 @@
       handleSubmit() {
         let that = this;
         this.getSelectUserRows();
-        console.log(that.selectUserRows)
         that.$emit('ok', that.selectUserRows, that.selectUserIds);
         that.searchReset(0)
         that.close();
@@ -270,17 +287,22 @@
       },
       // 根据选择的id来查询用户信息
       initQueryUserByDepId(selectedDepIds) {
-        queryUserByDepId({id: selectedDepIds.toString()}).then((res) => {
+        this.loading = true
+        return queryUserByDepId({id: selectedDepIds.toString()}).then((res) => {
           if (res.success) {
             this.dataSource = res.result;
             this.ipagination.total = res.result.length;
           }
+        }).finally(() => {
+          this.loading = false
         })
       },
       queryDepartTree() {
         queryDepartTreeList().then((res) => {
           if (res.success) {
             this.departTree = res.result;
+            // 默认展开父节点
+            this.expandedKeys = this.departTree.map(item => item.id)
           }
         })
       },

+ 1 - 1
ant-design-vue-jeecg/src/components/jeecgbiz/modal/SelectUserListModal.vue

@@ -46,7 +46,7 @@
             width: 200
           },
           {
-            title: '用户真实姓名',
+            title: '用户姓名',
             align: "center",
             dataIndex: 'realname',
           },

+ 8 - 0
ant-design-vue-jeecg/src/components/layouts/IframePageView.vue

@@ -5,6 +5,8 @@
 </template>
 
 <script>
+  import Vue from 'vue'
+  import { ACCESS_TOKEN } from "@/store/mutation-types"
   import PageLayout from '../page/PageLayout'
   import RouteView from './RouteView'
 
@@ -40,6 +42,12 @@
           /*update_begin author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
           if(this.$route.meta.internalOrExternal != undefined && this.$route.meta.internalOrExternal==true){
             this.closeCurrent();
+            //外部url加入token
+            let tokenStr = "${token}";
+            if(url.indexOf(tokenStr)!=-1){
+              let token = Vue.ls.get(ACCESS_TOKEN);
+               this.url = url.replace(tokenStr,token);
+            }
             window.open(this.url);
           }
           /*update_end author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */

+ 62 - 12
ant-design-vue-jeecg/src/components/layouts/TabLayout.vue

@@ -80,30 +80,41 @@
     },
     created() {
       if (this.$route.path != indexKey) {
-        this.pageList.push({
-          name: 'dashboard-analysis',
-          path: indexKey,
-          fullPath: indexKey,
-          meta: {
-            icon: 'dashboard',
-            title: '首页'
-          }
-        })
-        this.linkList.push(indexKey)
+        this.addIndexToFirst()
       }
+      // update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
+      let storeKey = 'route:title:' + this.$route.fullPath
+      let routeTitle = this.$ls.get(storeKey)
+      if (routeTitle) {
+        this.$route.meta.title = routeTitle
+      }
+      // update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
       this.pageList.push(this.$route)
       this.linkList.push(this.$route.fullPath)
       this.activePage = this.$route.fullPath
     },
     watch: {
       '$route': function(newRoute) {
+        //console.log("新的路由",newRoute)
         this.activePage = newRoute.fullPath
         if (!this.multipage) {
           this.linkList = [newRoute.fullPath]
           this.pageList = [Object.assign({},newRoute)]
-        } else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
+        // update-begin-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
+        } else if(indexKey==newRoute.fullPath) {
+          //首页时 判断是否缓存 没有缓存 刷新之
+          if (newRoute.meta.keepAlive === false) {
+            this.routeReload()
+          }
+        // update-end-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
+        }else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
           this.linkList.push(newRoute.fullPath)
           this.pageList.push(Object.assign({},newRoute))
+          // update-begin-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍
+          if (newRoute.meta.keepAlive) {
+            this.routeReload()
+          }
+          // update-end-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍
         } else if (this.linkList.indexOf(newRoute.fullPath) >= 0) {
           let oldIndex = this.linkList.indexOf(newRoute.fullPath)
           let oldPositionRoute = this.pageList[oldIndex]
@@ -114,6 +125,7 @@
         let index = this.linkList.lastIndexOf(key)
         let waitRouter = this.pageList[index]
         this.$router.push(Object.assign({},waitRouter));
+        this.changeTitle(waitRouter.meta.title)
       },
       'multipage': function(newVal) {
         if(this.reloadFlag){
@@ -122,9 +134,44 @@
             this.pageList = [this.$route]
           }
         }
-      }
+      },
+      // update-begin-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
+      device() {
+        if (this.multipage && this.linkList.indexOf(indexKey) === -1) {
+          this.addIndexToFirst()
+        }
+      },
+      // update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
     },
     methods: {
+      // update-begin-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
+      // 将首页添加到第一位
+      addIndexToFirst() {
+        this.pageList.splice(0, 0, {
+          name: 'dashboard-analysis',
+          path: indexKey,
+          fullPath: indexKey,
+          meta: {
+            icon: 'dashboard',
+            title: '首页'
+          }
+        })
+        this.linkList.splice(0, 0, indexKey)
+      },
+      // update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
+
+      // update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
+      changeTitle(title) {
+        let projectTitle = "Jeecg-Boot 企业级快速开发平台"
+        // 首页特殊处理
+        if (this.$route.path === indexKey) {
+          document.title = projectTitle
+        } else {
+          document.title = title + ' · ' + projectTitle
+        }
+      },
+      // update-end-author:sunjianlei date:20200120 for: 动态更改页面标题
+
       changePage(key) {
         this.activePage = key
       },
@@ -236,6 +283,9 @@
           let currRouter = this.pageList[keyIndex]
           let meta = Object.assign({},currRouter.meta,{title:title})
           this.pageList.splice(keyIndex, 1, Object.assign({},currRouter,{meta:meta}))
+          if (key === this.activePage) {
+            this.changeTitle(title)
+          }
         }
       },
       //update-end-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title

+ 3 - 3
ant-design-vue-jeecg/src/components/layouts/UserLayout.vue

@@ -17,12 +17,12 @@
 
       <div class="footer">
         <div class="links">
-          <a href="http://jeecg-boot.mydoc.io" target="_blank">帮助</a>
+          <a href="http://doc.jeecg.com" target="_blank">帮助</a>
           <a href="https://github.com/zhangdaiscott/jeecg-boot" target="_blank">隐私</a>
-          <a href="https://github.com/zhangdaiscott/jeecg-boot" target="_blank">条款</a>
+          <a href="https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE" target="_blank">条款</a>
         </div>
         <div class="copyright">
-          Copyright &copy; 2019 <a href="http://www.jeecg.org" target="_blank">JEECG开源社区</a> 出品
+          Copyright &copy; 2019 <a href="http://www.jeecg.com" target="_blank">JEECG开源社区</a> 出品
         </div>
       </div>
     </div>

+ 1 - 1
ant-design-vue-jeecg/src/components/page/GlobalFooter.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="footer">
     <div class="links">
-      <a href="http://www.jeecg.org" target="_blank">JEECG 首页</a>
+      <a href="http://www.jeecg.com" target="_blank">JEECG 首页</a>
       <a href="https://github.com/zhangdaiscott/jeecg-boot" target="_blank">
         <a-icon type="github"/>
       </a>

+ 1 - 1
ant-design-vue-jeecg/src/components/page/GlobalHeader.vue

@@ -197,7 +197,7 @@
       &.dark {
         color: #000000;
         box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
-        background-color: @primary-color;
+        background-color: white !important;
       }
     }
 

+ 12 - 0
ant-design-vue-jeecg/src/components/page/GlobalLayout.vue

@@ -154,6 +154,10 @@
         //此处触发动态路由被点击事件
         this.findMenuBykey(this.menus,value.key)
         this.$emit("dynamicRouterShow",value.key,this.activeMenu.meta.title)
+        // update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
+        let storeKey = 'route:title:' + this.activeMenu.path
+        this.$ls.set(storeKey, this.activeMenu.meta.title)
+        // update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
       },
       findMenuBykey(menus,key){
         for(let i of menus){
@@ -337,6 +341,10 @@
             font-size: 16px;
             padding: 4px;
           }
+
+          .anticon {
+            color: white;
+          }
         }
       }
 
@@ -349,6 +357,10 @@
             &:hover {
               background: rgba(0, 0, 0, 0.05);
             }
+
+            .anticon {
+              color: black;
+            }
           }
         }
       }

+ 36 - 0
ant-design-vue-jeecg/src/components/tools/DynamicNotice.vue

@@ -0,0 +1,36 @@
+<template>
+  <component
+    :is="comp"
+    :formData="formData"
+    ref="compModel"
+    v-if="comp">
+  </component>
+</template>
+<script>
+  export default {
+    name: 'DynamicNotice',
+    data () {
+      return {
+        compName: this.path
+      }
+    },
+    computed: {
+      comp: function () {
+        if(!this.path){
+          return null;
+        }
+        return () => import(`@/views/${this.path}.vue`)
+      }
+    },
+    props: ['path','formData'],
+    methods: {
+      detail () {
+        setTimeout(() => {
+          if(this.path){
+            this.$refs.compModel.view(this.formData);
+          }
+        }, 200)
+      },
+    }
+  }
+</script>

+ 12 - 1
ant-design-vue-jeecg/src/components/tools/HeaderNotice.vue

@@ -72,6 +72,7 @@
       </a-badge>
     </span>
     <show-announcement ref="ShowAnnouncement" @ok="modalFormOk"></show-announcement>
+    <dynamic-notice ref="showDynamNotice" :path="openPath" :formData="formData"/>
   </a-popover>
 </template>
 
@@ -79,11 +80,13 @@
   import { getAction,putAction } from '@/api/manage'
   import ShowAnnouncement from './ShowAnnouncement'
   import store from '@/store/'
+  import DynamicNotice from './DynamicNotice'
 
 
   export default {
     name: "HeaderNotice",
     components: {
+      DynamicNotice,
       ShowAnnouncement,
     },
     data () {
@@ -105,6 +108,8 @@
         websock: null,
         lockReconnect:false,
         heartCheck:null,
+        formData:{},
+        openPath:''
       }
     },
     computed:{
@@ -172,7 +177,13 @@
           }
         });
         this.hovered = false;
-        this.$refs.ShowAnnouncement.detail(record);
+        if(record.openType==='component'){
+          this.openPath = record.openPage;
+          this.formData = {id:record.busId};
+          this.$refs.showDynamNotice.detail(record.openPage);
+        }else{
+          this.$refs.ShowAnnouncement.detail(record);
+        }
       },
       toMyAnnouncement(){
 

+ 13 - 3
ant-design-vue-jeecg/src/components/tools/ShowAnnouncement.vue

@@ -5,11 +5,14 @@
     :visible="visible"
     :bodyStyle ="bodyStyle"
     @cancel="handleCancel"
-    destroyOnClose
-    :footer="null">
+    destroyOnClose>
     <template slot="title">
       <a-button icon="fullscreen" class="custom-btn" @click="handleClickToggleFullScreen"/>
     </template>
+    <template slot="footer">
+      <a-button key="back" @click="handleCancel">关闭</a-button>
+      <a-button v-if="record.openType==='url'&&record.readFlag!=='1'" type="primary" @click="toHandle">去处理</a-button>
+    </template>
     <a-card class="daily-article" :loading="loading">
       <a-card-meta
         :title="record.titile"
@@ -74,7 +77,14 @@
           this.modelStyle.style.top = '50px'
         }
         this.modelStyle.fullScreen = mode
-      }
+      },
+      toHandle(){
+        if(this.record.openType==='url'&&this.record.readFlag!== '1'){
+          this.visible = false;
+          //链接跳转
+          this.$router.push({path: this.record.openPage})
+        }
+      },
     }
   }
 </script>

+ 42 - 19
ant-design-vue-jeecg/src/components/tools/UserMenu.vue

@@ -5,7 +5,8 @@
     <span class="action" @click="showClick">
       <a-icon type="search"></a-icon>
     </span>
-    <span v-show="shows" class="borders">
+    <!-- update-begin author:sunjianlei date:20200219 for: 菜单搜索改为动态组件,在手机端呈现出弹出框 -->
+    <component :is="searchMenuComp" v-show="searchMenuVisible || isMobile()" class="borders" :visible="searchMenuVisible" title="搜索菜单" :footer="null" @cancel="searchMenuVisible=false">
       <a-select
         class="search-input"
         showSearch
@@ -13,16 +14,20 @@
         placeholder="搜索菜单"
         optionFilterProp="children"
         :filterOption="filterOption"
+        :open="isMobile()?true:null"
+        :getPopupContainer="(node) => node.parentNode"
+        :style="isMobile()?{width: '100%',marginBottom:'50px'}:{}"
         @change="searchMethods"
         @blur="hiddenClick"
       >
-        <a-select-option v-for="site in search " :value="site.id">{{site.meta.title}}</a-select-option>
+        <a-select-option v-for="site in searchMenuOptions" :value="site.id">{{site.meta.title}}</a-select-option>
       </a-select>
-    </span>
-    <!-- update-end author:sunjianlei date:20191@20 for: 解决全局样式冲突的问题 -->
+    </component>
+    <!-- update-end author:sunjianlei date:20200219 for: 菜单搜索改为动态组件,在手机端呈现出弹出框 -->
+    <!-- update-end author:sunjianlei date:20191220 for: 解决全局样式冲突的问题 -->
     <!-- update_end  author:zhaoxin date:20191129 for: 做头部菜单栏导航 -->
     <span class="action">
-      <a class="logout_title" target="_blank" href="http://jeecg-boot.mydoc.io">
+      <a class="logout_title" target="_blank" href="http://doc.jeecg.com">
         <a-icon type="question-circle-o"></a-icon>
       </a>
     </span>
@@ -95,9 +100,11 @@
     mixins: [mixinDevice],
     data(){
       return{
-        //菜单搜索
-        search:[],
-        shows:false
+        // update-begin author:sunjianlei date:20200219 for: 头部菜单搜索规范命名 --------------
+        searchMenuOptions:[],
+        searchMenuComp: 'span',
+        searchMenuVisible: false,
+        // update-begin author:sunjianlei date:20200219 for: 头部菜单搜索规范命名 --------------
       }
     },
     components: {
@@ -116,10 +123,8 @@
     /* update_begin author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
     created() {
       let lists = []
-      console.log("permissionMenuList: ",this.permissionMenuList)
       this.searchMenus(lists,this.permissionMenuList)
-      this.search=[...lists]
-      console.log(this.search)
+      this.searchMenuOptions=[...lists]
     },
     computed: {
       ...mapState({
@@ -129,10 +134,21 @@
       })
     },
     /* update_end author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
+    watch: {
+      // update-begin author:sunjianlei date:20200219 for: 菜单搜索改为动态组件,在手机端呈现出弹出框
+      device: {
+        immediate: true,
+        handler() {
+          this.searchMenuVisible = false
+          this.searchMenuComp = this.isMobile() ? 'a-modal' : 'span'
+        },
+      },
+      // update-end author:sunjianlei date:20200219 for: 菜单搜索改为动态组件,在手机端呈现出弹出框
+    },
     methods: {
       /* update_begin author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
-      showClick(){
-        this.shows = !this.shows
+      showClick() {
+        this.searchMenuVisible = true
       },
       hiddenClick(){
         this.shows = false
@@ -141,8 +157,8 @@
       ...mapActions(["Logout"]),
       ...mapGetters(["nickname", "avatar","userInfo"]),
       getAvatar(){
-        console.log('url = '+ window._CONFIG['imgDomainURL']+"/"+this.avatar())
-        return window._CONFIG['imgDomainURL']+"/"+this.avatar()
+        console.log('url = '+ window._CONFIG['staticDomainURL']+"/"+this.avatar())
+        return window._CONFIG['staticDomainURL']+"/"+this.avatar()
       },
       handleLogout() {
         const that = this
@@ -189,10 +205,17 @@
       filterOption(input, option) {
         return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
       },
-      searchMethods(value){
-        let jump = this.search.filter(item=>item.id==value)
-        this.$router.push({ path:jump[0].path})
+      // update_begin author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
+      searchMethods(value) {
+        let route = this.searchMenuOptions.filter(item => item.id === value)[0]
+        if (route.meta.internalOrExternal === true || route.component.includes('layouts/IframePageView')) {
+          window.open(route.meta.url, '_blank')
+        } else {
+          this.$router.push({ path: route.path })
+        }
+        this.searchMenuVisible = false
       }
+      // update_end author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
       /*update_end author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
     }
   }
@@ -203,7 +226,7 @@
   /* update-begin author:sunjianlei date:20191220 for: 解决全局样式冲突问题 */
   .user-wrapper .search-input {
     width: 180px;
-    color: white;
+    color: inherit;
 
     /deep/ {
       .ant-select-selection {

+ 2 - 2
ant-design-vue-jeecg/src/main.js

@@ -18,8 +18,8 @@ import VueApexCharts from 'vue-apexcharts'
 
 import preview from 'vue-photo-preview'
 import 'vue-photo-preview/dist/skin.css'
-import "@jeecg/antd-online-re"
-import '@jeecg/antd-online-re/dist/OnlineForm.css'
+import "@jeecg/antd-online-214"
+import '@jeecg/antd-online-214/dist/OnlineForm.css'
 
 import {
   ACCESS_TOKEN,

+ 4 - 4
ant-design-vue-jeecg/src/mixins/JeecgListMixin.js

@@ -236,9 +236,9 @@ export const JeecgListMixin = {
           return
         }
         if (typeof window.navigator.msSaveBlob !== 'undefined') {
-          window.navigator.msSaveBlob(new Blob([data]), fileName+'.xls')
+          window.navigator.msSaveBlob(new Blob([data],{type: 'application/vnd.ms-excel'}), fileName+'.xls')
         }else{
-          let url = window.URL.createObjectURL(new Blob([data]))
+          let url = window.URL.createObjectURL(new Blob([data],{type: 'application/vnd.ms-excel'}))
           let link = document.createElement('a')
           link.style.display = 'none'
           link.href = url
@@ -286,7 +286,7 @@ export const JeecgListMixin = {
       if(text && text.indexOf(",")>0){
         text = text.substring(0,text.indexOf(","))
       }
-      return window._CONFIG['imgDomainURL']+"/"+text
+      return window._CONFIG['staticDomainURL']+"/"+text
     },
     /* 文件下载 */
     uploadFile(text){
@@ -297,7 +297,7 @@ export const JeecgListMixin = {
       if(text.indexOf(",")>0){
         text = text.substring(0,text.indexOf(","))
       }
-      window.open(window._CONFIG['domianURL'] + "/sys/common/download/"+text);
+      window.open(window._CONFIG['staticDomainURL']+ "/"+text);
     },
   }
 

+ 78 - 0
ant-design-vue-jeecg/src/mixins/OnlAutoListMixin.js

@@ -0,0 +1,78 @@
+export const HrefJump = {
+  data() {
+    return {
+      fieldHrefSlots: [],
+      hrefComponent: {
+        model: {
+          title: '',
+          width: '100%',
+          visible: false,
+          destroyOnClose: true,
+          style: {
+            top: 0,
+            left: 0,
+            height: '100%',
+            margin: 0,
+            padding: 0
+          },
+          bodyStyle: { padding: '8px', height: 'calc(100vh - 108px)', overflow: 'auto', overflowX: 'hidden' },
+          // 隐藏掉取消按钮
+          cancelButtonProps: { style: { display: 'none' } },
+          afterClose: () => {
+            // 恢复body的滚动
+            document.body.style.overflow = null
+          }
+        },
+        on: {
+          ok: () => this.hrefComponent.model.visible = false,
+          cancel: () => this.hrefComponent.model.visible = false
+        },
+        is: null,
+        params: {},
+      }
+    }
+  },
+  methods: {
+    //支持链接href跳转
+    handleClickFieldHref(field, record) {
+      let href = field.href
+      let urlPattern = /(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?/
+      let compPattern = /\.vue(\?.*)?$/
+      if (typeof href === 'string') {
+        href = href.trim().replace(/\${([^}]+)?}/g, (s1, s2) => record[s2])
+        if (urlPattern.test(href)) {
+          window.open(href, '_blank')
+        } else if (compPattern.test(href)) {
+          this.openHrefCompModal(href)
+        } else {
+          this.$router.push(href)
+        }
+      }
+    },
+    openHrefCompModal(href) {
+      // 解析 href 参数
+      let index = href.indexOf('?')
+      let path = href
+      if (index !== -1) {
+        path = href.substring(0, index)
+        let paramString = href.substring(index + 1, href.length)
+        let paramArray = paramString.split('&')
+        let params = {}
+        paramArray.forEach(paramObject => {
+          let paramItem = paramObject.split('=')
+          params[paramItem[0]] = paramItem[1]
+        })
+        this.hrefComponent.params = params
+      } else {
+        this.hrefComponent.params = {}
+      }
+      this.hrefComponent.model.visible = true
+      this.hrefComponent.model.title = '@/views/' + path
+      this.hrefComponent.is = () => import('@/views/' + (path.startsWith('/')?path.slice(1):path))
+      // 禁止body滚动,防止滚动穿透
+      setTimeout(() => {
+        document.body.style.overflow = 'hidden'
+      }, 300)
+    },
+  }
+}

+ 13 - 0
ant-design-vue-jeecg/src/store/modules/user.js

@@ -120,6 +120,19 @@ const user = {
           sessionStorage.setItem(USER_AUTH,JSON.stringify(authData));
           sessionStorage.setItem(SYS_BUTTON_AUTH,JSON.stringify(allAuthData));
           if (menuData && menuData.length > 0) {
+            //update--begin--autor:qinfeng-----date:20200109------for:JEECG-63 一级菜单的子菜单全部是隐藏路由,则一级菜单不显示------
+            menuData.forEach((item, index) => {
+              if (item["children"]) {
+                let hasChildrenMenu = item["children"].filter((i) => {
+                  return !i.hidden || i.hidden == false
+                })
+                if (hasChildrenMenu == null || hasChildrenMenu.length == 0) {
+                  item["hidden"] = true
+                }
+              }
+            })
+            console.log(" menu show json ", menuData)
+            //update--end--autor:qinfeng-----date:20200109------for:JEECG-63 一级菜单的子菜单全部是隐藏路由,则一级菜单不显示------
             commit('SET_PERMISSIONLIST', menuData)
           } else {
             reject('getPermissionList: permissions must be a non-null array !')

+ 28 - 26
ant-design-vue-jeecg/src/utils/authFilter.js

@@ -1,4 +1,3 @@
-
 import { USER_AUTH,SYS_BUTTON_AUTH } from "@/store/mutation-types"
 
 export function disabledAuthFilter(code,formData) {
@@ -10,27 +9,30 @@ export function disabledAuthFilter(code,formData) {
 }
 
 function nodeDisabledAuth(code,formData){
-  console.log("页面权限禁用--NODE--开始");
-  var permissionList = [];
+  let permissionList = [];
   try {
-    var obj = formData;
     //console.log("页面权限禁用--NODE--开始",obj);
-    if (obj) {
-      let bpmList = obj.permissionList;
-      for (var bpm of bpmList) {
-        if(bpm.type == '2') {
-          permissionList.push(bpm);
-        }
-      }
+    if (formData) {
+      let bpmList = formData.permissionList;
+      permissionList = bpmList.filter(item=>item.type=='2')
+      // for (let bpm of bpmList) {
+      //   if(bpm.type == '2') {
+      //     permissionList.push(bpm);
+      //   }
+      // }
+    }else{
+      return false;
     }
   } catch (e) {
     //console.log("页面权限异常----", e);
   }
-  if (permissionList === null || permissionList === "" || permissionList === undefined||permissionList.length<=0) {
+  if (permissionList.length ==  0) {
     return false;
   }
+
+  console.log("流程节点页面权限禁用--NODE--开始");
   let permissions = [];
-  for (var item of permissionList) {
+  for (let item of permissionList) {
     if(item.type == '2') {
       permissions.push(item.action);
     }
@@ -39,9 +41,9 @@ function nodeDisabledAuth(code,formData){
   if (!permissions.includes(code)) {
     return false;
   }else{
-    for (var item2 of permissionList) {
+    for (let item2 of permissionList) {
       if(code === item2.action){
-        console.log("页面权限禁用--NODE--生效");
+        console.log("流程节点页面权限禁用--NODE--生效");
         return true;
       }
     }
@@ -50,21 +52,21 @@ function nodeDisabledAuth(code,formData){
 }
 
 function globalDisabledAuth(code){
-  console.log("页面禁用权限--Global--开始");
+  //console.log("全局页面禁用权限--Global--开始");
 
   var permissionList = [];
   var allPermissionList = [];
 
   //let authList = Vue.ls.get(USER_AUTH);
   let authList = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
-  for (var auth of authList) {
+  for (let auth of authList) {
     if(auth.type == '2') {
       permissionList.push(auth);
     }
   }
   //console.log("页面禁用权限--Global--",sessionStorage.getItem(SYS_BUTTON_AUTH));
   let allAuthList = JSON.parse(sessionStorage.getItem(SYS_BUTTON_AUTH) || "[]");
-  for (var gauth of allAuthList) {
+  for (let gauth of allAuthList) {
     if(gauth.type == '2') {
       allPermissionList.push(gauth);
     }
@@ -73,7 +75,7 @@ function globalDisabledAuth(code){
   var  gFlag = false;//禁用命中
   var invalidFlag = false;//无效命中
   if(allPermissionList != null && allPermissionList != "" && allPermissionList != undefined && allPermissionList.length > 0){
-    for (var itemG of allPermissionList) {
+    for (let itemG of allPermissionList) {
       if(code === itemG.action){
         if(itemG.status == '0'){
           invalidFlag = true;
@@ -92,7 +94,7 @@ function globalDisabledAuth(code){
     return gFlag;
   }
   let permissions = [];
-  for (var item of permissionList) {
+  for (let item of permissionList) {
     if(item.type == '2') {
       permissions.push(item.action);
     }
@@ -101,9 +103,9 @@ function globalDisabledAuth(code){
   if (!permissions.includes(code)) {
     return gFlag;
   }else{
-    for (var item2 of permissionList) {
+    for (let item2 of permissionList) {
       if(code === item2.action){
-        console.log("页面权限解除禁用--Global--生效");
+        console.log("全局页面权限解除禁用--Global--生效");
         gFlag = false;
       }
     }
@@ -134,12 +136,12 @@ function hasColoum(item,authList){
 //权限无效时不做控制,有效时控制,只能控制 显示不显示
 //根据授权码前缀获取未授权的列信息
 function getNoAuthCols(pre){
-  var permissionList = [];
-  var allPermissionList = [];
+  let permissionList = [];
+  let allPermissionList = [];
 
   //let authList = Vue.ls.get(USER_AUTH);
   let authList = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
-  for (var auth of authList) {
+  for (let auth of authList) {
     //显示策略,有效状态
     if(auth.type == '1'&&startWith(auth.action,pre)) {
       permissionList.push(substrPre(auth.action,pre));
@@ -147,7 +149,7 @@ function getNoAuthCols(pre){
   }
   //console.log("页面禁用权限--Global--",sessionStorage.getItem(SYS_BUTTON_AUTH));
   let allAuthList = JSON.parse(sessionStorage.getItem(SYS_BUTTON_AUTH) || "[]");
-  for (var gauth of allAuthList) {
+  for (let gauth of allAuthList) {
     //显示策略,有效状态
     if(gauth.type == '1'&&gauth.status == '1'&&startWith(gauth.action,pre)) {
       allPermissionList.push(substrPre(gauth.action,pre));

+ 1 - 1
ant-design-vue-jeecg/src/utils/commonUploadFile.js

@@ -38,7 +38,7 @@ const getUploadFileList=(paths)=>{
         uid:uidGenerator(),
         name:getFileName(arr[a]),
         status: 'done',
-        url: window._CONFIG['domianURL']+"/sys/common/view/"+arr[a],
+        url: window._CONFIG['staticDomainURL']+"/"+arr[a],
         response:{
           status:"history",
           message:arr[a]

+ 22 - 18
ant-design-vue-jeecg/src/utils/hasPermission.js

@@ -2,35 +2,37 @@ import { USER_AUTH,SYS_BUTTON_AUTH } from "@/store/mutation-types"
 
 const hasPermission = {
     install (Vue, options) {
-        console.log(options);
+        //console.log(options);
           Vue.directive('has', {
             inserted: (el, binding, vnode)=>{
-                console.log("页面权限控制----");
+                //console.log("页面权限控制----");
+                console.time()
                 //节点权限处理,如果命中则不进行全局权限处理
                 if(!filterNodePermission(el, binding, vnode)){
                   filterGlobalPermission(el, binding, vnode);
                 }
+                console.timeEnd() //计时结束并输出时长
             }
           });
     }
 };
 
 /**
- * 全局权限控制
+ * 流程节点权限控制
  */
 export function filterNodePermission(el, binding, vnode) {
-  console.log("页面权限--NODE--");
-
-  var permissionList = [];
+  let permissionList = [];
   try {
-    var obj = vnode.context.$props.formData;
+    let obj = vnode.context.$props.formData;
     if (obj) {
       let bpmList = obj.permissionList;
-      for (var bpm of bpmList) {
+      for (let bpm of bpmList) {
         if(bpm.type != '2') {
           permissionList.push(bpm);
         }
       }
+    }else{
+      return false;
     }
   } catch (e) {
     //console.log("页面权限异常----", e);
@@ -39,8 +41,10 @@ export function filterNodePermission(el, binding, vnode) {
     //el.parentNode.removeChild(el)
     return false;
   }
+
+  console.log("流程节点页面权限--NODE--");
   let permissions = [];
-  for (var item of permissionList) {
+  for (let item of permissionList) {
     if(item.type != '2') {
       permissions.push(item.action);
     }
@@ -51,7 +55,7 @@ export function filterNodePermission(el, binding, vnode) {
     //el.parentNode.removeChild(el)
     return false;
   }else{
-    for (var item2 of permissionList) {
+    for (let item2 of permissionList) {
       if(binding.value === item2.action){
         return true;
       }
@@ -64,29 +68,29 @@ export function filterNodePermission(el, binding, vnode) {
  * 全局权限控制
  */
 export function filterGlobalPermission(el, binding, vnode) {
-  console.log("页面权限--Global--");
+  console.log("全局页面权限--Global--");
 
-  var permissionList = [];
-  var allPermissionList = [];
+  let permissionList = [];
+  let allPermissionList = [];
 
   //let authList = Vue.ls.get(USER_AUTH);
   let authList = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
-  for (var auth of authList) {
+  for (let auth of authList) {
     if(auth.type != '2') {
       permissionList.push(auth);
     }
   }
   //console.log("页面权限--Global--",sessionStorage.getItem(SYS_BUTTON_AUTH));
   let allAuthList = JSON.parse(sessionStorage.getItem(SYS_BUTTON_AUTH) || "[]");
-  for (var gauth of allAuthList) {
+  for (let gauth of allAuthList) {
     if(gauth.type != '2') {
       allPermissionList.push(gauth);
     }
   }
   //设置全局配置是否有命中
-  var invalidFlag = false;//无效命中
+  let invalidFlag = false;//无效命中
   if(allPermissionList != null && allPermissionList != "" && allPermissionList != undefined && allPermissionList.length > 0){
-    for (var itemG of allPermissionList) {
+    for (let itemG of allPermissionList) {
       if(binding.value === itemG.action){
         if(itemG.status == '0'){
           invalidFlag = true;
@@ -103,7 +107,7 @@ export function filterGlobalPermission(el, binding, vnode) {
     return;
   }
   let permissions = [];
-  for (var item of permissionList) {
+  for (let item of permissionList) {
     if(item.type != '2'){
       permissions.push(item.action);
     }

+ 8 - 1
ant-design-vue-jeecg/src/utils/request.js

@@ -5,9 +5,16 @@ import { VueAxios } from './axios'
 import {Modal, notification} from 'ant-design-vue'
 import { ACCESS_TOKEN } from "@/store/mutation-types"
 
+//自动设置后台服务 baseURL (也可以手工指定写死项目名字)
+let baseDomain = window._CONFIG['domianURL'];
+let baseProject = baseDomain.substring(baseDomain.lastIndexOf("/"));
+console.log("baseDomain= ",baseDomain)
+console.log("baseProject= ",baseProject)
+
 // 创建 axios 实例
 const service = axios.create({
-  baseURL: '/jeecg-boot', // api base_url
+  //baseURL: '/jeecg-boot',
+  baseURL: baseProject, // api base_url
   timeout: 9000 // 请求超时时间
 })
 

+ 125 - 6
ant-design-vue-jeecg/src/utils/util.js

@@ -257,6 +257,62 @@ export function cssExpand(css, id) {
   document.head.appendChild(style)
 }
 
+
+/** 用于js增强事件,运行JS代码,可以传参 */
+// options 所需参数:
+//    参数名         类型            说明
+//    vm             VueComponent    vue实例
+//    event          Object          event对象
+//    jsCode         String          待执行的js代码
+//    errorMessage   String          执行出错后的提示(控制台)
+export function jsExpand(options = {}) {
+
+  // 绑定到window上的keyName
+  let windowKeyName = 'J_CLICK_EVENT_OPTIONS'
+  if (typeof window[windowKeyName] != 'object') {
+    window[windowKeyName] = {}
+  }
+
+  // 随机生成JS增强的执行id,防止冲突
+  let id = randomString(16, 'qwertyuioplkjhgfdsazxcvbnm'.toUpperCase())
+  // 封装按钮点击事件
+  let code = `
+    (function (o_${id}) {
+      try {
+        (function (globalEvent, vm) {
+          ${options.jsCode}
+        })(o_${id}.event, o_${id}.vm)
+      } catch (e) {
+        o_${id}.error(e)
+      }
+      o_${id}.done()
+    })(window['${windowKeyName}']['EVENT_${id}'])
+  `
+  // 创建script标签
+  const script = document.createElement('script')
+  // 将需要传递的参数挂载到window对象上
+  window[windowKeyName]['EVENT_' + id] = {
+    vm: options.vm,
+    event: options.event,
+    // 当执行完成时,无论如何都会调用的回调事件
+    done() {
+      // 执行完后删除新增的 script 标签不会撤销执行结果(已产生的结果不会被撤销)
+      script.outerHTML = ''
+      delete window[windowKeyName]['EVENT_' + id]
+    },
+    // 当js运行出错的时候调用的事件
+    error(e) {
+      console.group(`${options.errorMessage || '用户自定义JS增强代码运行出错'}(${new Date()})`)
+      console.error(e)
+      console.groupEnd()
+    }
+  }
+  // 将事件挂载到document中
+  script.innerHTML = code
+  document.body.appendChild(script)
+}
+
+
 /**
  * 重复值验证工具方法
  *
@@ -270,12 +326,39 @@ export function cssExpand(css, id) {
  * @param callback
  */
 export function validateDuplicateValue(tableName, fieldName, fieldVal, dataId, callback) {
-  let params = { tableName, fieldName, fieldVal, dataId }
-  api.duplicateCheck(params).then(res => {
-    res['success'] ? callback() : callback(res['message'])
-  }).catch(err => {
-    callback(err.message || err)
-  })
+  if (fieldVal) {
+    let params = { tableName, fieldName, fieldVal, dataId }
+    api.duplicateCheck(params).then(res => {
+      res['success'] ? callback() : callback(res['message'])
+    }).catch(err => {
+      callback(err.message || err)
+    })
+  } else {
+    callback()
+  }
+}
+
+/**
+ * 根据编码校验规则code,校验传入的值是否合法
+ *
+ * 使用示例:
+ * { validator: (rule, value, callback) => validateCheckRule('common', value, callback) }
+ *
+ * @param ruleCode 编码校验规则 code
+ * @param value 被验证的值
+ * @param callback
+ */
+export function validateCheckRule(ruleCode, value, callback) {
+  if (ruleCode && value) {
+    value = encodeURIComponent(value)
+    api.checkRuleByCode({ ruleCode, value }).then(res => {
+      res['success'] ? callback() : callback(res['message'])
+    }).catch(err => {
+      callback(err.message || err)
+    })
+  } else {
+    callback()
+  }
 }
 
 /**
@@ -295,4 +378,40 @@ export function pushIfNotExist(array, value, key) {
   }
   array.push(value)
   return true
+}
+
+/**
+ * 可用于判断是否成功
+ * @type {symbol}
+ */
+export const succeedSymbol = Symbol()
+/**
+ * 可用于判断是否失败
+ * @type {symbol}
+ */
+export const failedSymbol = Symbol()
+
+/**
+ * 使 promise 无论如何都会 resolve,除非传入的参数不是一个Promise对象或返回Promise对象的方法
+ * 一般用在 Promise.all 中
+ *
+ * @param promise 可传Promise对象或返回Promise对象的方法
+ * @returns {Promise<any>}
+ */
+export function alwaysResolve(promise) {
+  return new Promise((resolve, reject) => {
+    let p = promise
+    if (typeof promise === 'function') {
+      p = promise()
+    }
+    if (p instanceof Promise) {
+      p.then(data => {
+        resolve({ type: succeedSymbol, data })
+      }).catch(error => {
+        resolve({ type: failedSymbol, error })
+      })
+    } else {
+      reject('alwaysResolve: 传入的参数不是一个Promise对象或返回Promise对象的方法')
+    }
+  })
 }

+ 1 - 1
ant-design-vue-jeecg/src/views/account/center/Index.vue

@@ -133,7 +133,7 @@
     methods: {
       ...mapGetters(["nickname", "avatar"]),
       getAvatar(){
-          return window._CONFIG['imgDomainURL']+"/"+this.avatar();
+          return window._CONFIG['staticDomainURL']+"/"+this.avatar();
       },
       getTeams() {
         this.$http.get('/api/workplace/teams')

+ 7 - 7
ant-design-vue-jeecg/src/views/dashboard/IndexChart.vue

@@ -20,14 +20,14 @@
         </chart-card>
       </a-col>
       <a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
-        <chart-card :loading="loading" title="访问量" :total="8846 | NumberFormat">
+        <chart-card :loading="loading" title="订单量" :total="8846 | NumberFormat">
           <a-tooltip title="指标说明" slot="action">
             <a-icon type="info-circle-o" />
           </a-tooltip>
           <div>
             <mini-area />
           </div>
-          <template slot="footer">日访问量<span> {{ '1234' | NumberFormat }}</span></template>
+          <template slot="footer">日订单量<span> {{ '1234' | NumberFormat }}</span></template>
         </chart-card>
       </a-col>
       <a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
@@ -85,7 +85,7 @@
               </a-col>
             </a-row>
           </a-tab-pane>
-          <a-tab-pane tab="访问量" key="2">
+          <a-tab-pane tab="销售趋势" key="2">
             <a-row>
               <a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
                 <bar title="销售额趋势" :dataSource="barData"/>
@@ -101,10 +101,10 @@
 
     <a-row>
       <a-col :span="24">
-        <a-card :loading="loading" :bordered="false" title="最近一周访问次数统计" :style="{ marginTop: '24px' }">
+        <a-card :loading="loading" :bordered="false" title="最近一周访问统计" :style="{ marginTop: '24px' }">
           <a-row>
             <a-col :span="6">
-              <head-info title="今日访问IP" :content="loginfo.todayIp"></head-info>
+              <head-info title="今日IP" :content="loginfo.todayIp"></head-info>
             </a-col>
             <a-col :span="2">
               <a-spin class='circle-cust'>
@@ -112,7 +112,7 @@
               </a-spin>
             </a-col>
             <a-col :span="6">
-              <head-info title="今日访问次数" :content="loginfo.todayVisitCount"></head-info>
+              <head-info title="今日访问" :content="loginfo.todayVisitCount"></head-info>
             </a-col>
             <a-col :span="2">
               <a-spin class='circle-cust'>
@@ -120,7 +120,7 @@
               </a-spin>
             </a-col>
             <a-col :span="6">
-              <head-info title="访问总次数" :content="loginfo.totalVisitCount"></head-info>
+              <head-info title="总访问量" :content="loginfo.totalVisitCount"></head-info>
             </a-col>
             <a-col :span="2">
               <a-spin class='circle-cust'>

+ 1 - 1
ant-design-vue-jeecg/src/views/dashboard/Workplace.vue

@@ -185,7 +185,7 @@
     },
     created() {
       this.user = this.userInfo
-      this.avatar = window._CONFIG['imgDomainURL'] +"/"+ this.userInfo.avatar
+      this.avatar = window._CONFIG['staticDomainURL'] +"/"+ this.userInfo.avatar
       console.log('this.avatar :'+ this.avatar)
 
       getRoleList().then(res => {

+ 75 - 40
ant-design-vue-jeecg/src/views/jeecg/SelectDemo.vue

@@ -9,7 +9,7 @@
         <a-row :gutter="24">
           <a-col :span="12">
             <a-form-item label="性别">
-              <j-dict-select-tag v-model="formData.sex" title="性别" dictCode="sex"/>
+              <j-dict-select-tag v-model="formData.sex" title="性别" dictCode="sex" placeholder="请选择性别"/>
             <!--  <j-dict-select-tag title="性别" dictCode="sex" disabled/>-->
             </a-form-item>
           </a-col>
@@ -176,34 +176,28 @@
         <a-row :gutter="24">
           <a-col>
 
-            <a-form-item label="最大化弹窗">
-              <a-button @click="()=>modal.visible=true">最大化弹窗</a-button>
+            <a-form-item label="JModal弹窗">
+              <a-button style="margin-right: 8px;" @click="()=>modal.visible=true">点击弹出JModal</a-button>
+              <span style="margin-right: 8px;">全屏化:<a-switch v-model="modal.fullscreen"/></span>
+              <span style="margin-right: 8px;">允许切换全屏:<a-switch v-model="modal.switchFullscreen"/></span>
+              <span>锁定Body滚动:<a-switch v-model="modal.lockScroll"/></span>
+
             </a-form-item>
 
-            <a-modal
-              :visible="modal.visible"
-              :width="modal.width"
-              :style="modal.style"
-              @ok="()=>modal.visible=false"
-              @cancel="()=>modal.visible=false">
-
-              <template slot="title">
-                <div style="width: 100%;height:20px;padding-right:32px;">
-                  <div style="float: left;">{{ modal.title }}</div>
-                  <div style="float: right;">
-                    <a-button
-                      icon="fullscreen"
-                      style="width:56px;height:100%;border:0"
-                      @click="handleClickToggleFullScreen"/>
-                  </div>
-                </div>
-              </template>
+            <j-modal
+              :visible.sync="modal.visible"
+              :width="1200"
+              :title="modal.title"
+              :lockScroll="modal.lockScroll"
+              :fullscreen.sync="modal.fullscreen"
+              :switchFullscreen="modal.switchFullscreen"
+            >
 
               <template v-for="(i,k) of 30">
                 <p :key="k">这是主体内容,高度是自适应的</p>
               </template>
 
-            </a-modal>
+            </j-modal>
 
           </a-col>
         </a-row>
@@ -217,10 +211,10 @@
         <a-row :gutter="24">
           <a-col :span="12">
             <a-form-item label="树字典">
-              <j-tree-dict parentCode="B01" />
+              <j-tree-dict v-model="formData.treeDict" placeholder="请选择树字典" parentCode="A01" />
             </a-form-item>
           </a-col>
-          <a-col :span="12"></a-col>
+          <a-col :span="12">选中的值(v-model):{{ formData.treeDict }}</a-col>
         </a-row>
 
         <a-row :gutter="24">
@@ -262,6 +256,45 @@
             </a-form-item>
           </a-col>
         </a-row>
+
+        <a-row :gutter="24">
+          <a-col :span="12">
+            <a-form-item label="高级查询">
+              <j-super-query :fieldList="superQuery.fieldList" />
+            </a-form-item>
+          </a-col>
+        </a-row>
+
+        <a-row :gutter="24">
+          <a-col :span="12">
+            <a-form-item label="高级查询(自定义按钮)">
+              <j-super-query :fieldList="superQuery.fieldList">
+                <!-- 直接在内部写一个按钮即可,点击事件自动添加 -->
+                <a-button type="primary" ghost icon="clock-circle">高级查询</a-button>
+              </j-super-query>
+            </a-form-item>
+          </a-col>
+        </a-row>
+        <a-row :gutter="24">
+          <a-col :span="12">
+            <a-form-item label="图片上传">
+              <j-image-upload v-model="imgList"></j-image-upload>
+            </a-form-item>
+          </a-col>
+          <a-col :spapn="12">选中的值(v-model):{{ imgList }}</a-col>
+        </a-row>
+        <a-row :gutter="24" style="margin-top: 65px;margin-bottom:50px;">
+          <a-col :span="12">
+            <a-form-item label="文件上传">
+              <j-upload v-model="fileList"></j-upload>
+            </a-form-item>
+          </a-col>
+          <a-col :spapn="12">
+            选中的值(v-model):
+            <j-ellipsis :value="fileList" :length="30" v-if="fileList.length>0"/>
+          </a-col>
+        </a-row>
+
       </a-form>
     </div>
 
@@ -286,10 +319,15 @@
   import JTreeDict from "../../components/jeecg/JTreeDict.vue";
   import JCron from "@/components/jeecg/JCron.vue";
   import JTreeSelect from '@/components/jeecg/JTreeSelect'
+  import JSuperQuery from '@/components/jeecg/JSuperQuery'
+  import JUpload from '@/components/jeecg/JUpload'
+  import JImageUpload from '@/components/jeecg/JImageUpload'
 
   export default {
     name: 'SelectDemo',
     components: {
+      JImageUpload,
+      JUpload,
       JTreeDict,
       JDictSelectTag,
       JSelectDepart,
@@ -299,7 +337,7 @@
       JCheckbox,
       JCodeEditor,
       JDate, JEditor, JEllipsis, JGraphicCode, JSlider, JSelectMultiple,
-      JCron, JTreeSelect
+      JCron, JTreeSelect, JSuperQuery
     },
     data() {
       return {
@@ -352,11 +390,20 @@ sayHi('hello, world!')`
         modal: {
           title: '这里是标题',
           visible: false,
-          width: '100%',
-          style: { top: '20px' },
-          fullScreen: true
+          lockScroll: true,
+          fullscreen: true,
+          switchFullscreen: true,
         },
         cron: '',
+        superQuery: {
+          fieldList: [
+            { type: 'input', value: 'name', text: '姓名', },
+            { type: 'select', value: 'sex', text: '性别', dictCode: 'sex' },
+            { type: 'number', value: 'age', text: '年龄', }
+          ]
+        },
+        fileList:[],
+        imgList:[],
       }
     },
     computed: {
@@ -399,18 +446,6 @@ sayHi('hello, world!')`
       handleJSliderSuccess(value) {
         this.jslider.value = value
       },
-      /** 切换全屏显示 */
-      handleClickToggleFullScreen() {
-        let mode = !this.modal.fullScreen
-        if (mode) {
-          this.modal.width = '100%'
-          this.modal.style.top = '20px'
-        } else {
-          this.modal.width = '1200px'
-          this.modal.style.top = '50px'
-        }
-        this.modal.fullScreen = mode
-      },
       setCorn(data){
         this.$nextTick(() => {
           this.form.cronExpression = data;

+ 8 - 6
ant-design-vue-jeecg/src/views/jeecg/helloworld.vue

@@ -19,11 +19,13 @@
         <a-cascader :options="areaOptions" @change="onChange" :showSearch="{filter}" placeholder="Please select" />
       </a-form-item>
       </a-col>
-      <a-col :md="24" :sm="24">
-        <a-form-item :wrapperCol="{ span: 12, offset: 5 }">
-          <a-button type="primary" htmlType="submit">Submit</a-button>
-        </a-form-item>
-      </a-col>
+      <a-form-item :wrapperCol="{ span: 12, offset: 5 }">
+        <a-col :md="24" :sm="24">
+          <a-form-item :wrapperCol="{ span: 12, offset: 5 }">
+            <a-button type="primary" htmlType="submit">Submit</a-button>
+          </a-form-item>
+        </a-col>
+      </a-form-item>
     </a-form>
   </a-card>
 </template>
@@ -68,4 +70,4 @@
       })
     }
   }
-</script>
+</script>

+ 7 - 6
ant-design-vue-jeecg/src/views/jeecg/modules/JeecgDemoModal.vue

@@ -35,12 +35,13 @@
         <a-form-item
           :labelCol="labelCol"
           :wrapperCol="wrapperCol"
-          label="sex">
-          <a-select v-decorator="['sex', {}]" placeholder="请选择性别">
-            <a-select-option value="">请选择性别</a-select-option>
-            <a-select-option value="1">男性</a-select-option>
-            <a-select-option value="2">女性</a-select-option>
-          </a-select>
+          label="性别">
+         <!-- <a-select v-decorator="['sex', {}]" placeholder="请选择性别">
+            <a-select-option value="">请选择</a-select-option>
+            <a-select-option value="1">男</a-select-option>
+            <a-select-option value="2">女</a-select-option>
+          </a-select>-->
+          <j-dict-select-tag type="radio" v-decorator="['sex', {}]" :trigger-change="true" dictCode="sex"/>
         </a-form-item>
         <a-form-item
           :labelCol="labelCol"

+ 1 - 1
ant-design-vue-jeecg/src/views/jeecg/report/ArchivesStatisticst.vue

@@ -2,7 +2,7 @@
   <a-card :bordered="false">
     <a-tabs defaultActiveKey="1" @change="callback">
       <a-tab-pane tab="柱状图" key="1">
-        <a-row :gutter="24">
+        <a-row>
           <a-col :span="10">
             <a-radio-group :value="barType" @change="statisticst">
               <a-radio-button value="year">按年统计</a-radio-button>

+ 8 - 24
ant-design-vue-jeecg/src/views/jeecg/tablist/form/JeecgOrderCustomerModal.vue

@@ -43,24 +43,7 @@
           :wrapperCol="wrapperCol"
           label="身份证扫描件"
           hasFeedback>
-          <a-upload
-            :action="uploadAction"
-            listType="picture-card"
-            :headers="headers"
-            :fileList="fileList"
-            @change="handleChange"
-            @preview="handlePreview"
-          >
-            <a-button>
-              <a-icon type="upload"/>
-              upload
-            </a-button>
-          </a-upload>
-          <a-modal :visible="previewVisible" :footer="null" @cancel="handlePicCancel">
-            <img alt="example" style="width: 100%" :src="previewImage"/>
-          </a-modal>
-
-          <br/>
+          <j-image-upload text="上传" v-model="fileList" :isMultiple="true"></j-image-upload>
         </a-form-item>
         <a-form-item
           :labelCol="labelCol"
@@ -88,11 +71,11 @@
   import pick from 'lodash.pick'
   import Vue from 'vue'
   import {ACCESS_TOKEN} from "@/store/mutation-types"
-
-  import { getUploadFileList,getFilePaths } from '@/utils/commonUploadFile.js'
+  import JImageUpload from '../../../../components/jeecg/JImageUpload'
 
   export default {
     name: "JeecgOrderCustomerModal",
+    components: { JImageUpload },
     data() {
       return {
         title: "操作",
@@ -177,7 +160,7 @@
           add: "/test/order/addCustomer",
           edit: "/test/order/editCustomer",
           fileUpload: window._CONFIG['domianURL'] + "/sys/common/upload",
-          imgerver: window._CONFIG['domianURL'] + "/sys/common/view",
+          imgerver: window._CONFIG['staticDomainURL'],
           getOrderCustomerList: "/test/order/listOrderCustomerByMainId",
         },
         validatorRules: {
@@ -222,8 +205,6 @@
 
         this.form.resetFields();
         this.orderId = record.orderId;
-        let currFileList = getUploadFileList(record.idcardPic)
-        this.fileList = [...currFileList]
         this.model = Object.assign({}, record);
         if (record.id) {
           this.hiding = false;
@@ -232,6 +213,9 @@
           this.$nextTick(() => {
             this.form.setFieldsValue(pick(this.model, 'id', 'name', 'sex', 'idcard','telphone', 'orderId', 'createBy', 'createTime', 'updateBy', 'updateTime'))
           });
+          setTimeout(() => {
+            this.fileList = record.idcardPic
+          }, 5)
         } else {
           this.addStatus = false;
           this.editStatus = true;
@@ -262,7 +246,7 @@
             let formData = Object.assign(this.model, values);
             console.log(formData);
             formData.orderId = this.orderId;
-            formData.idcardPic = getFilePaths(this.fileList)
+            formData.idcardPic = this.fileList;
             httpAction(httpurl, formData, method).then((res) => {
               if (res.success) {
                 that.$message.success(res.message);

+ 10 - 7
ant-design-vue-jeecg/src/views/modules/online/cgform/OnlCgformCopyList.vue

@@ -6,13 +6,13 @@
       <a-form layout="inline">
         <a-row :gutter="24">
 
-          <a-col :md="6" :sm="24">
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
             <a-form-item label="表名">
               <a-input placeholder="请输入表名" v-model="queryParam.tableName"></a-input>
             </a-form-item>
           </a-col>
 
-          <a-col :md="6" :sm="24">
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
             <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
               <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
               <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
@@ -25,10 +25,10 @@
 
     <!-- 操作按钮区域 -->
     <div class="table-operator">
-      <a-button @click="doCgformButton" type="primary" icon="highlight" style="margin-left:8px">自定义按钮</a-button>
-      <a-button @click="doEnhanceJs" type="primary" icon="strikethrough" style="margin-left:8px">JS增强</a-button>
-      <a-button @click="doEnhanceSql" type="primary" icon="filter" style="margin-left:8px">SQL增强</a-button>
-      <a-button @click="doEnhanceJava" type="primary" icon="tool" style="margin-left:8px">Java增强</a-button>
+      <a-button @click="doCgformButton" type="primary" icon="highlight">自定义按钮</a-button>
+      <a-button @click="doEnhanceJs" type="primary" icon="strikethrough">JS增强</a-button>
+      <a-button @click="doEnhanceSql" type="primary" icon="filter">SQL增强</a-button>
+      <a-button @click="doEnhanceJava" type="primary" icon="tool">Java增强</a-button>
 
       <a-dropdown v-if="selectedRowKeys.length > 0">
         <a-menu slot="overlay">
@@ -37,7 +37,7 @@
             删除
           </a-menu-item>
         </a-menu>
-        <a-button style="margin-left: 8px"> 批量操作
+        <a-button> 批量操作
           <a-icon type="down"/>
         </a-button>
       </a-dropdown>
@@ -348,6 +348,9 @@
     }
   }
 </script>
+<style scoped>
+  @import '~@assets/less/common.less';
+</style>
 <style lang="less">
   .ant-card-body .table-operator {
     margin-bottom: 18px;

+ 31 - 16
ant-design-vue-jeecg/src/views/modules/online/cgform/OnlCgformHeadList.vue

@@ -6,18 +6,22 @@
       <a-form layout="inline">
         <a-row :gutter="24">
 
-          <a-col :md="6" :sm="24">
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
             <a-form-item label="表名">
               <a-input placeholder="请输入表名" v-model="queryParam.tableName"></a-input>
             </a-form-item>
           </a-col>
-          <a-col :md="6" :sm="24">
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
             <a-form-item label="表类型">
               <j-dict-select-tag dictCode="cgform_table_type" v-model="queryParam.tableType"/>
             </a-form-item>
           </a-col>
-
-          <a-col :md="6" :sm="24">
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="表描述">
+              <a-input placeholder="请输入表描述" v-model="queryParam.tableTxt"></a-input>
+            </a-form-item>
+          </a-col>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
             <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
               <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
               <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
@@ -31,12 +35,12 @@
     <!-- 操作按钮区域 -->
     <div class="table-operator">
       <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
-      <a-button @click="doCgformButton" type="primary" icon="highlight" style="margin-left:8px">自定义按钮</a-button>
-      <a-button @click="doEnhanceJs" type="primary" icon="strikethrough" style="margin-left:8px">JS增强</a-button>
-      <a-button @click="doEnhanceSql" type="primary" icon="filter" v-has="'online:sql'" style="margin-left:8px">SQL增强</a-button>
-      <a-button @click="doEnhanceJava" type="primary" icon="tool" style="margin-left:8px">Java增强</a-button>
-      <a-button @click="importOnlineForm" type="primary" icon="database" style="margin-left:8px">从数据库导入表单</a-button>
-      <a-button @click="goGenerateCode" v-has="'online:goGenerateCode'" type="primary" icon="database" style="margin-left:8px">代码生成</a-button>
+      <a-button @click="doCgformButton" type="primary" icon="highlight">自定义按钮</a-button>
+      <a-button @click="doEnhanceJs" type="primary" icon="strikethrough">JS增强</a-button>
+      <a-button @click="doEnhanceSql" type="primary" icon="filter">SQL增强</a-button>
+      <a-button @click="doEnhanceJava" type="primary" icon="tool">Java增强</a-button>
+      <a-button @click="importOnlineForm" type="primary" icon="database">从数据库导入表单</a-button>
+      <a-button @click="goGenerateCode" type="primary" icon="database">代码生成</a-button>
 
       <a-dropdown v-if="selectedRowKeys.length > 0">
         <a-menu slot="overlay">
@@ -45,7 +49,7 @@
             删除
           </a-menu-item>
         </a-menu>
-        <a-button style="margin-left: 8px"> 批量操作
+        <a-button> 批量操作
           <a-icon type="down"/>
         </a-button>
       </a-dropdown>
@@ -204,8 +208,12 @@
             title: '表类型',
             align: 'center',
             dataIndex: 'tableType',
-            customRender: (text) => {
-              return filterDictText(this.tableTypeDictOptions, `${text}`)
+            customRender: (text, record) => {
+              let tbTypeText = filterDictText(this.tableTypeDictOptions, `${text}`)
+              if(record.isTree === 'Y'){
+                tbTypeText+='(树)'
+              }
+              return tbTypeText;
             }
           },
           {
@@ -316,10 +324,14 @@
         this.syncFormId = id
       },
       goPageOnline(rd) {
-        if(rd.isTree=='Y'){
-          this.$router.push({ path: '/online/cgformTreeList/' + rd.id })
+        if(rd.themeTemplate === 'erp'){
+          this.$router.push({ path: '/online/cgformErpList/' + rd.id })
         }else{
-          this.$router.push({ path: '/online/cgformList/' + rd.id })
+          if(rd.isTree=='Y'){
+            this.$router.push({ path: '/online/cgformTreeList/' + rd.id })
+          }else{
+            this.$router.push({ path: '/online/cgformList/' + rd.id })
+          }
         }
       },
       handleOnlineUrlClose() {
@@ -438,6 +450,9 @@
     }
   }
 </script>
+<style scoped>
+  @import '~@assets/less/common.less';
+</style>
 <style lang="less">
   .ant-card-body .table-operator {
     margin-bottom: 18px;

+ 55 - 49
ant-design-vue-jeecg/src/views/modules/online/cgform/auto/OnlCgformAutoList.vue

@@ -40,16 +40,15 @@
     <!-- 操作按钮区域 -->
     <div class="table-operator">
       <a-button v-if="buttonSwitch.add" @click="handleAdd" type="primary" icon="plus">新增</a-button>
-      <a-button v-if="buttonSwitch.import" @click="handleImportXls" type="primary" icon="upload" style="margin-left:8px">导入</a-button>
-      <a-button v-if="buttonSwitch.export" @click="handleExportXls" type="primary" icon="download" style="margin-left:8px">导出</a-button>
+      <a-button v-if="buttonSwitch.import" @click="handleImportXls" type="primary" icon="upload">导入</a-button>
+      <a-button v-if="buttonSwitch.export" @click="handleExportXls" type="primary" icon="download">导出</a-button>
       <template v-if="cgButtonList && cgButtonList.length>0" v-for="(item,index) in cgButtonList">
         <a-button
           v-if=" item.optType=='js' "
           :key=" 'cgbtn'+index "
           @click="cgButtonJsHandler(item.buttonCode)"
           type="primary"
-          :icon="item.buttonIcon"
-          style="margin-left:8px">
+          :icon="item.buttonIcon">
           {{ item.buttonName }}
         </a-button>
         <a-button
@@ -57,8 +56,7 @@
           :key=" 'cgbtn'+index "
           @click="cgButtonActionHandler(item.buttonCode)"
           type="primary"
-          :icon="item.buttonIcon"
-          style="margin-left:8px">
+          :icon="item.buttonIcon">
           {{ item.buttonName }}
         </a-button>
       </template>
@@ -69,13 +67,11 @@
         :fieldList="superQuery.fieldList"
         :saveCode="$route.fullPath"
         :loading="table.loading"
-        style="margin-left: 8px;"
         @handleSuperQuery="handleSuperQuery"/>
 
       <a-button
         v-if="buttonSwitch.batch_delete"
         @click="handleDelBatch"
-        style="margin-left:8px"
         v-show="table.selectedRowKeys.length > 0"
         ghost
         type="primary"
@@ -103,6 +99,16 @@
         :scroll="table.scroll"
         style="min-height: 300px">
 
+        <!-- 支持链接href跳转 -->
+        <template
+          v-for="field of fieldHrefSlots"
+          :slot="field.slotName"
+          slot-scope="text, record"
+        >
+          <a @click="handleClickFieldHref(field,record)">{{ text }}</a>
+        </template>
+
+
         <template slot="dateSlot" slot-scope="text">
           <span>{{ getFormatDate(text) }}</span>
         </template>
@@ -149,23 +155,17 @@
               更多 <a-icon type="down" />
             </a>
             <a-menu slot="overlay">
-              <a-menu-item >
+              <a-menu-item v-if="buttonSwitch.detail">
                 <a href="javascript:;" @click="handleDetail(record)">详情</a>
               </a-menu-item>
               <template v-if="hasBpmStatus">
                 <template v-if="record.bpm_status == '1'||record.bpm_status == ''|| record.bpm_status == null">
-                    <a-menu-item>
-                      <a href="javascript:;" @click="startProcess(record)">提交流程</a>
-                    </a-menu-item>
                     <a-menu-item v-if="buttonSwitch.delete">
                       <a-popconfirm title="确定删除吗?" @confirm="() => handleDeleteOne(record)">
                         <a>删除</a>
                       </a-popconfirm>
                     </a-menu-item>
                 </template>
-                <template v-else>
-                    <a-menu-item @click="handlePreviewPic(record)">审批进度</a-menu-item>
-                </template>
               </template>
               <template v-else>
                 <a-menu-item v-if="buttonSwitch.delete">
@@ -175,7 +175,7 @@
                 </a-menu-item>
                </template>
               <template v-if="cgButtonLinkList && cgButtonLinkList.length>0" v-for="(btnItem,btnIndex) in cgButtonLinkList">
-                <a-menu-item :key=" 'cgbtnLink'+btnIndex ">
+                <a-menu-item :key=" 'cgbtnLink'+btnIndex " v-if="showLinkButton(btnItem,record)">
                   <a href="javascript:void(0);" @click="cgButtonLinkHandler(record,btnItem.buttonCode,btnItem.optType)">
                     <a-icon v-if="btnItem.buttonIcon" :type="btnItem.buttonIcon" />
                     {{ btnItem.buttonName }}
@@ -192,20 +192,27 @@
 
       <j-import-modal ref="importModal" :url="getImportUrl()" @ok="importOk"></j-import-modal>
 
+      <!-- 跳转Href的动态组件方式 -->
+      <a-modal v-bind="hrefComponent.model" v-on="hrefComponent.on">
+        <component :is="hrefComponent.is" v-bind="hrefComponent.params"/>
+      </a-modal>
+
     </div>
   </a-card>
 </template>
 
 <script>
 
+  import { HrefJump } from '@/mixins/OnlAutoListMixin'
   import { postAction,getAction,deleteAction,downFile } from '@/api/manage'
   import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
-  import { filterObj } from '@/utils/util';
+  import { cloneObject, filterObj } from '@/utils/util'
   import JImportModal from '@/components/jeecg/JImportModal'
   import JSuperQuery from '@comp/jeecg/JSuperQuery'
 
   export default {
     name: 'OnlCgFormAutoList',
+    mixins: [HrefJump],
     components: {
       JSuperQuery,
       JImportModal,
@@ -222,7 +229,6 @@
           optPre:"/online/cgform/api/form/",
           exportXls:'/online/cgform/api/exportXls/',
           buttonAction:'/online/cgform/api/doButton',
-          startProcess: "/process/extActProcess/startMutilProcess",
         },
         flowCodePre:"onl_",
         isorter:{
@@ -282,7 +288,8 @@
           delete:true,
           batch_delete:true,
           import:true,
-          export:true
+          export:true,
+          detail:true
         },
         hasBpmStatus:false,
         checkboxFlag:false,
@@ -304,8 +311,7 @@
       this.cgButtonJsHandler('mounted')
     },
     watch: {
-      '$route.path'(newVal,oldVal) {
-        console.log('$route.path: ',oldVal)
+      '$route'() {
         // 刷新参数放到这里去触发,就可以刷新相同界面了
         this.initAutoList()
       }
@@ -343,30 +349,6 @@
           this.hasBpmStatus = false;
         }
       },
-      startProcess: function(record){
-        var that = this;
-        this.$confirm({
-          title:"提示",
-          content:"确认提交流程吗?",
-          onOk: function(){
-            var param = {
-              flowCode:that.flowCodePre+that.currentTableName,
-              id:record.id,
-              formUrl:"modules/bpm/task/form/OnlineFormDetail",
-              formUrlMobile:"modules/bpm/task/form/OnlineFormDetail"
-            }
-            postAction(that.url.startProcess,param).then((res)=>{
-              if(res.success){
-                that.$message.success(res.message);
-                that.loadData();
-                that.onClearSelected();
-              }else{
-                that.$message.warning(res.message);
-              }
-            });
-          }
-        });
-      },
       initQueryInfo(){
         getAction(`${this.url.getQueryInfo}${this.code}`).then((res)=>{
           console.log("--onlineList-获取查询条件配置",res);
@@ -407,6 +389,7 @@
               this.table.pagination = false
             }
 
+            this.fieldHrefSlots = res.result.fieldHrefSlots
             this.dictOptions = res.result.dictOptions
             this.formTemplate = res.result.formTemplate
             this.description = res.result.description
@@ -441,6 +424,8 @@
             this.hasBpmStatusFilter();
             this.loadData();
             this.initQueryInfo();
+            //加载新路由,清空checkbox选中
+            this.table.selectedRowKeys = [];
           }else{
             this.$message.warning(res.message)
           }
@@ -569,6 +554,10 @@
         this.cgButtonLinkHandler(record,"beforeEdit","js")
         this.$refs.modal.edit(this.formTemplate,record.id);
       },
+      showLinkButton(item,record){
+        let btn = new ButtonExpHandler(item.exp,record);
+        return btn.show;
+      },
       handleDetail(record){
         this.$refs.modal.detail(this.formTemplate,record.id);
       },
@@ -604,7 +593,8 @@
               dictCode: field.dictCode,
               dictTable: field.dictTable,
               dictText: field.dictText,
-              options: field.enum || field.options
+              options: field.enum || field.options,
+              order: field.order,
             })
           }
           let fieldList = []
@@ -630,6 +620,17 @@
               setField(fieldList, field)
             }
           }
+          // 冒泡排序
+          for (let i = 0; i < fieldList.length; i++) {
+            for (let j = i + 1; j < fieldList.length; j++) {
+              let temp1 = fieldList[i]
+              let temp2 = fieldList[j]
+              if (temp1.order > temp2.order) {
+                fieldList[i] = temp2
+                fieldList[j] = temp1
+              }
+            }
+          }
           this.superQuery.fieldList = fieldList
         }
       },
@@ -641,7 +642,7 @@
         if(text && text.indexOf(",")>0){
           text = text.substring(0,text.indexOf(","))
         }
-        return window._CONFIG['imgDomainURL']+"/"+text
+        return window._CONFIG['staticDomainURL']+"/"+text
       },
       downloadRowFile(text){
         if(!text){
@@ -651,7 +652,7 @@
         if(text.indexOf(",")>0){
           text = text.substring(0,text.indexOf(","))
         }
-        window.open(window._CONFIG['downloadUrl']+"/"+text);//TODO 下载的方法
+        window.open(window._CONFIG['staticDomainURL']+"/"+text);//TODO 下载的方法
       },
       handleDelBatch(){
         if(this.table.selectedRowKeys.length<=0){
@@ -777,13 +778,15 @@
         }
       },
       initButtonSwitch(hideColumns){
+        Object.keys(this.buttonSwitch).forEach(key=>{
+          this.buttonSwitch[key]=true
+        })
         if(hideColumns && hideColumns.length>0){
           Object.keys(this.buttonSwitch).forEach(key=>{
             if(hideColumns.indexOf(key)>=0){
               this.buttonSwitch[key]=false
             }
           })
-
         }
       },
 
@@ -801,6 +804,9 @@
     }
   }
 </script>
+<style scoped>
+  @import '~@assets/less/common.less';
+</style>
 <style>
   .ant-card-body .table-operator{
     margin-bottom: 18px;

+ 4 - 21
ant-design-vue-jeecg/src/views/modules/online/cgform/auto/OnlCgformTreeList.vue

@@ -98,15 +98,6 @@
               <a-menu-item >
                 <a @click="handleDetail(record)">详情</a>
               </a-menu-item>
-
-              <a-menu-item v-if="showSubmitFlowButton(record)">
-                <a @click="startProcess(record)">提交流程</a>
-              </a-menu-item>
-
-              <template v-if="showViewFlowButton(record)">
-                  <a-menu-item @click="handlePreviewPic(record)">审批进度</a-menu-item>
-              </template>
-
               <a-menu-item v-if="showOptButton('delete',record)">
                 <a-popconfirm title="确定删除吗?" @confirm="() => handleDeleteOne(record)">
                   <a>删除</a>
@@ -146,7 +137,7 @@
   export default {
     name: 'OnlCgformTreeList',
     components: {
-      JImportModal
+      JImportModal,
     },
     data() {
       return {
@@ -183,7 +174,6 @@
           optPre:"/online/cgform/api/form/",
           exportXls:'/online/cgform/api/exportXls/',
           buttonAction:'/online/cgform/api/doButton',
-          startProcess: "/process/extActProcess/startMutilProcess"
         },
         isorter:{
           column: 'create_time',
@@ -482,7 +472,7 @@
         if(text && text.indexOf(",")>0){
           text = text.substring(0,text.indexOf(","))
         }
-        return window._CONFIG['imgDomainURL']+"/"+text
+        return window._CONFIG['staticDomainURL']+"/"+text
       },
       downloadRowFile(text){
         if(!text){
@@ -492,7 +482,7 @@
         if(text.indexOf(",")>0){
           text = text.substring(0,text.indexOf(","))
         }
-        window.open(window._CONFIG['downloadUrl']+"/"+text);
+        window.open(window._CONFIG['staticDomainURL']+"/"+text);
       },
       /*-------数据格式化-end----------*/
 
@@ -651,14 +641,6 @@
         }
         return true
       },
-      showSubmitFlowButton(record){
-        if(this.hasBpmStatus){
-          if(record.bpm_status ==null || record.bpm_status =='' || record.bpm_status == '1'){
-            return true
-          }
-        }
-        return false
-      },
       showViewFlowButton(record){
         if(this.hasBpmStatus){
           if(record.bpm_status !=null && record.bpm_status !='' && record.bpm_status != '1'){
@@ -691,6 +673,7 @@
           }
         });
       },
+
     }
   }
 </script>

+ 111 - 0
ant-design-vue-jeecg/src/views/modules/online/cgform/auto/erp/OnlCgformErpList.vue

@@ -0,0 +1,111 @@
+<template>
+  <a-card :bordered="false" style="height: 100%">
+    <online-common-list
+      :ref="'onl_'+mainModel.currentTableName"
+      :code="code"
+      :model="mainModel"
+      @seleted="onSelected">
+    </online-common-list>
+
+    <a-tabs defaultActiveKey="0">
+      <a-tab-pane v-for="(item,index) in subList" :tab="item.description" :key="index+''" :forceRender="true" >
+        <online-common-list
+          :ref="item.currentTableName"
+          :code="item.code"
+          :model="item"
+          :main="selectedRow">
+        </online-common-list>
+      </a-tab-pane>
+    </a-tabs>
+  </a-card>
+</template>
+
+<script>
+  import { getAction } from '@/api/manage'
+
+  export default {
+    name: 'OnlCgformErpList',
+    components:{
+    },
+    data(){
+      return {
+        code:'',
+        url: {
+          getColumns: '/online/cgform/api/getErpColumns/',
+        },
+        mainModel:{},
+        subList:[],
+        mainId:'',
+        selectedRow:{}
+
+      }
+    },
+    watch: {
+      '$route'() {
+        // 刷新参数放到这里去触发,就可以刷新相同界面了
+        this.initColumnConfig()
+      }
+    },
+
+    created() {
+      this.initColumnConfig();
+    },
+    methods:{
+      getSubIndex(index){
+        return index+1 + ''
+      },
+      getSubRef(item){
+        let ref = item.currentTableName
+        console.log("ref string",ref)
+        return ref;
+      },
+      initColumnConfig(){
+        if(!this.$route.params.code){
+          return false
+        }
+        this.code = this.$route.params.code
+        getAction(`${this.url.getColumns}${this.code}`).then((res)=>{
+          console.log("erp表单配置",res)
+          if(res.success){
+            this.mainModel = res.result.main
+            this.subList = res.result.subList
+
+            this.$nextTick(()=>{
+              this.$refs['onl_'+this.mainModel.currentTableName].initListByModel();
+              if(this.subList && this.subList.length>0){
+                for(let item of this.subList){
+                  this.$refs[item.currentTableName][0].initListByModel();
+                }
+              }
+            });
+
+          }
+        })
+      },
+      onSelected(row){
+        console.log("onSelected",row)
+        this.selectedRow = row;
+      }
+
+
+    }
+  }
+</script>
+
+<style>
+  .ant-card-body .table-operator{
+    margin-bottom: 18px;
+  }
+  .ant-table-tbody .ant-table-row td{
+    padding-top:15px;
+    padding-bottom:15px;
+  }
+  .anty-row-operator button{margin: 0 5px}
+  .ant-btn-danger{background-color: #ffffff}
+
+  .anty-img-wrap{height:25px;position: relative;}
+  .anty-img-wrap > img{max-height:100%;}
+  .ant-modal-cust-warp{height: 100%}
+  .ant-modal-cust-warp .ant-modal-body{height:calc(100% - 110px) !important;overflow-y: auto}
+  .ant-modal-cust-warp .ant-modal-content{height:90% !important;overflow-y: hidden}
+</style>

+ 1 - 0
ant-design-vue-jeecg/src/views/modules/online/cgform/util/TableUtils.js

@@ -109,6 +109,7 @@ export function getMasterTableInitialData() {
       // table2
       isShowForm: '0',
       isShowList: '0',
+      isReadOnly: '1',
       fieldShowType: 'text',
       fieldLength: '120',
       queryMode: 'single',

+ 33 - 7
ant-design-vue-jeecg/src/views/modules/oss/OSSFileList.vue

@@ -31,7 +31,21 @@
           @change="handleChange">
         <a-button>
           <a-icon type="upload"/>
-          文件上传
+          OSS文件上传
+        </a-button>
+      </a-upload>
+
+      <a-upload
+        name="file"
+        :multiple="false"
+        :action="minioUploadAction"
+        :headers="tokenHeader"
+        :showUploadList="false"
+        :beforeUpload="beforeUpload"
+        @change="handleChange">
+        <a-button>
+          <a-icon type="upload"/>
+          MINIO文件上传
         </a-button>
       </a-upload>
     </div>
@@ -58,7 +72,9 @@
           @change="handleTableChange">
 
         <span slot="action" slot-scope="text, record">
-            <a @click="ossDelete(record.id)">删除</a>
+          <a @click="handlePreview(record)">预览</a>
+          <a-divider type="vertical"/>
+          <a @click="ossDelete(record.id)">删除</a>
         </span>
 
       </a-table>
@@ -108,14 +124,18 @@
         url: {
           upload: "/oss/file/upload",
           list: "/oss/file/list",
-          delete: "/oss/file/delete"
+          delete: "/oss/file/delete",
+          minioUpload: "/sys/upload/uploadMinio"
         }
       }
     },
     computed: {
       uploadAction() {
         return window._CONFIG['domianURL'] + this.url.upload;
-      }
+      },
+      minioUploadAction() {
+        return window._CONFIG['domianURL'] + this.url.minioUpload;
+      },
     },
     methods: {
       beforeUpload(file) {
@@ -139,10 +159,10 @@
             this.loadData()
             this.$message.success(`${info.file.name} 上传成功!`);
           } else {
-            this.$message.error(`${info.file.name} 上传失败.`);
+            this.$message.error(`${info.file.response.message}`);
           }
         } else if (info.file.status === 'error') {
-          this.$message.error(`${info.file.name} 上传失败.`);
+          this.$message.error(`${info.file.response.message}`);
         }
       },
       ossDelete(id) {
@@ -154,11 +174,17 @@
             that.handleDelete(id)
           }
         });
+      },
+      handlePreview(record) {
+        if (record && record.url) {
+          let url = window._CONFIG['onlinePreviewDomainURL'] + '?url=' + encodeURIComponent(record.url)
+          window.open(url, '_blank')
+        }
       }
     }
   }
 </script>
 
 <style scoped>
-  @import '~@assets/less/common.less'
+  @import '~@assets/less/common.less';
 </style>

+ 89 - 79
ant-design-vue-jeecg/src/views/system/DepartList.vue

@@ -17,8 +17,7 @@
         <div style="background: #fff;padding-left:16px;height: 100%; margin-top: 5px">
           <a-alert type="info" :showIcon="true">
             <div slot="message">
-              当前选择:
-              <a v-if="this.currSelected.title">{{ getCurrSelectedTitle() }}</a>
+              当前选择:<span v-if="this.currSelected.title">{{ getCurrSelectedTitle() }}</span>
               <a v-if="this.currSelected.title" style="margin-left: 10px" @click="onClearSelected">取消选择</a>
             </div>
           </a-alert>
@@ -72,82 +71,90 @@
       <!---- author:os_chengtgen -- date:20190827 --  for:切换父子勾选模式 =======------>
     </a-col>
     <a-col :md="12" :sm="24">
-      <a-card :bordered="false">
-        <a-form :form="form">
-          <a-form-item
-            :labelCol="labelCol"
-            :wrapperCol="wrapperCol"
-            label="机构名称">
-            <a-input placeholder="请输入机构/部门名称" v-decorator="['departName', validatorRules.departName ]"/>
-          </a-form-item>
-          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="上级部门">
-            <a-tree-select
-              style="width:100%"
-              :dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
-              :treeData="treeData"
-              :disabled="disable"
-              v-model="model.parentId"
-              placeholder="无">
-            </a-tree-select>
-          </a-form-item>
-          <a-form-item
-            :labelCol="labelCol"
-            :wrapperCol="wrapperCol"
-            label="机构编码">
-            <a-input disabled placeholder="请输入机构编码" v-decorator="['orgCode', validatorRules.orgCode ]"/>
-          </a-form-item>
-          <a-form-item
-            :labelCol="labelCol"
-            :wrapperCol="wrapperCol"
-            label="机构类型">
-            <template v-if="orgCategoryDisabled">
-              <a-radio-group v-decorator="['orgCategory',validatorRules.orgCategory]" placeholder="请选择机构类型">
-                <a-radio value="1">
-                  公司
-                </a-radio>
-              </a-radio-group>
-            </template>
-            <template v-else>
-              <a-radio-group v-decorator="['orgCategory',validatorRules.orgCategory]" placeholder="请选择机构类型">
-                <a-radio value="2">
-                  部门
-                </a-radio>
-                <a-radio value="3">
-                  岗位
-                </a-radio>
-              </a-radio-group>
-            </template>
-          </a-form-item>
-          <a-form-item
-            :labelCol="labelCol"
-            :wrapperCol="wrapperCol"
-            label="排序">
-            <a-input-number v-decorator="[ 'departOrder',{'initialValue':0}]"/>
-          </a-form-item>
-          <a-form-item
-            :labelCol="labelCol"
-            :wrapperCol="wrapperCol"
-            label="手机号">
-            <a-input placeholder="请输入手机号" v-decorator="['mobile', {'initialValue':''}]"/>
-          </a-form-item>
-          <a-form-item
-            :labelCol="labelCol"
-            :wrapperCol="wrapperCol"
-            label="地址">
-            <a-input placeholder="请输入地址" v-decorator="['address', {'initialValue':''}]"/>
-          </a-form-item>
-          <a-form-item
-            :labelCol="labelCol"
-            :wrapperCol="wrapperCol"
-            label="备注">
-            <a-textarea placeholder="请输入备注" v-decorator="['memo', {'initialValue':''}]"/>
-          </a-form-item>
-        </a-form>
-        <div class="anty-form-btn">
-          <a-button @click="emptyCurrForm" type="default" htmlType="button" icon="sync">重置</a-button>
-          <a-button @click="submitCurrForm" type="primary" htmlType="button" icon="form">修改并保存</a-button>
-        </div>
-      </a-card>
+      <a-tabs defaultActiveKey="1">
+        <a-tab-pane tab="基本信息" key="1" >
+          <a-card :bordered="false">
+            <a-form :form="form">
+              <a-form-item
+                :labelCol="labelCol"
+                :wrapperCol="wrapperCol"
+                label="机构名称">
+                <a-input placeholder="请输入机构/部门名称" v-decorator="['departName', validatorRules.departName ]"/>
+              </a-form-item>
+              <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="上级部门">
+                <a-tree-select
+                  style="width:100%"
+                  :dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
+                  :treeData="treeData"
+                  :disabled="disable"
+                  v-model="model.parentId"
+                  placeholder="无">
+                </a-tree-select>
+              </a-form-item>
+              <a-form-item
+                :labelCol="labelCol"
+                :wrapperCol="wrapperCol"
+                label="机构编码">
+                <a-input disabled placeholder="请输入机构编码" v-decorator="['orgCode', validatorRules.orgCode ]"/>
+              </a-form-item>
+              <a-form-item
+                :labelCol="labelCol"
+                :wrapperCol="wrapperCol"
+                label="机构类型">
+                <template v-if="orgCategoryDisabled">
+                  <a-radio-group v-decorator="['orgCategory',validatorRules.orgCategory]" placeholder="请选择机构类型">
+                    <a-radio value="1">
+                      公司
+                    </a-radio>
+                  </a-radio-group>
+                </template>
+                <template v-else>
+                  <a-radio-group v-decorator="['orgCategory',validatorRules.orgCategory]" placeholder="请选择机构类型">
+                    <a-radio value="2">
+                      部门
+                    </a-radio>
+                    <a-radio value="3">
+                      岗位
+                    </a-radio>
+                  </a-radio-group>
+                </template>
+              </a-form-item>
+              <a-form-item
+                :labelCol="labelCol"
+                :wrapperCol="wrapperCol"
+                label="排序">
+                <a-input-number v-decorator="[ 'departOrder',{'initialValue':0}]"/>
+              </a-form-item>
+              <a-form-item
+                :labelCol="labelCol"
+                :wrapperCol="wrapperCol"
+                label="手机号">
+                <a-input placeholder="请输入手机号" v-decorator="['mobile', {'initialValue':''}]"/>
+              </a-form-item>
+              <a-form-item
+                :labelCol="labelCol"
+                :wrapperCol="wrapperCol"
+                label="地址">
+                <a-input placeholder="请输入地址" v-decorator="['address', {'initialValue':''}]"/>
+              </a-form-item>
+              <a-form-item
+                :labelCol="labelCol"
+                :wrapperCol="wrapperCol"
+                label="备注">
+                <a-textarea placeholder="请输入备注" v-decorator="['memo', {'initialValue':''}]"/>
+              </a-form-item>
+            </a-form>
+            <div class="anty-form-btn">
+              <a-button @click="emptyCurrForm" type="default" htmlType="button" icon="sync">重置</a-button>
+              <a-button @click="submitCurrForm" type="primary" htmlType="button" icon="form">修改并保存</a-button>
+            </div>
+          </a-card>
+        </a-tab-pane>
+        <a-tab-pane tab="部门权限" key="2" forceRender>
+          <depart-auth-modal ref="departAuth"/>
+        </a-tab-pane>
+      </a-tabs>
+
     </a-col>
     <depart-modal ref="departModal" @ok="loadTree"></depart-modal>
   </a-row>
@@ -158,6 +165,7 @@
   import {queryDepartTreeList, searchByKeywords, deleteByDepartId} from '@/api/api'
   import {httpAction, deleteAction} from '@/api/manage'
   import {JeecgListMixin} from '@/mixins/JeecgListMixin'
+  import DepartAuthModal from './modules/DepartAuthModal'
   // 表头
   const columns = [
     {
@@ -201,6 +209,7 @@
     name: 'DepartList',
     mixins: [JeecgListMixin],
     components: {
+      DepartAuthModal,
       DepartModal
     },
     data() {
@@ -403,7 +412,7 @@
         this.selectedKeys = [record.key]
         this.model.parentId = record.parentId
         this.setValuesToForm(record)
-
+        this.$refs.departAuth.show(record.id);
 
       },
       // 触发onSelect事件时,为部门树右侧的form表单赋值
@@ -425,6 +434,7 @@
         this.currSelected = {}
         this.form.resetFields()
         this.selectedKeys = []
+        this.$refs.departAuth.departId = ''
       },
       handleNodeTypeChange(val) {
         this.currSelected.nodeType = val

+ 27 - 6
ant-design-vue-jeecg/src/views/system/DepartUserList.vue

@@ -6,7 +6,7 @@
           <a-input-search @search="onSearch" style="width:100%;margin-top: 10px" placeholder="请输入部门名称"/>
           <!-- 树-->
 
-          <template>
+          <template v-if="userIdentity === '2' && departTree.length>0">
 
             <!--组织机构-->
             <a-tree
@@ -16,10 +16,14 @@
               @select="onSelect"
               :dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
               :treeData="departTree"
+              :autoExpandParent="autoExpandParent"
             />
 
           </template>
-
+          <div style="margin-top: 24px;" v-else-if="userIdentity === '2' && departTree.length==0">
+            <h3><span>您的部门下暂无有效部门信息</span></h3>
+          </div>
+          <div style="margin-top: 24px;" v-else><h3>普通员工暂此权限</h3></div>
         </div>
       </a-card>
     </a-col>
@@ -30,7 +34,10 @@
             <Dept-Base-Info ref="DeptBaseInfo"></Dept-Base-Info>
           </a-tab-pane>
           <a-tab-pane tab="用户信息" key="2">
-            <Dept-User-Info ref="DeptUserInfo"></Dept-User-Info>
+            <Dept-User-Info ref="DeptUserInfo" @clearSelectedDepartKeys="clearSelectedDepartKeys"></Dept-User-Info>
+          </a-tab-pane>
+          <a-tab-pane tab="部门角色" key="3" forceRender>
+            <dept-role-info ref="DeptRoleInfo" @clearSelectedDepartKeys="clearSelectedDepartKeys"/>
           </a-tab-pane>
         </a-tabs>
       </a-card>
@@ -40,13 +47,15 @@
 <script>
   import DeptBaseInfo from './modules/DeptBaseInfo'
   import DeptUserInfo from './modules/DeptUserInfo'
-  import {queryDepartTreeList, searchByKeywords} from '@/api/api'
+  import {queryMyDepartTreeList, searchByKeywords} from '@/api/api'
   import {JeecgListMixin} from '@/mixins/JeecgListMixin'
+  import DeptRoleInfo from './modules/DeptRoleInfo'
 
   export default {
     name: 'DepartUserList',
     mixins: [JeecgListMixin],
     components: {
+      DeptRoleInfo,
       DeptBaseInfo,
       DeptUserInfo,
     },
@@ -85,6 +94,7 @@
           nodes: [],
           edges: []
         },
+        userIdentity:"",
       }
     },
     methods: {
@@ -94,12 +104,19 @@
       loadData() {
         this.refresh();
       },
+      clearSelectedDepartKeys() {
+        this.checkedKeys = [];
+        this.selectedKeys = [];
+        this.currentDeptId = '';
+        this.$refs.DeptUserInfo.currentDeptId='';
+        this.$refs.DeptRoleInfo.currentDeptId='';
+      },
       loadTree() {
         var that = this
         that.treeData = []
         that.departTree = []
-        queryDepartTreeList().then((res) => {
-          if (res.success) {
+        queryMyDepartTreeList().then((res) => {
+          if (res.success && res.result ) {
             for (let i = 0; i < res.result.length; i++) {
               let temp = res.result[i]
               that.treeData.push(temp)
@@ -109,6 +126,7 @@
             }
             this.loading = false
           }
+          that.userIdentity = res.message
         })
       },
       setThisExpandedKeys(node) {
@@ -161,6 +179,7 @@
 
         this.$refs.DeptBaseInfo.open(record);
         this.$refs.DeptUserInfo.open(record);
+        this.$refs.DeptRoleInfo.open(record);
         // }
         // else {
         //   this.checkedKeys = [];
@@ -180,6 +199,8 @@
         this.$refs.DeptBaseInfo.open(record);
         this.$refs.DeptUserInfo.onClearSelected();
         this.$refs.DeptUserInfo.open(record);
+        this.$refs.DeptRoleInfo.onClearSelected();
+        this.$refs.DeptRoleInfo.open(record);
       },
     },
     created() {

+ 13 - 1
ant-design-vue-jeecg/src/views/system/DictList.vue

@@ -30,6 +30,7 @@
         <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
           <a-button type="primary" icon="import">导入</a-button>
         </a-upload>
+        <a-button type="primary" icon="sync" @click="refleshCache()">刷新缓存</a-button>
 
         <a-button type="primary" icon="hdd" @click="openDeleteList">回收站</a-button>
       </div>
@@ -70,6 +71,7 @@
   import DictModal from './modules/DictModal'
   import DictItemList from './DictItemList'
   import DictDeleteList from './DictDeleteList'
+  import { getAction } from '@/api/manage'
 
   export default {
     name: "DictList",
@@ -132,6 +134,7 @@
           delete: "/sys/dict/delete",
           exportXlsUrl: "sys/dict/exportXls",
           importExcelUrl: "sys/dict/importExcel",
+          refleshCache: "sys/dict/refleshCache",
         },
       }
     },
@@ -165,9 +168,18 @@
         that.queryParam.dictCode = "";
         that.loadData(this.ipagination.current);
       },
-
       openDeleteList(){
         this.$refs.dictDeleteList.show()
+      },
+      refleshCache(){
+        getAction(this.url.refleshCache).then((res) => {
+          if (res.success) {
+            this.$message.success("刷新缓存完成!");
+          }
+        }).catch(e=>{
+          this.$message.warn("刷新缓存失败!");
+          console.log("刷新失败",e)
+        })
       }
     },
     watch: {

+ 38 - 9
ant-design-vue-jeecg/src/views/system/NewPermissionList.vue

@@ -29,7 +29,9 @@
         :dataSource="dataSource"
         :loading="loading"
         @expand="expandSubmenu"
-        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}">
+        :expandedRowKeys="expandedRowKeys"
+        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+        @expandedRowsChange="handleExpandedRowsChange">
 
         <span slot="action" slot-scope="text, record">
           <a @click="handleEdit(record)">编辑</a>
@@ -79,7 +81,7 @@
 
 <script>
   import PermissionModal from './modules/PermissionModal'
-  import { getSystemMenuList,getSystemSubmenu } from '@/api/api'
+  import { getSystemMenuList, getSystemSubmenu, getSystemSubmenuBatch } from '@/api/api'
   import { JeecgListMixin } from '@/mixins/JeecgListMixin'
   import PermissionDataRuleList from './PermissionDataRuleList'
   import JEllipsis from '@/components/jeecg/JEllipsis'
@@ -140,7 +142,7 @@
   ]
 
   export default {
-    name: 'PermissionList',
+    name: 'PermissionListAsync',
     mixins: [JeecgListMixin],
     components: {
       PermissionDataRuleList,
@@ -153,6 +155,8 @@
         // 表头
         columns: columns,
         loading: false,
+        // 展开的行,受控属性
+        expandedRowKeys: [],
         url: {
           list: '/sys/permission/list',
           delete: '/sys/permission/delete',
@@ -162,23 +166,45 @@
     },
     methods: {
       loadData() {
-        this.dataSource = []
+        this.loading = true
         getSystemMenuList().then((res) => {
           if (res.success) {
-            console.log(res.result)
             this.dataSource = res.result
+            return this.loadDataByExpandedRows(this.dataSource)
           }
+        }).finally(()=>{
+          this.loading = false
         })
       },
       expandSubmenu(expanded, record){
-        if(expanded){
+        if (expanded && (!record.children || record.children.length === 0)) {
           getSystemSubmenu({parentId:record.id}).then((res) => {
             if (res.success) {
               record.children = res.result
             }
           })
         }
-
+      },
+      // 根据已展开的行查询数据(用于保存后刷新时异步加载子级的数据)
+      loadDataByExpandedRows(dataList) {
+        if (this.expandedRowKeys.length > 0) {
+          return getSystemSubmenuBatch({ parentIds: this.expandedRowKeys.join(',') }).then((res) => {
+            if (res.success) {
+              let childrenMap = res.result
+              let fn = (list) => {
+                list.forEach(data => {
+                  if (this.expandedRowKeys.includes(data.id)) {
+                    data.children = childrenMap[data.id]
+                    fn(data.children)
+                  }
+                })
+              }
+              fn(dataList)
+            }
+          })
+        } else {
+          return Promise.resolve()
+        }
       },
       // 打开数据规则编辑
       handleDataRule(record) {
@@ -189,10 +215,13 @@
         this.$refs.modalForm.localMenuType = 1;
         this.$refs.modalForm.disableSubmit = false;
         this.$refs.modalForm.edit({status:'1',permsType:'1',route:true,'parentId':record.id});
-      }
+      },
+      handleExpandedRowsChange(expandedRows) {
+        this.expandedRowKeys = expandedRows
+      },
     }
   }
 </script>
 <style scoped>
-  @import '~@assets/less/common.less'
+  @import '~@assets/less/common.less';
 </style>

+ 10 - 3
ant-design-vue-jeecg/src/views/system/PermissionList.vue

@@ -28,7 +28,9 @@
         :pagination="false"
         :dataSource="dataSource"
         :loading="loading"
-        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}">
+        :expandedRowKeys="expandedRowKeys"
+        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+        @expandedRowsChange="handleExpandedRowsChange">
 
         <span slot="action" slot-scope="text, record">
           <a @click="handleEdit(record)">编辑</a>
@@ -152,6 +154,8 @@
         // 表头
         columns: columns,
         loading: false,
+        // 展开的行,受控属性
+        expandedRowKeys: [],
         url: {
           list: '/sys/permission/list',
           delete: '/sys/permission/delete',
@@ -178,10 +182,13 @@
         this.$refs.modalForm.localMenuType = 1;
         this.$refs.modalForm.disableSubmit = false;
         this.$refs.modalForm.edit({status:'1',permsType:'1',route:true,'parentId':record.id});
-      }
+      },
+      handleExpandedRowsChange(expandedRows) {
+        this.expandedRowKeys = expandedRows
+      },
     }
   }
 </script>
 <style scoped>
-  @import '~@assets/less/common.less'
+  @import '~@assets/less/common.less';
 </style>

+ 1 - 1
ant-design-vue-jeecg/src/views/system/RoleList.vue

@@ -67,8 +67,8 @@
 
         <span slot="action" slot-scope="text, record">
           <a @click="handleEdit(record)">编辑</a>
-
           <a-divider type="vertical" />
+
           <a-dropdown>
             <a class="ant-dropdown-link">
               更多 <a-icon type="down" />

+ 22 - 21
ant-design-vue-jeecg/src/views/system/RoleUserList.vue

@@ -60,26 +60,27 @@
             :rowSelection="{selectedRowKeys: selectedRowKeys1, onChange: onSelectChange1, type:'radio'}"
             @change="handleTableChange">
           <span slot="action" slot-scope="text, record">
-          <a @click="handleOpen(record)">用户</a>
-          <a-divider type="vertical"/>
-          <a-dropdown>
-            <a class="ant-dropdown-link">
-              更多 <a-icon type="down"/>
-            </a>
-            <a-menu slot="overlay">
-              <a-menu-item>
-                <a @click="handlePerssion(record.id)">授权</a>
-              </a-menu-item>
-              <a-menu-item>
-                <a @click="handleEdit(record)">编辑</a>
-              </a-menu-item>
-              <a-menu-item>
-                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete1(record.id)">
-                  <a>删除</a>
-                </a-popconfirm>
-              </a-menu-item>
-            </a-menu>
-          </a-dropdown>
+            <a @click="handleOpen(record)">用户</a>
+            <a-divider type="vertical"/>
+
+            <a-dropdown>
+              <a class="ant-dropdown-link">
+                更多 <a-icon type="down"/>
+              </a>
+              <a-menu slot="overlay">
+                <a-menu-item>
+                  <a @click="handlePerssion(record.id)">授权</a>
+                </a-menu-item>
+                <a-menu-item>
+                  <a @click="handleEdit(record)">编辑</a>
+                </a-menu-item>
+                <a-menu-item>
+                  <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete1(record.id)">
+                    <a>删除</a>
+                  </a-popconfirm>
+                </a-menu-item>
+              </a-menu>
+            </a-dropdown>
         </span>
           </a-table>
         </div>
@@ -530,7 +531,7 @@
       },
       handlePerssion(roleId){
         this.$refs.modalUserRole.show(roleId);
-      }
+      },
     }
   }
 </script>

+ 178 - 0
ant-design-vue-jeecg/src/views/system/SysCheckRuleList.vue

@@ -0,0 +1,178 @@
+<template>
+  <a-card :bordered="false">
+
+    <!-- 查询区域 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="searchQuery">
+        <a-row :gutter="24">
+
+          <a-col :md="6" :sm="8">
+            <a-form-item label="规则名称">
+              <a-input placeholder="请输入规则名称" v-model="queryParam.ruleName"/>
+            </a-form-item>
+          </a-col>
+          <a-col :md="6" :sm="8">
+            <a-form-item label="规则Code">
+              <a-input placeholder="请输入规则Code" v-model="queryParam.ruleCode"/>
+            </a-form-item>
+          </a-col>
+          <template v-if="toggleSearchStatus">
+          </template>
+          <a-col :md="6" :sm="8">
+            <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
+              <a @click="handleToggleSearch" style="margin-left: 8px">
+                {{ toggleSearchStatus ? '收起' : '展开' }}
+                <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
+              </a>
+            </span>
+          </a-col>
+
+        </a-row>
+      </a-form>
+    </div>
+
+    <!-- 操作按钮区域 -->
+    <div class="table-operator">
+      <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
+      <a-button type="primary" icon="download" @click="handleExportXls('编码校验规则')">导出</a-button>
+      <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
+        <a-button type="primary" icon="import">导入</a-button>
+      </a-upload>
+      <a-dropdown v-if="selectedRowKeys.length > 0">
+        <a-menu slot="overlay">
+          <a-menu-item key="1" @click="batchDel">
+            <a-icon type="delete"/>
+            删除
+          </a-menu-item>
+        </a-menu>
+        <a-button style="margin-left: 8px"> 批量操作
+          <a-icon type="down"/>
+        </a-button>
+      </a-dropdown>
+    </div>
+
+    <!-- table区域-begin -->
+    <a-alert type="info" showIcon style="margin-bottom: 16px;">
+      <template slot="message">
+        <span>已选择</span>
+        <a style="font-weight: 600;padding: 0 4px;">{{ selectedRowKeys.length }}</a>
+        <span>项</span>
+        <template v-if="selectedRowKeys.length>0">
+          <a-divider type="vertical"/>
+          <a @click="onClearSelected">清空</a>
+        </template>
+      </template>
+    </a-alert>
+
+    <a-table
+      ref="table"
+      size="middle"
+      bordered
+      rowKey="id"
+      :columns="columns"
+      :dataSource="dataSource"
+      :pagination="ipagination"
+      :loading="loading"
+      :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+      @change="handleTableChange">
+
+      <template slot="action" slot-scope="text, record">
+        <a @click="handleEdit(record)">编辑</a>
+        <a-divider type="vertical"/>
+        <a @click="handleTest(record)">功能测试</a>
+        <a-divider type="vertical"/>
+        <a-dropdown>
+          <a class="ant-dropdown-link">
+            <span>更多</span>
+            <a-icon type="down"/>
+          </a>
+          <a-menu slot="overlay">
+            <a-menu-item>
+              <a-popconfirm title="确定删除吗?" @confirm="handleDelete(record.id)">删除</a-popconfirm>
+            </a-menu-item>
+          </a-menu>
+        </a-dropdown>
+      </template>
+
+    </a-table>
+    <!-- table区域-end -->
+
+    <!-- 表单区域 -->
+    <sys-check-rule-modal ref="modalForm" @ok="modalFormOk"/>
+
+    <sys-check-rule-test-modal ref="testModal"/>
+
+  </a-card>
+</template>
+
+<script>
+  import JEllipsis from '@/components/jeecg/JEllipsis'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import SysCheckRuleModal from './modules/SysCheckRuleModal'
+  import SysCheckRuleTestModal from './modules/SysCheckRuleTestModal'
+
+  export default {
+    name: 'SysCheckRuleList',
+    mixins: [JeecgListMixin],
+    components: { SysCheckRuleModal, SysCheckRuleTestModal, JEllipsis },
+    data() {
+      return {
+        description: '编码校验规则管理页面',
+        // 表头
+        columns: [
+          {
+            title: '#',
+            key: 'rowIndex',
+            width: 60,
+            align: 'center',
+            customRender: (t, r, i) => i + 1
+          },
+          {
+            title: '规则名称',
+            align: 'center',
+            dataIndex: 'ruleName'
+          },
+          {
+            title: '规则Code',
+            align: 'center',
+            dataIndex: 'ruleCode'
+          },
+          {
+            title: '规则描述',
+            align: 'center',
+            dataIndex: 'ruleDescription',
+            customRender: (t) => (<j-ellipsis value={t} length={48}/>)
+          },
+          {
+            title: '操作',
+            dataIndex: 'action',
+            align: 'center',
+            scopedSlots: { customRender: 'action' },
+          }
+        ],
+        url: {
+          list: '/sys/checkRule/list',
+          delete: '/sys/checkRule/delete',
+          deleteBatch: '/sys/checkRule/deleteBatch',
+          exportXlsUrl: 'sys/checkRule/exportXls',
+          importExcelUrl: 'sys/checkRule/importExcel',
+        },
+      }
+    },
+    computed: {
+      importExcelUrl: function () {
+        return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`
+      }
+    },
+    methods: {
+      handleTest(record) {
+        this.$refs.testModal.open(record.ruleCode)
+      }
+    }
+  }
+</script>
+<style scoped>
+  @import '~@assets/less/common.less';
+</style>

+ 194 - 0
ant-design-vue-jeecg/src/views/system/SysDataSourceList.vue

@@ -0,0 +1,194 @@
+<template>
+  <a-card :bordered="false">
+
+    <!-- 查询区域 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="searchQuery">
+        <a-row :gutter="24">
+
+          <a-col :md="6" :sm="8">
+            <a-form-item label="数据源名称">
+              <a-input placeholder="请输入数据源名称" v-model="queryParam.name"/>
+            </a-form-item>
+          </a-col>
+
+          <a-col :md="6" :sm="8">
+            <a-form-item label="数据库类型">
+              <j-dict-select-tag v-model="queryParam.dbType" placeholder="请选择数据库类型" dict-code="database_type"/>
+            </a-form-item>
+          </a-col>
+
+          <a-col :md="6" :sm="8">
+            <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
+            </span>
+          </a-col>
+
+        </a-row>
+      </a-form>
+    </div>
+
+    <!-- 操作按钮区域 -->
+    <div class="table-operator">
+      <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
+      <a-button type="primary" icon="download" @click="handleExportXls('多数据源管理')">导出</a-button>
+      <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
+        <a-button type="primary" icon="import">导入</a-button>
+      </a-upload>
+      <a-dropdown v-if="selectedRowKeys.length > 0">
+        <a-menu slot="overlay">
+          <a-menu-item key="1" @click="batchDel">
+            <a-icon type="delete"/>
+            删除
+          </a-menu-item>
+        </a-menu>
+        <a-button style="margin-left: 8px"> 批量操作
+          <a-icon type="down"/>
+        </a-button>
+      </a-dropdown>
+    </div>
+
+    <!-- table区域-begin -->
+    <div>
+
+      <a-alert type="info" showIcon style="margin-bottom: 16px;">
+        <template slot="message">
+          <span>已选择</span>
+          <a style="font-weight: 600;padding: 0 4px;">{{ selectedRowKeys.length }}</a>
+          <span>项</span>
+          <a style="margin-left: 24px" @click="onClearSelected">清空</a>
+        </template>
+      </a-alert>
+
+      <a-table
+        ref="table"
+        size="middle"
+        bordered
+        rowKey="id"
+        :columns="columns"
+        :dataSource="dataSource"
+        :pagination="ipagination"
+        :loading="loading"
+        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+        @change="handleTableChange">
+
+        <span slot="action" slot-scope="text, record">
+          <a @click="handleEdit(record)">编辑</a>
+
+          <a-divider type="vertical"/>
+          <a-dropdown>
+            <a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+                  <a>删除</a>
+                </a-popconfirm>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+
+      </a-table>
+    </div>
+    <!-- table区域-end -->
+
+    <!-- 表单区域 -->
+    <sys-data-source-modal ref="modalForm" @ok="modalFormOk"/>
+
+  </a-card>
+</template>
+
+<script>
+  import JEllipsis from '@/components/jeecg/JEllipsis'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import SysDataSourceModal from './modules/SysDataSourceModal'
+
+  export default {
+    name: 'SysDataSourceList',
+    mixins: [JeecgListMixin],
+    components: { JEllipsis, SysDataSourceModal },
+    data() {
+      let ellipsis = (v, l = 20) => (<j-ellipsis value={v} length={l}/>)
+      return {
+        description: '多数据源管理管理页面',
+        // 表头
+        columns: [
+          {
+            title: '#',
+            dataIndex: '',
+            key: 'rowIndex',
+            width: 60,
+            align: 'center',
+            customRender: (t, r, index) => index + 1
+          },
+          {
+            title: '数据源名称',
+            align: 'center',
+            dataIndex: 'name'
+          },
+          {
+            title: '数据源编码',
+            align: 'center',
+            dataIndex: 'code'
+          },
+          {
+            title: '备注',
+            align: 'center',
+            dataIndex: 'remark',
+            customRender: (t) => ellipsis(t)
+          },
+          {
+            title: '数据库类型',
+            align: 'center',
+            dataIndex: 'dbType_dictText'
+          },
+          {
+            title: '驱动类',
+            align: 'center',
+            dataIndex: 'dbDriver',
+            customRender: (t) => ellipsis(t)
+          },
+          {
+            title: '数据源地址',
+            align: 'center',
+            dataIndex: 'dbUrl',
+            customRender: (t) => ellipsis(t)
+          },
+          {
+            title: '数据库名称',
+            align: 'center',
+            dataIndex: 'dbName'
+          },
+          {
+            title: '用户名',
+            align: 'center',
+            dataIndex: 'dbUsername'
+          },
+          {
+            title: '操作',
+            dataIndex: 'action',
+            align: 'center',
+            scopedSlots: { customRender: 'action' },
+          }
+        ],
+        url: {
+          list: '/sys/dataSource/list',
+          delete: '/sys/dataSource/delete',
+          deleteBatch: '/sys/dataSource/deleteBatch',
+          exportXlsUrl: 'sys/dataSource/exportXls',
+          importExcelUrl: 'sys/dataSource/importExcel',
+        },
+      }
+    },
+    computed: {
+      importExcelUrl() {
+        return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`
+      }
+    },
+    methods: {}
+  }
+</script>
+<style scoped>
+  @import '~@assets/less/common.less';
+</style>

+ 11 - 1
ant-design-vue-jeecg/src/views/system/UserAnnouncementList.vue

@@ -46,6 +46,7 @@
       </span>
     </a-table>
     <show-announcement ref="ShowAnnouncement"></show-announcement>
+    <dynamic-notice ref="showDynamNotice" :path="openPath" :formData="formData"/>
   </a-card>
 </template>
 
@@ -54,11 +55,13 @@
   import { getAction,putAction } from '@/api/manage'
   import ShowAnnouncement from '@/components/tools/ShowAnnouncement'
   import {JeecgListMixin} from '@/mixins/JeecgListMixin'
+  import DynamicNotice from '../../components/tools/DynamicNotice'
 
   export default {
     name: "UserAnnouncementList",
     mixins: [JeecgListMixin],
     components: {
+      DynamicNotice,
       ShowAnnouncement
     },
     data () {
@@ -130,6 +133,7 @@
           readAllMsg:"sys/sysAnnouncementSend/readAll",
         },
         loading:false,
+        openPath:''
       }
     },
     methods: {
@@ -143,7 +147,13 @@
             this.loadData();
           }
         });
-        this.$refs.ShowAnnouncement.detail(record);
+        if(record.openType==='component'){
+          this.openPath = record.openPage;
+          this.formData = {id:record.busId};
+          this.$refs.showDynamNotice.detail();
+        }else{
+          this.$refs.ShowAnnouncement.detail(record);
+        }
       },
       readAll(){
         var that = this;

+ 21 - 16
ant-design-vue-jeecg/src/views/system/UserList.vue

@@ -66,10 +66,12 @@
     <!-- 操作按钮区域 -->
     <div class="table-operator" style="border-top: 5px">
       <a-button @click="handleAdd" type="primary" icon="plus">添加用户</a-button>
+      <a-button @click="handleSyncUser"  v-has="'user:syncbpm'" type="primary" icon="plus">同步流程</a-button>
       <a-button type="primary" icon="download" @click="handleExportXls('用户信息')">导出</a-button>
       <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
         <a-button type="primary" icon="import">导入</a-button>
       </a-upload>
+      <a-button type="primary" icon="hdd" @click="recycleBinVisible=true">回收站</a-button>
       <a-dropdown v-if="selectedRowKeys.length > 0">
         <a-menu slot="overlay" @click="handleMenuClick">
           <a-menu-item key="1">
@@ -171,17 +173,22 @@
     <password-modal ref="passwordmodal" @ok="passwordModalOk"></password-modal>
 
     <sys-user-agent-modal ref="sysUserAgentModal"></sys-user-agent-modal>
+
+    <!-- 用户回收站 -->
+    <user-recycle-bin-modal :visible.sync="recycleBinVisible" @ok="modalFormOk"/>
+
   </a-card>
 </template>
 
 <script>
   import UserModal from './modules/UserModal'
   import PasswordModal from './modules/PasswordModal'
-  import {putAction} from '@/api/manage';
+  import {putAction,getFileAccessHttpUrl} from '@/api/manage';
   import {frozenBatch} from '@/api/api'
   import {JeecgListMixin} from '@/mixins/JeecgListMixin'
   import SysUserAgentModal from "./modules/SysUserAgentModal";
   import JInput from '@/components/jeecg/JInput'
+  import UserRecycleBinModal from './modules/UserRecycleBinModal'
 
   export default {
     name: "UserList",
@@ -190,12 +197,14 @@
       SysUserAgentModal,
       UserModal,
       PasswordModal,
-      JInput
+      JInput,
+      UserRecycleBinModal
     },
     data() {
       return {
         description: '这是用户管理页面',
         queryParam: {},
+        recycleBinVisible: false,
         columns: [
           /*{
             title: '#',
@@ -214,7 +223,7 @@
             width: 120
           },
           {
-            title: '真实姓名',
+            title: '用户姓名',
             align: "center",
             width: 100,
             dataIndex: 'realname',
@@ -237,7 +246,7 @@
           {
             title: '生日',
             align: "center",
-            width: 180,
+            width: 100,
             dataIndex: 'birthday'
           },
           {
@@ -247,9 +256,10 @@
             dataIndex: 'phone'
           },
           {
-            title: '邮箱',
+            title: '部门',
             align: "center",
-            dataIndex: 'email'
+            width: 180,
+            dataIndex: 'orgCode'
           },
           {
             title: '状态',
@@ -257,13 +267,6 @@
             width: 80,
             dataIndex: 'status_dictText'
           },
-         /* {
-            title: '创建时间',
-            align: "center",
-            width: 150,
-            dataIndex: 'createTime',
-            sorter: true
-          },*/
           {
             title: '操作',
             dataIndex: 'action',
@@ -274,7 +277,7 @@
 
         ],
         url: {
-          imgerver: window._CONFIG['domianURL'] + "/sys/common/view",
+          imgerver: window._CONFIG['staticDomainURL'],
           syncUser: "/process/extActProcess/doSyncUser",
           list: "/sys/user/list",
           delete: "/sys/user/delete",
@@ -291,7 +294,7 @@
     },
     methods: {
       getAvatarView: function (avatar) {
-        return this.url.imgerver + "/" + avatar;
+        return getFileAccessHttpUrl(avatar,this.url.imgerver,"http")
       },
 
       batchFrozen: function (status) {
@@ -363,6 +366,8 @@
         this.$refs.sysUserAgentModal.agentSettings(username);
         this.$refs.sysUserAgentModal.title = "用户代理人设置";
       },
+      handleSyncUser() {
+      },
       passwordModalOk() {
         //TODO 密码修改完成 不需要刷新页面,可以把datasource中的数据更新一下
       }
@@ -372,4 +377,4 @@
 </script>
 <style scoped>
   @import '~@assets/less/common.less'
-</style>
+</style>

+ 14 - 13
ant-design-vue-jeecg/src/views/system/modules/AddressListLeft.vue

@@ -1,7 +1,7 @@
 <template>
   <a-card :loading="cardLoading" :bordered="false" style="height: 100%;">
     <a-spin :spinning="loading">
-      <a-input-search @search="handleSearch" style="width:100%;margin-top: 10px" placeholder="输入组织机构名称进行查询..."/>
+      <a-input-search @search="handleSearch" style="width:100%;margin-top: 10px" placeholder="输入机构名称查询..." allowClear enterButton />
 
       <a-tree
         showLine
@@ -67,20 +67,21 @@
         promise.then(res => {
           if (res.success) {
             this.treeDataSource = res.result
-
+            // update-begin- --- author:wangshuai ------ date:20200102 ---- for:去除默认选中第一条数据、默认展开所有第一级
             // 默认选中第一条数据、默认展开所有第一级
-            if (res.result.length > 0) {
-              this.expandedKeys = []
-              res.result.forEach((item, index) => {
-                if (index === 0) {
-                  this.selectedKeys = [item.id]
-                  this.emitInput(item.orgCode)
-                }
-                this.expandedKeys.push(item.id)
-              })
-            }
+            // if (res.result.length > 0) {
+            //   this.expandedKeys = []
+            //   res.result.forEach((item, index) => {
+            //     if (index === 0) {
+            //       this.selectedKeys = [item.id]
+            //       this.emitInput(item.orgCode)
+            //     }
+            //     this.expandedKeys.push(item.id)
+            //   })
+            // }
+           // update-end- --- author:wangshuai ------ date:20200102 ---- for:去除默认选中第一条数据、默认展开所有第一级
           } else {
-            this.$message.warn('组织机构查询失败:' + res.message)
+            this.$message.warn(res.message)
             console.error('组织机构查询失败:', res)
           }
         }).finally(() => {

+ 26 - 13
ant-design-vue-jeecg/src/views/system/modules/AddressListRight.vue

@@ -65,12 +65,6 @@
             align: 'center',
             customRender: (t, r, i) => parseInt(i) + 1
           },
-          {
-            title: '部门',
-            width: '20%',
-            align: 'center',
-            dataIndex: 'departName'
-          },
           {
             title: '姓名',
             width: '15%',
@@ -83,6 +77,12 @@
             align: 'center',
             dataIndex: 'workNo'
           },
+          {
+            title: '部门',
+            width: '20%',
+            align: 'center',
+            dataIndex: 'departName'
+          },
           {
             title: '职务',
             width: '15%',
@@ -91,7 +91,7 @@
             customRender: (text) => (text || '').split(',').map(t => this.positionInfo[t] ? this.positionInfo[t] : t).join(',')
           },
           {
-            title: '机',
+            title: '机',
             width: '15%',
             align: 'center',
             dataIndex: 'telephone'
@@ -130,14 +130,26 @@
     methods: {
 
       loadData(pageNum, orgCode) {
-        if (!orgCode) {
-          return
-        }
-        //加载数据 若传入参数1则加载第一页的内容
+        this.loading = true
         if (pageNum === 1) {
-          this.ipagination.current = 1
+            this.ipagination.current = 1
         }
-        this.loading = true
+        // update-begin- --- author:wangshuai ------ date:20200102 ---- for:传过来的部门编码为空全查
+        if (!orgCode) {
+            getAction(this.url.list, {
+                ...this.getQueryParams()
+            }).then((res) => {
+                if (res.success) {
+                    this.dataSource = res.result.records
+                    this.ipagination.total = res.result.total
+                }
+            }).finally(() => {
+                this.loading = false
+                this.cardLoading = false
+            })
+          // update-end- --- author:wangshuai ------ date:20200102 ---- for:传过来的部门编码为空全查
+        }else{
+        //加载数据 若传入参数1则加载第一页的内容
         getAction(this.url.list, {
           orgCode,
           ...this.getQueryParams()
@@ -150,6 +162,7 @@
           this.loading = false
           this.cardLoading = false
         })
+        }
       },
 
       searchQuery() {

+ 184 - 0
ant-design-vue-jeecg/src/views/system/modules/DepartAuthModal.vue

@@ -0,0 +1,184 @@
+<template>
+  <a-card :bordered="false">
+    <template v-if="this.departId">
+      <a-form>
+        <a-form-item label='所拥有的权限'>
+          <a-tree
+            checkable
+            @check="onCheck"
+            :checkedKeys="checkedKeys"
+            :treeData="treeData"
+            @expand="onExpand"
+            @select="onTreeNodeSelect"
+            :selectedKeys="selectedKeys"
+            :expandedKeys="expandedKeysss"
+            :checkStrictly="checkStrictly"
+            style="height:500px;overflow: auto;">
+            <span slot="hasDatarule" slot-scope="{slotTitle,ruleFlag}">
+              {{ slotTitle }}
+              <a-icon v-if="ruleFlag" type="align-left" style="margin-left:5px;color: red;"></a-icon>
+            </span>
+          </a-tree>
+        </a-form-item>
+      </a-form>
+      <div class="anty-form-btn">
+        <a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
+          <a-menu slot="overlay">
+            <!-- 简化Tree逻辑,使用默认checkStrictly为false的行为,即默认父子关联
+            <a-menu-item key="1" @click="switchCheckStrictly(1)">父子关联</a-menu-item>
+            <a-menu-item key="2" @click="switchCheckStrictly(2)">取消关联</a-menu-item>
+            -->
+            <a-menu-item key="3" @click="checkALL">全部勾选</a-menu-item>
+            <a-menu-item key="4" @click="cancelCheckALL">取消全选</a-menu-item>
+            <a-menu-item key="5" @click="expandAll">展开所有</a-menu-item>
+            <a-menu-item key="6" @click="closeAll">合并所有</a-menu-item>
+          </a-menu>
+          <a-button>
+            树操作 <a-icon type="up" />
+          </a-button>
+        </a-dropdown>
+        <a-button style="float: right" @click="handleSubmit" type="primary" htmlType="button" icon="form">保存</a-button>
+      </div>
+    </template>
+    <div v-else style="height:330px;"><h3>请先选择一个部门!</h3></div>
+    <depart-datarule-modal ref="datarule"/>
+  </a-card>
+</template>
+
+<script>
+  import {queryTreeListForRole,queryDepartPermission,saveDepartPermission} from '@/api/api'
+  import DepartDataruleModal from './DepartDataruleModal'
+
+  export default {
+    name: 'DepartAuthModal',
+    components: { DepartDataruleModal },
+    data(){
+      return {
+        departId:"",
+        treeData: [],
+        defaultCheckedKeys:[],
+        checkedKeys:[],
+        halfCheckedKeys:[],
+        expandedKeysss:[],
+        allTreeKeys:[],
+        autoExpandParent: true,
+        checkStrictly: false,
+        title:"部门权限配置",
+        visible: false,
+        loading: false,
+        selectedKeys:[]
+      }
+    },
+    methods: {
+      onTreeNodeSelect(id){
+        if(id && id.length>0){
+          this.selectedKeys = id
+        }
+        this.$refs.datarule.show(this.selectedKeys[0],this.departId)
+      },
+      onCheck (checkedKeys, { halfCheckedKeys }) {
+        // 保存选中的和半选中的,后面保存的时候合并提交
+        this.checkedKeys = checkedKeys
+        this.halfCheckedKeys = halfCheckedKeys
+      },
+      show(departId){
+        this.departId=departId
+        this.loadData();
+      },
+      close () {
+        this.reset()
+        this.$emit('close');
+        this.visible = false;
+      },
+      onExpand(expandedKeys){
+        this.expandedKeysss = expandedKeys;
+        this.autoExpandParent = false
+      },
+      reset () {
+        this.expandedKeysss = []
+        this.checkedKeys = []
+        this.defaultCheckedKeys = []
+        this.loading = false
+      },
+      expandAll () {
+        this.expandedKeysss = this.allTreeKeys
+      },
+      closeAll () {
+        this.expandedKeysss = []
+      },
+      checkALL () {
+        this.checkedKeys = this.allTreeKeys
+      },
+      cancelCheckALL () {
+        this.checkedKeys = []
+      },
+      handleCancel () {
+        this.close()
+      },
+      handleSubmit() {
+        let that = this;
+        if(!that.departId){
+          this.$message.warning('请点击选择一个部门!')
+        }
+        let checkedKeys = [...that.checkedKeys, ...that.halfCheckedKeys]
+        const permissionIds = checkedKeys.join(",")
+        let params =  {
+          departId:that.departId,
+          permissionIds,
+          lastpermissionIds:that.defaultCheckedKeys.join(","),
+        };
+        that.loading = true;
+        saveDepartPermission(params).then((res)=>{
+          if(res.success){
+            that.$message.success(res.message);
+            that.loading = false;
+            that.loadData();
+          }else {
+            that.$message.error(res.message);
+            that.loading = false;
+          }
+        })
+      },
+      convertTreeListToKeyLeafPairs(treeList, keyLeafPair = []) {
+        for(const {key, isLeaf, children} of treeList) {
+          keyLeafPair.push({key, isLeaf})
+          if(children && children.length > 0) {
+            this.convertTreeListToKeyLeafPairs(children, keyLeafPair)
+          }
+        }
+        return keyLeafPair;
+      },
+      emptyCurrForm() {
+        this.form.resetFields()
+      },
+      loadData(){
+        queryTreeListForRole().then((res) => {
+          this.treeData = res.result.treeList
+          this.allTreeKeys = res.result.ids
+          const keyLeafPairs = this.convertTreeListToKeyLeafPairs(this.treeData)
+          queryDepartPermission({departId:this.departId}).then((res)=>{
+            // 过滤出 leaf node 即可,即选中的
+            // Tree组件中checkStrictly默认为false的时候,选中子节点,父节点会自动设置选中或半选中
+            // 保存 checkedKeys 以及 halfCheckedKeys 以便于未做任何操作时提交表单数据
+            const checkedKeys = [...res.result].filter(key => {
+              const keyLeafPair = keyLeafPairs.filter(item => item.key === key)[0]
+              return keyLeafPair && keyLeafPair.isLeaf
+            })
+            const halfCheckedKeys = [...res.result].filter(key => {
+              const keyLeafPair = keyLeafPairs.filter(item => item.key === key)[0]
+              return keyLeafPair && !keyLeafPair.isLeaf
+            })
+            this.checkedKeys = [...checkedKeys];
+            this.halfCheckedKeys = [...halfCheckedKeys]
+            this.defaultCheckedKeys = [...halfCheckedKeys, ...checkedKeys];
+            this.expandedKeysss = this.allTreeKeys;
+          })
+        })
+      }
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 116 - 0
ant-design-vue-jeecg/src/views/system/modules/DepartDataruleModal.vue

@@ -0,0 +1,116 @@
+<template>
+  <a-drawer
+    title="数据规则/按钮权限配置"
+    width="365"
+    :closable="false"
+    @close="onClose"
+    :visible="visible"
+  >
+    <a-tabs defaultActiveKey="1">
+      <a-tab-pane tab="数据规则" key="1">
+
+        <a-checkbox-group v-model="dataruleChecked" v-if="dataruleList.length>0">
+          <a-row>
+            <a-col :span="24" v-for="(item,index) in dataruleList" :key=" 'dr'+index ">
+              <a-checkbox :value="item.id">{{ item.ruleName }}</a-checkbox>
+            </a-col>
+
+            <a-col :span="24">
+              <div style="width: 100%;margin-top: 15px">
+                <a-button @click="saveDataruleForRole" type="primary" size="small" icon="save">点击保存</a-button>
+              </div>
+            </a-col>
+          </a-row>
+        </a-checkbox-group>
+        <div v-else><h3>无配置信息!</h3></div>
+
+      </a-tab-pane>
+    </a-tabs>
+
+  </a-drawer>
+</template>
+
+<script>
+  import ARow from 'ant-design-vue/es/grid/Row'
+  import ACol from 'ant-design-vue/es/grid/Col'
+  import { getAction,postAction } from '@/api/manage'
+
+  export default {
+    name: 'DepartDataruleModal',
+    components: { ACol, ARow },
+    data(){
+      return {
+        functionId:'',
+        departId:'',
+        visible:false,
+        tabList: [{
+          key: '1',
+          tab: '数据规则',
+        }, {
+          key: '2',
+          tab: '按钮权限',
+        }],
+        activeTabKey: '1',
+        url:{
+          datarule:"/sys/sysDepartPermission/datarule",
+        },
+        dataruleList:[],
+        dataruleChecked:[]
+      }
+    },
+    methods:{
+      loadData(){
+        getAction(`${this.url.datarule}/${this.functionId}/${this.departId}`).then(res=>{
+          if(res.success){
+            this.dataruleList = res.result.datarule
+            let drChecked = res.result.drChecked
+            if(drChecked){
+              this.dataruleChecked = drChecked.split(",")
+            }
+          }
+        })
+      },
+      saveDataruleForRole(){
+        if(!this.dataruleChecked || this.dataruleChecked.length==0){
+          this.$message.warning("请注意,现未勾选任何数据权限!")
+        }
+        let params = {
+          permissionId:this.functionId,
+          departId:this.departId,
+          dataRuleIds:this.dataruleChecked.join(",")
+        }
+        postAction(this.url.datarule,params).then(res=>{
+          if(res.success){
+            this.$message.success(res.message)
+          }else{
+            this.$message.error(res.message)
+          }
+        })
+      },
+      show(functionId,departId){
+        this.onReset()
+        this.functionId = functionId
+        this.departId = departId
+        this.visible=true
+        this.loadData()
+      },
+      onClose(){
+        this.visible=false
+        this.onReset()
+      },
+      onTabChange (key) {
+        this.activeTabKey = key
+      },
+      onReset(){
+        this.functionId=''
+        this.departId=''
+        this.dataruleList=[]
+        this.dataruleChecked=[]
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 217 - 0
ant-design-vue-jeecg/src/views/system/modules/DeptRoleAuthModal.vue

@@ -0,0 +1,217 @@
+<template>
+  <a-drawer
+    :title="title"
+    :maskClosable="true"
+    width=650
+    placement="right"
+    :closable="true"
+    @close="close"
+    :visible="visible"
+    style="height: calc(100% - 55px);overflow: auto;padding-bottom: 53px;">
+
+    <a-form>
+      <a-form-item label='所拥有的部门权限'>
+
+        <a-tree
+          v-if="treeData.length>0"
+          checkable
+          @check="onCheck"
+          :checkedKeys="checkedKeys"
+          :treeData="treeData"
+          @expand="onExpand"
+          @select="onTreeNodeSelect"
+          :selectedKeys="selectedKeys"
+          :expandedKeys="expandedKeysss"
+          :checkStrictly="checkStrictly">
+          <span slot="hasDatarule" slot-scope="{slotTitle,ruleFlag}">
+            {{ slotTitle }}<a-icon v-if="ruleFlag" type="align-left" style="margin-left:5px;color: red;"></a-icon>
+          </span>
+        </a-tree>
+        <div v-else><h3>无可配置部门权限!</h3></div>
+      </a-form-item>
+    </a-form>
+
+    <div class="drawer-bootom-button">
+      <a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
+        <a-menu slot="overlay">
+          <a-menu-item key="3" @click="checkALL">全部勾选</a-menu-item>
+          <a-menu-item key="4" @click="cancelCheckALL">取消全选</a-menu-item>
+          <a-menu-item key="5" @click="expandAll">展开所有</a-menu-item>
+          <a-menu-item key="6" @click="closeAll">合并所有</a-menu-item>
+        </a-menu>
+        <a-button>
+          树操作 <a-icon type="up" />
+        </a-button>
+      </a-dropdown>
+      <a-popconfirm title="确定放弃编辑?" @confirm="close" okText="确定" cancelText="取消">
+        <a-button style="margin-right: .8rem">取消</a-button>
+      </a-popconfirm>
+      <a-button @click="handleSubmit(false)" type="primary" :loading="loading" ghost style="margin-right: 0.8rem">仅保存</a-button>
+      <a-button @click="handleSubmit(true)" type="primary" :loading="loading">保存并关闭</a-button>
+    </div>
+    <dept-role-datarule-modal ref="datarule"></dept-role-datarule-modal>
+  </a-drawer>
+
+</template>
+<script>
+  import {queryTreeListForDeptRole,queryDeptRolePermission,saveDeptRolePermission} from '@/api/api'
+  import RoleDataruleModal from './RoleDataruleModal.vue'
+  import DeptRoleDataruleModal from './DeptRoleDataruleModal'
+
+  export default {
+    name: "DeptRoleAuthModal",
+    components:{
+      DeptRoleDataruleModal,
+      RoleDataruleModal
+    },
+    data(){
+      return {
+        departId:"",
+        roleId:"",
+        treeData: [],
+        defaultCheckedKeys:[],
+        checkedKeys:[],
+        halfCheckedKeys:[],
+        expandedKeysss:[],
+        allTreeKeys:[],
+        autoExpandParent: true,
+        checkStrictly: false,
+        title:"部门角色权限配置",
+        visible: false,
+        loading: false,
+        selectedKeys:[]
+      }
+    },
+    methods: {
+      onTreeNodeSelect(id){
+        if(id && id.length>0){
+          this.selectedKeys = id
+        }
+        this.$refs.datarule.show(this.selectedKeys[0],this.departId,this.roleId)
+      },
+      onCheck (checkedKeys, { halfCheckedKeys }) {
+        // 保存选中的和半选中的,后面保存的时候合并提交
+        this.checkedKeys = checkedKeys
+        this.halfCheckedKeys = halfCheckedKeys
+      },
+      show(roleId,departId){
+        this.departId = departId
+        this.roleId=roleId
+        this.visible = true;
+      },
+      close () {
+        this.reset()
+        this.$emit('close');
+        this.visible = false;
+      },
+      onExpand(expandedKeys){
+        this.expandedKeysss = expandedKeys;
+        this.autoExpandParent = false
+      },
+      reset () {
+        this.expandedKeysss = []
+        this.checkedKeys = []
+        this.defaultCheckedKeys = []
+        this.loading = false
+      },
+      expandAll () {
+        this.expandedKeysss = this.allTreeKeys
+      },
+      closeAll () {
+        this.expandedKeysss = []
+      },
+      checkALL () {
+        this.checkedKeys = this.allTreeKeys
+      },
+      cancelCheckALL () {
+        this.checkedKeys = []
+      },
+      handleCancel () {
+        this.close()
+      },
+      handleSubmit(exit) {
+        let that = this;
+        let checkedKeys = [...that.checkedKeys, ...that.halfCheckedKeys]
+        const permissionIds = checkedKeys.join(",")
+        let params =  {
+          roleId:that.roleId,
+          permissionIds,
+          lastpermissionIds:that.defaultCheckedKeys.join(","),
+        };
+        that.loading = true;
+        console.log("请求参数:",params);
+        saveDeptRolePermission(params).then((res)=>{
+          if(res.success){
+            that.$message.success(res.message);
+            that.loading = false;
+            if (exit) {
+              that.close()
+            }
+          }else {
+            that.$message.error(res.message);
+            that.loading = false;
+            if (exit) {
+              that.close()
+            }
+          }
+          this.loadData();
+        })
+      },
+      convertTreeListToKeyLeafPairs(treeList, keyLeafPair = []) {
+        for(const {key, isLeaf, children} of treeList) {
+          keyLeafPair.push({key, isLeaf})
+          if(children && children.length > 0) {
+            this.convertTreeListToKeyLeafPairs(children, keyLeafPair)
+          }
+        }
+        return keyLeafPair;
+      },
+      loadData(){
+        queryTreeListForDeptRole({departId:this.departId}).then((res) => {
+          this.treeData = res.result.treeList
+          this.allTreeKeys = res.result.ids
+          const keyLeafPairs = this.convertTreeListToKeyLeafPairs(this.treeData)
+          queryDeptRolePermission({roleId:this.roleId}).then((res)=>{
+            // 过滤出 leaf node 即可,即选中的
+            // Tree组件中checkStrictly默认为false的时候,选中子节点,父节点会自动设置选中或半选中
+            // 保存 checkedKeys 以及 halfCheckedKeys 以便于未做任何操作时提交表单数据
+            const checkedKeys = [...res.result].filter(key => {
+              const keyLeafPair = keyLeafPairs.filter(item => item.key === key)[0]
+              return keyLeafPair && keyLeafPair.isLeaf
+            })
+            const halfCheckedKeys = [...res.result].filter(key => {
+              const keyLeafPair = keyLeafPairs.filter(item => item.key === key)[0]
+              return keyLeafPair && !keyLeafPair.isLeaf
+            })
+            this.checkedKeys = [...checkedKeys];
+            this.halfCheckedKeys = [...halfCheckedKeys]
+            this.defaultCheckedKeys = [...halfCheckedKeys, ...checkedKeys];
+            this.expandedKeysss = this.allTreeKeys;
+          })
+        })
+      }
+    },
+    watch: {
+      visible () {
+        if (this.visible ) {
+          this.loadData();
+        }
+      }
+    }
+  }
+
+</script>
+<style lang="scss" scoped>
+  .drawer-bootom-button {
+    position: absolute;
+    bottom: 0;
+    width: 100%;
+    border-top: 1px solid #e8e8e8;
+    padding: 10px 16px;
+    text-align: right;
+    left: 0;
+    background: #fff;
+    border-radius: 0 0 2px 2px;
+  }
+
+</style>

+ 122 - 0
ant-design-vue-jeecg/src/views/system/modules/DeptRoleDataruleModal.vue

@@ -0,0 +1,122 @@
+<template>
+  <a-drawer
+    title="数据规则/按钮权限配置"
+    width="365"
+    :closable="false"
+    @close="onClose"
+    :visible="visible"
+  >
+
+    <a-tabs defaultActiveKey="1">
+      <a-tab-pane tab="数据规则" key="1">
+
+        <a-checkbox-group v-model="dataruleChecked" v-if="dataruleList.length>0">
+          <a-row>
+            <a-col :span="24" v-for="(item,index) in dataruleList" :key=" 'dr'+index ">
+              <a-checkbox :value="item.id">{{ item.ruleName }}</a-checkbox>
+            </a-col>
+
+            <a-col :span="24">
+              <div style="width: 100%;margin-top: 15px">
+                <a-button @click="saveDataruleForRole" type="primary" size="small" icon="save">点击保存</a-button>
+              </div>
+            </a-col>
+          </a-row>
+        </a-checkbox-group>
+        <div v-else><h3>无配置信息!</h3></div>
+
+      </a-tab-pane>
+      <!--<a-tab-pane tab="按钮权限" key="2">敬请期待!!!</a-tab-pane>-->
+    </a-tabs>
+
+  </a-drawer>
+</template>
+
+<script>
+  import ARow from 'ant-design-vue/es/grid/Row'
+  import ACol from 'ant-design-vue/es/grid/Col'
+  import { getAction,postAction } from '@/api/manage'
+
+  export default {
+    name: 'DeptRoleDataruleModal',
+    components: { ACol, ARow },
+    data(){
+      return {
+        departId:'',
+        functionId:'',
+        roleId:'',
+        visible:false,
+        tabList: [{
+          key: '1',
+          tab: '数据规则',
+        }, {
+          key: '2',
+          tab: '按钮权限',
+        }],
+        activeTabKey: '1',
+        url:{
+          datarule:"/sys/sysDepartRole/datarule",
+        },
+        dataruleList:[],
+        dataruleChecked:[]
+      }
+    },
+    methods:{
+      loadData(){
+        getAction(`${this.url.datarule}/${this.functionId}/${this.departId}/${this.roleId}`).then(res=>{
+          console.log(res)
+          if(res.success){
+            this.dataruleList = res.result.datarule
+            let drChecked = res.result.drChecked
+            if(drChecked){
+              this.dataruleChecked = drChecked.split(",")
+            }
+          }
+        })
+      },
+      saveDataruleForRole(){
+        if(!this.dataruleChecked || this.dataruleChecked.length==0){
+          this.$message.warning("请注意,现未勾选任何数据权限!")
+        }
+        let params = {
+          permissionId:this.functionId,
+          roleId:this.roleId,
+          dataRuleIds:this.dataruleChecked.join(",")
+        }
+        console.log("保存数据权限",params)
+        postAction(this.url.datarule,params).then(res=>{
+          if(res.success){
+            this.$message.success(res.message)
+          }else{
+            this.$message.error(res.message)
+          }
+        })
+      },
+      show(functionId,departId,roleId){
+        this.onReset()
+        this.departId = departId
+        this.functionId = functionId
+        this.roleId = roleId
+        this.visible=true
+        this.loadData()
+      },
+      onClose(){
+        this.visible=false
+        this.onReset()
+      },
+      onTabChange (key) {
+        this.activeTabKey = key
+      },
+      onReset(){
+        this.functionId=''
+        this.roleId=''
+        this.dataruleList=[]
+        this.dataruleChecked=[]
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 196 - 0
ant-design-vue-jeecg/src/views/system/modules/DeptRoleInfo.vue

@@ -0,0 +1,196 @@
+<template>
+  <a-card :bordered="false">
+    <!-- 查询区域 -->
+    <div class="table-page-search-wrapper">
+      <!-- 搜索区域 -->
+      <a-form layout="inline">
+        <a-row :gutter="10">
+          <a-col :md="10" :sm="12">
+            <a-form-item label="部门角色名称" style="margin-left:8px">
+              <a-input placeholder="请输入部门角色" v-model="queryParam.roleName"></a-input>
+            </a-form-item>
+          </a-col>
+          <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+            <a-col :md="6" :sm="24">
+              <a-button type="primary" @click="searchQuery" icon="search" style="margin-left: 18px">查询</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
+            </a-col>
+          </span>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 操作按钮区域 -->
+    <div class="table-operator" :md="24" :sm="24">
+      <a-button @click="handleAdd" type="primary" icon="plus">部门角色录入</a-button>
+      <a-dropdown v-if="selectedRowKeys.length > 0">
+        <a-menu slot="overlay">
+          <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item>
+        </a-menu>
+        <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button>
+      </a-dropdown>
+    </div>
+    <!-- table区域-begin -->
+    <div>
+      <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
+        <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">
+          {{selectedRowKeys.length }}</a>项
+        <a style="margin-left: 24px" @click="onClearSelected">清空</a>
+      </div>
+      <a-table
+        ref="table"
+        size="middle"
+        bordered
+        rowKey="id"
+        :columns="columns"
+        :dataSource="dataSource"
+        :pagination="ipagination"
+        :loading="loading"
+        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+        @change="handleTableChange">
+        <span slot="action" slot-scope="text, record">
+          <a @click="handleEdit(record)">编辑</a>
+          <a-divider type="vertical"/>
+          <a-dropdown>
+            <a class="ant-dropdown-link">
+              更多 <a-icon type="down"/>
+            </a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+                  <a>删除</a>
+                </a-popconfirm>
+              </a-menu-item>
+              <a-menu-item>
+                <a href="javascript:;" @click="handleDetail(record)">详情</a>
+              </a-menu-item>
+              <a-menu-item>
+                <a @click="handlePerssion(record)">授权</a>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+      </a-table>
+    </div>
+    <!-- table区域-end -->
+    <!-- 表单区域 -->
+    <sys-depart-role-modal ref="modalForm" @ok="modalFormOk"/>
+    <dept-role-auth-modal ref="modalDeptRole" />
+  </a-card>
+</template>
+
+<script>
+  import {JeecgListMixin} from '@/mixins/JeecgListMixin'
+  import {getAction} from '@/api/manage'
+  import SysDepartRoleModal from './SysDepartRoleModal'
+  import DeptRoleAuthModal from './DeptRoleAuthModal'
+
+  export default {
+    name: 'DeptRoleInfo',
+    components: { DeptRoleAuthModal, SysDepartRoleModal },
+    mixins: [JeecgListMixin],
+    data() {
+      return {
+        description: '部门角色信息',
+        currentDeptId: '',
+        // 表头
+        columns: [{
+          title: '部门角色名称',
+          align: "center",
+          dataIndex: 'roleName'
+        },
+        {
+          title: '部门角色编码',
+          align: "center",
+          dataIndex: 'roleCode'
+        },
+        {
+          title: '部门',
+          align: "center",
+          dataIndex: 'departId_dictText'
+        },
+        {
+          title: '备注',
+          align: "center",
+          dataIndex: 'description'
+        },
+        {
+          title: '操作',
+          dataIndex: 'action',
+          scopedSlots: {customRender: 'action'},
+          align: "center",
+          width: 170
+        }],
+        url: {
+          list: "/sys/sysDepartRole/list",
+          delete: "/sys/sysDepartRole/delete",
+          deleteBatch: "/sys/sysDepartRole/deleteBatch",
+        }
+      }
+    },
+    created() {
+    },
+    methods: {
+      searchReset() {
+        this.queryParam = {}
+        this.currentDeptId = '';
+        this.loadData(1);
+        this.$emit('clearSelectedDepartKeys')
+      },
+      loadData(arg) {
+        if (!this.url.list) {
+          this.$message.error("请设置url.list属性!")
+          return
+        }
+        //加载数据 若传入参数1则加载第一页的内容
+        if (arg === 1) {
+          this.ipagination.current = 1;
+        }
+        let params = this.getQueryParams();//查询条件
+        params.deptId = this.currentDeptId;
+        getAction(this.url.list, params).then((res) => {
+          if (res.success && res.result) {
+            this.dataSource = res.result.records;
+            this.ipagination.total = res.result.total;
+          }
+        })
+      },
+      open(record) {
+        this.currentDeptId = record.id;
+        this.loadData(1);
+      },
+      clearList() {
+        this.currentDeptId = '';
+        this.dataSource = [];
+      },
+      hasSelectDept() {
+        if (this.currentDeptId == '') {
+          this.$message.error("请选择一个部门!")
+          return false;
+        }
+        return true;
+      },
+      handleEdit: function (record) {
+        this.$refs.modalForm.title = "编辑";
+        this.$refs.modalForm.departDisabled = true;
+        this.$refs.modalForm.disableSubmit = false;
+        this.$refs.modalForm.edit(record,record.departId);
+      },
+      handleAdd: function () {
+        if (this.currentDeptId == '') {
+          this.$message.error("请选择一个部门!")
+        } else {
+          this.$refs.modalForm.departDisabled = true;
+          this.$refs.modalForm.add(this.currentDeptId);
+          this.$refs.modalForm.title = "新增";
+        }
+      },
+      handlePerssion: function(record){
+        this.$refs.modalDeptRole.show(record.id,record.departId);
+      },
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 200 - 0
ant-design-vue-jeecg/src/views/system/modules/DeptRoleUserModal.vue

@@ -0,0 +1,200 @@
+<template>
+  <a-drawer
+    :title="title"
+    :maskClosable="true"
+    width=600
+    placement="right"
+    :closable="true"
+    @close="close"
+    :visible="visible"
+    style="height: calc(100% - 55px);overflow: auto;padding-bottom: 53px;">
+
+    <a-spin :spinning="confirmLoading">
+
+      <a-form :form="form" v-if="designNameOption.length>0">
+        <a-form-item label=''>
+          <a-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
+            <a-card :style="{ marginTop: '12px',height:'auto' }">
+              <a-checkbox-group @change="designNameChange" v-model="designNameValue" style="width: 100%">
+                <a-row>
+                  <template v-for="(des) in designNameOption">
+                    <a-col :span="6">
+                      <a-checkbox :value="des.value">{{ des.text }}</a-checkbox>
+                    </a-col>
+                  </template>
+                </a-row>
+              </a-checkbox-group>
+            </a-card>
+          </a-col>
+        </a-form-item>
+      </a-form>
+      <div v-else><h3>无可配置角色!</h3></div>
+    </a-spin>
+    <div class="drawer-bootom-button">
+      <a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
+        <a-menu slot="overlay">
+          <a-menu-item key="1" @click="checkALL">全部勾选</a-menu-item>
+          <a-menu-item key="2" @click="cancelCheckALL">取消全选</a-menu-item>
+        </a-menu>
+        <a-button>
+          操作 <a-icon type="up" />
+        </a-button>
+      </a-dropdown>
+      <a-popconfirm  title="确定放弃编辑?" @confirm="close" okText="确定" cancelText="取消">
+        <a-button style="margin-right: .8rem">取消</a-button>
+      </a-popconfirm>
+      <a-button @click="handleSubmit(true)" type="primary">保存</a-button>
+    </div>
+  </a-drawer>
+</template>
+
+<script>
+  import {httpAction, getAction} from '@/api/manage'
+  import  JEllipsis  from '@/components/jeecg/JEllipsis'
+  import {initDictOptions} from '@/components/dict/JDictSelectUtil'
+
+  export default {
+    name: 'DeptRoleUserModal',
+    components: {
+      JEllipsis
+    },
+    data() {
+      return {
+        currentDeptId:"",
+        title: "部门角色分配",
+        visible: false,
+        model: {},
+        labelCol: {
+          xs: {span: 24},
+          sm: {span: 5},
+        },
+        wrapperCol: {
+          xs: {span: 24},
+          sm: {span: 16},
+        },
+        confirmLoading: false,
+        form: this.$form.createForm(this),
+        validatorRules: {},
+        url: {
+          add: "/sys/sysDepartRole/deptRoleUserAdd",
+          getDeptRoleList:"/sys/sysDepartRole/getDeptRoleList",
+          getDeptRoleByUserId:"/sys/sysDepartRole/getDeptRoleByUserId"
+        },
+        designNameOption: [],
+        userId: "",
+        newRoleId:"",
+        oldRoleId:"",
+        designNameValue:[],
+        desformList: [],
+      }
+    },
+    created() {
+
+    },
+    methods: {
+      add(record,departId) {
+        this.userId = record.id;
+        this.currentDeptId = departId;
+        this.loadDesformList();
+        this.edit({});
+      },
+      edit(record) {
+        this.form.resetFields();
+        this.model = Object.assign({}, record);
+        this.visible = true;
+        getAction(this.url.getDeptRoleByUserId,{userId:this.userId}).then((res) => {
+          if (res.success) {
+            var designName = [];
+            for (let value of res.result) {
+              designName.push(value.droleId)
+            }
+            this.oldRoleId=designName.join(",");
+            this.designNameValue = designName;
+            this.newRoleId = designName.join(",");
+          }
+        });
+      },
+      close() {
+        this.$emit('close');
+        this.visible = false;
+      },
+      handleSubmit() {
+        const that = this;
+        // 触发表单验证
+        that.confirmLoading = true;
+        let  httpurl = this.url.add;
+        let  method = 'post';
+        let formData = Object.assign(this.model, {});
+        //时间格式化
+        formData.userId = this.userId;
+        formData.newRoleId=this.newRoleId;
+        formData.oldRoleId=this.oldRoleId;
+        httpAction(httpurl, formData, method).then((res) => {
+          if (res.success) {
+            that.$message.success(res.message);
+            that.$emit('reload');
+            that.$emit('ok');
+          } else {
+            that.$message.warning(res.message);
+          }
+        }).finally(() => {
+          that.confirmLoading = false;
+          that.close();
+        })
+      },
+      handleCancel() {
+        this.designNameOption=[];
+        this.designNameValue=[];
+        this.close()
+      },
+      designNameChange(selectedValue) {
+        this.newRoleId=selectedValue.join(",");
+      },
+      checkALL(){
+        var designName = [];
+        for (let value of this.desformList) {
+          designName.push(
+            value.id
+          )
+        }
+        this.designNameValue = designName;
+        this.newRoleId=designName.join(",");
+      },
+      cancelCheckALL(){
+        this.designNameValue=[];
+        this.newRoleId="";
+      },
+      /** 加载desform */
+      loadDesformList() {
+        getAction(this.url.getDeptRoleList, { departId: this.currentDeptId }).then((res) => {
+          if (res.success) {
+            this.desformList = res.result
+            var designName = [];
+            for (let value of this.desformList) {
+              designName.push({
+                value: value.id,
+                text: value.roleName,
+              })
+            }
+            this.designNameOption = designName;
+          }
+        });
+      },
+    }
+
+  }
+</script>
+
+<style scoped>
+  .drawer-bootom-button {
+    position: absolute;
+    bottom: 0;
+    width: 100%;
+    border-top: 1px solid #e8e8e8;
+    padding: 10px 16px;
+    text-align: right;
+    left: 0;
+    background: #fff;
+    border-radius: 0 0 2px 2px;
+  }
+</style>

+ 55 - 15
ant-design-vue-jeecg/src/views/system/modules/DeptUserInfo.vue

@@ -7,7 +7,7 @@
         <a-row :gutter="10">
           <a-col :md="10" :sm="12">
             <a-form-item label="用户账号" style="margin-left:8px">
-              <a-input placeholder="请输入名称查询" v-model="queryParam.username"></a-input>
+              <a-input placeholder="请输入账号" v-model="queryParam.username"></a-input>
             </a-form-item>
           </a-col>
           <!--<a-col :md="8" :sm="8">-->
@@ -25,7 +25,7 @@
       </a-form>
     </div>
     <!-- 操作按钮区域 -->
-    <div class="table-operator" :md="24" :sm="24" style="margin: -46px 0px 10px 2px">
+    <div class="table-operator" :md="24" :sm="24" style="margin-top: -15px">
       <a-button @click="handleAdd" type="primary" icon="plus" style="margin-top: 16px">用户录入</a-button>
       <!--<a-button @click="handleEdit" type="primary" icon="edit" style="margin-top: 16px">用户编辑</a-button>-->
       <a-button @click="handleAddUserDepart" type="primary" icon="plus">添加已有用户</a-button>
@@ -34,7 +34,7 @@
         <a-menu slot="overlay">
           <a-menu-item key="1" @click="batchDel">
             <a-icon type="delete"/>
-            删除关系
+            取消关联
           </a-menu-item>
         </a-menu>
         <a-button style="margin-left: 8px"> 批量操作
@@ -80,10 +80,13 @@
               </a-menu-item>
 
               <a-menu-item>
-                <a-popconfirm title="确定要删除关系吗?" @confirm="() => handleDelete(record.id)">
-                  <a>删除关系</a>
+                <a-popconfirm title="确定取消与选中部门关联吗?" @confirm="() => handleDelete(record.id)">
+                  <a>取消关联</a>
                 </a-popconfirm>
               </a-menu-item>
+              <a-menu-item>
+                <a href="javascript:;" @click="handleDeptRole(record)">分配部门角色</a>
+              </a-menu-item>
             </a-menu>
           </a-dropdown>
         </span>
@@ -96,6 +99,7 @@
     <!-- 表单区域 -->
     <user-modal ref="modalForm" @ok="modalFormOk"></user-modal>
     <Select-User-Modal ref="selectUserModal" @selectFinished="selectOK"></Select-User-Modal>
+    <dept-role-user-modal ref="deptRoleUser"></dept-role-user-modal>
   </a-card>
 </template>
 
@@ -104,11 +108,13 @@
   import {getAction, postAction, deleteAction} from '@/api/manage'
   import SelectUserModal from './SelectUserModal'
   import UserModal from './UserModal'
+  import DeptRoleUserModal from './DeptRoleUserModal'
 
   export default {
     name: "DeptUserInfo",
     mixins: [JeecgListMixin],
     components: {
+      DeptRoleUserModal,
       SelectUserModal,
       UserModal
     },
@@ -127,6 +133,21 @@
             align: "center",
             dataIndex: 'realname'
           },
+          {
+            title: '性别',
+            align: "center",
+            dataIndex: 'sex_dictText'
+          },
+          {
+            title: '电话',
+            align: "center",
+            dataIndex: 'phone'
+          },
+          {
+            title: '部门',
+            align: "center",
+            dataIndex: 'orgCode'
+          },
           {
             title: '操作',
             dataIndex: 'action',
@@ -146,7 +167,12 @@
     },
 
     methods: {
-
+      searchReset() {
+        this.queryParam = {}
+        this.currentDeptId = '';
+        this.loadData(1);
+        this.$emit('clearSelectedDepartKeys')
+      },
       loadData(arg) {
         if (!this.url.list) {
           this.$message.error("请设置url.list属性!")
@@ -156,11 +182,11 @@
         if (arg === 1) {
           this.ipagination.current = 1;
         }
-        if (this.currentDeptId === '') return;
-        var params = this.getQueryParams();//查询条件
+        //if (this.currentDeptId === '') return;
+        let params = this.getQueryParams();//查询条件
         params.depId = this.currentDeptId;
         getAction(this.url.list, params).then((res) => {
-          if (res.success) {
+          if (res.success && res.result) {
             this.dataSource = res.result.records;
             this.ipagination.total = res.result.total;
           }
@@ -172,6 +198,11 @@
           this.$message.error("请设置url.deleteBatch属性!")
           return
         }
+        if (!this.currentDeptId) {
+          this.$message.error("未选中任何部门,无法取消部门与用户的关联!")
+          return
+        }
+
         if (this.selectedRowKeys.length <= 0) {
           this.$message.warning('请选择一条记录!');
           return;
@@ -183,12 +214,12 @@
           var that = this;
           console.log(this.currentDeptId);
           this.$confirm({
-            title: "确认删除",
-            content: "是否删除选中数据?",
+            title: "确认取消",
+            content: "是否取消用户与选中部门的关联?",
             onOk: function () {
               deleteAction(that.url.deleteBatch, {depId: that.currentDeptId, userIds: ids}).then((res) => {
                 if (res.success) {
-                  that.$message.success(res.message);
+                  that.$message.success("删除用户与选中部门关系成功!");
                   that.loadData();
                   that.onClearSelected();
                 } else {
@@ -204,10 +235,15 @@
           this.$message.error("请设置url.delete属性!")
           return
         }
+        if (!this.currentDeptId) {
+          this.$message.error("未选中任何部门,无法取消部门与用户的关联!")
+          return
+        }
+
         var that = this;
         deleteAction(that.url.delete, {depId: this.currentDeptId, userId: id}).then((res) => {
           if (res.success) {
-            that.$message.success(res.message);
+            that.$message.success("删除用户与选中部门关系成功!");
             if (this.selectedRowKeys.length>0){
                for(let i =0; i<this.selectedRowKeys.length;i++){
                    if (this.selectedRowKeys[i] == id){
@@ -232,14 +268,14 @@
         this.dataSource = [];
       },
       hasSelectDept() {
-        if (this.currentDeptId == null) {
+        if (this.currentDeptId == '') {
           this.$message.error("请选择一个部门!")
           return false;
         }
         return true;
       },
       handleAddUserDepart() {
-        if (this.currentDeptId == '') {
+        if (this.currentDeptId == '' ) {
           this.$message.error("请选择一个部门!")
         } else {
           this.$refs.selectUserModal.visible = true;
@@ -277,6 +313,10 @@
             this.$message.warning(res.message);
           }
         })
+      },
+      handleDeptRole(record){
+        this.$refs.deptRoleUser.add(record,this.currentDeptId);
+        this.$refs.deptRoleUser.title = "部门角色分配";
       }
     }
   }

+ 2 - 2
ant-design-vue-jeecg/src/views/system/modules/PasswordModal.vue

@@ -30,7 +30,7 @@
 </template>
 
 <script>
-  import {changPassword} from '@/api/api'
+  import {changePassword} from '@/api/api'
 
   export default {
     name: "PasswordModal",
@@ -96,7 +96,7 @@
           if (!err) {
             this.confirmLoading = true;
             let formData = Object.assign(this.model, values);
-            changPassword(formData).then((res)=>{
+            changePassword(formData).then((res)=>{
               if(res.success){
                 this.$message.success(res.message);
                 this.$emit('ok');

+ 7 - 7
ant-design-vue-jeecg/src/views/system/modules/SelectUserListModal.vue

@@ -13,13 +13,13 @@
 
           <a-col :span="6">
             <a-form-item label="账号">
-              <a-input placeholder="请输入账号查询" v-model="queryParam.username"></a-input>
+              <a-input placeholder="请输入账号" v-model="queryParam.username"></a-input>
             </a-form-item>
           </a-col>
 
           <a-col :span="6">
             <a-form-item label="性别">
-              <a-select v-model="queryParam.sex" placeholder="请选择性别查询">
+              <a-select v-model="queryParam.sex" placeholder="请选择性别">
                 <a-select-option value="">请选择性别查询</a-select-option>
                 <a-select-option value="1">男性</a-select-option>
                 <a-select-option value="2">女性</a-select-option>
@@ -31,20 +31,20 @@
           <template v-if="toggleSearchStatus">
             <a-col :span="6">
               <a-form-item label="邮箱">
-                <a-input placeholder="请输入邮箱查询" v-model="queryParam.email"></a-input>
+                <a-input placeholder="请输入邮箱" v-model="queryParam.email"></a-input>
               </a-form-item>
             </a-col>
 
             <a-col :span="6">
               <a-form-item label="手机号码">
-                <a-input placeholder="请输入手机号码查询" v-model="queryParam.phone"></a-input>
+                <a-input placeholder="请输入手机号码" v-model="queryParam.phone"></a-input>
               </a-form-item>
             </a-col>
 
             <a-col :span="6">
               <a-form-item label="状态">
-                <a-select v-model="queryParam.status" placeholder="请选择用户状态查询">
-                  <a-select-option value="">请选择用户状态</a-select-option>
+                <a-select v-model="queryParam.status" placeholder="请选择状态">
+                  <a-select-option value="">请选择状态</a-select-option>
                   <a-select-option value="1">正常</a-select-option>
                   <a-select-option value="2">解冻</a-select-option>
                 </a-select>
@@ -101,7 +101,7 @@
           fixed:'left',
           width:200
         },{
-          title: '真实姓名',
+          title: '用户名称',
           align:"center",
           dataIndex: 'realname',
         },{

+ 18 - 6
ant-design-vue-jeecg/src/views/system/modules/SelectUserModal.vue

@@ -12,12 +12,12 @@
 
       <!-- 查询区域 -->
       <div class="table-page-search-wrapper">
-        <a-form layout="inline">
+        <a-form layout="inline"  @keyup.enter.native="searchQuery">
           <a-row :gutter="24">
 
             <a-col :span="10">
-              <a-form-item label="姓名">
-                <a-input placeholder="请输入姓名" v-model="queryParam.username"></a-input>
+              <a-form-item label="用户账号">
+                <a-input placeholder="请输入用户账号" v-model="queryParam.username"></a-input>
               </a-form-item>
             </a-col>
             <a-col :span="8">
@@ -83,7 +83,7 @@
           {
             title: '用户账号',
             align: "center",
-            width: 113,
+            width: 100,
             dataIndex: 'username'
           },
           {
@@ -93,10 +93,22 @@
             dataIndex: 'realname'
           },
           {
-            title: '状态',
+            title: '性别',
+            align: "center",
+            width: 100,
+            dataIndex: 'sex_dictText'
+          },
+          {
+            title: '电话',
             align: "center",
             width: 100,
-            dataIndex: 'status'
+            dataIndex: 'phone'
+          },
+          {
+            title: '部门',
+            align: "center",
+            width: 150,
+            dataIndex: 'orgCode'
           }
         ],
         columns2: [

+ 37 - 38
ant-design-vue-jeecg/src/views/system/modules/SysAnnouncementModal.vue

@@ -12,16 +12,16 @@
 
     <a-spin :spinning="confirmLoading">
       <a-form :form="form">
-        <a-row class="form-row" :gutter="{ xs: 8, sm: 16, md: 24, lg: 32 }">
-          <a-col :lg="12">
+        <a-row style="width: 100%;">
+          <a-col :span="24/2">
             <a-form-item
               :labelCol="labelCol"
               :wrapperCol="wrapperCol"
               label="标题">
-              <a-input placeholder="请输入标题" v-decorator="['titile', validatorRules.title]" :readOnly="disableSubmit" style="width: 90%"/>
+              <a-input placeholder="请输入标题" v-decorator="['titile', validatorRules.title]" :readOnly="disableSubmit"/>
             </a-form-item>
           </a-col>
-          <a-col :lg="12">
+          <a-col :span="24/2">
             <a-form-item
               :labelCol="labelCol"
               :wrapperCol="wrapperCol"
@@ -30,76 +30,68 @@
                 v-decorator="[ 'msgCategory', validatorRules.msgCategory]"
                 placeholder="请选择消息类型"
                 :disabled="disableSubmit"
-                :getPopupContainer = "(target) => target.parentNode"
-                style="width: 80%" >
+                :getPopupContainer = "(target) => target.parentNode">
                 <a-select-option value="1">通知公告</a-select-option>
                 <a-select-option value="2">系统消息</a-select-option>
               </a-select>
             </a-form-item>
           </a-col>
         </a-row>
-
-        <a-row class="form-row" :gutter="24">
-          <a-col :lg="12">
+        <a-row style="width: 100%;">
+          <a-col :span="24/2">
             <a-form-item
               :labelCol="labelCol"
               :wrapperCol="wrapperCol"
-              label="开始时间:"
-              style="margin-left: 27px">
-              <j-date  v-decorator="[ 'startTime', validatorRules.startTime]" placeholder="请选择开始时间" showTime dateFormat="YYYY-MM-DD HH:mm:ss" ></j-date>
+              label="开始时间:">
+              <j-date style="width: 100%" :getCalendarContainer="node => node.parentNode" v-decorator="[ 'startTime', validatorRules.startTime]" placeholder="请选择开始时间" showTime dateFormat="YYYY-MM-DD HH:mm:ss" ></j-date>
             </a-form-item>
           </a-col>
-          <a-col :lg="12">
+          <a-col :span="24/2">
             <a-form-item
               :labelCol="labelCol"
               :wrapperCol="wrapperCol"
               label="结束时间"
               class="endTime">
-              <j-date  v-decorator="[ 'endTime', validatorRules.endTime]" placeholder="请选择结束时间" showTime dateFormat="YYYY-MM-DD HH:mm:ss"></j-date>
+              <j-date style="width: 100%" :getCalendarContainer="node => node.parentNode" v-decorator="[ 'endTime', validatorRules.endTime]" placeholder="请选择结束时间" showTime dateFormat="YYYY-MM-DD HH:mm:ss"></j-date>
             </a-form-item>
           </a-col>
         </a-row>
-
-        <a-row class="form-row" :gutter="32">
-          <a-col :lg="9">
+        <a-row style="width: 100%;">
+          <a-col :span="24/2">
             <a-form-item
               :labelCol="labelCol"
               :wrapperCol="wrapperCol"
-              label="优先级"
-              style="margin-left: 27px">
+              label="优先级">
               <a-select
                 v-decorator="[ 'priority', {}]"
                 placeholder="请选择优先级"
                 :disabled="disableSubmit"
-                :getPopupContainer = "(target) => target.parentNode"
-                style="margin-left: 5px;width: 135%">
+                :getPopupContainer = "(target) => target.parentNode">
                 <a-select-option value="L">低</a-select-option>
                 <a-select-option value="M">中</a-select-option>
                 <a-select-option value="H">高</a-select-option>
               </a-select>
             </a-form-item>
           </a-col>
-          <a-col :lg="15" push="3">
+          <a-col :span="24/2">
             <a-form-item
               :labelCol="labelCol"
               :wrapperCol="wrapperCol"
-              label="通告对象类型"
-              style="margin-left: -14px">
+              label="通告类型">
               <a-select
                 v-decorator="[ 'msgType', validatorRules.msgType]"
-                placeholder="请选择通告对象类型"
+                placeholder="请选择通告类型"
                 :disabled="disableSubmit"
                 @change="chooseMsgType"
-                :getPopupContainer = "(target) => target.parentNode"
-                style="width: 200px;margin-left: 5px">
+                :getPopupContainer = "(target) => target.parentNode">
                 <a-select-option value="USER">指定用户</a-select-option>
                 <a-select-option value="ALL">全体用户</a-select-option>
               </a-select>
             </a-form-item>
           </a-col>
         </a-row>
-        <a-row>
-          <a-col :lg="24" pull="2">
+        <a-row style="width: 100%;">
+          <a-col :span="24/2">
             <a-form-item
               :labelCol="labelCol"
               :wrapperCol="wrapperCol"
@@ -110,20 +102,19 @@
                 placeholder="请选择用户"
                 v-model="selectedUser"
                 @dropdownVisibleChange="selectUserIds"
-                style="width: 119%"
               >
               </a-select>
             </a-form-item>
           </a-col>
         </a-row>
-        <a-row>
-          <a-col :lg="24" pull="3">
+        <a-row style="width: 100%;">
+          <a-col :span="24">
             <a-form-item
-              :labelCol="labelCol"
-              :wrapperCol="wrapperCol"
+              :labelCol="labelColX1"
+              :wrapperCol="wrapperColX1"
               label="内容"
-              style="margin-left: 5px">
-              <j-editor  style="width: 130%" v-decorator="[ 'msgContent', {} ]" triggerChange></j-editor>
+              class="j-field-content">
+              <j-editor v-decorator="[ 'msgContent', {} ]" triggerChange></j-editor>
             </a-form-item>
           </a-col>
         </a-row>
@@ -153,11 +144,19 @@
         model: {},
         labelCol: {
           xs: { span: 24 },
-          sm: { span: 5 },
+          sm: { span: 6 },
         },
         wrapperCol: {
           xs: { span: 24 },
-          sm: { span: 16 },
+          sm: { span: 18 },
+        },
+        labelColX1: {
+          xs: { span: 24 },
+          sm: { span: 3 },
+        },
+        wrapperColX1: {
+          xs: { span: 24 },
+          sm: { span: 21 },
         },
 
         confirmLoading: false,

+ 379 - 0
ant-design-vue-jeecg/src/views/system/modules/SysCheckRuleModal.vue

@@ -0,0 +1,379 @@
+<template>
+  <a-modal
+    :title="title"
+    :width="1000"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="关闭">
+
+    <a-spin :spinning="confirmLoading">
+      <a-form :form="form">
+
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="规则名称">
+          <a-input placeholder="请输入规则名称" v-decorator="['ruleName', validatorRules.ruleName]"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="规则Code">
+          <a-input placeholder="请输入规则Code" v-decorator="['ruleCode', validatorRules.ruleCode]"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="规则描述">
+          <a-textarea placeholder="请输入规则描述" v-decorator="['ruleDescription', {}]"/>
+        </a-form-item>
+
+      </a-form>
+      <!-- 规则设计 -->
+      <a-tabs v-model="tabs.activeKey">
+        <a-tab-pane tab="局部规则" :key="tabs.design.key" forceRender>
+          <a-alert type="info" showIcon message="局部规则按照你输入的位数有序的校验。"/>
+          <j-editable-table
+            ref="designTable"
+            dragSort
+            rowNumber
+            :maxHeight="240"
+            :columns="tabs.design.columns"
+            :dataSource="tabs.design.dataSource"
+            style="margin-top: 8px;"
+          >
+
+            <template #action="props">
+              <my-action-button :rowEvent="props"/>
+            </template>
+
+          </j-editable-table>
+        </a-tab-pane>
+        <a-tab-pane tab="全局规则" :key="tabs.global.key" forceRender>
+          <j-editable-table
+            ref="globalTable"
+            dragSort
+            rowNumber
+            actionButton
+            :maxHeight="240"
+            :columns="tabs.global.columns"
+            :dataSource="tabs.global.dataSource"
+          >
+
+            <template #actionButtonAfter>
+              <a-alert type="info" showIcon message="全局规则可校验用户输入的所有字符;全局规则的优先级比局部规则的要高。" style="margin-bottom: 8px;"/>
+            </template>
+
+            <template #action="props">
+              <my-action-button :rowEvent="props" allowEmpty/>
+            </template>
+
+          </j-editable-table>
+        </a-tab-pane>
+      </a-tabs>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+  import pick from 'lodash.pick'
+  import { httpAction } from '@/api/manage'
+  import { validateDuplicateValue, alwaysResolve, failedSymbol } from '@/utils/util'
+  import { FormTypes } from '@/utils/JEditableTableUtil'
+  import JEditableTable from '@comp/jeecg/JEditableTable'
+
+  export default {
+    name: 'SysCheckRuleModal',
+    components: {
+      JEditableTable,
+      'my-action-button': {
+        props: { rowEvent: Object, allowEmpty: Boolean },
+        methods: {
+          confirmIsShow() {
+            const { index, allValues: { inputValues } } = this.rowEvent
+            let value = inputValues[index]
+            return value.digits || value.pattern
+          },
+          handleLineAdd() {
+            const { target } = this.rowEvent
+            target.add()
+          },
+          handleLineDelete() {
+            const { rowId, target } = this.rowEvent
+            target.removeRows(rowId)
+          },
+          renderDeleteButton() {
+            if (this.allowEmpty || this.rowEvent.index > 0) {
+              if (this.confirmIsShow()) {
+                return (
+                  <a-popconfirm title="确定要删除吗?" onConfirm={this.handleLineDelete}>
+                    <a-button icon="minus"/>
+                  </a-popconfirm>
+                )
+              } else {
+                return (
+                  <a-button icon="minus" onClick={this.handleLineDelete}/>
+                )
+              }
+            }
+            return ''
+          },
+        },
+        render() {
+          return (
+            <div>
+              <a-button onClick={this.handleLineAdd} icon="plus"/>
+              &nbsp;
+              {this.renderDeleteButton()}
+            </div>
+          )
+        }
+      }
+    },
+    data() {
+      return {
+        title: '操作',
+        visible: false,
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 5 },
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 16 },
+        },
+        confirmLoading: false,
+        form: this.$form.createForm(this),
+        validatorRules: {
+          ruleName: { rules: [{ required: true, message: '请输入规则名称!' },] },
+          ruleCode: {
+            rules: [
+              { required: true, message: '请输入规则Code!' },
+              { validator: (rule, value, callback) => validateDuplicateValue('sys_check_rule', 'rule_code', value, this.model.id, callback) }
+            ]
+          },
+        },
+        tabs: {
+          activeKey: 'design',
+          global: {
+            key: 'global',
+            columns: [
+              {
+                title: '优先级',
+                key: 'priority',
+                width: '15%',
+                type: FormTypes.select,
+                defaultValue: '1',
+                options: [
+                  { title: '优先运行', value: '1' },
+                  { title: '最后运行', value: '0' },
+                ],
+                validateRules: []
+              },
+              {
+                title: '规则(正则表达式)',
+                key: 'pattern',
+                width: '50%',
+                type: FormTypes.input,
+                validateRules: [
+                  { required: true, message: '规则不能为空' },
+                  { handler: this.validatePatternHandler },
+                ]
+              },
+              {
+                title: '提示文本',
+                key: 'message',
+                width: '20%',
+                type: FormTypes.input,
+                validateRules: [
+                  { required: true, message: '${title}不能为空' },
+                ]
+              },
+              {
+                title: '操作',
+                key: 'action',
+                width: '15%',
+                slotName: 'action',
+                type: FormTypes.slot
+              }
+            ],
+            dataSource: [],
+          },
+          design: {
+            key: 'design',
+            columns: [
+              {
+                title: '位数',
+                key: 'digits',
+                width: '15%',
+                type: FormTypes.inputNumber,
+                validateRules: [
+                  { required: true, message: '${title}不能为空' },
+                  { pattern: /^[1-9]\d*$/, message: '请输入零以上的正整数' },
+                ]
+              },
+              {
+                title: '规则(正则表达式)',
+                key: 'pattern',
+                width: '50%',
+                type: FormTypes.input,
+                validateRules: [
+                  { required: true, message: '规则不能为空' },
+                  { handler: this.validatePatternHandler }
+                ]
+              },
+              {
+                title: '提示文本',
+                key: 'message',
+                width: '20%',
+                type: FormTypes.input,
+                validateRules: [
+                  { required: true, message: '${title}不能为空' },
+                ]
+              },
+              {
+                title: '操作',
+                key: 'action',
+                width: '15%',
+                slotName: 'action',
+                type: FormTypes.slot
+              },
+            ],
+            dataSource: [],
+          }
+        },
+        url: {
+          add: '/sys/checkRule/add',
+          edit: '/sys/checkRule/edit',
+        },
+      }
+    },
+    created() {
+    },
+    methods: {
+
+      validatePatternHandler(type, value, row, column, callback, target) {
+        if (type === 'blur' || type === 'getValues') {
+          try {
+            new RegExp(value)
+            callback(true)
+          } catch (e) {
+            callback(false, '请输入正确的正则表达式')
+          }
+        } else {
+          callback(true) // 不填写或者填写 null 代表不进行任何操作
+        }
+      },
+
+      add() {
+        this.edit({})
+      },
+      edit(record) {
+        this.form.resetFields()
+        this.tabs.activeKey = this.tabs.design.key
+        this.tabs.global.dataSource = []
+        this.tabs.design.dataSource = [{ digits: '', pattern: '', message: '' }]
+        this.model = Object.assign({}, record)
+        this.visible = true
+        this.$nextTick(() => {
+          this.form.setFieldsValue(pick(this.model, 'ruleName', 'ruleCode', 'ruleDescription'))
+          // 子表数据
+          let ruleJson = this.model.ruleJson
+          if (ruleJson) {
+            let ruleList = JSON.parse(ruleJson)
+            // 筛选出全局规则和局部规则
+            let global = [], design = [], priority = '1'
+            ruleList.forEach(rule => {
+              if (rule.digits === '*') {
+                global.push(Object.assign(rule, { priority }))
+              } else {
+                priority = '0'
+                design.push(rule)
+              }
+            })
+            this.tabs.global.dataSource = global
+            this.tabs.design.dataSource = design
+          }
+        })
+      },
+      close() {
+        this.$emit('close')
+        this.visible = false
+      },
+      handleOk() {
+        Promise.all([
+          // 主表单校验
+          alwaysResolve(new Promise((resolve, reject) => {
+            this.form.validateFields((error, values) => error ? reject(error) : resolve(values))
+          })),
+          // 局部规则子表校验
+          alwaysResolve(this.$refs.designTable.getValuesPromise),
+          // 全局规则子表校验
+          alwaysResolve(this.$refs.globalTable.getValuesPromise),
+        ]).then(results => {
+          let [mainResult, designResult, globalResult] = results
+
+          if (mainResult.type === failedSymbol) {
+            return Promise.reject('主表校验未通过')
+          } else if (designResult.type === failedSymbol) {
+            this.tabs.activeKey = this.tabs.design.key
+            return Promise.reject('局部规则子表校验未通过')
+          } else if (globalResult.type === failedSymbol) {
+            this.tabs.activeKey = this.tabs.global.key
+            return Promise.reject('全局规则子表校验未通过')
+          } else {
+            // 所有校验已通过,这一步是整合数据
+            let mainValues = mainResult.data, globalValues = globalResult.data, designValues = designResult.data
+
+            // 整合两个子表的数据
+            let firstGlobal = [], afterGlobal = []
+            globalValues.forEach(v => {
+              v.digits = '*'
+              if (v.priority === '1') {
+                firstGlobal.push(v)
+              } else {
+                afterGlobal.push(v)
+              }
+            })
+            let concatValues = firstGlobal.concat(designValues).concat(afterGlobal)
+            let subValues = concatValues.map(i => pick(i, 'digits', 'pattern', 'message'))
+
+            // 生成 formData,用于传入后台
+            let ruleJson = JSON.stringify(subValues)
+            let formData = Object.assign(this.model, mainValues, { ruleJson })
+
+            // 判断请求方式和请求地址,并发送请求
+            let method = 'post', httpUrl = this.url.add
+            if (this.model.id) {
+              method = 'put'
+              httpUrl = this.url.edit
+            }
+            this.confirmLoading = true
+            return httpAction(httpUrl, formData, method)
+          }
+        }).then((res) => {
+          if (res.success) {
+            this.$message.success(res.message)
+            this.$emit('ok')
+            this.close()
+          } else {
+            this.$message.warning(res.message)
+          }
+        }).catch(e => {
+          console.error(e)
+        }).finally(() => {
+          this.confirmLoading = false
+        })
+      },
+      handleCancel() {
+        this.close()
+      },
+
+    }
+  }
+</script>
+
+<style lang="scss" scoped></style>

+ 58 - 0
ant-design-vue-jeecg/src/views/system/modules/SysCheckRuleTestModal.vue

@@ -0,0 +1,58 @@
+<template>
+  <a-modal
+    title="功能测试"
+    :width="800"
+    :visible="visible"
+    @ok="visible=false"
+    @cancel="visible=false"
+  >
+    <a-form :form="form">
+      <a-form-item label="功能测试">
+        <a-input placeholder="请输入" v-decorator="['test', validatorRules.test]" @change="e=>testValue=e.target.value"/>
+      </a-form-item>
+    </a-form>
+    <a-row type="flex" :gutter="8">
+      <a-col v-for="(str,index) of testValue">
+        <a-row>
+          <a-col>
+            <a-input :value="str" style="text-align: center;width: 40px;"/>
+          </a-col>
+          <a-col style="text-align: center;">{{index+1}}</a-col>
+        </a-row>
+      </a-col>
+    </a-row>
+
+  </a-modal>
+</template>
+
+<script>
+  import { validateCheckRule } from '@/utils/util'
+
+  export default {
+    name: 'SysCheckRuleModal',
+    data() {
+      return {
+        title: '操作',
+        visible: false,
+        ruleCode: '',
+        testValue: '',
+        form: this.$form.createForm(this),
+        validatorRules: {
+          test: {
+            rules: [{ validator: (rule, value, callback) => validateCheckRule(this.ruleCode, value, callback) }]
+          }
+        },
+      }
+    },
+    methods: {
+      open(ruleCode) {
+        this.ruleCode = ruleCode
+        this.form.resetFields()
+        this.testValue = ''
+        this.visible = true
+      },
+    }
+  }
+</script>
+
+<style lang="scss" scoped></style>

+ 227 - 0
ant-design-vue-jeecg/src/views/system/modules/SysDataSourceModal.vue

@@ -0,0 +1,227 @@
+<template>
+  <a-modal
+    :title="title"
+    :width="800"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="关闭">
+
+    <a-spin :spinning="confirmLoading">
+      <a-form :form="form">
+
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="数据源名称">
+          <a-input placeholder="请输入数据源名称" v-decorator="['name', validatorRules.name]"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="数据源编码">
+          <a-input placeholder="请输入数据源编码" :disabled="!!model.id" v-decorator="['code', validatorRules.code]"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="数据库类型">
+          <j-dict-select-tag placeholder="请选择数据库类型" dict-code="database_type" triggerChange v-decorator="['dbType', validatorRules.dbType]" @change="handleDbTypeChange"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="驱动类">
+          <a-input placeholder="请输入驱动类" v-decorator="['dbDriver', validatorRules.dbDriver]"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="数据源地址">
+          <a-input placeholder="请输入数据源地址" v-decorator="['dbUrl', validatorRules.dbUrl]"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="数据库名称">
+          <a-input placeholder="请输入数据库名称" v-decorator="['dbName', validatorRules.dbName]"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="用户名">
+          <a-input placeholder="请输入用户名" v-decorator="['dbUsername', validatorRules.dbUsername]"/>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="密码">
+          <a-row :gutter="8">
+            <a-col :span="21">
+              <a-input-password placeholder="请输入密码" v-decorator="['dbPassword', validatorRules.dbPassword]"/>
+            </a-col>
+            <a-col :span="3">
+              <a-button type="primary" size="small" style="width: 100%" @click="handleTest">测试</a-button>
+            </a-col>
+          </a-row>
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="备注">
+          <a-textarea placeholder="请输入备注" v-decorator="['remark', {}]"/>
+        </a-form-item>
+      </a-form>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+  import pick from 'lodash.pick'
+  import { httpAction, postAction } from '@/api/manage'
+  import { validateDuplicateValue } from '@/utils/util'
+
+  export default {
+    name: 'SysDataSourceModal',
+    components: {},
+    data() {
+      return {
+        title: '操作',
+        visible: false,
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 5 },
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 16 },
+        },
+
+        confirmLoading: false,
+        form: this.$form.createForm(this),
+        validatorRules: {
+          code: {
+            validateFirst: true,
+            rules: [
+              { required: true, message: '请输入数据源编码!' },
+              {
+                validator: (rule, value, callback) => {
+                  let pattern = /^[a-z|A-Z][a-z|A-Z\d_-]{0,}$/
+                  if (!pattern.test(value)) {
+                    callback('编码必须以字母开头,可包含数字、下划线、横杠')
+                  } else {
+                    validateDuplicateValue('sys_data_source', 'code', value, this.model.id, callback)
+                  }
+                }
+              }
+            ]
+          },
+          name: { rules: [{ required: true, message: '请输入数据源名称!' }] },
+          dbType: { rules: [{ required: true, message: '请选择数据库类型!' }] },
+          dbDriver: { rules: [{ required: true, message: '请输入驱动类!' }] },
+          dbUrl: { rules: [{ required: true, message: '请输入数据源地址!' }] },
+          dbName: { rules: [{ required: true, message: '请输入数据库名称!' }] },
+          dbUsername: { rules: [{ required: true, message: '请输入用户名!' }] },
+          dbPassword: { rules: [{ required: true, message: '请输入密码!' }] }
+        },
+        url: {
+          add: '/sys/dataSource/add',
+          edit: '/sys/dataSource/edit',
+        },
+        dbDriverMap: {
+          // MySQL 数据库
+          '1': { dbDriver: 'com.mysql.jdbc.Driver' },
+          // Oracle
+          '2': { dbDriver: 'oracle.jdbc.OracleDriver' },
+          // SQLServer 数据库
+          '3': { dbDriver: 'com.microsoft.sqlserver.jdbc.SQLServerDriver' },
+        }
+      }
+    },
+    created() {
+    },
+    methods: {
+      add() {
+        this.edit({})
+      },
+      edit(record) {
+        this.form.resetFields()
+        this.model = Object.assign({}, record)
+        this.visible = true
+        this.$nextTick(() => {
+          this.form.setFieldsValue(pick(this.model, 'code', 'name', 'remark', 'dbType', 'dbDriver', 'dbUrl', 'dbName', 'dbUsername', 'dbPassword'))
+        })
+      },
+      close() {
+        this.$emit('close')
+        this.visible = false
+      },
+      handleOk() {
+        // 触发表单验证
+        this.form.validateFields((err, values) => {
+          if (!err) {
+            this.confirmLoading = true
+            let formData = Object.assign(this.model, values)
+            let httpUrl = this.url.add, method = 'post'
+            if (this.model.id) {
+              httpUrl = this.url.edit
+              method = 'put'
+              // 由于编码的特殊性,所以不能更改
+              formData['code'] = undefined
+            }
+            httpAction(httpUrl, formData, method).then((res) => {
+              if (res.success) {
+                this.$message.success(res.message)
+                this.$emit('ok')
+                this.close()
+              } else {
+                this.$message.warning(res.message)
+              }
+            }).finally(() => {
+              this.confirmLoading = false
+            })
+          }
+        })
+      },
+      handleCancel() {
+        this.close()
+      },
+      // 测试数据源配置是否可以正常连接
+      handleTest() {
+        let keys = ['dbType', 'dbDriver', 'dbUrl', 'dbName', 'dbUsername', 'dbPassword']
+        // 获取以上字段的值,并清除校验状态
+        let fieldsValues = this.form.getFieldsValue(keys)
+        let setFields = {}
+        keys.forEach(key => setFields[key] = { value: fieldsValues[key], errors: null })
+        // 清除校验状态,目的是可以让错误文字闪烁
+        this.form.setFields(setFields)
+        // 重新校验
+        this.$nextTick(() => {
+          this.form.validateFields(keys, (errors, values) => {
+            if (!errors) {
+              let loading = this.$message.loading('连接中……', 0)
+              postAction('/online/cgreport/api/testConnection', fieldsValues).then(res => {
+                if (res.success) {
+                  this.$message.success('连接成功')
+                } else throw new Error(res.message)
+              }).catch(error => {
+                this.$warning({ title: '连接失败', content: error.message || error })
+              }).finally(() => loading())
+            }
+          })
+        })
+      },
+      // 数据库类型更改时,联动更改数据库驱动
+      handleDbTypeChange(val) {
+        let dbDriver = this.dbDriverMap[val]
+        if (dbDriver) {
+          this.form.setFieldsValue(dbDriver)
+        }
+      },
+    }
+  }
+</script>
+
+<style lang="scss" scoped></style>

+ 162 - 0
ant-design-vue-jeecg/src/views/system/modules/SysDepartRoleModal.vue

@@ -0,0 +1,162 @@
+<template>
+  <a-modal
+    :title="title"
+    :width="800"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="关闭">
+    
+    <a-spin :spinning="confirmLoading">
+      <a-form :form="form">
+      
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="部门角色名称">
+          <a-input placeholder="请输入部门角色名称" v-decorator="['roleName', validatorRules.roleName]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="部门角色编码">
+          <a-input placeholder="请输入部门角色编码" v-decorator="['roleCode', validatorRules.roleCode]" />
+        </a-form-item>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="描述">
+          <a-input placeholder="请输入描述" v-decorator="['description', validatorRules.description]" />
+        </a-form-item>
+		
+      </a-form>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+  import { httpAction } from '@/api/manage'
+  import pick from 'lodash.pick'
+  import {duplicateCheck } from '@/api/api'
+
+  export default {
+    name: "SysDepartRoleModal",
+    data () {
+      return {
+        title:"操作",
+        visible: false,
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 5 },
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 16 },
+        },
+
+        confirmLoading: false,
+        form: this.$form.createForm(this),
+        validatorRules:{
+          roleName:{
+            rules: [
+              { required: true, message: '请输入部门角色名称!' },
+              { min: 2, max: 30, message: '长度在 2 到 30 个字符', trigger: 'blur' }
+            ]},
+          roleCode:{
+            rules: [
+              { required: true, message: '请输入部门角色编码!'},
+              { min: 0, max: 64, message: '长度不超过 64 个字符', trigger: 'blur' },
+              { validator: this.validateRoleCode}
+            ]},
+          description:{
+            rules: [
+              { min: 0, max: 126, message: '长度不超过 126 个字符', trigger: 'blur' }
+            ]}
+        },
+        url: {
+          add: "/sys/sysDepartRole/add",
+          edit: "/sys/sysDepartRole/edit",
+        },
+      }
+    },
+    created () {
+    },
+    methods: {
+      add (departId) {
+        this.edit({},departId);
+      },
+      edit (record,departId) {
+        this.departId = departId;
+        this.form.resetFields();
+        this.model = Object.assign({}, record);
+        this.visible = true;
+        this.$nextTick(() => {
+          this.form.setFieldsValue(pick(this.model,'roleName','roleCode','description'))
+        });
+      },
+      close () {
+        this.$emit('close');
+        this.visible = false;
+      },
+      handleOk () {
+        const that = this;
+        // 触发表单验证
+        this.form.validateFields((err, values) => {
+          if (!err) {
+            that.confirmLoading = true;
+            let httpurl = '';
+            let method = '';
+            if(!this.model.id){
+              httpurl+=this.url.add;
+              method = 'post';
+            }else{
+              httpurl+=this.url.edit;
+               method = 'put';
+            }
+            let formData = Object.assign(this.model, values);
+            formData.departId = this.departId;
+            httpAction(httpurl,formData,method).then((res)=>{
+              if(res.success){
+                that.$message.success(res.message);
+                that.$emit('ok');
+              }else{
+                that.$message.warning(res.message);
+              }
+            }).finally(() => {
+              that.confirmLoading = false;
+              that.close();
+            })
+          }
+        })
+      },
+      handleCancel () {
+        this.close()
+      },
+      validateRoleCode(rule, value, callback){
+        if(/[\u4E00-\u9FA5]/g.test(value)){
+          callback("部门角色编码不可输入汉字!");
+        }else{
+          var params = {
+            tableName: "sys_depart_role",
+            fieldName: "role_code",
+            fieldVal: value,
+            dataId: this.model.id,
+          };
+          duplicateCheck(params).then((res)=>{
+            if(res.success){
+              callback();
+            }else{
+              callback(res.message);
+            }
+          });
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+
+</style>

+ 95 - 27
ant-design-vue-jeecg/src/views/system/modules/UserModal.vue

@@ -36,8 +36,8 @@
           </a-form-item>
         </template>
 
-        <a-form-item label="用户名" :labelCol="labelCol" :wrapperCol="wrapperCol" >
-          <a-input placeholder="请输入用户名" v-decorator="[ 'realname', validatorRules.realname]" />
+        <a-form-item label="用户名" :labelCol="labelCol" :wrapperCol="wrapperCol" >
+          <a-input placeholder="请输入用户名" v-decorator="[ 'realname', validatorRules.realname]" />
         </a-form-item>
 
         <a-form-item label="工号" :labelCol="labelCol" :wrapperCol="wrapperCol">
@@ -71,23 +71,33 @@
             <a-button slot="enterButton" icon="search">选择</a-button>
           </a-input-search>
         </a-form-item>
-        <a-form-item label="头像" :labelCol="labelCol" :wrapperCol="wrapperCol">
-          <a-upload
-            listType="picture-card"
-            class="avatar-uploader"
-            :showUploadList="false"
-            :action="uploadAction"
-            :data="{'isup':1}"
-            :headers="headers"
-            :beforeUpload="beforeUpload"
-            @change="handleChange"
+       <!-- update--begin--autor:wangshuai-----date:20200108------for:新增身份和负责部门------ -->
+        <a-form-item label="身份" :labelCol="labelCol" :wrapperCol="wrapperCol">
+          <a-radio-group
+            v-model="identity"
+            @change="identityChange">
+            <a-radio value="1">普通用户</a-radio>
+            <a-radio value="2">上级</a-radio>
+          </a-radio-group>
+        </a-form-item>
+        <a-form-item label="负责部门" :labelCol="labelCol" :wrapperCol="wrapperCol"  v-if="departIdShow==true">
+          <a-select
+            mode="multiple"
+            style="width: 100%"
+            placeholder="请选择负责部门"
+            v-model="departIds"
+            optionFilterProp = "children"
+            :getPopupContainer = "(target) => target.parentNode"
+            :dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
           >
-            <img v-if="picUrl" :src="getAvatarView()" alt="头像" style="height:104px;max-width:300px"/>
-            <div v-else>
-              <a-icon :type="uploadLoading ? 'loading' : 'plus'" />
-              <div class="ant-upload-text">上传</div>
-            </div>
-          </a-upload>
+            <a-select-option v-for="item in resultDepartOptions" :key="item.key" :value="item.key"
+            >{{item.title}}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <!-- update--end--autor:wangshuai-----date:20200108------for:新增身份和负责部门------ -->
+        <a-form-item label="头像" :labelCol="labelCol" :wrapperCol="wrapperCol">
+          <j-image-upload class="avatar-uploader" text="上传" v-model="fileList" ></j-image-upload>
         </a-form-item>
 
         <a-form-item label="生日" :labelCol="labelCol" :wrapperCol="wrapperCol">
@@ -145,10 +155,12 @@
   import {addUser,editUser,queryUserRole,queryall } from '@/api/api'
   import { disabledAuthFilter } from "@/utils/authFilter"
   import {duplicateCheck } from '@/api/api'
+  import JImageUpload from '../../../components/jeecg/JImageUpload'
 
   export default {
     name: "UserModal",
     components: {
+      JImageUpload,
       departWindow,
       JSelectPosition
     },
@@ -164,6 +176,7 @@
         checkedDepartKeys:[],
         checkedDepartNames:[], // 保存部门的名称 =>title
         checkedDepartNameString:"", // 保存部门的名称 =>title
+        resultDepartOptions:[],
         userId:"", //保存用户id
         disableSubmit:false,
         userDepartModel:{userId:'',departIdList:[]}, // 保存SysUserDepart的用户部门中间表数据需要的对象
@@ -213,6 +226,8 @@
             ]
           }
         },
+        departIdShow:false,
+        departIds:[], //负责部门id
         title:"操作",
         visible: false,
         model: {},
@@ -233,11 +248,13 @@
         picUrl: "",
         url: {
           fileUpload: window._CONFIG['domianURL']+"/sys/common/upload",
-          imgerver: window._CONFIG['domianURL']+"/sys/common/view",
+          imgerver: window._CONFIG['staticDomainURL'],
           userWithDepart: "/sys/user/userDepartList", // 引入为指定用户查看部门信息需要的url
           userId:"/sys/user/generateUserId", // 引入生成添加用户情况下的url
           syncUserByUserName:"/process/extActProcess/doSyncUserByUserName",//同步用户到工作流
         },
+        identity:"1",
+        fileList:[],
       }
     },
     created () {
@@ -287,6 +304,9 @@
           this.checkedDepartNames=[];
           this.checkedDepartNameString = "";
           this.userId=""
+          this.resultDepartOptions=[];
+          this.departId=[];
+          this.departIdShow=false;
       },
       add () {
         this.picUrl = "";
@@ -301,7 +321,9 @@
         that.form.resetFields();
         if(record.hasOwnProperty("id")){
           that.loadUserRoles(record.id);
-          this.picUrl = "Has no pic url yet";
+          setTimeout(() => {
+            this.fileList = record.avatar;
+          }, 5)
         }
         that.userId = record.id;
         that.visible = true;
@@ -309,6 +331,14 @@
         that.$nextTick(() => {
           that.form.setFieldsValue(pick(this.model,'username','sex','realname','email','phone','activitiSync','workNo','telephone','post'))
         });
+        //身份为上级显示负责部门,否则不显示
+        if(this.model.identity=="2"){
+            this.identity="2";
+            this.departIdShow=true;
+        }else{
+            this.identity="1";
+            this.departIdShow=false;
+        }
         // 调用查询用户对应的部门信息的方法
         that.checkedDepartKeys = [];
         that.loadCheckedDeparts();
@@ -320,10 +350,25 @@
         getAction(that.url.userWithDepart,{userId:that.userId}).then((res)=>{
           that.checkedDepartNames = [];
           if(res.success){
+            var depart=[];
+            var departId=[];
             for (let i = 0; i < res.result.length; i++) {
               that.checkedDepartNames.push(res.result[i].title);
               this.checkedDepartNameString = this.checkedDepartNames.join(",");
               that.checkedDepartKeys.push(res.result[i].key);
+              //新增负责部门选择下拉框
+              depart.push({
+                  key:res.result[i].key,
+                  title:res.result[i].title
+              })
+              departId.push(res.result[i].key)
+            }
+            that.resultDepartOptions=depart;
+            //判断部门id是否存在,不存在择直接默认当前所在部门
+            if(this.model.departIds){
+                this.departIds=this.model.departIds.split(",");
+            }else{
+                this.departIds=departId;
             }
             that.userDepartModel.departIdList = that.checkedDepartKeys
           }else{
@@ -341,6 +386,11 @@
         this.checkedDepartNameString='';
         this.checkedDepartKeys = [];
         this.selectedDepartKeys = [];
+        this.resultDepartOptions=[];
+        this.departIds=[];
+        this.departIdShow=false;
+        this.identity="1";
+        this.fileList=[];
       },
       moment,
       handleSubmit () {
@@ -350,17 +400,22 @@
         this.form.validateFields((err, values) => {
           if (!err) {
             that.confirmLoading = true;
-            let avatar = that.model.avatar;
             if(!values.birthday){
               values.birthday = '';
             }else{
               values.birthday = values.birthday.format(this.dateFormat);
             }
             let formData = Object.assign(this.model, values);
-            formData.avatar = avatar;
+            formData.avatar = that.fileList;
             formData.selectedroles = this.selectedRole.length>0?this.selectedRole.join(","):'';
             formData.selecteddeparts = this.userDepartModel.departIdList.length>0?this.userDepartModel.departIdList.join(","):'';
-
+            formData.identity=this.identity;
+            //如果是上级择传入departIds,否则为空
+            if(this.identity==="2"){
+              formData.departIds=this.departIds.join(",");
+            }else{
+              formData.departIds="";
+            }
             // that.addDepartsToUser(that,formData); // 调用根据当前用户添加部门信息的方法
             let obj;
             if(!this.model.id){
@@ -380,7 +435,6 @@
               that.confirmLoading = false;
               that.checkedDepartNames = [];
               that.userDepartModel.departIdList = {userId:'',departIdList:[]};
-
               that.close();
             })
 
@@ -528,9 +582,6 @@
           }
         }
       },
-      getAvatarView(){
-        return this.url.imgerver +"/"+ this.model.avatar;
-      },
       // 搜索用户对应的部门API
       onSearch(){
         this.$refs.departWindow.add(this.checkedDepartKeys,this.userId);
@@ -543,11 +594,21 @@
         this.checkedDepartNameString = '';
         this.userId = formData.userId;
         this.userDepartModel.userId = formData.userId;
+        this.departIds=[];
+        this.resultDepartOptions=[];
+        var depart=[];
         for (let i = 0; i < formData.departIdList.length; i++) {
           this.selectedDepartKeys.push(formData.departIdList[i].key);
           this.checkedDepartNames.push(formData.departIdList[i].title);
           this.checkedDepartNameString = this.checkedDepartNames.join(",");
+          //新增部门选择,如果上面部门选择后不为空直接付给负责部门
+          depart.push({
+              key:formData.departIdList[i].key,
+              title:formData.departIdList[i].title
+          })
+          this.departIds.push(formData.departIdList[i].key)
         }
+        this.resultDepartOptions=depart;
         this.userDepartModel.departIdList = this.selectedDepartKeys;
         this.checkedDepartKeys = this.selectedDepartKeys  //更新当前的选择keys
        },
@@ -560,6 +621,13 @@
           this.drawerWidth = 700;
         }
       },
+      identityChange(e){
+        if(e.target.value==="1"){
+            this.departIdShow=false;
+        }else{
+            this.departIdShow=true;
+        }
+      }
     }
   }
 </script>

+ 191 - 0
ant-design-vue-jeecg/src/views/system/modules/UserRecycleBinModal.vue

@@ -0,0 +1,191 @@
+<template>
+  <a-modal
+    :width="1000"
+    :title="title"
+    :visible="innerVisible"
+    @cancel="handleCancel"
+    cancelText="关闭"
+    :okButtonProps="{style:{display:'none'}}"
+  >
+    <a-alert type="info" showIcon style="margin-bottom: 16px;">
+      <template slot="message">
+        <span>已选择</span>
+        <a style="font-weight: 600;padding: 0 4px;">{{ selectedRowKeys.length }}</a>
+        <span>项</span>
+        <template v-if="selectedRowKeys.length>0">
+          <a-divider type="vertical"/>
+          <a @click="handleClearSelection">清空选择</a>
+          <a-divider type="vertical"/>
+          <a @click="handleRevertBatch">批量还原</a>
+          <a-divider type="vertical"/>
+          <a @click="handleDeleteBatch">批量删除</a>
+        </template>
+      </template>
+    </a-alert>
+
+    <a-table
+      ref="table"
+      rowKey="id"
+      size="middle"
+      bordered
+      :columns="columns"
+      :loading="loading"
+      :dataSource="dataSource"
+      :pagination="false"
+      :rowSelection="{selectedRowKeys, onChange: handleTableSelectChange}"
+    >
+
+      <!-- 显示头像 -->
+      <template slot="avatarslot" slot-scope="text, record, index">
+        <div class="anty-img-wrap">
+          <a-avatar shape="square" :src="url.getAvatar(record.avatar)" icon="user"/>
+        </div>
+      </template>
+
+      <span slot="action" slot-scope="text, record">
+        <a @click="handleRevert([record.id])"><a-icon type="redo"/> 还原用户</a>
+        <a-divider type="vertical"/>
+        <a @click="handleDelete([record.id])"><a-icon type="delete"/> 彻底删除</a>
+      </span>
+    </a-table>
+
+  </a-modal>
+</template>
+
+<script>
+
+  // 高度封装的请求,请务必使用 superRequest.call(this,{}) 的方式调用
+  function superRequest(options) {
+    this.loading = !!options.loading
+    options.promise.then(res => {
+      if (res.success && typeof options.success === 'function') {
+        options.success(res)
+      } else {
+        throw new Error(res.message)
+      }
+    }).catch(e => {
+      console.error('查询已删除的用户失败:', e)
+      this.$message.warning('查询已删除的用户失败:' + (e.message || e))
+    }).finally(() => {
+      this.loading = false
+    })
+  }
+
+  export default {
+    name: 'UserRecycleBinModal',
+    props: {
+      visible: {
+        type: Boolean,
+        default: false
+      },
+    },
+    data() {
+      return {
+        title: '用户回收站',
+        loading: false,
+        innerVisible: false,
+        selectedRowKeys: [],
+        dataSource: [],
+        columns: [
+          { title: '#', align: 'center', key: 'rowIndex', width: 80, customRender: (t, r, i) => i + 1 },
+          { title: '账号', align: 'center', dataIndex: 'username' },
+          { title: '姓名', align: 'center', dataIndex: 'realname', },
+          { title: '头像', align: 'center', dataIndex: 'avatar', scopedSlots: { customRender: 'avatarslot' } },
+          { title: '部门', align: 'center', dataIndex: 'orgCode' },
+          { title: '操作', align: 'center', dataIndex: 'action', width: 200, scopedSlots: { customRender: 'action' } }
+        ],
+        url: {
+          getAvatar: (path) => `window._CONFIG['staticDomainURL']/${path}`,
+          // 回收站操作,get = 获取列表;put = 取回;delete = 彻底删除
+          recycleBin: '/sys/user/recycleBin',
+        },
+      }
+    },
+    watch: {
+      visible: {
+        immediate: true,
+        handler(val) {
+          if (val) {
+            this.loadData()
+          }
+          this.innerVisible = val
+        }
+      },
+      innerVisible(val) {
+        this.$emit('update:visible', val)
+      },
+    },
+    methods: {
+      loadData() {
+        superRequest.call(this, {
+          loading: true,
+          promise: this.$http.get(this.url.recycleBin),
+          success: res => this.dataSource = res.result
+        })
+      },
+      handleOk() {
+        this.loadData()
+        this.$emit('ok')
+      },
+      handleCancel() {
+        this.innerVisible = false
+      },
+      // 还原用户
+      handleRevert(userIds) {
+        this.$confirm({
+          title: '恢复用户',
+          content: `您确定要恢复这 ${userIds.length} 个用户吗?`,
+          centered: true,
+          onOk: () => {
+            superRequest.call(this, {
+              loading: true,
+              promise: this.$http.put(this.url.recycleBin, userIds),
+              success: () => {
+                this.handleOk()
+                this.handleClearSelection()
+                this.$message.success(`还原 ${userIds.length} 个用户成功!`)
+              }
+            })
+          }
+        })
+      },
+      // 彻底删除用户
+      handleDelete(userIds) {
+        this.$confirm({
+          title: '彻底删除用户',
+          content: (<div>
+            <p>您确定要彻底删除这 {userIds.length} 个用户吗?</p>
+            <p style="color:red;">注意:彻底删除后将无法恢复,请谨慎操作!</p>
+          </div>),
+          centered: true,
+          onOk: () => {
+            superRequest.call(this, {
+              loading: true,
+              promise: this.$http.delete(this.url.recycleBin + `?userIds=${userIds.join(',')}`),
+              success: () => {
+                this.loadData()
+                this.handleClearSelection()
+                this.$message.success(`彻底删除 ${userIds.length} 个用户成功!`)
+              }
+            })
+          },
+        })
+      },
+      handleRevertBatch() {
+        this.handleRevert(this.selectedRowKeys)
+      },
+      handleDeleteBatch() {
+        this.handleDelete(this.selectedRowKeys)
+      },
+      handleClearSelection() {
+        this.handleTableSelectChange([], [])
+      },
+      handleTableSelectChange(selectedRowKeys, selectionRows) {
+        this.selectedRowKeys = selectedRowKeys
+        this.selectionRows = selectionRows
+      },
+    }
+  }
+</script>
+
+<style lang="scss" scoped></style>

+ 17 - 8
ant-design-vue-jeecg/src/views/system/modules/UserRoleModal.vue

@@ -45,7 +45,8 @@
       <a-popconfirm title="确定放弃编辑?" @confirm="close" okText="确定" cancelText="取消">
         <a-button style="margin-right: .8rem">取消</a-button>
       </a-popconfirm>
-      <a-button @click="handleSubmit" type="primary" :loading="loading">提交</a-button>
+      <a-button @click="handleSubmit(false)" type="primary" :loading="loading" ghost style="margin-right: 0.8rem">仅保存</a-button>
+      <a-button @click="handleSubmit(true)" type="primary" :loading="loading">保存并关闭</a-button>
     </div>
 
     <role-datarule-modal ref="datarule"></role-datarule-modal>
@@ -134,7 +135,7 @@
       handleCancel () {
         this.close()
       },
-      handleSubmit(){
+      handleSubmit(exit) {
         let that = this;
         let params =  {
           roleId:that.roleId,
@@ -147,18 +148,20 @@
           if(res.success){
             that.$message.success(res.message);
             that.loading = false;
-            that.close();
+            if (exit) {
+              that.close()
+            }
           }else {
             that.$message.error(res.message);
             that.loading = false;
-            that.close();
+            if (exit) {
+              that.close()
+            }
           }
+          this.loadData();
         })
       },
-    },
-  watch: {
-    visible () {
-      if (this.visible) {
+      loadData(){
         queryTreeListForRole().then((res) => {
           this.treeData = res.result.treeList
           this.allTreeKeys = res.result.ids
@@ -170,6 +173,12 @@
           })
         })
       }
+    },
+  watch: {
+    visible () {
+      if (this.visible) {
+        this.loadData();
+      }
     }
   }
   }

+ 14 - 13
ant-design-vue-jeecg/src/views/user/Alteration.vue

@@ -1,13 +1,13 @@
 <template>
-  <a-card :bordered="false" style="width: 160%;text-align: center;margin-left:-25%">
+  <a-card :bordered="false" style="width: 130%;text-align: center;margin-left:-10%">
     <a-steps class="steps" :current="currentTab">
-      <a-step title="账户信息" />
-      <a-step title="身份验证" />
-      <a-step title="更改密码" />
-      <a-step title="完成" />
+      <a-step title="用户账户"/>
+      <a-step title="手机验证"/>
+      <a-step title="密码"/>
+      <a-step title="完成"/>
     </a-steps>
     <div class="content">
-      <step1 v-if="currentTab === 0" @nextStep="nextStep"  />
+      <step1 v-if="currentTab === 0" @nextStep="nextStep"/>
       <step2 v-if="currentTab === 1" @nextStep="nextStep" @prevStep="prevStep" :userList="userList"/>
       <step3 v-if="currentTab === 2" @nextStep="nextStep" @prevStep="prevStep" :userList="userList"/>
       <step4 v-if="currentTab === 3" @prevStep="prevStep" @finish="finish" :userList="userList"/>
@@ -20,6 +20,7 @@
   import Step2 from './Step2'
   import Step3 from './Step3'
   import Step4 from './Step4'
+
   export default {
     name: "Alteration",
     components: {
@@ -28,11 +29,11 @@
       Step3,
       Step4
     },
-    data () {
+    data() {
       return {
         description: '将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。',
         currentTab: 0,
-        userList:{},
+        userList: {},
         // form
         form: null,
       }
@@ -40,19 +41,19 @@
     methods: {
 
       // handler
-      nextStep (data) {
-        this.userList=data;
+      nextStep(data) {
+        this.userList = data;
         if (this.currentTab < 4) {
           this.currentTab += 1
         }
       },
-      prevStep (data) {
-        this.userList=data;
+      prevStep(data) {
+        this.userList = data;
         if (this.currentTab > 0) {
           this.currentTab -= 1
         }
       },
-      finish () {
+      finish() {
         this.currentTab = 0
       }
     }

+ 35 - 27
ant-design-vue-jeecg/src/views/user/Login.vue

@@ -9,7 +9,7 @@
           <a-form-item>
             <a-input
               size="large"
-              v-decorator="['username',validatorRules.username,{ validator: this.handleUsernameOrEmail }]"
+              v-decorator="['username',{initialValue:'admin', rules: validatorRules.username.rules}]"
               type="text"
               placeholder="请输入帐户名 / jeecg">
               <a-icon slot="prefix" type="user" :style="{ color: 'rgba(0,0,0,.25)' }"/>
@@ -18,7 +18,7 @@
 
           <a-form-item>
             <a-input
-              v-decorator="['password',validatorRules.password]"
+              v-decorator="['password',{initialValue:'123456', rules: validatorRules.password.rules}]"
               size="large"
               type="password"
               autocomplete="false"
@@ -28,7 +28,7 @@
           </a-form-item>
 
           <a-row :gutter="0">
-            <a-col :span="14">
+            <a-col :span="16">
               <a-form-item>
                 <a-input
                   v-decorator="['inputCode',validatorRules.inputCode]"
@@ -36,13 +36,13 @@
                   type="text"
                   @change="inputCodeChange"
                   placeholder="请输入验证码">
-                  <a-icon slot="prefix" v-if=" inputCodeContent==verifiedCode " type="smile" :style="{ color: 'rgba(0,0,0,.25)' }"/>
-                  <a-icon slot="prefix" v-else type="frown" :style="{ color: 'rgba(0,0,0,.25)' }"/>
+                  <a-icon slot="prefix" type="smile" :style="{ color: 'rgba(0,0,0,.25)' }"/>
                 </a-input>
               </a-form-item>
             </a-col>
-            <a-col  :span="10">
-              <j-graphic-code @success="generateCode" ref="jgraphicCodeRef" style="float: right" remote></j-graphic-code>
+            <a-col :span="8" style="text-align: right">
+              <img style="margin-top: 2px;" :src="randCodeImage" @click="handleChangeCheckCode"/>
+              <!--<j-graphic-code @success="generateCode" ref="jgraphicCodeRef" style="float: right" remote></j-graphic-code>-->
             </a-col>
           </a-row>
 
@@ -88,7 +88,7 @@
         <router-link :to="{ name: 'alteration'}" class="forge-password" style="float: right;">
           忘记密码
         </router-link>
-        <router-link :to="{ name: 'register'}" class="forge-password" style="float: right;margin-right: 10px" >
+       <router-link :to="{ name: 'register'}" class="forge-password" style="float: right;margin-right: 10px" >
           注册账户
         </router-link>
       </a-form-item>
@@ -173,8 +173,7 @@
   import Vue from 'vue'
   import { ACCESS_TOKEN ,ENCRYPTED_STRING} from "@/store/mutation-types"
   import JGraphicCode from '@/components/jeecg/JGraphicCode'
-  import { putAction } from '@/api/manage'
-  import { postAction } from '@/api/manage'
+  import { putAction,postAction,getAction } from '@/api/manage'
   import { encryption , getEncryptedString } from '@/utils/encryption/aesEncrypt'
   import store from '@/store/'
   import { USER_INFO } from "@/store/mutation-types"
@@ -202,11 +201,11 @@
           smsSendBtn: false,
         },
         validatorRules:{
-          username:{rules: [{ required: true, message: '请输入用户名!',validator: 'click'}]},
+          username:{rules: [{ required: true, message: '请输入用户名!'},{validator: this.handleUsernameOrEmail}]},
           password:{rules: [{ required: true, message: '请输入密码!',validator: 'click'}]},
           mobile:{rules: [{validator:this.validateMobile}]},
           captcha:{rule: [{ required: true, message: '请输入验证码!'}]},
-          inputCode:{rules: [{ required: true, message: '请输入验证码!'},{validator: this.validateInputCode}]}
+          inputCode:{rules: [{ required: true, message: '请输入验证码!'}]}
         },
         verifiedCode:"",
         inputCodeContent:"",
@@ -216,12 +215,16 @@
         departVisible:false,
         departSelected:"",
         currentUsername:"",
-        validate_status:""
+        validate_status:"",
+        currdatetime:'',
+        randCodeImage:''
       }
     },
     created () {
+      this.currdatetime = new Date().getTime();
       Vue.ls.remove(ACCESS_TOKEN)
       this.getRouterData();
+      this.handleChangeCheckCode();
       // update-begin- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉,有点问题
       //this.getEncrypte();
       // update-end- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉,有点问题
@@ -257,10 +260,9 @@
               loginParams.password = values.password
               loginParams.remember_me = values.rememberMe
               // update-begin- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉,有点问题
-              let checkParams = this.$refs.jgraphicCodeRef.getLoginParam()
-              loginParams.captcha = checkParams.checkCode
-              loginParams.checkKey = checkParams.checkKey
-
+              loginParams.captcha = that.inputCodeContent
+              loginParams.checkKey = that.currdatetime
+              console.log("登录参数",loginParams)
               that.Login(loginParams).then((res) => {
                 this.departConfirm(res)
               }).catch((err) => {
@@ -339,6 +341,16 @@
           this.stepCaptchaVisible = false
         })
       },
+      handleChangeCheckCode(){
+        this.currdatetime = new Date().getTime();
+        getAction(`/sys/randomImage/${this.currdatetime}`).then(res=>{
+          if(res.success){
+            this.randCodeImage = res.result
+          }else{
+            this.$message.error(res.message)
+          }
+        })
+      },
       loginSuccess () {
         // update-begin- author:sunjianlei --- date:20190812 --- for: 登录成功后不解除禁用按钮,防止多次点击
         // this.loginBtn = false
@@ -384,12 +396,6 @@
       },
       inputCodeChange(e){
         this.inputCodeContent = e.target.value
-        if(!e.target.value||0==e.target.value){
-          this.inputCodeNull=true
-        }else{
-          this.inputCodeContent = this.inputCodeContent.toLowerCase()
-          this.inputCodeNull=false
-        }
       },
       departConfirm(res){
         if(res.success){
@@ -452,10 +458,12 @@
       },
     getRouterData(){
       this.$nextTick(() => {
-        this.form.setFieldsValue({
-        'username': this.$route.params.username
-      });
-    })
+        if (this.$route.params.username) {
+          this.form.setFieldsValue({
+            'username': this.$route.params.username
+          });
+        }
+      })
     },
     //获取密码加密规则
     getEncrypte(){

+ 1 - 1
ant-design-vue-jeecg/src/views/user/RegisterResult.vue

@@ -26,7 +26,7 @@
     },
     computed: {
       email () {
-        let v = this.form && this.form.username || 'xxx'
+        let v = this.form ? this.form.username || this.form.mobile : ' XXX '
         let title = `你的账户:${v} 注册成功`
         this.username = v;
         return title

+ 54 - 49
ant-design-vue-jeecg/src/views/user/Step1.vue

@@ -1,14 +1,14 @@
 <template>
   <div class="main">
 
-    <a-form  style="max-width: 500px; margin: 40px auto 0;" :form="form">
+    <a-form style="max-width: 500px; margin: 40px auto 0;" :form="form" @keyup.enter.native="nextStep">
       <a-form-item>
         <a-input
           v-decorator="['username',validatorRules.username]"
           size="large"
           type="text"
           autocomplete="false"
-          placeholder="请输入用户或手机号">
+          placeholder="请输入用户账号或手机号">
           <a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }"/>
         </a-input>
       </a-form-item>
@@ -32,6 +32,7 @@
         </a-col>
       </a-row>
       <a-form-item :wrapperCol="{span: 19, offset: 5}">
+        <router-link style="float: left;line-height: 40px;" :to="{ name: 'login' }">使用已有账户登录</router-link>
         <a-button type="primary" @click="nextStep">下一步</a-button>
       </a-form-item>
     </a-form>
@@ -40,95 +41,99 @@
 
 <script>
   import JGraphicCode from '@/components/jeecg/JGraphicCode'
-  import { getAction } from  '@/api/manage'
-  import {checkOnlyUser } from '@/api/api'
+  import {getAction} from '@/api/manage'
+  import {checkOnlyUser} from '@/api/api'
+
   export default {
     name: "Step1",
     components: {
       JGraphicCode
     },
-    data () {
+    data() {
       return {
         form: this.$form.createForm(this),
         inputCodeContent: "",
-        inputCodeNull:true,
-        verifiedCode:"",
+        inputCodeNull: true,
+        verifiedCode: "",
         validatorRules: {
-          username:{rules: [{ required: false},{validator: this.validateInputUsername}]},
-          inputCode:{rules: [{ required: true, message: '请输入验证码!'},{validator: this.validateInputCode}]},
+          username: {rules: [{required: false}, {validator: this.validateInputUsername}]},
+          inputCode: {rules: [{required: true, message: '请输入验证码!'}, {validator: this.validateInputCode}]},
         },
 
       }
     },
     methods: {
-      nextStep () {
+      nextStep() {
         let that = this
         this.form.validateFields((err, values) => {
-          if (!err){
-          var params={}
-          var reg=/^[1-9]\d*$|^0$/;
-          var username=values.username;
-          if(reg.test(username)==true) {
-            params.phone=username;
-          }else{
-            params.username=username;
-          }
-            getAction("/sys/user/querySysUser",params).then((res)=>{
-              if(res.success){
-            var userList={
-              username:res.result.username,
-              phone:res.result.phone
-            };
-             setTimeout(function () {
-              that.$emit('nextStep',userList)
-            })
+          if (!err) {
+            let isPhone = false;
+            var params = {}
+            var reg = /^[1-9]\d*$|^0$/;
+            var username = values.username;
+            if (reg.test(username) == true) {
+              params.phone = username;
+              isPhone = true
+            } else {
+              params.username = username;
+            }
+            getAction("/sys/user/querySysUser", params).then((res) => {
+              if (res.success) {
+                var userList = {
+                  username: res.result.username,
+                  phone: res.result.phone,
+                  isPhone: isPhone
+                };
+                setTimeout(function () {
+                  that.$emit('nextStep', userList)
+                })
+              }
+            });
           }
-          });
-        }
-    })
+        })
 
       },
-      validateInputCode(rule, value, callback){
+      validateInputCode(rule, value, callback) {
         if (!value || this.verifiedCode == this.inputCodeContent) {
           callback();
         } else {
           callback(new Error("您输入的验证码不正确!"));
         }
       },
-      inputCodeChange(e){
+      inputCodeChange(e) {
         this.inputCodeContent = e.target.value;
         console.log(this.inputCodeContent)
-        if(!e.target.value||0==e.target.value){
-          this.inputCodeNull=true
-        }else{
+        if (!e.target.value || 0 == e.target.value) {
+          this.inputCodeNull = true
+        } else {
           this.inputCodeContent = this.inputCodeContent.toLowerCase()
-          this.inputCodeNull=false
+          this.inputCodeNull = false
         }
       },
-      generateCode(value){
+      generateCode(value) {
         this.verifiedCode = value.toLowerCase();
         console.log(this.verifiedCode);
       },
-      validateInputUsername(rule, value, callback){
+      validateInputUsername(rule, value, callback) {
         console.log(value);
-        var reg=/^[0-9]+.?[0-9]*/;
-        if(!value){
+        var reg = /^[0-9]+.?[0-9]*/;
+        if (!value) {
           callback("请输入用户名和手机号!");
         }
 
         //判断用户输入账号还是手机号码
-        if(reg.test(value)){
+        if (reg.test(value)) {
           var params = {
-            phone : value,
+            phone: value,
           };
           checkOnlyUser(params).then((res) => {
             if (res.success) {
-            callback("用户名不存在!")
-          } else {
-            callback()
-          }
-        })
-        }else{
+              callback("用户名不存在!")
+            } else {
+              callback()
+            }
+          })
+        } else {
           var params = {
             username: value,
           };

+ 119 - 111
ant-design-vue-jeecg/src/views/user/Step2.vue

@@ -1,80 +1,79 @@
 <template>
   <div>
-    <a-form :form="form"  style="max-width: 500px; margin: 40px auto 0;">
-    <a-form-item
-    label="账号名"
-    :labelCol="{span: 5}"
-    :wrapperCol="{span: 19}"
-    >
-      <a-input
-        type="text"
-        autocomplete="false"
-        :style="{width:'310px'}"
-        :value="accountName"
-        disabled>
-      </a-input>
-    </a-form-item>
-    <a-form-item
-    label="手机"
-    :labelCol="{span: 5}"
-    :wrapperCol="{span: 19}"
-    >
-      <a-input
-        type="text"
-        autocomplete="false"
-        :style="{width:'310px'}"
-        placeholder="请输入手机号"
-        :value="phone"
-        disabled>
-        <a-icon slot="prefix" type="phone" :style="{ color: 'rgba(0,0,0,.25)'}" />
-      </a-input>
-    </a-form-item>
+    <a-form :form="form" style="max-width: 500px; margin: 40px auto 0;" @keyup.enter.native="nextStep">
+      <a-form-item
+        label="账号名"
+        :labelCol="{span: 5}"
+        :wrapperCol="{span: 19}"
+      >
+        <a-input
+          type="text"
+          autocomplete="false"
+          :style="{width:'310px'}"
+          :value="accountName"
+          disabled>
+        </a-input>
+      </a-form-item>
+      <a-form-item
+        label="手机"
+        :labelCol="{span: 5}"
+        :wrapperCol="{span: 19}"
+      >
+        <a-input
+          type="text"
+          autocomplete="false"
+          :style="{width:'310px'}"
+          v-decorator="['phone',{initialValue: defaultPhone, rules: validatorRules.phone.rule}]"
+          placeholder="请输入手机号">
+          <a-icon slot="prefix" type="phone" :style="{ color: 'rgba(0,0,0,.25)'}"/>
+        </a-input>
+      </a-form-item>
       <a-form-item
         label="验证码"
         :labelCol="{span: 5}"
         :wrapperCol="{span: 19}"
         v-if="show">
-          <a-row :gutter="16" style="margin-left: 35px">
-            <a-col class="gutter-row" :span="10">
-                <a-input
-                  v-decorator="['captcha',validatorRules.captcha]"
-                  type="text"
-                  placeholder="手机短信验证码" >
-                </a-input>
-            </a-col>
-            <a-col class="gutter-row" :span="8" >
-              <a-button
-                tabindex="-1"
-                size="default"
-                :disabled="state.smsSendBtn"
-                @click.stop.prevent="getCaptcha"
-                v-text="!state.smsSendBtn && '获取验证码' || (state.time+' s')"></a-button>
-            </a-col>
-          </a-row>
+        <a-row :gutter="16" style="margin-left: 2px">
+          <a-col class="gutter-row" :span="12">
+            <a-input
+              v-decorator="['captcha',validatorRules.captcha]"
+              type="text"
+              placeholder="手机短信验证码">
+            </a-input>
+          </a-col>
+          <a-col class="gutter-row" :span="8">
+            <a-button
+              tabindex="-1"
+              size="default"
+              :disabled="state.smsSendBtn"
+              @click.stop.prevent="getCaptcha"
+              v-text="!state.smsSendBtn && '获取验证码' || (state.time+' s')"></a-button>
+          </a-col>
+        </a-row>
       </a-form-item>
       <a-form-item :wrapperCol="{span: 19, offset: 5}">
-      <a-button style="margin-left: 8px" @click="prevStep">上一步</a-button>
-       <a-button type="primary" @click="nextStep" style="margin-left: 20px">下一步</a-button>
-    </a-form-item>
+        <a-button style="margin-left: 8px" @click="prevStep">上一步</a-button>
+        <a-button type="primary" @click="nextStep" style="margin-left: 20px">下一步</a-button>
+      </a-form-item>
 
     </a-form>
   </div>
 </template>
 
 <script>
-  import { postAction } from '@/api/manage'
+  import {postAction} from '@/api/manage'
+
   export default {
     name: "Step2",
-    props:['userList'],
-    data () {
+    props: ['userList'],
+    data() {
       return {
         form: this.$form.createForm(this),
         loading: false,
-        accountName:this.userList.username,
-        phone:this.userList.phone,
-        dropList:"0",
+        accountName: this.userList.username,
+        dropList: "0",
         captcha: "",
-        show:true,
+        show: true,
         state: {
           time: 60,
           smsSendBtn: false,
@@ -83,58 +82,66 @@
           captcha: "",
           mobile: "",
         },
-        validatorRules:{
-          captcha:{rule: [{ required: true, message: '请输入短信验证码!'},{validator:this.validateCaptcha}]},
+        validatorRules: {
+          captcha: {rule: [{required: true, message: '请输入短信验证码!'}, {validator: this.validateCaptcha}]},
+          phone: {rule: [{required: true, message: '请输入手机号码!'}]},
         },
       }
     },
+    computed: {
+      defaultPhone: function(){
+        if(this.userList.isPhone){
+          return this.userList.phone
+        }
+        return null;
+      }
+    },
     methods: {
-      nextStep () {
+      nextStep() {
         let that = this
         that.loading = true
         this.form.validateFields((err, values) => {
           console.log(values);
           if (!err) {
-            if(that.dropList=="0"){
-              if(values.captcha==undefined){
+            if (that.dropList == "0") {
+              if (values.captcha == undefined) {
                 this.cmsFailed("请输入短信验证码!");
-              }else{
-                var params={}
-                params.phone=this.userList.phone;
-                params.smscode=values.captcha;
-                postAction("/sys/user/phoneVerification",params).then((res)=>{
-                  if(res.success){
-                  console.log(res);
-                  var userList={
-                    username:this.userList.username,
-                    phone:this.userList.phone,
-                    smscode:res.result
-                  };
-                  setTimeout(function () {
-                    that.$emit('nextStep',userList)
-                  },0)
-                }else{
-                  this.cmsFailed(res.message);
-                }
-              })
+              } else {
+                var params = {}
+                params.phone = this.userList.phone;
+                params.smscode = values.captcha;
+                postAction("/sys/user/phoneVerification", params).then((res) => {
+                  if (res.success) {
+                    console.log(res);
+                    var userList = {
+                      username: this.userList.username,
+                      phone: this.userList.phone,
+                      smscode: res.result
+                    };
+                    setTimeout(function () {
+                      that.$emit('nextStep', userList)
+                    }, 0)
+                  } else {
+                    this.cmsFailed(res.message);
+                  }
+                })
 
               }
             }
 
 
-
-        }
-      })
+          }
+        })
       },
-      prevStep () {
-        this.$emit('prevStep',this.userList);
+      prevStep() {
+        this.$emit('prevStep', this.userList);
       },
-      getCaptcha (e) {
+      getCaptcha(e) {
         e.preventDefault();
         let that = this;
-          this.state.smsSendBtn = true;
-          let interval = window.setInterval(() => {
-              if (that.state.time-- <= 0) {
+        this.state.smsSendBtn = true;
+        let interval = window.setInterval(() => {
+          if (that.state.time-- <= 0) {
             that.state.time = 60;
             that.state.smsSendBtn = false;
             window.clearInterval(interval);
@@ -147,30 +154,30 @@
           smsmode: "2"
         };
         postAction("/sys/sms", smsParams).then(res => {
-          if(!res.success ){
-          setTimeout(hide, 1);
-          this.cmsFailed(res.message);
-        }
-        setTimeout(hide, 500);
-      })
+          if (!res.success) {
+            setTimeout(hide, 1);
+            this.cmsFailed(res.message);
+          }
+          setTimeout(hide, 500);
+        })
       },
-      cmsFailed(err){
-        this.$notification[ 'error' ]({
+      cmsFailed(err) {
+        this.$notification['error']({
           message: "验证错误",
-          description:err,
+          description: err,
           duration: 4,
         });
       },
-      handleChangeSelect(value){
-        var that=this;
+      handleChangeSelect(value) {
+        var that = this;
         console.log(value);
-      if(value==0){
-        that.dropList="0";
-        that.show=true;
-      }else{
-        that.dropList="1";
-        that.show=false;
-      }
+        if (value == 0) {
+          that.dropList = "0";
+          that.show = true;
+        } else {
+          that.dropList = "1";
+          that.show = false;
+        }
       },
     }
 
@@ -181,10 +188,11 @@
   .stepFormText {
     margin-bottom: 24px;
   }
-    .ant-form-item-label,
-    .ant-form-item-control {
-      line-height: 22px;
-    }
+
+  .ant-form-item-label,
+  .ant-form-item-control {
+    line-height: 22px;
+  }
 
   .getCaptcha {
     display: block;

+ 0 - 1
ant-design-vue-jeecg/vue.config.js

@@ -30,7 +30,6 @@ module.exports = {
       .set('@comp', resolve('src/components'))
       .set('@views', resolve('src/views'))
       .set('@layout', resolve('src/layout'))
-      .set('@static', resolve('src/static'))
   },
 
   css: {

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 3300 - 3202
ant-design-vue-jeecg/yarn.lock


+ 1 - 1
jeecg-boot/Dockerfile

@@ -50,7 +50,7 @@ RUN  cd /etc/yum.repos.d/ \
 # 前端迁移到系统文件中 默认是80端口 同级目录下的html地址
 ADD  ant-design-vue-jeecg/dist/ /var/www/html/
 # 拷贝相关的jar包
-ADD jeecg-boot/jeecg-boot-module-system/target/jeecg-boot-module-system-2.1.1.jar jeecgboot.jar
+ADD jeecg-boot/jeecg-boot-module-system/target/jeecg-boot-module-system-2.1.4.jar jeecgboot.jar
 EXPOSE  80  8080 81
 ENTRYPOINT /bin/sh -c   /etc/init.d/start.sh
 

+ 3 - 3
jeecg-boot/README.md

@@ -1,7 +1,7 @@
 Jeecg-Boot 快速开发平台
 ===============
 
-当前最新版本: 2.1.3(发布日期:20191226
+当前最新版本: 2.1.4(发布日期:20200224
 
 
 ## 后端技术架构
@@ -37,11 +37,11 @@ Jeecg-Boot 快速开发平台
 ## 技术文档
 
 
-- 在线演示 :  [http://boot.jeecg.org](http://boot.jeecg.org)
+- 在线演示 :  [http://boot.jeecg.com](http://boot.jeecg.com)
 
 - 在线文档:  [http://doc.jeecg.com/1273753](http://doc.jeecg.com/1273753)
 
-- 常见问题:  [入门常见问题大全](http://www.jeecg.org/forum.php?mod=viewthread&tid=7816&extra=page%3D1)
+- 常见问题:  [入门常见问题大全](http://bbs.jeecg.com/forum.php?mod=viewthread&tid=7816&extra=page%3D1)
 
 - QQ交流群 :  ①284271917、②769925425
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 580 - 417
jeecg-boot/db/mysql-5.7.sql


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 5079
jeecg-boot/db/oracle11g.sql


+ 0 - 0
jeecg-boot/db/sqlserver2017.sql


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.