Browse Source

若依 1.1

RuoYi 5 years ago
parent
commit
bcee37b84b
93 changed files with 3327 additions and 237 deletions
  1. 6 6
      README.md
  2. 1 1
      ruoyi-ui/package.json
  3. 25 0
      ruoyi-ui/src/api/monitor/logininfor.js
  4. 25 0
      ruoyi-ui/src/api/monitor/operlog.js
  5. 9 0
      ruoyi-ui/src/api/system/config.js
  6. 9 0
      ruoyi-ui/src/api/system/dict/data.js
  7. 9 0
      ruoyi-ui/src/api/system/dict/type.js
  8. 9 0
      ruoyi-ui/src/api/system/post.js
  9. 9 0
      ruoyi-ui/src/api/system/role.js
  10. 10 1
      ruoyi-ui/src/api/system/user.js
  11. 50 0
      ruoyi-ui/src/assets/styles/ruoyi.scss
  12. 2 1
      ruoyi-ui/src/main.js
  13. 7 0
      ruoyi-ui/src/utils/ruoyi.js
  14. 94 6
      ruoyi-ui/src/views/monitor/logininfor/index.vue
  15. 9 3
      ruoyi-ui/src/views/monitor/online/index.vue
  16. 95 7
      ruoyi-ui/src/views/monitor/operlog/index.vue
  17. 89 14
      ruoyi-ui/src/views/system/config/index.vue
  18. 92 14
      ruoyi-ui/src/views/system/dict/data.vue
  19. 93 19
      ruoyi-ui/src/views/system/dict/index.vue
  20. 67 15
      ruoyi-ui/src/views/system/notice/index.vue
  21. 89 15
      ruoyi-ui/src/views/system/post/index.vue
  22. 84 15
      ruoyi-ui/src/views/system/role/index.vue
  23. 85 10
      ruoyi-ui/src/views/system/user/index.vue
  24. 1 1
      ruoyi-ui/vue.config.js
  25. 9 1
      ruoyi/pom.xml
  26. 10 30
      ruoyi/sql/ry_20191111.sql
  27. 872 0
      ruoyi/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
  28. 406 0
      ruoyi/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
  29. 113 0
      ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Excel.java
  30. 18 0
      ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Excels.java
  31. 1 0
      ruoyi/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
  32. 49 2
      ruoyi/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java
  33. 24 0
      ruoyi/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
  34. 43 0
      ruoyi/src/main/java/com/ruoyi/project/common/CommonController.java
  35. 33 0
      ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java
  36. 32 0
      ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java
  37. 11 0
      ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysLogininfor.java
  38. 18 0
      ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysOperLog.java
  39. 2 2
      ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysLogininforMapper.java
  40. 2 2
      ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysOperLogMapper.java
  41. 2 2
      ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysLogininforService.java
  42. 2 2
      ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysOperLogService.java
  43. 3 4
      ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysLogininforServiceImpl.java
  44. 4 6
      ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysOperLogServiceImpl.java
  45. 17 5
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java
  46. 3 4
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java
  47. 17 7
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java
  48. 17 7
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java
  49. 2 4
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java
  50. 3 2
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
  51. 17 5
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysPostController.java
  52. 18 7
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java
  53. 17 6
      ruoyi/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
  54. 25 0
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysConfig.java
  55. 32 1
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDept.java
  56. 31 0
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictData.java
  57. 23 0
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictType.java
  58. 34 1
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysMenu.java
  59. 22 0
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysNotice.java
  60. 25 0
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysPost.java
  61. 35 1
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRole.java
  62. 50 1
      ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUser.java
  63. 9 1
      ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysConfigMapper.java
  64. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictDataMapper.java
  65. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictTypeMapper.java
  66. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysNoticeMapper.java
  67. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysPostMapper.java
  68. 7 0
      ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMapper.java
  69. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java
  70. 9 1
      ruoyi/src/main/java/com/ruoyi/project/system/service/ISysConfigService.java
  71. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictDataService.java
  72. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictTypeService.java
  73. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java
  74. 17 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/ISysPostService.java
  75. 16 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/ISysRoleService.java
  76. 8 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserService.java
  77. 13 1
      ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysConfigServiceImpl.java
  78. 11 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictDataServiceImpl.java
  79. 11 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictTypeServiceImpl.java
  80. 11 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java
  81. 37 1
      ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysPostServiceImpl.java
  82. 36 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysRoleServiceImpl.java
  83. 15 0
      ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java
  84. 1 1
      ruoyi/src/main/resources/application.yml
  85. 1 1
      ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml
  86. 1 1
      ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml
  87. 7 0
      ruoyi/src/main/resources/mybatis/system/SysConfigMapper.xml
  88. 7 0
      ruoyi/src/main/resources/mybatis/system/SysDictDataMapper.xml
  89. 7 0
      ruoyi/src/main/resources/mybatis/system/SysDictTypeMapper.xml
  90. 7 0
      ruoyi/src/main/resources/mybatis/system/SysNoticeMapper.xml
  91. 7 0
      ruoyi/src/main/resources/mybatis/system/SysPostMapper.xml
  92. 7 0
      ruoyi/src/main/resources/mybatis/system/SysRoleMapper.xml
  93. 7 0
      ruoyi/src/main/resources/mybatis/system/SysUserMapper.xml

+ 6 - 6
README.md

@@ -49,12 +49,12 @@
         <td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
     </tr>
     <tr>
-        <td><img src="https://oscimg.oschina.net/oscnet/97fcdc766fa04c03722aef4b3d77f71e8d2.jpg"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/642858372da91853c39e2d4746f036ea171.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/707825ad3f29de74a8d6d02fbd73ad631ea.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/46be40cc6f01aa300eed53a19b5012bf484.jpg"/></td>
     </tr>
     <tr>
-        <td><img src="https://oscimg.oschina.net/oscnet/8678d5204148e2610c9d02822274a961dcf.jpg"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/feb2b25a08bf9dd121b8f51274ae935ead6.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/4284796d4cea240d181b8f2201813dda710.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/3ecfac87a049f7fe36abbcaafb2c40d36cf.jpg"/></td>
     </tr>
 	<tr>
         <td><img src="https://oscimg.oschina.net/oscnet/71c2d48905221a09a728df4aff4160b8607.jpg"/></td>
@@ -65,8 +65,8 @@
         <td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
     </tr>
 	<tr>
-        <td><img src="https://oscimg.oschina.net/oscnet/c162686bf3a39e3cd6b4fd6b5919f515ebf.jpg"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/412fb931faa8b3e3de6f9cbbc5b7979cf36.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/fdea1d8bb8625c27bf964176a2c8ebc6945.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/509d2708cfd762b6e6339364cac1cc1970c.jpg"/></td>
     </tr>
 	<tr>
         <td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>

+ 1 - 1
ruoyi-ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "ruoyi",
-  "version": "1.0.0",
+  "version": "1.1.0",
   "description": "若依管理系统",
   "author": "若依",
   "license": "MIT",

+ 25 - 0
ruoyi-ui/src/api/monitor/logininfor.js

@@ -7,4 +7,29 @@ export function list(query) {
     method: 'get',
     params: query
   })
+}
+
+// 删除登录日志
+export function delLogininfor(infoId) {
+  return request({
+    url: '/monitor/logininfor/' + infoId,
+    method: 'delete'
+  })
+}
+
+// 清空登录日志
+export function cleanLogininfor() {
+  return request({
+    url: '/monitor/logininfor/clean',
+    method: 'delete'
+  })
+}
+
+// 导出登录日志
+export function exportLogininfor(query) {
+  return request({
+    url: '/monitor/logininfor/export',
+    method: 'get',
+    params: query
+  })
 }

+ 25 - 0
ruoyi-ui/src/api/monitor/operlog.js

@@ -7,4 +7,29 @@ export function list(query) {
     method: 'get',
     params: query
   })
+}
+
+// 删除操作日志
+export function delOperlog(operId) {
+  return request({
+    url: '/monitor/operlog/' + operId,
+    method: 'delete'
+  })
+}
+
+// 清空操作日志
+export function cleanOperlog() {
+  return request({
+    url: '/monitor/operlog/clean',
+    method: 'delete'
+  })
+}
+
+// 导出操作日志
+export function exportOperlog(query) {
+  return request({
+    url: '/monitor/operlog/export',
+    method: 'get',
+    params: query
+  })
 }

+ 9 - 0
ruoyi-ui/src/api/system/config.js

@@ -49,4 +49,13 @@ export function delConfig(configId) {
     url: '/system/config/' + configId,
     method: 'delete'
   })
+}
+
+// 导出参数
+export function exportConfig(query) {
+  return request({
+    url: '/system/config/export',
+    method: 'get',
+    params: query
+  })
 }

+ 9 - 0
ruoyi-ui/src/api/system/dict/data.js

@@ -49,4 +49,13 @@ export function delData(dictCode) {
     url: '/system/dict/data/' + dictCode,
     method: 'delete'
   })
+}
+
+// 导出字典数据
+export function exportData(query) {
+  return request({
+    url: '/system/dict/data/export',
+    method: 'get',
+    params: query
+  })
 }

+ 9 - 0
ruoyi-ui/src/api/system/dict/type.js

@@ -42,3 +42,12 @@ export function delType(dictId) {
     method: 'delete'
   })
 }
+
+// 导出字典类型
+export function exportType(query) {
+  return request({
+    url: '/system/dict/type/export',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
ruoyi-ui/src/api/system/post.js

@@ -41,4 +41,13 @@ export function delPost(postId) {
     url: '/system/post/' + postId,
     method: 'delete'
   })
+}
+
+// 导出岗位
+export function exportPost(query) {
+  return request({
+    url: '/system/post/export',
+    method: 'get',
+    params: query
+  })
 }

+ 9 - 0
ruoyi-ui/src/api/system/role.js

@@ -63,4 +63,13 @@ export function delRole(roleId) {
     url: '/system/role/' + roleId,
     method: 'delete'
   })
+}
+
+// 导出角色
+export function exportRole(query) {
+  return request({
+    url: '/system/role/export',
+    method: 'get',
+    params: query
+  })
 }

+ 10 - 1
ruoyi-ui/src/api/system/user.js

@@ -43,6 +43,15 @@ export function delUser(userId) {
   })
 }
 
+// 导出用户
+export function exportUser(query) {
+  return request({
+    url: '/system/user/export',
+    method: 'get',
+    params: query
+  })
+}
+
 // 用户密码重置
 export function resetUserPwd(userId, password) {
   const data = {
@@ -106,4 +115,4 @@ export function uploadAvatar(data) {
     method: 'post',
     data: data
   })
-}
+}

+ 50 - 0
ruoyi-ui/src/assets/styles/ruoyi.scss

@@ -3,6 +3,56 @@
  * Copyright (c) 2019 ruoyi
  */
 
+ /** 基础通用 **/
+.pt5 {
+	padding-top: 5px;
+}
+.pr5 {
+	padding-right: 5px;
+}
+.pb5 {
+	padding-bottom: 5px;
+}
+.mt5 {
+	margin-top: 5px;
+}
+.mr5 {
+	margin-right: 5px;
+}
+.mb5 {
+	margin-bottom: 5px;
+}
+.mb8 {
+	margin-bottom: 8px;
+}
+.ml5 {
+	margin-left: 5px;
+}
+.mt10 {
+	margin-top: 10px;
+}
+.mr10 {
+	margin-right: 10px;
+}
+.mb10 {
+	margin-bottom: 10px;
+}
+.ml0 {
+	margin-left: 10px;
+}
+.mt20 {
+	margin-top: 20px;
+}
+.mr20 {
+	margin-right: 20px;
+}
+.mb20 {
+	margin-bottom: 20px;
+}
+.m20 {
+	margin-left: 20px;
+}
+
 .el-table .el-table__header-wrapper th {
 	word-break: break-word;
 	background-color: #f8f8f9;

+ 2 - 1
ruoyi-ui/src/main.js

@@ -18,7 +18,7 @@ import './assets/icons' // icon
 import './permission' // permission control
 import { getDicts } from "@/api/system/dict/data";
 import { getConfigKey } from "@/api/system/config";
-import { parseTime, resetForm, addDateRange, selectDictLabel } from "@/utils/ruoyi";
+import { parseTime, resetForm, addDateRange, selectDictLabel, download } from "@/utils/ruoyi";
 import Pagination from "@/components/Pagination";
 
 // 全局方法挂载
@@ -28,6 +28,7 @@ Vue.prototype.parseTime = parseTime
 Vue.prototype.resetForm = resetForm
 Vue.prototype.addDateRange = addDateRange
 Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.download = download
 
 Vue.prototype.msgSuccess = function (msg) {
   this.$message({ showClose: true, message: msg, type: "success" });

+ 7 - 0
ruoyi-ui/src/utils/ruoyi.js

@@ -3,6 +3,8 @@
  * Copyright (c) 2019 ruoyi
  */
 
+const baseURL = process.env.VUE_APP_BASE_API
+
 // 日期格式化
 export function parseTime(time, pattern) {
 	if (arguments.length === 0) {
@@ -73,6 +75,11 @@ export function selectDictLabel(datas, value) {
 	return actions.join('');
 }
 
+// 通用下载方法
+export function download(fileName) {
+	window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
+}
+
 // 字符串格式化(%s )
 export function sprintf(str) {
 	var args = arguments, flag = true, i = 1;

+ 94 - 6
ruoyi-ui/src/views/monitor/logininfor/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true" label-width="68px">
-      <el-form-item label="登录地址">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+      <el-form-item label="登录地址" prop="ipaddr">
         <el-input
           v-model="queryParams.ipaddr"
           placeholder="请输入登录地址"
@@ -11,7 +11,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="用户名称">
+      <el-form-item label="用户名称" prop="userName">
         <el-input
           v-model="queryParams.userName"
           placeholder="请输入用户名称"
@@ -21,7 +21,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="状态">
+      <el-form-item label="状态" prop="status">
         <el-select
           v-model="queryParams.status"
           placeholder="登录状态"
@@ -51,10 +51,43 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
-    <el-table v-loading="loading" :data="list" style="width: 100%;">
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['monitor:logininfor:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          @click="handleClean"
+          v-hasPermi="['monitor:logininfor:remove']"
+        >清空</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:logininfor:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="访问编号" align="center" prop="infoId" />
       <el-table-column label="用户名称" align="center" prop="userName" />
       <el-table-column label="登录地址" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
@@ -81,13 +114,17 @@
 </template>
 
 <script>
-import { list } from "@/api/monitor/logininfor";
+import { list, delLogininfor, cleanLogininfor, exportLogininfor } from "@/api/monitor/logininfor";
 
 export default {
   data() {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 表格数据
@@ -131,6 +168,57 @@ export default {
     handleQuery() {
       this.queryParams.pageNum = 1;
       this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.infoId)
+      this.multiple = !selection.length
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const infoIds = row.infoId || this.ids;
+      this.$confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delLogininfor(infoIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 清空按钮操作 */
+    handleClean() {
+        this.$confirm('是否确认清空所有登录日志数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return cleanLogininfor();
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("清空成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportLogininfor(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
     }
   }
 };

+ 9 - 3
ruoyi-ui/src/views/monitor/online/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true">
-      <el-form-item label="登录地址">
+    <el-form :model="queryParams" ref="queryForm" :inline="true">
+      <el-form-item label="登录地址" prop="ipaddr">
         <el-input
           v-model="queryParams.ipaddr"
           placeholder="请输入登录地址"
@@ -10,7 +10,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="用户名称">
+      <el-form-item label="用户名称" prop="userName">
         <el-input
           v-model="queryParams.userName"
           placeholder="请输入用户名称"
@@ -21,6 +21,7 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
@@ -102,6 +103,11 @@ export default {
       this.pageNum = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
     /** 强退按钮操作 */
     handleForceLogout(row) {
       this.$confirm('是否确认强退名称为"' + row.userName + '"的数据项?', "警告", {

+ 95 - 7
ruoyi-ui/src/views/monitor/operlog/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true" label-width="68px">
-      <el-form-item label="系统模块">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+      <el-form-item label="系统模块" prop="title">
         <el-input
           v-model="queryParams.title"
           placeholder="请输入系统模块"
@@ -11,7 +11,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="操作人员">
+      <el-form-item label="操作人员" prop="operName">
         <el-input
           v-model="queryParams.operName"
           placeholder="请输入操作人员"
@@ -21,7 +21,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="类型">
+      <el-form-item label="类型" prop="businessType">
         <el-select
           v-model="queryParams.businessType"
           placeholder="操作类型"
@@ -37,7 +37,7 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="状态">
+      <el-form-item label="状态" prop="status">
         <el-select
           v-model="queryParams.status"
           placeholder="操作状态"
@@ -67,10 +67,43 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
-    <el-table v-loading="loading" :data="list" style="width: 100%;">
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['monitor:operlog:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          @click="handleClean"
+          v-hasPermi="['monitor:operlog:remove']"
+        >清空</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:config:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="日志编号" align="center" prop="operId" />
       <el-table-column label="系统模块" align="center" prop="title" />
       <el-table-column label="操作类型" align="center" prop="businessType" :formatter="typeFormat" />
@@ -150,13 +183,17 @@
 </template>
 
 <script>
-import { list } from "@/api/monitor/operlog";
+import { list, delOperlog, cleanOperlog, exportOperlog } from "@/api/monitor/operlog";
 
 export default {
   data() {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 表格数据
@@ -215,10 +252,61 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.operId)
+      this.multiple = !selection.length
+    },
     /** 详细按钮操作 */
     handleView(row) {
       this.open = true;
       this.form = row;
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const operIds = row.operId || this.ids;
+      this.$confirm('是否确认删除日志编号为"' + operIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delOperlog(operIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 清空按钮操作 */
+    handleClean() {
+        this.$confirm('是否确认清空所有操作日志数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return cleanOperlog();
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("清空成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportOperlog(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
     }
   }
 };

+ 89 - 14
ruoyi-ui/src/views/system/config/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true" label-width="68px">
-      <el-form-item label="参数名称">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+      <el-form-item label="参数名称" prop="configName">
         <el-input
           v-model="queryParams.configName"
           placeholder="请输入参数名称"
@@ -11,7 +11,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="参数键名">
+      <el-form-item label="参数键名" prop="configKey">
         <el-input
           v-model="queryParams.configKey"
           placeholder="请输入参数键名"
@@ -21,7 +21,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="系统内置">
+      <el-form-item label="系统内置" prop="configType">
         <el-select v-model="queryParams.configType" placeholder="系统内置" clearable size="small">
           <el-option
             v-for="dict in typeOptions"
@@ -45,11 +45,53 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:config:add']">新增</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
-    <el-table v-loading="loading" :data="configList">
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:config:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:config:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:config:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:config:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="参数主键" align="center" prop="configId" />
       <el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
       <el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
@@ -63,10 +105,10 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button 
-            size="mini" 
-            type="text" 
-            icon="el-icon-edit" 
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['system:config:edit']"
           >修改</el-button>
@@ -123,13 +165,19 @@
 </template>
 
 <script>
-import { listConfig, getConfig, delConfig, addConfig, updateConfig } from "@/api/system/config";
+import { listConfig, getConfig, delConfig, addConfig, updateConfig, exportConfig } from "@/api/system/config";
 
 export default {
   data() {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 参数表格数据
@@ -209,16 +257,29 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
       this.open = true;
       this.title = "添加参数";
     },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.configId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
-      getConfig(row.configId).then(response => {
+      const configId = row.configId || this.ids
+      getConfig(configId).then(response => {
         this.form = response.data;
         this.open = true;
         this.title = "修改参数";
@@ -254,16 +315,30 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除名称为"' + row.configName + '"的数据项?', "警告", {
+      const configIds = row.configId || this.ids;
+      this.$confirm('是否确认删除参数编号为"' + configIds + '"的数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delConfig(row.configId);
+          return delConfig(configIds);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");
         }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有参数数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportConfig(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
     }
   }
 };

+ 92 - 14
ruoyi-ui/src/views/system/dict/data.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true">
-      <el-form-item label="字典名称">
+    <el-form :model="queryParams" ref="queryForm" :inline="true">
+      <el-form-item label="字典名称" prop="dictType">
         <el-select v-model="queryParams.dictType" size="small">
           <el-option
             v-for="item in typeOptions"
@@ -11,7 +11,7 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="字典标签">
+      <el-form-item label="字典标签" prop="dictLabel">
         <el-input
           v-model="queryParams.dictLabel"
           placeholder="请输入字典标签"
@@ -20,7 +20,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="状态">
+      <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="数据状态" clearable size="small">
           <el-option
             v-for="dict in statusOptions"
@@ -32,11 +32,53 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
-    <el-table v-loading="loading" :data="dataList" style="width: 100%;">
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:dict:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:dict:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:dict:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:dict:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="字典编码" align="center" prop="dictCode" />
       <el-table-column label="字典标签" align="center" prop="dictLabel" />
       <el-table-column label="字典键值" align="center" prop="dictValue" />
@@ -50,10 +92,10 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button 
-            size="mini" 
-            type="text" 
-            icon="el-icon-edit" 
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['system:dict:edit']"
           >修改</el-button>
@@ -113,7 +155,7 @@
 </template>
 
 <script>
-import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
+import { listData, getData, delData, addData, updateData, exportData } from "@/api/system/dict/data";
 import { listType, getType } from "@/api/system/dict/type";
 
 export default {
@@ -121,10 +163,18 @@ export default {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 字典表格数据
       dataList: [],
+      // 默认字典类型
+      defaultDictType: "",
       // 弹出层标题
       title: "",
       // 是否显示弹出层
@@ -170,6 +220,7 @@ export default {
     getType(dictId) {
       getType(dictId).then(response => {
         this.queryParams.dictType = response.data.dictType;
+        this.defaultDictType = response.data.dictType;
         this.getList();
       });
     },
@@ -214,6 +265,12 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.dictType = this.defaultDictType;
+      this.handleQuery();
+    },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
@@ -221,10 +278,17 @@ export default {
       this.title = "添加字典数据";
       this.form.dictType = this.queryParams.dictType;
     },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.dictCode)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
-      getData(row.dictCode).then(response => {
+      const dictCode = row.dictCode || this.ids
+      getData(dictCode).then(response => {
         this.form = response.data;
         this.open = true;
         this.title = "修改字典数据";
@@ -260,16 +324,30 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除名称为"' + row.dictLabel + '"的数据项?', "警告", {
+      const dictCodes = row.dictCode || this.ids;
+      this.$confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delData(row.dictCode);
+          return delData(dictCodes);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");
         }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportData(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
     }
   }
 };

+ 93 - 19
ruoyi-ui/src/views/system/dict/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true" label-width="68px">
-      <el-form-item label="字典名称">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+      <el-form-item label="字典名称" prop="dictName">
         <el-input
           v-model="queryParams.dictName"
           placeholder="请输入字典名称"
@@ -11,7 +11,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="字典类型">
+      <el-form-item label="字典类型" prop="dictType">
         <el-input
           v-model="queryParams.dictType"
           placeholder="请输入字典类型"
@@ -21,7 +21,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="状态">
+      <el-form-item label="状态" prop="status">
         <el-select
           v-model="queryParams.status"
           placeholder="字典状态"
@@ -39,7 +39,7 @@
       </el-form-item>
       <el-form-item label="创建时间">
         <el-date-picker
-          v-model="queryParams.createTime"
+          v-model="dateRange"
           size="small"
           style="width: 240px"
           value-format="yyyy-MM-dd"
@@ -51,14 +51,56 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
-    <el-table v-loading="loading" :data="typeList" style="width: 100%;">
-      <el-table-column label="字典主键" align="center" prop="dictId" />
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:dict:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:dict:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:dict:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:dict:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="字典编号" align="center" prop="dictId" />
       <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
-      <el-table-column label="字典类型" align="center">
+      <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
         <template slot-scope="scope">
           <router-link :to="'/dict/type/data/' + scope.row.dictId" class="link-type">
             <span>{{ scope.row.dictType }}</span>
@@ -74,10 +116,10 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button 
-            size="mini" 
-            type="text" 
-            icon="el-icon-edit" 
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['system:dict:edit']"
           >修改</el-button>
@@ -131,13 +173,19 @@
 </template>
 
 <script>
-import { listType, getType, delType, addType, updateType } from "@/api/system/dict/type";
+import { listType, getType, delType, addType, updateType, exportType } from "@/api/system/dict/type";
 
 export default {
   data() {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 字典表格数据
@@ -181,8 +229,7 @@ export default {
     /** 查询字典类型列表 */
     getList() {
       this.loading = true;
-      listType(this.addDateRange(this.queryParams, this.dateRange)).then(
-        response => {
+      listType(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
           this.typeList = response.rows;
           this.total = response.total;
           this.loading = false;
@@ -214,16 +261,29 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
       this.open = true;
       this.title = "添加字典类型";
     },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.dictId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
-      getType(row.dictId).then(response => {
+      const dictId = row.dictId || this.ids
+      getType(dictId).then(response => {
         this.form = response.data;
         this.open = true;
         this.title = "修改字典类型";
@@ -259,16 +319,30 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除名称为"' + row.dictName + '"的数据项?', "警告", {
+      const dictIds = row.dictId || this.ids;
+      this.$confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delType(row.dictId);
+          return delType(dictIds);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");
         }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有类型数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportType(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
     }
   }
 };

+ 67 - 15
ruoyi-ui/src/views/system/notice/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true" label-width="68px">
-      <el-form-item label="公告标题">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+      <el-form-item label="公告标题" prop="noticeTitle">
         <el-input
           v-model="queryParams.noticeTitle"
           placeholder="请输入公告标题"
@@ -10,7 +10,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="操作人员">
+      <el-form-item label="操作人员" prop="createBy">
         <el-input
           v-model="queryParams.createBy"
           placeholder="请输入操作人员"
@@ -19,7 +19,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="类型">
+      <el-form-item label="类型" prop="noticeType">
         <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable size="small">
           <el-option
             v-for="dict in typeOptions"
@@ -31,11 +31,44 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:notice:add']">新增</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
-    <el-table v-loading="loading" :data="noticeList">
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:notice:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:notice:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:notice:remove']"
+        >删除</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="序号" align="center" prop="noticeId" width="100" />
       <el-table-column
         label="公告标题"
@@ -65,10 +98,10 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button 
-            size="mini" 
-            type="text" 
-            icon="el-icon-edit" 
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['system:notice:edit']"
           >修改</el-button>
@@ -125,7 +158,7 @@
           </el-col>
           <el-col :span="24">
             <el-form-item label="内容">
-               <Editor v-model="form.noticeContent"/>
+              <Editor v-model="form.noticeContent" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -139,7 +172,7 @@
 </template>
 
 <script>
-import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
+import { listNotice, getNotice, delNotice, addNotice, updateNotice, exportNotice } from "@/api/system/notice";
 import Editor from '@/components/Editor';
 
 export default {
@@ -150,6 +183,12 @@ export default {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 公告表格数据
@@ -231,6 +270,17 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.noticeId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
@@ -240,7 +290,8 @@ export default {
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
-      getNotice(row.noticeId).then(response => {
+      const noticeId = row.noticeId || this.ids
+      getNotice(noticeId).then(response => {
         this.form = response.data;
         this.open = true;
         this.title = "修改公告";
@@ -276,12 +327,13 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除公告标题为"' + row.noticeTitle + '"的数据项?', "警告", {
+      const noticeIds = row.noticeId || this.ids
+      this.$confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delNotice(row.noticeId);
+          return delNotice(noticeIds);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");

+ 89 - 15
ruoyi-ui/src/views/system/post/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true" label-width="68px">
-      <el-form-item label="岗位编码">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+      <el-form-item label="岗位编码" prop="postCode">
         <el-input
           v-model="queryParams.postCode"
           placeholder="请输入岗位编码"
@@ -10,7 +10,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="岗位名称">
+      <el-form-item label="岗位名称" prop="postName">
         <el-input
           v-model="queryParams.postName"
           placeholder="请输入岗位名称"
@@ -19,7 +19,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="状态">
+      <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="岗位状态" clearable size="small">
           <el-option
             v-for="dict in statusOptions"
@@ -31,11 +31,53 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:post:add']">新增</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
-    <el-table v-loading="loading" :data="postList">
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:post:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:post:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:post:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:post:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="岗位编号" align="center" prop="postId" />
       <el-table-column label="岗位编码" align="center" prop="postCode" />
       <el-table-column label="岗位名称" align="center" prop="postName" />
@@ -48,10 +90,10 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button 
-            size="mini" 
-            type="text" 
-            icon="el-icon-edit" 
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
             v-hasPermi="['system:post:edit']"
           >修改</el-button>
@@ -65,7 +107,7 @@
         </template>
       </el-table-column>
     </el-table>
-
+    
     <pagination
       v-show="total>0"
       :total="total"
@@ -108,13 +150,19 @@
 </template>
 
 <script>
-import { listPost, getPost, delPost, addPost, updatePost } from "@/api/system/post";
+import { listPost, getPost, delPost, addPost, updatePost, exportPost } from "@/api/system/post";
 
 export default {
   data() {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 岗位表格数据
@@ -191,6 +239,17 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.postId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
@@ -200,7 +259,8 @@ export default {
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
-      getPost(row.postId).then(response => {
+      const postId = row.postId || this.ids
+      getPost(postId).then(response => {
         this.form = response.data;
         this.open = true;
         this.title = "修改岗位";
@@ -236,16 +296,30 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除岗位名称为"' + row.postName + '"的数据项?', "警告", {
+      const postIds = row.postId || this.ids;
+      this.$confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delPost(row.postId);
+          return delPost(postIds);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");
         }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有岗位数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportPost(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
     }
   }
 };

+ 84 - 15
ruoyi-ui/src/views/system/role/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
-    <el-form :inline="true">
-      <el-form-item label="角色名称">
+    <el-form :model="queryParams" ref="queryForm" :inline="true">
+      <el-form-item label="角色名称" prop="roleName">
         <el-input
           v-model="queryParams.roleName"
           placeholder="请输入角色名称"
@@ -11,7 +11,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="权限字符">
+      <el-form-item label="权限字符" prop="roleKey">
         <el-input
           v-model="queryParams.roleKey"
           placeholder="请输入权限字符"
@@ -21,7 +21,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="状态">
+      <el-form-item label="状态" prop="status">
         <el-select
           v-model="queryParams.status"
           placeholder="角色状态"
@@ -51,6 +51,12 @@
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
         <el-button
           type="primary"
           icon="el-icon-plus"
@@ -58,15 +64,45 @@
           @click="handleAdd"
           v-hasPermi="['system:role:add']"
         >新增</el-button>
-      </el-form-item>
-    </el-form>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:role:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:role:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:post:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
 
-    <el-table v-loading="loading" :data="roleList">
+    <el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="角色编号" prop="roleId" width="120" />
       <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
-      <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="180" />
-      <el-table-column label="显示顺序" prop="roleSort" width="120" />
-      <el-table-column label="状态" align="center" width="120">
+      <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
+      <el-table-column label="显示顺序" prop="roleSort" width="100" />
+      <el-table-column label="状态" align="center" width="100">
         <template slot-scope="scope">
           <el-switch
             v-model="scope.row.status"
@@ -197,7 +233,7 @@
 </template>
 
 <script>
-import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus } from "@/api/system/role";
+import { listRole, getRole, delRole, addRole, updateRole, exportRole, dataScope, changeRoleStatus } from "@/api/system/role";
 import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu";
 import { treeselect as deptTreeselect, roleDeptTreeselect } from "@/api/system/dept";
 
@@ -206,6 +242,12 @@ export default {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 角色表格数据
@@ -384,6 +426,18 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.roleId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
@@ -394,10 +448,11 @@ export default {
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
+      const roleId = row.roleId || this.ids
       this.$nextTick(() => {
-        this.getRoleMenuTreeselect(row.roleId);
+        this.getRoleMenuTreeselect(roleId);
       });
-      getRole(row.roleId).then(response => {
+      getRole(roleId).then(response => {
         this.form = response.data;
         this.open = true;
         this.title = "修改角色";
@@ -462,16 +517,30 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除名称为"' + row.roleName + '"的数据项?', "警告", {
+      const roleIds = row.roleId || this.ids;
+      this.$confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delRole(row.roleId);
+          return delRole(roleIds);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");
         }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有角色数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportRole(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
     }
   }
 };

+ 85 - 10
ruoyi-ui/src/views/system/user/index.vue

@@ -27,8 +27,8 @@
       </el-col>
       <!--用户数据-->
       <el-col :span="20" :xs="24">
-        <el-form :inline="true" label-width="68px">
-          <el-form-item label="用户名称">
+        <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+          <el-form-item label="用户名称" prop="userName">
             <el-input
               v-model="queryParams.userName"
               placeholder="请输入用户名称"
@@ -38,7 +38,7 @@
               @keyup.enter.native="handleQuery"
             />
           </el-form-item>
-          <el-form-item label="手机号码">
+          <el-form-item label="手机号码" prop="phonenumber">
             <el-input
               v-model="queryParams.phonenumber"
               placeholder="请输入手机号码"
@@ -48,7 +48,7 @@
               @keyup.enter.native="handleQuery"
             />
           </el-form-item>
-          <el-form-item label="状态">
+          <el-form-item label="状态" prop="status">
             <el-select
               v-model="queryParams.status"
               placeholder="用户状态"
@@ -78,11 +78,53 @@
           </el-form-item>
           <el-form-item>
             <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-            <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
           </el-form-item>
         </el-form>
 
-        <el-table v-loading="loading" :data="userList">
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button
+              type="primary"
+              icon="el-icon-plus"
+              size="mini"
+              @click="handleAdd"
+              v-hasPermi="['system:user:add']"
+            >新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              type="success"
+              icon="el-icon-edit"
+              size="mini"
+              :disabled="single"
+              @click="handleUpdate"
+              v-hasPermi="['system:user:edit']"
+            >修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              type="danger"
+              icon="el-icon-delete"
+              size="mini"
+              :disabled="multiple"
+              @click="handleDelete"
+              v-hasPermi="['system:user:remove']"
+            >删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              type="warning"
+              icon="el-icon-download"
+              size="mini"
+              @click="handleExport"
+              v-hasPermi="['system:user:export']"
+            >导出</el-button>
+          </el-col>
+        </el-row>
+
+        <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="40" align="center" />
           <el-table-column label="用户编号" align="center" prop="userId" />
           <el-table-column label="用户名称" align="center" prop="userName" />
           <el-table-column label="用户昵称" align="center" prop="nickName" />
@@ -246,7 +288,7 @@
 </template>
 
 <script>
-import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus } from "@/api/system/user";
+import { listUser, getUser, delUser, addUser, updateUser, exportUser, resetUserPwd, changeUserStatus } from "@/api/system/user";
 import { treeselect } from "@/api/system/dept";
 import { listPost } from "@/api/system/post";
 import { listRole } from "@/api/system/role";
@@ -259,6 +301,12 @@ export default {
     return {
       // 遮罩层
       loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
       // 总条数
       total: 0,
       // 用户表格数据
@@ -430,6 +478,18 @@ export default {
       this.queryParams.page = 1;
       this.getList();
     },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.userId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
@@ -446,7 +506,8 @@ export default {
       this.getTreeselect();
       this.getPosts();
       this.getRoles();
-      getUser(row.userId).then(response => {
+      const userId = row.userId || this.ids
+      getUser(userId).then(response => {
         this.form = response.data;
         this.form.postIds = response.postIds;
         this.form.roleIds = response.roleIds;
@@ -500,16 +561,30 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除名称为"' + row.userName + '"的数据项?', "警告", {
+      const userIds = row.userId || this.ids;
+      this.$confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          return delUser(row.userId);
+          return delUser(userIds);
         }).then(() => {
           this.getList();
           this.msgSuccess("删除成功");
         }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有用户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportUser(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
     }
   }
 };

+ 1 - 1
ruoyi-ui/vue.config.js

@@ -17,7 +17,7 @@ module.exports = {
   // 部署生产环境和开发环境下的URL。
   // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
   // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
-  publicPath: process.env.NODE_ENV === "production" ? "./" : "/",
+  publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
   // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
   outputDir: 'dist',
   // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)

+ 9 - 1
ruoyi/pom.xml

@@ -5,7 +5,7 @@
 
 	<groupId>com.ruoyi</groupId>
 	<artifactId>ruoyi</artifactId>
-	<version>1.0</version>
+	<version>1.1</version>
 	<packaging>jar</packaging>
 
 	<name>ruoyi</name>
@@ -32,6 +32,7 @@
 		<bitwalker.version>1.19</bitwalker.version>
 		<jwt.version>0.9.0</jwt.version>
 		<swagger.version>2.9.2</swagger.version>
+		<poi.version>3.17</poi.version>
 		<oshi.version>3.9.1</oshi.version>
 	</properties>
 
@@ -223,6 +224,13 @@
 			<groupId>net.java.dev.jna</groupId>
 			<artifactId>jna-platform</artifactId>
 		</dependency>
+		
+		<!-- excel工具 -->
+		<dependency>
+			<groupId>org.apache.poi</groupId>
+			<artifactId>poi-ooxml</artifactId>
+			<version>${poi.version}</version>
+		</dependency>
 
 	</dependencies>
 

+ 10 - 30
ruoyi/sql/ry_20191008.sql → ruoyi/sql/ry_20191111.sql

@@ -136,7 +136,7 @@ create table sys_menu (
   path              varchar(200)    default ''                 comment '路由地址',
   component         varchar(255)    default null               comment '组件路径',
   is_frame          int(1)          default 1                  comment '是否为外链(0是 1否)',
-  menu_type         char(1)         default ''                 comment '菜单类型(0目录 1菜单 2按钮)',
+  menu_type         char(1)         default ''                 comment '菜单类型(M目录 C菜单 F按钮)',
   visible           char(1)         default 0                  comment '菜单状态(0显示 1隐藏)',
   perms             varchar(100)    default null               comment '权限标识',
   icon              varchar(100)    default '#'                comment '菜单图标',
@@ -152,10 +152,10 @@ create table sys_menu (
 -- 初始化-菜单信息表数据
 -- ----------------------------
 -- 一级菜单
-insert into sys_menu values('1', '系统管理', '0', '1', 'system',   null,  1, 'M', '0', '', 'system',   'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统管理目录');
-insert into sys_menu values('2', '系统监控', '0', '2', 'monitor',  null,  1, 'M', '0', '', 'monitor',  'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统监控目录');
-insert into sys_menu values('3', '系统工具', '0', '3', 'tool',     null,  1, 'M', '0', '', 'tool',     'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统工具目录');
-INSERT INTO sys_menu VALUES('4', '若依官网', '0', '4', 'http://ruoyi.vip',  NULL ,  0, 'M', '0', '', 'guide',     'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '若依官网');
+insert into sys_menu values('1', '系统管理', '0', '1', 'system',           null,   1, 'M', '0', '', 'system',   'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统管理目录');
+insert into sys_menu values('2', '系统监控', '0', '2', 'monitor',          null,   1, 'M', '0', '', 'monitor',  'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统监控目录');
+insert into sys_menu values('3', '系统工具', '0', '3', 'tool',             null,   1, 'M', '0', '', 'tool',     'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统工具目录');
+insert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', null ,  0, 'M', '0', '', 'guide',    'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '若依官网地址');
 -- 二级菜单
 insert into sys_menu values('100',  '用户管理', '1',   '1', 'user',       'system/user/index',        1, 'C', '0', 'system:user:list',        'user',          'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '用户管理菜单');
 insert into sys_menu values('101',  '角色管理', '1',   '2', 'role',       'system/role/index',        1, 'C', '0', 'system:role:list',        'peoples',       'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '角色管理菜单');
@@ -550,27 +550,7 @@ create table sys_logininfor (
 
 
 -- ----------------------------
--- 15、在线用户记录
--- ----------------------------
-drop table if exists sys_user_online;
-create table sys_user_online (
-  sessionId         varchar(50)   default ''                comment '用户会话id',
-  user_name         varchar(50)   default ''                comment '用户账号',
-  dept_name         varchar(50)   default ''                comment '部门名称',
-  ipaddr            varchar(50)   default ''                comment '登录IP地址',
-  login_location    varchar(255)  default ''                comment '登录地点',
-  browser           varchar(50)   default ''                comment '浏览器类型',
-  os                varchar(50)   default ''                comment '操作系统',
-  status            varchar(10)   default ''                comment '在线状态on_line在线off_line离线',
-  start_timestamp   datetime                                comment 'session创建时间',
-  last_access_time  datetime                                comment 'session最后访问时间',
-  expire_time       int(5)        default 0                 comment '超时时间,单位为分钟',
-  primary key (sessionId)
-) engine=innodb comment = '在线用户记录';
-
-
--- ----------------------------
--- 16、定时任务调度表
+-- 15、定时任务调度表
 -- ----------------------------
 drop table if exists sys_job;
 create table sys_job (
@@ -596,7 +576,7 @@ insert into sys_job values(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryM
 
 
 -- ----------------------------
--- 17、定时任务调度日志表
+-- 16、定时任务调度日志表
 -- ----------------------------
 drop table if exists sys_job_log;
 create table sys_job_log (
@@ -613,7 +593,7 @@ create table sys_job_log (
 
 
 -- ----------------------------
--- 18、通知公告表
+-- 17、通知公告表
 -- ----------------------------
 drop table if exists sys_notice;
 create table sys_notice (
@@ -638,7 +618,7 @@ insert into sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨
 
 
 -- ----------------------------
--- 19、代码生成业务表
+-- 18、代码生成业务表
 -- ----------------------------
 drop table if exists gen_table;
 create table gen_table (
@@ -663,7 +643,7 @@ create table gen_table (
 
 
 -- ----------------------------
--- 20、代码生成业务表字段
+-- 19、代码生成业务表字段
 -- ----------------------------
 drop table if exists gen_table_column;
 create table gen_table_column (

+ 872 - 0
ruoyi/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java

@@ -0,0 +1,872 @@
+package com.ruoyi.common.utils.poi;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.Type;
+import com.ruoyi.framework.aspectj.lang.annotation.Excels;
+import com.ruoyi.framework.config.RuoYiConfig;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.reflect.ReflectUtils;
+
+/**
+ * Excel相关处理
+ * 
+ * @author ruoyi
+ */
+public class ExcelUtil<T>
+{
+    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
+
+    /**
+     * Excel sheet最大行数,默认65536
+     */
+    public static final int sheetSize = 65536;
+
+    /**
+     * 工作表名称
+     */
+    private String sheetName;
+
+    /**
+     * 导出类型(EXPORT:导出数据;IMPORT:导入模板)
+     */
+    private Type type;
+
+    /**
+     * 工作薄对象
+     */
+    private Workbook wb;
+
+    /**
+     * 工作表对象
+     */
+    private Sheet sheet;
+
+    /**
+     * 样式列表
+     */
+    private Map<String, CellStyle> styles;
+
+    /**
+     * 导入导出数据列表
+     */
+    private List<T> list;
+
+    /**
+     * 注解列表
+     */
+    private List<Object[]> fields;
+
+    /**
+     * 实体对象
+     */
+    public Class<T> clazz;
+
+    public ExcelUtil(Class<T> clazz)
+    {
+        this.clazz = clazz;
+    }
+
+    public void init(List<T> list, String sheetName, Type type)
+    {
+        if (list == null)
+        {
+            list = new ArrayList<T>();
+        }
+        this.list = list;
+        this.sheetName = sheetName;
+        this.type = type;
+        createExcelField();
+        createWorkbook();
+    }
+
+    /**
+     * 对excel表单默认第一个索引名转换成list
+     * 
+     * @param is 输入流
+     * @return 转换后集合
+     */
+    public List<T> importExcel(InputStream is) throws Exception
+    {
+        return importExcel(StringUtils.EMPTY, is);
+    }
+
+    /**
+     * 对excel表单指定表格索引名转换成list
+     * 
+     * @param sheetName 表格索引名
+     * @param is 输入流
+     * @return 转换后集合
+     */
+    public List<T> importExcel(String sheetName, InputStream is) throws Exception
+    {
+        this.type = Type.IMPORT;
+        this.wb = WorkbookFactory.create(is);
+        List<T> list = new ArrayList<T>();
+        Sheet sheet = null;
+        if (StringUtils.isNotEmpty(sheetName))
+        {
+            // 如果指定sheet名,则取指定sheet中的内容.
+            sheet = wb.getSheet(sheetName);
+        }
+        else
+        {
+            // 如果传入的sheet名不存在则默认指向第1个sheet.
+            sheet = wb.getSheetAt(0);
+        }
+
+        if (sheet == null)
+        {
+            throw new IOException("文件sheet不存在");
+        }
+
+        int rows = sheet.getPhysicalNumberOfRows();
+
+        if (rows > 0)
+        {
+            // 定义一个map用于存放excel列的序号和field.
+            Map<String, Integer> cellMap = new HashMap<String, Integer>();
+            // 获取表头
+            Row heard = sheet.getRow(0);
+            for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
+            {
+                Cell cell = heard.getCell(i);
+                if (StringUtils.isNotNull(cell != null))
+                {
+                    String value = this.getCellValue(heard, i).toString();
+                    cellMap.put(value, i);
+                }
+                else
+                {
+                    cellMap.put(null, i);
+                }
+            }
+            // 有数据时才处理 得到类的所有field.
+            Field[] allFields = clazz.getDeclaredFields();
+            // 定义一个map用于存放列的序号和field.
+            Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
+            for (int col = 0; col < allFields.length; col++)
+            {
+                Field field = allFields[col];
+                Excel attr = field.getAnnotation(Excel.class);
+                if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
+                {
+                    // 设置类的私有字段属性可访问.
+                    field.setAccessible(true);
+                    Integer column = cellMap.get(attr.name());
+                    fieldsMap.put(column, field);
+                }
+            }
+            for (int i = 1; i < rows; i++)
+            {
+                // 从第2行开始取数据,默认第一行是表头.
+                Row row = sheet.getRow(i);
+                T entity = null;
+                for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet())
+                {
+                    Object val = this.getCellValue(row, entry.getKey());
+
+                    // 如果不存在实例则新建.
+                    entity = (entity == null ? clazz.newInstance() : entity);
+                    // 从map中得到对应列的field.
+                    Field field = fieldsMap.get(entry.getKey());
+                    // 取得类型,并根据对象类型设置值.
+                    Class<?> fieldType = field.getType();
+                    if (String.class == fieldType)
+                    {
+                        String s = Convert.toStr(val);
+                        if (StringUtils.endsWith(s, ".0"))
+                        {
+                            val = StringUtils.substringBefore(s, ".0");
+                        }
+                        else
+                        {
+                            val = Convert.toStr(val);
+                        }
+                    }
+                    else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType))
+                    {
+                        val = Convert.toInt(val);
+                    }
+                    else if ((Long.TYPE == fieldType) || (Long.class == fieldType))
+                    {
+                        val = Convert.toLong(val);
+                    }
+                    else if ((Double.TYPE == fieldType) || (Double.class == fieldType))
+                    {
+                        val = Convert.toDouble(val);
+                    }
+                    else if ((Float.TYPE == fieldType) || (Float.class == fieldType))
+                    {
+                        val = Convert.toFloat(val);
+                    }
+                    else if (BigDecimal.class == fieldType)
+                    {
+                        val = Convert.toBigDecimal(val);
+                    }
+                    else if (Date.class == fieldType)
+                    {
+                        if (val instanceof String)
+                        {
+                            val = DateUtils.parseDate(val);
+                        }
+                        else if (val instanceof Double)
+                        {
+                            val = DateUtil.getJavaDate((Double) val);
+                        }
+                    }
+                    if (StringUtils.isNotNull(fieldType))
+                    {
+                        Excel attr = field.getAnnotation(Excel.class);
+                        String propertyName = field.getName();
+                        if (StringUtils.isNotEmpty(attr.targetAttr()))
+                        {
+                            propertyName = field.getName() + "." + attr.targetAttr();
+                        }
+                        else if (StringUtils.isNotEmpty(attr.readConverterExp()))
+                        {
+                            val = reverseByExp(String.valueOf(val), attr.readConverterExp());
+                        }
+                        ReflectUtils.invokeSetter(entity, propertyName, val);
+                    }
+                }
+                list.add(entity);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @return 结果
+     */
+    public AjaxResult exportExcel(List<T> list, String sheetName)
+    {
+        this.init(list, sheetName, Type.EXPORT);
+        return exportExcel();
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param sheetName 工作表的名称
+     * @return 结果
+     */
+    public AjaxResult importTemplateExcel(String sheetName)
+    {
+        this.init(null, sheetName, Type.IMPORT);
+        return exportExcel();
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @return 结果
+     */
+    public AjaxResult exportExcel()
+    {
+        OutputStream out = null;
+        try
+        {
+            // 取出一共有多少个sheet.
+            double sheetNo = Math.ceil(list.size() / sheetSize);
+            for (int index = 0; index <= sheetNo; index++)
+            {
+                createSheet(sheetNo, index);
+
+                // 产生一行
+                Row row = sheet.createRow(0);
+                int column = 0;
+                // 写入各个字段的列头名称
+                for (Object[] os : fields)
+                {
+                    Excel excel = (Excel) os[1];
+                    this.createCell(excel, row, column++);
+                }
+                if (Type.EXPORT.equals(type))
+                {
+                    fillExcelData(index, row);
+                }
+            }
+            String filename = encodingFilename(sheetName);
+            out = new FileOutputStream(getAbsoluteFile(filename));
+            wb.write(out);
+            return AjaxResult.success(filename);
+        }
+        catch (Exception e)
+        {
+            log.error("导出Excel异常{}", e.getMessage());
+            throw new CustomException("导出Excel失败,请联系网站管理员!");
+        }
+        finally
+        {
+            if (wb != null)
+            {
+                try
+                {
+                    wb.close();
+                }
+                catch (IOException e1)
+                {
+                    e1.printStackTrace();
+                }
+            }
+            if (out != null)
+            {
+                try
+                {
+                    out.close();
+                }
+                catch (IOException e1)
+                {
+                    e1.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * 填充excel数据
+     * 
+     * @param index 序号
+     * @param row 单元格行
+     */
+    public void fillExcelData(int index, Row row)
+    {
+        int startNo = index * sheetSize;
+        int endNo = Math.min(startNo + sheetSize, list.size());
+        for (int i = startNo; i < endNo; i++)
+        {
+            row = sheet.createRow(i + 1 - startNo);
+            // 得到导出对象.
+            T vo = (T) list.get(i);
+            int column = 0;
+            for (Object[] os : fields)
+            {
+                Field field = (Field) os[0];
+                Excel excel = (Excel) os[1];
+                // 设置实体类私有属性可访问
+                field.setAccessible(true);
+                this.addCell(excel, row, vo, field, column++);
+            }
+        }
+    }
+
+    /**
+     * 创建表格样式
+     * 
+     * @param wb 工作薄对象
+     * @return 样式列表
+     */
+    private Map<String, CellStyle> createStyles(Workbook wb)
+    {
+        // 写入各条记录,每条记录对应excel表中的一行
+        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
+        CellStyle style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.THIN);
+        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        Font dataFont = wb.createFont();
+        dataFont.setFontName("Arial");
+        dataFont.setFontHeightInPoints((short) 10);
+        style.setFont(dataFont);
+        styles.put("data", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        Font headerFont = wb.createFont();
+        headerFont.setFontName("Arial");
+        headerFont.setFontHeightInPoints((short) 10);
+        headerFont.setBold(true);
+        headerFont.setColor(IndexedColors.WHITE.getIndex());
+        style.setFont(headerFont);
+        styles.put("header", style);
+
+        return styles;
+    }
+
+    /**
+     * 创建单元格
+     */
+    public Cell createCell(Excel attr, Row row, int column)
+    {
+        // 创建列
+        Cell cell = row.createCell(column);
+        // 写入列信息
+        cell.setCellValue(attr.name());
+        setDataValidation(attr, row, column);
+        cell.setCellStyle(styles.get("header"));
+        return cell;
+    }
+
+    /**
+     * 设置单元格信息
+     * 
+     * @param value 单元格值
+     * @param attr 注解相关
+     * @param cell 单元格信息
+     */
+    public void setCellVo(Object value, Excel attr, Cell cell)
+    {
+        if (ColumnType.STRING == attr.cellType())
+        {
+            cell.setCellType(CellType.NUMERIC);
+            cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
+        }
+        else if (ColumnType.NUMERIC == attr.cellType())
+        {
+            cell.setCellType(CellType.NUMERIC);
+            cell.setCellValue(Integer.parseInt(value + ""));
+        }
+    }
+
+    /**
+     * 创建表格样式
+     */
+    public void setDataValidation(Excel attr, Row row, int column)
+    {
+        if (attr.name().indexOf("注:") >= 0)
+        {
+            sheet.setColumnWidth(column, 6000);
+        }
+        else
+        {
+            // 设置列宽
+            sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
+            row.setHeight((short) (attr.height() * 20));
+        }
+        // 如果设置了提示信息则鼠标放上去提示.
+        if (StringUtils.isNotEmpty(attr.prompt()))
+        {
+            // 这里默认设了2-101列提示.
+            setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column);
+        }
+        // 如果设置了combo属性则本列只能选择不能输入
+        if (attr.combo().length > 0)
+        {
+            // 这里默认设了2-101列只能选择不能输入.
+            setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
+        }
+    }
+
+    /**
+     * 添加单元格
+     */
+    public Cell addCell(Excel attr, Row row, T vo, Field field, int column)
+    {
+        Cell cell = null;
+        try
+        {
+            // 设置行高
+            row.setHeight((short) (attr.height() * 20));
+            // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
+            if (attr.isExport())
+            {
+                // 创建cell
+                cell = row.createCell(column);
+                cell.setCellStyle(styles.get("data"));
+
+                // 用于读取对象中的属性
+                Object value = getTargetValue(vo, field, attr);
+                String dateFormat = attr.dateFormat();
+                String readConverterExp = attr.readConverterExp();
+                if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
+                {
+                    cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
+                }
+                else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
+                {
+                    cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp));
+                }
+                else
+                {
+                    // 设置列类型
+                    setCellVo(value, attr, cell);
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            log.error("导出Excel失败{}", e);
+        }
+        return cell;
+    }
+
+    /**
+     * 设置 POI XSSFSheet 单元格提示
+     * 
+     * @param sheet 表单
+     * @param promptTitle 提示标题
+     * @param promptContent 提示内容
+     * @param firstRow 开始行
+     * @param endRow 结束行
+     * @param firstCol 开始列
+     * @param endCol 结束列
+     */
+    public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,
+            int firstCol, int endCol)
+    {
+        DataValidationHelper helper = sheet.getDataValidationHelper();
+        DataValidationConstraint constraint = helper.createCustomConstraint("DD1");
+        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
+        DataValidation dataValidation = helper.createValidation(constraint, regions);
+        dataValidation.createPromptBox(promptTitle, promptContent);
+        dataValidation.setShowPromptBox(true);
+        sheet.addValidationData(dataValidation);
+    }
+
+    /**
+     * 设置某些列的值只能输入预制的数据,显示下拉框.
+     * 
+     * @param sheet 要设置的sheet.
+     * @param textlist 下拉框显示的内容
+     * @param firstRow 开始行
+     * @param endRow 结束行
+     * @param firstCol 开始列
+     * @param endCol 结束列
+     * @return 设置好的sheet.
+     */
+    public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol)
+    {
+        DataValidationHelper helper = sheet.getDataValidationHelper();
+        // 加载下拉列表内容
+        DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);
+        // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
+        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
+        // 数据有效性对象
+        DataValidation dataValidation = helper.createValidation(constraint, regions);
+        // 处理Excel兼容性问题
+        if (dataValidation instanceof XSSFDataValidation)
+        {
+            dataValidation.setSuppressDropDownArrow(true);
+            dataValidation.setShowErrorBox(true);
+        }
+        else
+        {
+            dataValidation.setSuppressDropDownArrow(false);
+        }
+
+        sheet.addValidationData(dataValidation);
+    }
+
+    /**
+     * 解析导出值 0=男,1=女,2=未知
+     * 
+     * @param propertyValue 参数值
+     * @param converterExp 翻译注解
+     * @return 解析后值
+     * @throws Exception
+     */
+    public static String convertByExp(String propertyValue, String converterExp) throws Exception
+    {
+        try
+        {
+            String[] convertSource = converterExp.split(",");
+            for (String item : convertSource)
+            {
+                String[] itemArray = item.split("=");
+                if (itemArray[0].equals(propertyValue))
+                {
+                    return itemArray[1];
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            throw e;
+        }
+        return propertyValue;
+    }
+
+    /**
+     * 反向解析值 男=0,女=1,未知=2
+     * 
+     * @param propertyValue 参数值
+     * @param converterExp 翻译注解
+     * @return 解析后值
+     * @throws Exception
+     */
+    public static String reverseByExp(String propertyValue, String converterExp) throws Exception
+    {
+        try
+        {
+            String[] convertSource = converterExp.split(",");
+            for (String item : convertSource)
+            {
+                String[] itemArray = item.split("=");
+                if (itemArray[1].equals(propertyValue))
+                {
+                    return itemArray[0];
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            throw e;
+        }
+        return propertyValue;
+    }
+
+    /**
+     * 编码文件名
+     */
+    public String encodingFilename(String filename)
+    {
+        filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
+        return filename;
+    }
+
+    /**
+     * 获取下载路径
+     * 
+     * @param filename 文件名称
+     */
+    public String getAbsoluteFile(String filename)
+    {
+        String downloadPath = RuoYiConfig.getDownloadPath() + filename;
+        File desc = new File(downloadPath);
+        if (!desc.getParentFile().exists())
+        {
+            desc.getParentFile().mkdirs();
+        }
+        return downloadPath;
+    }
+
+    /**
+     * 获取bean中的属性值
+     * 
+     * @param vo 实体对象
+     * @param field 字段
+     * @param excel 注解
+     * @return 最终的属性值
+     * @throws Exception
+     */
+    private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
+    {
+        Object o = field.get(vo);
+        if (StringUtils.isNotEmpty(excel.targetAttr()))
+        {
+            String target = excel.targetAttr();
+            if (target.indexOf(".") > -1)
+            {
+                String[] targets = target.split("[.]");
+                for (String name : targets)
+                {
+                    o = getValue(o, name);
+                }
+            }
+            else
+            {
+                o = getValue(o, target);
+            }
+        }
+        return o;
+    }
+
+    /**
+     * 以类的属性的get方法方法形式获取值
+     * 
+     * @param o
+     * @param name
+     * @return value
+     * @throws Exception
+     */
+    private Object getValue(Object o, String name) throws Exception
+    {
+        if (StringUtils.isNotEmpty(name))
+        {
+            Class<?> clazz = o.getClass();
+            String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
+            Method method = clazz.getMethod(methodName);
+            o = method.invoke(o);
+        }
+        return o;
+    }
+
+    /**
+     * 得到所有定义字段
+     */
+    private void createExcelField()
+    {
+        this.fields = new ArrayList<Object[]>();
+        List<Field> tempFields = new ArrayList<>();
+        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
+        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
+        for (Field field : tempFields)
+        {
+            // 单注解
+            if (field.isAnnotationPresent(Excel.class))
+            {
+                putToField(field, field.getAnnotation(Excel.class));
+            }
+
+            // 多注解
+            if (field.isAnnotationPresent(Excels.class))
+            {
+                Excels attrs = field.getAnnotation(Excels.class);
+                Excel[] excels = attrs.value();
+                for (Excel excel : excels)
+                {
+                    putToField(field, excel);
+                }
+            }
+        }
+    }
+
+    /**
+     * 放到字段集合中
+     */
+    private void putToField(Field field, Excel attr)
+    {
+        if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
+        {
+            this.fields.add(new Object[] { field, attr });
+        }
+    }
+
+    /**
+     * 创建一个工作簿
+     */
+    public void createWorkbook()
+    {
+        this.wb = new SXSSFWorkbook(500);
+    }
+
+    /**
+     * 创建工作表
+     * 
+     * @param sheetNo sheet数量
+     * @param index 序号
+     */
+    public void createSheet(double sheetNo, int index)
+    {
+        this.sheet = wb.createSheet();
+        this.styles = createStyles(wb);
+        // 设置工作表的名称.
+        if (sheetNo == 0)
+        {
+            wb.setSheetName(index, sheetName);
+        }
+        else
+        {
+            wb.setSheetName(index, sheetName + index);
+        }
+    }
+
+    /**
+     * 获取单元格值
+     * 
+     * @param row 获取的行
+     * @param column 获取单元格列号
+     * @return 单元格值
+     */
+    public Object getCellValue(Row row, int column)
+    {
+        if (row == null)
+        {
+            return row;
+        }
+        Object val = "";
+        try
+        {
+            Cell cell = row.getCell(column);
+            if (cell != null)
+            {
+                if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA)
+                {
+                    val = cell.getNumericCellValue();
+                    if (HSSFDateUtil.isCellDateFormatted(cell))
+                    {
+                        val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
+                    }
+                    else
+                    {
+                        if ((Double) val % 1 > 0)
+                        {
+                            val = new DecimalFormat("0.00").format(val);
+                        }
+                        else
+                        {
+                            val = new DecimalFormat("0").format(val);
+                        }
+                    }
+                }
+                else if (cell.getCellTypeEnum() == CellType.STRING)
+                {
+                    val = cell.getStringCellValue();
+                }
+                else if (cell.getCellTypeEnum() == CellType.BOOLEAN)
+                {
+                    val = cell.getBooleanCellValue();
+                }
+                else if (cell.getCellTypeEnum() == CellType.ERROR)
+                {
+                    val = cell.getErrorCellValue();
+                }
+
+            }
+        }
+        catch (Exception e)
+        {
+            return val;
+        }
+        return val;
+    }
+}

+ 406 - 0
ruoyi/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java

@@ -0,0 +1,406 @@
+package com.ruoyi.common.utils.reflect;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Date;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.utils.DateUtils;
+
+/**
+ * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
+ * 
+ * @author ruoyi
+ */
+@SuppressWarnings("rawtypes")
+public class ReflectUtils
+{
+    private static final String SETTER_PREFIX = "set";
+
+    private static final String GETTER_PREFIX = "get";
+
+    private static final String CGLIB_CLASS_SEPARATOR = "$$";
+
+    private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
+
+    /**
+     * 调用Getter方法.
+     * 支持多级,如:对象名.对象名.方法
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeGetter(Object obj, String propertyName)
+    {
+        Object object = obj;
+        for (String name : StringUtils.split(propertyName, "."))
+        {
+            String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
+            object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+        }
+        return (E) object;
+    }
+
+    /**
+     * 调用Setter方法, 仅匹配方法名。
+     * 支持多级,如:对象名.对象名.方法
+     */
+    public static <E> void invokeSetter(Object obj, String propertyName, E value)
+    {
+        Object object = obj;
+        String[] names = StringUtils.split(propertyName, ".");
+        for (int i = 0; i < names.length; i++)
+        {
+            if (i < names.length - 1)
+            {
+                String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
+                object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+            }
+            else
+            {
+                String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
+                invokeMethodByName(object, setterMethodName, new Object[] { value });
+            }
+        }
+    }
+
+    /**
+     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E getFieldValue(final Object obj, final String fieldName)
+    {
+        Field field = getAccessibleField(obj, fieldName);
+        if (field == null)
+        {
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            return null;
+        }
+        E result = null;
+        try
+        {
+            result = (E) field.get(obj);
+        }
+        catch (IllegalAccessException e)
+        {
+            logger.error("不可能抛出的异常{}", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
+     */
+    public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
+    {
+        Field field = getAccessibleField(obj, fieldName);
+        if (field == null)
+        {
+            // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            return;
+        }
+        try
+        {
+            field.set(obj, value);
+        }
+        catch (IllegalAccessException e)
+        {
+            logger.error("不可能抛出的异常: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 直接调用对象方法, 无视private/protected修饰符.
+     * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
+     * 同时匹配方法名+参数类型,
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
+            final Object[] args)
+    {
+        if (obj == null || methodName == null)
+        {
+            return null;
+        }
+        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
+        if (method == null)
+        {
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
+            return null;
+        }
+        try
+        {
+            return (E) method.invoke(obj, args);
+        }
+        catch (Exception e)
+        {
+            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
+            throw convertReflectionExceptionToUnchecked(msg, e);
+        }
+    }
+
+    /**
+     * 直接调用对象方法, 无视private/protected修饰符,
+     * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
+     * 只匹配函数名,如果有多个同名函数调用第一个。
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
+    {
+        Method method = getAccessibleMethodByName(obj, methodName, args.length);
+        if (method == null)
+        {
+            // 如果为空不报错,直接返回空。
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
+            return null;
+        }
+        try
+        {
+            // 类型转换(将参数数据类型转换为目标方法参数类型)
+            Class<?>[] cs = method.getParameterTypes();
+            for (int i = 0; i < cs.length; i++)
+            {
+                if (args[i] != null && !args[i].getClass().equals(cs[i]))
+                {
+                    if (cs[i] == String.class)
+                    {
+                        args[i] = Convert.toStr(args[i]);
+                        if (StringUtils.endsWith((String) args[i], ".0"))
+                        {
+                            args[i] = StringUtils.substringBefore((String) args[i], ".0");
+                        }
+                    }
+                    else if (cs[i] == Integer.class)
+                    {
+                        args[i] = Convert.toInt(args[i]);
+                    }
+                    else if (cs[i] == Long.class)
+                    {
+                        args[i] = Convert.toLong(args[i]);
+                    }
+                    else if (cs[i] == Double.class)
+                    {
+                        args[i] = Convert.toDouble(args[i]);
+                    }
+                    else if (cs[i] == Float.class)
+                    {
+                        args[i] = Convert.toFloat(args[i]);
+                    }
+                    else if (cs[i] == Date.class)
+                    {
+                        if (args[i] instanceof String)
+                        {
+                            args[i] = DateUtils.parseDate(args[i]);
+                        }
+                        else
+                        {
+                            args[i] = DateUtil.getJavaDate((Double) args[i]);
+                        }
+                    }
+                }
+            }
+            return (E) method.invoke(obj, args);
+        }
+        catch (Exception e)
+        {
+            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
+            throw convertReflectionExceptionToUnchecked(msg, e);
+        }
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     */
+    public static Field getAccessibleField(final Object obj, final String fieldName)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(fieldName, "fieldName can't be blank");
+        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
+        {
+            try
+            {
+                Field field = superClass.getDeclaredField(fieldName);
+                makeAccessible(field);
+                return field;
+            }
+            catch (NoSuchFieldException e)
+            {
+                continue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     * 匹配函数名+参数类型。
+     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+     */
+    public static Method getAccessibleMethod(final Object obj, final String methodName,
+            final Class<?>... parameterTypes)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(methodName, "methodName can't be blank");
+        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
+        {
+            try
+            {
+                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
+                makeAccessible(method);
+                return method;
+            }
+            catch (NoSuchMethodException e)
+            {
+                continue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     * 只匹配函数名。
+     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+     */
+    public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(methodName, "methodName can't be blank");
+        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
+        {
+            Method[] methods = searchType.getDeclaredMethods();
+            for (Method method : methods)
+            {
+                if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
+                {
+                    makeAccessible(method);
+                    return method;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+     */
+    public static void makeAccessible(Method method)
+    {
+        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
+                && !method.isAccessible())
+        {
+            method.setAccessible(true);
+        }
+    }
+
+    /**
+     * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+     */
+    public static void makeAccessible(Field field)
+    {
+        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
+                || Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
+        {
+            field.setAccessible(true);
+        }
+    }
+
+    /**
+     * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
+     * 如无法找到, 返回Object.class.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Class<T> getClassGenricType(final Class clazz)
+    {
+        return getClassGenricType(clazz, 0);
+    }
+
+    /**
+     * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
+     * 如无法找到, 返回Object.class.
+     */
+    public static Class getClassGenricType(final Class clazz, final int index)
+    {
+        Type genType = clazz.getGenericSuperclass();
+
+        if (!(genType instanceof ParameterizedType))
+        {
+            logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
+            return Object.class;
+        }
+
+        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
+
+        if (index >= params.length || index < 0)
+        {
+            logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+                    + params.length);
+            return Object.class;
+        }
+        if (!(params[index] instanceof Class))
+        {
+            logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
+            return Object.class;
+        }
+
+        return (Class) params[index];
+    }
+
+    public static Class<?> getUserClass(Object instance)
+    {
+        if (instance == null)
+        {
+            throw new RuntimeException("Instance must not be null");
+        }
+        Class clazz = instance.getClass();
+        if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
+        {
+            Class<?> superClass = clazz.getSuperclass();
+            if (superClass != null && !Object.class.equals(superClass))
+            {
+                return superClass;
+            }
+        }
+        return clazz;
+
+    }
+
+    /**
+     * 将反射时的checked exception转换为unchecked exception.
+     */
+    public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
+    {
+        if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
+                || e instanceof NoSuchMethodException)
+        {
+            return new IllegalArgumentException(msg, e);
+        }
+        else if (e instanceof InvocationTargetException)
+        {
+            return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
+        }
+        return new RuntimeException(msg, e);
+    }
+}

+ 113 - 0
ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Excel.java

@@ -0,0 +1,113 @@
+package com.ruoyi.framework.aspectj.lang.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 自定义导出Excel数据注解
+ * 
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel
+{
+    /**
+     * 导出到Excel中的名字.
+     */
+    public String name() default "";
+
+    /**
+     * 日期格式, 如: yyyy-MM-dd
+     */
+    public String dateFormat() default "";
+
+    /**
+     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+     */
+    public String readConverterExp() default "";
+
+    /**
+     * 导出类型(0数字 1字符串)
+     */
+    public ColumnType cellType() default ColumnType.STRING;
+
+    /**
+     * 导出时在excel中每个列的高度 单位为字符
+     */
+    public double height() default 14;
+
+    /**
+     * 导出时在excel中每个列的宽 单位为字符
+     */
+    public double width() default 16;
+
+    /**
+     * 文字后缀,如% 90 变成90%
+     */
+    public String suffix() default "";
+
+    /**
+     * 当值为空时,字段的默认值
+     */
+    public String defaultValue() default "";
+
+    /**
+     * 提示信息
+     */
+    public String prompt() default "";
+
+    /**
+     * 设置只能选择不能输入的列内容.
+     */
+    public String[] combo() default {};
+
+    /**
+     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+     */
+    public boolean isExport() default true;
+
+    /**
+     * 另一个类中的属性名称,支持多级获取,以小数点隔开
+     */
+    public String targetAttr() default "";
+
+    /**
+     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+     */
+    Type type() default Type.ALL;
+
+    public enum Type
+    {
+        ALL(0), EXPORT(1), IMPORT(2);
+        private final int value;
+
+        Type(int value)
+        {
+            this.value = value;
+        }
+
+        public int value()
+        {
+            return this.value;
+        }
+    }
+
+    public enum ColumnType
+    {
+        NUMERIC(0), STRING(1);
+        private final int value;
+
+        ColumnType(int value)
+        {
+            this.value = value;
+        }
+
+        public int value()
+        {
+            return this.value;
+        }
+    }
+}

+ 18 - 0
ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Excels.java

@@ -0,0 +1,18 @@
+package com.ruoyi.framework.aspectj.lang.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解集
+ * 
+ * @author ruoyi
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels
+{
+    Excel[] value();
+}

+ 1 - 0
ruoyi/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -98,6 +98,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                         "/**/*.js"
                 ).permitAll()
                 .antMatchers("/profile/**").anonymous()
+                .antMatchers("/common/download**").anonymous()
                 .antMatchers("/swagger-ui.html").anonymous()
                 .antMatchers("/swagger-resources/**").anonymous()
                 .antMatchers("/webjars/**").anonymous()

+ 49 - 2
ruoyi/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java

@@ -1,5 +1,7 @@
 package com.ruoyi.framework.config;
 
+import java.util.ArrayList;
+import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -8,8 +10,12 @@ import springfox.documentation.builders.ApiInfoBuilder;
 import springfox.documentation.builders.PathSelectors;
 import springfox.documentation.builders.RequestHandlerSelectors;
 import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
+import springfox.documentation.service.AuthorizationScope;
 import springfox.documentation.service.Contact;
+import springfox.documentation.service.SecurityReference;
 import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
 import springfox.documentation.spring.web.plugins.Docket;
 import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
@@ -33,6 +39,7 @@ public class SwaggerConfig
     public Docket createRestApi()
     {
         return new Docket(DocumentationType.SWAGGER_2)
+                .pathMapping("/dev-api")
                 // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
                 .apiInfo(apiInfo())
                 // 设置哪些接口暴露给Swagger展示
@@ -43,7 +50,47 @@ public class SwaggerConfig
                 //.apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
                 // 扫描所有 .apis(RequestHandlerSelectors.any())
                 .paths(PathSelectors.any())
-                .build();
+                .build()
+                /* 设置安全模式,swagger可以设置访问token */
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts());
+    }
+
+    /**
+     * 安全模式,这里指定token通过Authorization头请求头传递
+     */
+    private List<ApiKey> securitySchemes()
+    {
+        List<ApiKey> apiKeyList = new ArrayList<ApiKey>();
+        apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
+        return apiKeyList;
+    }
+    
+    /**
+     * 安全上下文
+     */
+    private List<SecurityContext> securityContexts()
+    {
+        List<SecurityContext> securityContexts = new ArrayList<>();
+        securityContexts.add(
+                SecurityContext.builder()
+                        .securityReferences(defaultAuth())
+                        .forPaths(PathSelectors.regex("^(?!auth).*$"))
+                        .build());
+        return securityContexts;
+    }
+    
+    /**
+     * 默认的安全上引用
+     */
+    private List<SecurityReference> defaultAuth()
+    {
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        List<SecurityReference> securityReferences = new ArrayList<>();
+        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+        return securityReferences;
     }
 
     /**
@@ -54,7 +101,7 @@ public class SwaggerConfig
         // 用ApiInfoBuilder进行定制
         return new ApiInfoBuilder()
                 // 设置标题
-                .title("标题:余心管理系统_接口文档")
+                .title("标题:若依管理系统_接口文档")
                 // 描述
                 .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
                 // 作者信息

+ 24 - 0
ruoyi/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java

@@ -5,6 +5,8 @@ import org.slf4j.LoggerFactory;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.authentication.AccountExpiredException;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 import org.springframework.web.servlet.NoHandlerFoundException;
@@ -82,6 +84,28 @@ public class GlobalExceptionHandler
         return AjaxResult.error(e.getMessage());
     }
 
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(BindException.class)
+    public AjaxResult validatedBindException(BindException e)
+    {
+        log.error(e.getMessage(), e);
+        String message = e.getAllErrors().get(0).getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Object validExceptionHandler(MethodArgumentNotValidException e)
+    {
+        log.error(e.getMessage(), e);
+        String message = e.getBindingResult().getFieldError().getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
     /**
      * 演示模式异常
      */

+ 43 - 0
ruoyi/src/main/java/com/ruoyi/project/common/CommonController.java

@@ -1,10 +1,17 @@
 package com.ruoyi.project.common;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.common.utils.file.FileUtils;
 import com.ruoyi.framework.config.RuoYiConfig;
 import com.ruoyi.framework.config.ServerConfig;
 import com.ruoyi.framework.web.domain.AjaxResult;
@@ -17,9 +24,45 @@ import com.ruoyi.framework.web.domain.AjaxResult;
 @RestController
 public class CommonController
 {
+    private static final Logger log = LoggerFactory.getLogger(CommonController.class);
+
     @Autowired
     private ServerConfig serverConfig;
 
+    /**
+     * 通用下载请求
+     * 
+     * @param fileName 文件名称
+     * @param delete 是否删除
+     */
+    @GetMapping("common/download")
+    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
+    {
+        try
+        {
+            if (!FileUtils.isValidFilename(fileName))
+            {
+                throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
+            }
+            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
+            String filePath = RuoYiConfig.getDownloadPath() + fileName;
+
+            response.setCharacterEncoding("utf-8");
+            response.setContentType("multipart/form-data");
+            response.setHeader("Content-Disposition",
+                    "attachment;fileName=" + FileUtils.setFileDownloadHeader(request, realFileName));
+            FileUtils.writeBytes(filePath, response.getOutputStream());
+            if (delete)
+            {
+                FileUtils.deleteFile(filePath);
+            }
+        }
+        catch (Exception e)
+        {
+            log.error("下载文件失败", e);
+        }
+    }
+
     /**
      * 通用上传请求
      */

+ 33 - 0
ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java

@@ -3,10 +3,16 @@ package com.ruoyi.project.monitor.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.framework.web.page.TableDataInfo;
 import com.ruoyi.project.monitor.domain.SysLogininfor;
 import com.ruoyi.project.monitor.service.ISysLogininforService;
@@ -31,4 +37,31 @@ public class SysLogininforController extends BaseController
         List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
         return getDataTable(list);
     }
+
+    @Log(title = "登陆日志", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysLogininfor logininfor)
+    {
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
+        return util.exportExcel(list, "登陆日志");
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "登陆日志", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{infoIds}")
+    public AjaxResult remove(@PathVariable Long[] infoIds)
+    {
+        return toAjax(logininforService.deleteLogininforByIds(infoIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "登陆日志", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        logininforService.cleanLogininfor();
+        return AjaxResult.success();
+    }
 }

+ 32 - 0
ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java

@@ -3,10 +3,16 @@ package com.ruoyi.project.monitor.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.framework.web.page.TableDataInfo;
 import com.ruoyi.project.monitor.domain.SysOperLog;
 import com.ruoyi.project.monitor.service.ISysOperLogService;
@@ -31,4 +37,30 @@ public class SysOperlogController extends BaseController
         List<SysOperLog> list = operLogService.selectOperLogList(operLog);
         return getDataTable(list);
     }
+
+    @Log(title = "操作日志", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysOperLog operLog)
+    {
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
+        return util.exportExcel(list, "操作日志");
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/{operIds}")
+    public AjaxResult remove(@PathVariable Long[] operIds)
+    {
+        return toAjax(operLogService.deleteOperLogByIds(operIds));
+    }
+
+    @Log(title = "操作日志", businessType = BusinessType.CLEAN)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        operLogService.cleanOperLog();
+        return AjaxResult.success();
+    }
 }

+ 11 - 0
ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysLogininfor.java

@@ -1,6 +1,8 @@
 package com.ruoyi.project.monitor.domain;
 
 import java.util.Date;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -13,30 +15,39 @@ public class SysLogininfor extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** ID */
+    @Excel(name = "序号", cellType = ColumnType.NUMERIC)
     private Long infoId;
 
     /** 用户账号 */
+    @Excel(name = "用户账号")
     private String userName;
 
     /** 登录状态 0成功 1失败 */
+    @Excel(name = "登录状态", readConverterExp = "0=成功,1=失败")
     private String status;
 
     /** 登录IP地址 */
+    @Excel(name = "登录地址")
     private String ipaddr;
 
     /** 登录地点 */
+    @Excel(name = "登录地点")
     private String loginLocation;
 
     /** 浏览器类型 */
+    @Excel(name = "浏览器")
     private String browser;
 
     /** 操作系统 */
+    @Excel(name = "操作系统")
     private String os;
 
     /** 提示消息 */
+    @Excel(name = "提示消息")
     private String msg;
 
     /** 访问时间 */
+    @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date loginTime;
 
     public Long getInfoId()

+ 18 - 0
ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysOperLog.java

@@ -1,6 +1,8 @@
 package com.ruoyi.project.monitor.domain;
 
 import java.util.Date;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -13,54 +15,70 @@ public class SysOperLog extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** 日志主键 */
+    @Excel(name = "操作序号", cellType = ColumnType.NUMERIC)
     private Long operId;
 
     /** 操作模块 */
+    @Excel(name = "操作模块")
     private String title;
 
     /** 业务类型(0其它 1新增 2修改 3删除) */
+    @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
     private Integer businessType;
 
     /** 业务类型数组 */
     private Integer[] businessTypes;
 
     /** 请求方法 */
+    @Excel(name = "请求方法")
     private String method;
 
     /** 请求方式 */
+    @Excel(name = "请求方式")
     private String requestMethod;
 
     /** 操作类别(0其它 1后台用户 2手机端用户) */
+    @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户")
     private Integer operatorType;
 
     /** 操作人员 */
+    @Excel(name = "操作人员")
     private String operName;
 
     /** 部门名称 */
+    @Excel(name = "部门名称")
     private String deptName;
 
     /** 请求url */
+    @Excel(name = "请求地址")
     private String operUrl;
 
     /** 操作地址 */
+    @Excel(name = "操作地址")
     private String operIp;
 
     /** 操作地点 */
+    @Excel(name = "操作地点")
     private String operLocation;
 
     /** 请求参数 */
+    @Excel(name = "请求参数")
     private String operParam;
 
     /** 返回参数 */
+    @Excel(name = "返回参数")
     private String jsonResult;
 
     /** 操作状态(0正常 1异常) */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=异常")
     private Integer status;
 
     /** 错误消息 */
+    @Excel(name = "错误消息")
     private String errorMsg;
 
     /** 操作时间 */
+    @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date operTime;
 
     public Long getOperId()

+ 2 - 2
ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysLogininforMapper.java

@@ -28,10 +28,10 @@ public interface SysLogininforMapper
     /**
      * 批量删除系统登录日志
      * 
-     * @param ids 需要删除的数据
+     * @param infoIds 需要删除的登录日志ID
      * @return 结果
      */
-    public int deleteLogininforByIds(String[] ids);
+    public int deleteLogininforByIds(Long[] infoIds);
 
     /**
      * 清空系统登录日志

+ 2 - 2
ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysOperLogMapper.java

@@ -28,10 +28,10 @@ public interface SysOperLogMapper
     /**
      * 批量删除系统操作日志
      * 
-     * @param ids 需要删除的数据
+     * @param operIds 需要删除的操作日志ID
      * @return 结果
      */
-    public int deleteOperLogByIds(String[] ids);
+    public int deleteOperLogByIds(Long[] operIds);
 
     /**
      * 查询操作日志详细

+ 2 - 2
ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysLogininforService.java

@@ -28,10 +28,10 @@ public interface ISysLogininforService
     /**
      * 批量删除系统登录日志
      * 
-     * @param ids 需要删除的数据
+     * @param infoIds 需要删除的登录日志ID
      * @return
      */
-    public int deleteLogininforByIds(String ids);
+    public int deleteLogininforByIds(Long[] infoIds);
 
     /**
      * 清空系统登录日志

+ 2 - 2
ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysOperLogService.java

@@ -28,10 +28,10 @@ public interface ISysOperLogService
     /**
      * 批量删除系统操作日志
      * 
-     * @param ids 需要删除的数据
+     * @param operIds 需要删除的操作日志ID
      * @return 结果
      */
-    public int deleteOperLogByIds(String ids);
+    public int deleteOperLogByIds(Long[] operIds);
 
     /**
      * 查询操作日志详细

+ 3 - 4
ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysLogininforServiceImpl.java

@@ -3,7 +3,6 @@ package com.ruoyi.project.monitor.service.impl;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.text.Convert;
 import com.ruoyi.project.monitor.domain.SysLogininfor;
 import com.ruoyi.project.monitor.mapper.SysLogininforMapper;
 import com.ruoyi.project.monitor.service.ISysLogininforService;
@@ -46,13 +45,13 @@ public class SysLogininforServiceImpl implements ISysLogininforService
     /**
      * 批量删除系统登录日志
      * 
-     * @param ids 需要删除的数据
+     * @param infoIds 需要删除的登录日志ID
      * @return
      */
     @Override
-    public int deleteLogininforByIds(String ids)
+    public int deleteLogininforByIds(Long[] infoIds)
     {
-        return logininforMapper.deleteLogininforByIds(Convert.toStrArray(ids));
+        return logininforMapper.deleteLogininforByIds(infoIds);
     }
 
     /**

+ 4 - 6
ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysOperLogServiceImpl.java

@@ -3,7 +3,6 @@ package com.ruoyi.project.monitor.service.impl;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.text.Convert;
 import com.ruoyi.project.monitor.domain.SysOperLog;
 import com.ruoyi.project.monitor.mapper.SysOperLogMapper;
 import com.ruoyi.project.monitor.service.ISysOperLogService;
@@ -45,13 +44,12 @@ public class SysOperLogServiceImpl implements ISysOperLogService
     /**
      * 批量删除系统操作日志
      * 
-     * @param ids 需要删除的数据
-     * @return
+     * @param operIds 需要删除的操作日志ID
+     * @return 结果
      */
-    @Override
-    public int deleteOperLogByIds(String ids)
+    public int deleteOperLogByIds(Long[] operIds)
     {
-        return operLogMapper.deleteOperLogByIds(Convert.toStrArray(ids));
+        return operLogMapper.deleteOperLogByIds(operIds);
     }
 
     /**

+ 17 - 5
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java

@@ -3,6 +3,7 @@ package com.ruoyi.project.system.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
@@ -45,6 +47,16 @@ public class SysConfigController extends BaseController
         return getDataTable(list);
     }
 
+    @Log(title = "参数管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:config:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysConfig config)
+    {
+        List<SysConfig> list = configService.selectConfigList(config);
+        ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
+        return util.exportExcel(list, "参数数据");
+    }
+
     /**
      * 根据参数编号获取详细信息
      */
@@ -71,7 +83,7 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:add')")
     @Log(title = "参数管理", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysConfig config)
+    public AjaxResult add(@Validated @RequestBody SysConfig config)
     {
         if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
         {
@@ -87,7 +99,7 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:edit')")
     @Log(title = "参数管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysConfig config)
+    public AjaxResult edit(@Validated @RequestBody SysConfig config)
     {
         if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
         {
@@ -102,9 +114,9 @@ public class SysConfigController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:config:remove')")
     @Log(title = "参数管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{configId}")
-    public AjaxResult remove(@PathVariable Long configId)
+    @DeleteMapping("/{configIds}")
+    public AjaxResult remove(@PathVariable Long[] configIds)
     {
-        return toAjax(configService.deleteConfigById(configId));
+        return toAjax(configService.deleteConfigByIds(configIds));
     }
 }

+ 3 - 4
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java

@@ -3,6 +3,7 @@ package com.ruoyi.project.system.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -10,7 +11,6 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -70,7 +70,6 @@ public class SysDeptController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:dept:query')")
     @GetMapping(value = "/roleDeptTreeselect/{roleId}")
-    @ResponseBody
     public AjaxResult roleDeptTreeselect(@PathVariable("roleId") Long roleId)
     {
         return AjaxResult.success(deptService.selectDeptListByRoleId(roleId));
@@ -82,7 +81,7 @@ public class SysDeptController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:dept:add')")
     @Log(title = "部门管理", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysDept dept)
+    public AjaxResult add(@Validated @RequestBody SysDept dept)
     {
         if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
         {
@@ -98,7 +97,7 @@ public class SysDeptController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:dept:edit')")
     @Log(title = "部门管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysDept dept)
+    public AjaxResult edit(@Validated @RequestBody SysDept dept)
     {
         if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
         {

+ 17 - 7
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java

@@ -3,6 +3,7 @@ package com.ruoyi.project.system.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -10,9 +11,9 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
@@ -35,7 +36,6 @@ public class SysDictDataController extends BaseController
 
     @PreAuthorize("@ss.hasPermi('system:dict:list')")
     @GetMapping("/list")
-    @ResponseBody
     public TableDataInfo list(SysDictData dictData)
     {
         startPage();
@@ -43,6 +43,16 @@ public class SysDictDataController extends BaseController
         return getDataTable(list);
     }
 
+    @Log(title = "字典数据", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysDictData dictData)
+    {
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
+        return util.exportExcel(list, "字典数据");
+    }
+
     /**
      * 查询字典数据详细
      */
@@ -69,7 +79,7 @@ public class SysDictDataController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:dict:add')")
     @Log(title = "字典数据", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysDictData dict)
+    public AjaxResult add(@Validated @RequestBody SysDictData dict)
     {
         dict.setCreateBy(SecurityUtils.getUsername());
         return toAjax(dictDataService.insertDictData(dict));
@@ -81,7 +91,7 @@ public class SysDictDataController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:dict:edit')")
     @Log(title = "字典数据", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysDictData dict)
+    public AjaxResult edit(@Validated @RequestBody SysDictData dict)
     {
         dict.setUpdateBy(SecurityUtils.getUsername());
         return toAjax(dictDataService.updateDictData(dict));
@@ -92,9 +102,9 @@ public class SysDictDataController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:dict:remove')")
     @Log(title = "字典类型", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{dictCode}")
-    public AjaxResult remove(@PathVariable Long dictCode)
+    @DeleteMapping("/{dictCodes}")
+    public AjaxResult remove(@PathVariable Long[] dictCodes)
     {
-        return toAjax(dictDataService.deleteDictDataById(dictCode));
+        return toAjax(dictDataService.deleteDictDataByIds(dictCodes));
     }
 }

+ 17 - 7
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java

@@ -3,6 +3,7 @@ package com.ruoyi.project.system.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -10,10 +11,10 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
@@ -36,7 +37,6 @@ public class SysDictTypeController extends BaseController
 
     @PreAuthorize("@ss.hasPermi('system:dict:list')")
     @GetMapping("/list")
-    @ResponseBody
     public TableDataInfo list(SysDictType dictType)
     {
         startPage();
@@ -44,6 +44,16 @@ public class SysDictTypeController extends BaseController
         return getDataTable(list);
     }
 
+    @Log(title = "字典类型", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysDictType dictType)
+    {
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
+        return util.exportExcel(list, "字典类型");
+    }
+
     /**
      * 查询字典类型详细
      */
@@ -60,7 +70,7 @@ public class SysDictTypeController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:dict:add')")
     @Log(title = "字典类型", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysDictType dict)
+    public AjaxResult add(@Validated @RequestBody SysDictType dict)
     {
         if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
         {
@@ -76,7 +86,7 @@ public class SysDictTypeController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:dict:edit')")
     @Log(title = "字典类型", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysDictType dict)
+    public AjaxResult edit(@Validated @RequestBody SysDictType dict)
     {
         if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
         {
@@ -91,9 +101,9 @@ public class SysDictTypeController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:dict:remove')")
     @Log(title = "字典类型", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{dictId}")
-    public AjaxResult remove(@PathVariable Long dictId)
+    @DeleteMapping("/{dictIds}")
+    public AjaxResult remove(@PathVariable Long[] dictIds)
     {
-        return toAjax(dictTypeService.deleteDictTypeById(dictId));
+        return toAjax(dictTypeService.deleteDictTypeByIds(dictIds));
     }
 }

+ 2 - 4
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java

@@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -71,7 +70,6 @@ public class SysMenuController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:menu:query')")
     @GetMapping(value = "/roleMenuTreeselect/{roleId}")
-    @ResponseBody
     public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
     {
         return AjaxResult.success(menuService.selectMenuListByRoleId(roleId));
@@ -83,7 +81,7 @@ public class SysMenuController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:menu:add')")
     @Log(title = "菜单管理", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody @Validated SysMenu menu)
+    public AjaxResult add(@Validated @RequestBody SysMenu menu)
     {
         if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
         {
@@ -99,7 +97,7 @@ public class SysMenuController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:menu:edit')")
     @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysMenu menu)
+    public AjaxResult edit(@Validated @RequestBody SysMenu menu)
     {
         if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
         {

+ 3 - 2
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java

@@ -3,6 +3,7 @@ package com.ruoyi.project.system.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -60,7 +61,7 @@ public class SysNoticeController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:notice:add')")
     @Log(title = "通知公告", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysNotice notice)
+    public AjaxResult add(@Validated @RequestBody SysNotice notice)
     {
         notice.setCreateBy(SecurityUtils.getUsername());
         return toAjax(noticeService.insertNotice(notice));
@@ -72,7 +73,7 @@ public class SysNoticeController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:notice:edit')")
     @Log(title = "通知公告", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysNotice notice)
+    public AjaxResult edit(@Validated @RequestBody SysNotice notice)
     {
         notice.setUpdateBy(SecurityUtils.getUsername());
         return toAjax(noticeService.updateNotice(notice));

+ 17 - 5
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysPostController.java

@@ -3,6 +3,7 @@ package com.ruoyi.project.system.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
@@ -44,6 +46,16 @@ public class SysPostController extends BaseController
         List<SysPost> list = postService.selectPostList(post);
         return getDataTable(list);
     }
+    
+    @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:config:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysPost post)
+    {
+        List<SysPost> list = postService.selectPostList(post);
+        ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
+        return util.exportExcel(list, "岗位数据");
+    }
 
     /**
      * 根据岗位编号获取详细信息
@@ -61,7 +73,7 @@ public class SysPostController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:post:add')")
     @Log(title = "岗位管理", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysPost post)
+    public AjaxResult add(@Validated @RequestBody SysPost post)
     {
         if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
         {
@@ -81,7 +93,7 @@ public class SysPostController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:post:edit')")
     @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysPost post)
+    public AjaxResult edit(@Validated @RequestBody SysPost post)
     {
         if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
         {
@@ -100,10 +112,10 @@ public class SysPostController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:post:remove')")
     @Log(title = "岗位管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{postId}")
-    public AjaxResult remove(@PathVariable Long postId)
+    @DeleteMapping("/{postIds}")
+    public AjaxResult remove(@PathVariable Long[] postIds)
     {
-        return toAjax(postService.deletePostById(postId));
+        return toAjax(postService.deletePostByIds(postIds));
     }
 
     /**

+ 18 - 7
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java

@@ -3,6 +3,7 @@ package com.ruoyi.project.system.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
@@ -42,6 +44,16 @@ public class SysRoleController extends BaseController
         return getDataTable(list);
     }
 
+    @Log(title = "角色管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:role:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysRole role)
+    {
+        List<SysRole> list = roleService.selectRoleList(role);
+        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
+        return util.exportExcel(list, "角色数据");
+    }
+
     /**
      * 根据角色编号获取详细信息
      */
@@ -58,7 +70,7 @@ public class SysRoleController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:role:add')")
     @Log(title = "角色管理", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysRole role)
+    public AjaxResult add(@Validated @RequestBody SysRole role)
     {
         if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
         {
@@ -79,7 +91,7 @@ public class SysRoleController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:role:edit')")
     @Log(title = "角色管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysRole role)
+    public AjaxResult edit(@Validated @RequestBody SysRole role)
     {
         roleService.checkRoleAllowed(role);
         if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
@@ -120,15 +132,14 @@ public class SysRoleController extends BaseController
     }
 
     /**
-     * 删除岗位
+     * 删除角色
      */
     @PreAuthorize("@ss.hasPermi('system:role:remove')")
     @Log(title = "角色管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{roleId}")
-    public AjaxResult remove(@PathVariable Long roleId)
+    @DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds)
     {
-        roleService.checkRoleAllowed(new SysRole(roleId));
-        return toAjax(roleService.deleteRoleById(roleId));
+        return toAjax(roleService.deleteRoleByIds(roleIds));
     }
 
     /**

+ 17 - 6
ruoyi/src/main/java/com/ruoyi/project/system/controller/SysUserController.java

@@ -3,6 +3,7 @@ package com.ruoyi.project.system.controller;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
@@ -53,6 +55,16 @@ public class SysUserController extends BaseController
         return getDataTable(list);
     }
 
+    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:user:export')")
+    @GetMapping("/export")
+    public AjaxResult export(SysUser user)
+    {
+        List<SysUser> list = userService.selectUserList(user);
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        return util.exportExcel(list, "用户数据");
+    }
+
     /**
      * 根据用户编号获取详细信息
      */
@@ -72,7 +84,7 @@ public class SysUserController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:user:add')")
     @Log(title = "用户管理", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysUser user)
+    public AjaxResult add(@Validated @RequestBody SysUser user)
     {
         if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName())))
         {
@@ -97,7 +109,7 @@ public class SysUserController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:user:edit')")
     @Log(title = "用户管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysUser user)
+    public AjaxResult edit(@Validated @RequestBody SysUser user)
     {
         userService.checkUserAllowed(user);
         if (UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
@@ -117,11 +129,10 @@ public class SysUserController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:user:remove')")
     @Log(title = "用户管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{userId}")
-    public AjaxResult remove(@PathVariable Long userId)
+    @DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
     {
-        userService.checkUserAllowed(new SysUser(userId));
-        return toAjax(userService.deleteUserById(userId));
+        return toAjax(userService.deleteUserByIds(userIds));
     }
 
     /**

+ 25 - 0
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysConfig.java

@@ -2,6 +2,10 @@ package com.ruoyi.project.system.domain;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -14,18 +18,23 @@ public class SysConfig extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** 参数主键 */
+    @Excel(name = "参数主键", cellType = ColumnType.NUMERIC)
     private Long configId;
 
     /** 参数名称 */
+    @Excel(name = "参数名称")
     private String configName;
 
     /** 参数键名 */
+    @Excel(name = "参数键名")
     private String configKey;
 
     /** 参数键值 */
+    @Excel(name = "参数键值")
     private String configValue;
 
     /** 系统内置(Y是 N否) */
+    @Excel(name = "系统内置", readConverterExp = "Y=是,N=否")
     private String configType;
 
     public Long getConfigId()
@@ -83,4 +92,20 @@ public class SysConfig extends BaseEntity
     {
         this.configType = configType;
     }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("configId", getConfigId())
+            .append("configName", getConfigName())
+            .append("configKey", getConfigKey())
+            .append("configValue", getConfigValue())
+            .append("configType", getConfigType())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
 }

+ 32 - 1
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDept.java

@@ -2,6 +2,11 @@ package com.ruoyi.project.system.domain;
 
 import java.util.ArrayList;
 import java.util.List;
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -45,7 +50,7 @@ public class SysDept extends BaseEntity
 
     /** 父部门名称 */
     private String parentName;
-
+    
     /** 子部门 */
     private List<SysDept> children = new ArrayList<SysDept>();
 
@@ -79,6 +84,8 @@ public class SysDept extends BaseEntity
         this.ancestors = ancestors;
     }
 
+    @NotBlank(message = "部门名称不能为空")
+    @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
     public String getDeptName()
     {
         return deptName;
@@ -89,6 +96,7 @@ public class SysDept extends BaseEntity
         this.deptName = deptName;
     }
 
+    @NotBlank(message = "显示顺序不能为空")
     public String getOrderNum()
     {
         return orderNum;
@@ -109,6 +117,7 @@ public class SysDept extends BaseEntity
         this.leader = leader;
     }
 
+    @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
     public String getPhone()
     {
         return phone;
@@ -119,6 +128,8 @@ public class SysDept extends BaseEntity
         this.phone = phone;
     }
 
+    @Email(message = "邮箱格式不正确")
+    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
     public String getEmail()
     {
         return email;
@@ -168,4 +179,24 @@ public class SysDept extends BaseEntity
     {
         this.children = children;
     }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("deptId", getDeptId())
+            .append("parentId", getParentId())
+            .append("ancestors", getAncestors())
+            .append("deptName", getDeptName())
+            .append("orderNum", getOrderNum())
+            .append("leader", getLeader())
+            .append("phone", getPhone())
+            .append("email", getEmail())
+            .append("status", getStatus())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
 }

+ 31 - 0
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictData.java

@@ -2,7 +2,11 @@ package com.ruoyi.project.system.domain;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -15,18 +19,23 @@ public class SysDictData extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** 字典编码 */
+    @Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
     private Long dictCode;
 
     /** 字典排序 */
+    @Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
     private Long dictSort;
 
     /** 字典标签 */
+    @Excel(name = "字典标签")
     private String dictLabel;
 
     /** 字典键值 */
+    @Excel(name = "字典键值")
     private String dictValue;
 
     /** 字典类型 */
+    @Excel(name = "字典类型")
     private String dictType;
 
     /** 样式属性(其他样式扩展) */
@@ -36,9 +45,11 @@ public class SysDictData extends BaseEntity
     private String listClass;
 
     /** 是否默认(Y是 N否) */
+    @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
     private String isDefault;
 
     /** 状态(0正常 1停用) */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
     private String status;
 
     public Long getDictCode()
@@ -142,4 +153,24 @@ public class SysDictData extends BaseEntity
     {
         this.status = status;
     }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("dictCode", getDictCode())
+            .append("dictSort", getDictSort())
+            .append("dictLabel", getDictLabel())
+            .append("dictValue", getDictValue())
+            .append("dictType", getDictType())
+            .append("cssClass", getCssClass())
+            .append("listClass", getListClass())
+            .append("isDefault", getIsDefault())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
 }

+ 23 - 0
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictType.java

@@ -2,6 +2,10 @@ package com.ruoyi.project.system.domain;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -14,15 +18,19 @@ public class SysDictType extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** 字典主键 */
+    @Excel(name = "字典主键", cellType = ColumnType.NUMERIC)
     private Long dictId;
 
     /** 字典名称 */
+    @Excel(name = "字典名称")
     private String dictName;
 
     /** 字典类型 */
+    @Excel(name = "字典类型")
     private String dictType;
 
     /** 状态(0正常 1停用) */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
     private String status;
 
     public Long getDictId()
@@ -68,4 +76,19 @@ public class SysDictType extends BaseEntity
     {
         this.status = status;
     }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("dictId", getDictId())
+            .append("dictName", getDictName())
+            .append("dictType", getDictType())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
 }

+ 34 - 1
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysMenu.java

@@ -1,8 +1,12 @@
 package com.ruoyi.project.system.domain;
 
+import java.util.ArrayList;
 import java.util.List;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.framework.web.domain.BaseEntity;
-import java.util.ArrayList;
 
 /**
  * 菜单权限表 sys_menu
@@ -62,6 +66,8 @@ public class SysMenu extends BaseEntity
         this.menuId = menuId;
     }
 
+    @NotBlank(message = "菜单名称不能为空")
+    @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
     public String getMenuName()
     {
         return menuName;
@@ -92,6 +98,7 @@ public class SysMenu extends BaseEntity
         this.parentId = parentId;
     }
 
+    @NotBlank(message = "显示顺序不能为空")
     public String getOrderNum()
     {
         return orderNum;
@@ -102,6 +109,7 @@ public class SysMenu extends BaseEntity
         this.orderNum = orderNum;
     }
 
+    @Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
     public String getPath()
     {
         return path;
@@ -112,6 +120,7 @@ public class SysMenu extends BaseEntity
         this.path = path;
     }
 
+    @Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
     public String getComponent()
     {
         return component;
@@ -132,6 +141,7 @@ public class SysMenu extends BaseEntity
         this.isFrame = isFrame;
     }
 
+    @NotBlank(message = "菜单类型不能为空")
     public String getMenuType()
     {
         return menuType;
@@ -152,6 +162,7 @@ public class SysMenu extends BaseEntity
         this.visible = visible;
     }
 
+    @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
     public String getPerms()
     {
         return perms;
@@ -181,4 +192,26 @@ public class SysMenu extends BaseEntity
     {
         this.children = children;
     }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("menuId", getMenuId())
+            .append("menuName", getMenuName())
+            .append("parentId", getParentId())
+            .append("orderNum", getOrderNum())
+            .append("path", getPath())
+            .append("component", getComponent())
+            .append("isFrame", getIsFrame())
+            .append("menuType", getMenuType())
+            .append("visible", getVisible())
+            .append("perms", getPerms())
+            .append("icon", getIcon())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
 }

+ 22 - 0
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysNotice.java

@@ -1,5 +1,9 @@
 package com.ruoyi.project.system.domain;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -41,6 +45,8 @@ public class SysNotice extends BaseEntity
         this.noticeTitle = noticeTitle;
     }
 
+    @NotBlank(message = "公告标题不能为空")
+    @Size(min = 0, max = 50, message = "公告标题不能超过50个字符")
     public String getNoticeTitle()
     {
         return noticeTitle;
@@ -75,4 +81,20 @@ public class SysNotice extends BaseEntity
     {
         return status;
     }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("noticeId", getNoticeId())
+            .append("noticeTitle", getNoticeTitle())
+            .append("noticeType", getNoticeType())
+            .append("noticeContent", getNoticeContent())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
 }

+ 25 - 0
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysPost.java

@@ -2,6 +2,10 @@ package com.ruoyi.project.system.domain;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -14,18 +18,23 @@ public class SysPost extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** 岗位序号 */
+    @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC)
     private Long postId;
 
     /** 岗位编码 */
+    @Excel(name = "岗位编码")
     private String postCode;
 
     /** 岗位名称 */
+    @Excel(name = "岗位名称")
     private String postName;
 
     /** 岗位排序 */
+    @Excel(name = "岗位排序")
     private String postSort;
 
     /** 状态(0正常 1停用) */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
     private String status;
 
     /** 用户是否存在此岗位标识 默认不存在 */
@@ -95,4 +104,20 @@ public class SysPost extends BaseEntity
     {
         this.flag = flag;
     }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("postId", getPostId())
+            .append("postCode", getPostCode())
+            .append("postName", getPostName())
+            .append("postSort", getPostSort())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
 }

+ 35 - 1
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRole.java

@@ -1,5 +1,11 @@
 package com.ruoyi.project.system.domain;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -12,21 +18,27 @@ public class SysRole extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** 角色ID */
+    @Excel(name = "角色序号", cellType = ColumnType.NUMERIC)
     private Long roleId;
 
     /** 角色名称 */
+    @Excel(name = "角色名称")
     private String roleName;
 
     /** 角色权限 */
+    @Excel(name = "角色权限")
     private String roleKey;
 
     /** 角色排序 */
+    @Excel(name = "角色排序")
     private String roleSort;
 
-    /** 数据范围 */
+    /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限) */
+    @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限")
     private String dataScope;
 
     /** 角色状态(0正常 1停用) */
+    @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
     private String status;
 
     /** 删除标志(0代表存在 2代表删除) */
@@ -71,6 +83,8 @@ public class SysRole extends BaseEntity
         return roleId != null && 1L == roleId;
     }
 
+    @NotBlank(message = "角色名称不能为空")
+    @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
     public String getRoleName()
     {
         return roleName;
@@ -81,6 +95,8 @@ public class SysRole extends BaseEntity
         this.roleName = roleName;
     }
 
+    @NotBlank(message = "权限字符不能为空")
+    @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
     public String getRoleKey()
     {
         return roleKey;
@@ -91,6 +107,7 @@ public class SysRole extends BaseEntity
         this.roleKey = roleKey;
     }
 
+    @NotBlank(message = "显示顺序不能为空")
     public String getRoleSort()
     {
         return roleSort;
@@ -160,4 +177,21 @@ public class SysRole extends BaseEntity
     {
         this.deptIds = deptIds;
     }
+    
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("roleId", getRoleId())
+            .append("roleName", getRoleName())
+            .append("roleKey", getRoleKey())
+            .append("roleSort", getRoleSort())
+            .append("dataScope", getDataScope())
+            .append("status", getStatus())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
 }

+ 50 - 1
ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUser.java

@@ -2,6 +2,14 @@ package com.ruoyi.project.system.domain;
 
 import java.util.Date;
 import java.util.List;
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
+import com.ruoyi.framework.aspectj.lang.annotation.Excels;
 import com.ruoyi.framework.web.domain.BaseEntity;
 
 /**
@@ -14,24 +22,30 @@ public class SysUser extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** 用户ID */
+    @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号")
     private Long userId;
 
     /** 部门ID */
     private Long deptId;
 
     /** 用户账号 */
+    @Excel(name = "登录名称")
     private String userName;
 
     /** 用户昵称 */
+    @Excel(name = "用户名称")
     private String nickName;
 
     /** 用户邮箱 */
+    @Excel(name = "用户邮箱")
     private String email;
 
     /** 手机号码 */
+    @Excel(name = "手机号码")
     private String phonenumber;
 
     /** 用户性别 */
+    @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
     private String sex;
 
     /** 用户头像 */
@@ -44,18 +58,22 @@ public class SysUser extends BaseEntity
     private String salt;
 
     /** 帐号状态(0正常 1停用) */
+    @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
     private String status;
 
     /** 删除标志(0代表存在 2代表删除) */
     private String delFlag;
 
     /** 最后登陆IP */
+    @Excel(name = "最后登陆IP")
     private String loginIp;
 
     /** 最后登陆时间 */
+    @Excel(name = "最后登陆时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date loginDate;
 
     /** 部门对象 */
+    @Excels({ @Excel(name = "部门名称", targetAttr = "deptName"), @Excel(name = "部门负责人", targetAttr = "leader") })
     private SysDept dept;
 
     /** 角色对象 */
@@ -107,6 +125,7 @@ public class SysUser extends BaseEntity
         this.deptId = deptId;
     }
 
+    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
     public String getNickName()
     {
         return nickName;
@@ -117,6 +136,8 @@ public class SysUser extends BaseEntity
         this.nickName = nickName;
     }
 
+    @NotBlank(message = "用户账号不能为空")
+    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
     public String getUserName()
     {
         return userName;
@@ -127,6 +148,8 @@ public class SysUser extends BaseEntity
         this.userName = userName;
     }
 
+    @Email(message = "邮箱格式不正确")
+    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
     public String getEmail()
     {
         return email;
@@ -137,6 +160,7 @@ public class SysUser extends BaseEntity
         this.email = email;
     }
 
+    @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
     public String getPhonenumber()
     {
         return phonenumber;
@@ -266,5 +290,30 @@ public class SysUser extends BaseEntity
     {
         this.postIds = postIds;
     }
-
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("userId", getUserId())
+            .append("deptId", getDeptId())
+            .append("userName", getUserName())
+            .append("nickName", getNickName())
+            .append("email", getEmail())
+            .append("phonenumber", getPhonenumber())
+            .append("sex", getSex())
+            .append("avatar", getAvatar())
+            .append("password", getPassword())
+            .append("salt", getSalt())
+            .append("status", getStatus())
+            .append("delFlag", getDelFlag())
+            .append("loginIp", getLoginIp())
+            .append("loginDate", getLoginDate())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .append("dept", getDept())
+            .toString();
+    }
 }

+ 9 - 1
ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysConfigMapper.java

@@ -53,8 +53,16 @@ public interface SysConfigMapper
     /**
      * 删除参数配置
      * 
-     * @param configId 需要删除的数据ID
+     * @param configId 参数ID
      * @return 结果
      */
     public int deleteConfigById(Long configId);
+
+    /**
+     * 批量删除参数信息
+     * 
+     * @param configIds 需要删除的参数ID
+     * @return 结果
+     */
+    public int deleteConfigByIds(Long[] configIds);
 }

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictDataMapper.java

@@ -60,6 +60,14 @@ public interface SysDictDataMapper
      */
     public int deleteDictDataById(Long dictCode);
 
+    /**
+     * 批量删除字典数据信息
+     * 
+     * @param dictCodes 需要删除的字典数据ID
+     * @return 结果
+     */
+    public int deleteDictDataByIds(Long[] dictCodes);
+
     /**
      * 新增字典数据信息
      * 

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictTypeMapper.java

@@ -51,6 +51,14 @@ public interface SysDictTypeMapper
      */
     public int deleteDictTypeById(Long dictId);
 
+    /**
+     * 批量删除字典类型信息
+     * 
+     * @param dictIds 需要删除的字典ID
+     * @return 结果
+     */
+    public int deleteDictTypeByIds(Long[] dictIds);
+
     /**
      * 新增字典类型信息
      * 

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysNoticeMapper.java

@@ -49,4 +49,12 @@ public interface SysNoticeMapper
      * @return 结果
      */
     public int deleteNoticeById(Long noticeId);
+
+    /**
+     * 批量删除公告信息
+     * 
+     * @param noticeIds 需要删除的公告ID
+     * @return 结果
+     */
+    public int deleteNoticeByIds(Long noticeIds);
 }

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysPostMapper.java

@@ -57,6 +57,14 @@ public interface SysPostMapper
      */
     public int deletePostById(Long postId);
 
+    /**
+     * 批量删除岗位信息
+     * 
+     * @param postIds 需要删除的岗位ID
+     * @return 结果
+     */
+    public int deletePostByIds(Long[] postIds);
+
     /**
      * 修改岗位信息
      * 

+ 7 - 0
ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMapper.java

@@ -97,4 +97,11 @@ public interface SysRoleMapper
      */
     public int deleteRoleById(Long roleId);
 
+    /**
+     * 批量删除角色信息
+     * 
+     * @param roleIds 需要删除的角色ID
+     * @return 结果
+     */
+    public int deleteRoleByIds(Long[] roleIds);
 }

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java

@@ -79,6 +79,14 @@ public interface SysUserMapper
      */
     public int deleteUserById(Long userId);
 
+    /**
+     * 批量删除用户信息
+     * 
+     * @param userIds 需要删除的用户ID
+     * @return 结果
+     */
+    public int deleteUserByIds(Long[] userIds);
+
     /**
      * 校验用户名称是否唯一
      * 

+ 9 - 1
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysConfigService.java

@@ -53,11 +53,19 @@ public interface ISysConfigService
     /**
      * 删除参数配置信息
      * 
-     * @param configId 需要删除的数据ID
+     * @param configId 参数ID
      * @return 结果
      */
     public int deleteConfigById(Long configId);
 
+    /**
+     * 批量删除参数信息
+     * 
+     * @param configIds 需要删除的参数ID
+     * @return 结果
+     */
+    public int deleteConfigByIds(Long[] configIds);
+
     /**
      * 校验参数键名是否唯一
      * 

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictDataService.java

@@ -51,6 +51,14 @@ public interface ISysDictDataService
      */
     public int deleteDictDataById(Long dictCode);
 
+    /**
+     * 批量删除字典数据信息
+     * 
+     * @param dictCodes 需要删除的字典数据ID
+     * @return 结果
+     */
+    public int deleteDictDataByIds(Long[] dictCodes);
+
     /**
      * 新增保存字典数据信息
      * 

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictTypeService.java

@@ -49,6 +49,14 @@ public interface ISysDictTypeService
      */
     public int deleteDictTypeById(Long dictId);
 
+    /**
+     * 批量删除字典信息
+     * 
+     * @param dictIds 需要删除的字典ID
+     * @return 结果
+     */
+    public int deleteDictTypeByIds(Long[] dictIds);
+
     /**
      * 新增保存字典类型信息
      * 

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java

@@ -49,4 +49,12 @@ public interface ISysNoticeService
      * @return 结果
      */
     public int deleteNoticeById(Long noticeId);
+    
+    /**
+     * 批量删除公告信息
+     * 
+     * @param noticeIds 需要删除的公告ID
+     * @return 结果
+     */
+    public int deleteNoticeByIds(Long noticeIds);
 }

+ 17 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysPostService.java

@@ -57,6 +57,14 @@ public interface ISysPostService
      */
     public String checkPostCodeUnique(SysPost post);
 
+    /**
+     * 通过岗位ID查询岗位使用数量
+     * 
+     * @param postId 岗位ID
+     * @return 结果
+     */
+    public int countUserPostById(Long postId);
+
     /**
      * 删除岗位信息
      * 
@@ -65,6 +73,15 @@ public interface ISysPostService
      */
     public int deletePostById(Long postId);
 
+    /**
+     * 批量删除岗位信息
+     * 
+     * @param postIds 需要删除的岗位ID
+     * @return 结果
+     * @throws Exception 异常
+     */
+    public int deletePostByIds(Long[] postIds);
+
     /**
      * 新增保存岗位信息
      * 

+ 16 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysRoleService.java

@@ -73,6 +73,14 @@ public interface ISysRoleService
      */
     public void checkRoleAllowed(SysRole role);
 
+    /**
+     * 通过角色ID查询角色使用数量
+     * 
+     * @param roleId 角色ID
+     * @return 结果
+     */
+    public int countUserRoleByRoleId(Long roleId);
+
     /**
      * 新增保存角色信息
      * 
@@ -112,4 +120,12 @@ public interface ISysRoleService
      * @return 结果
      */
     public int deleteRoleById(Long roleId);
+
+    /**
+     * 批量删除角色信息
+     * 
+     * @param roleIds 需要删除的角色ID
+     * @return 结果
+     */
+    public int deleteRoleByIds(Long[] roleIds);
 }

+ 8 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserService.java

@@ -146,4 +146,12 @@ public interface ISysUserService
      * @return 结果
      */
     public int deleteUserById(Long userId);
+
+    /**
+     * 批量删除用户信息
+     * 
+     * @param userIds 需要删除的用户ID
+     * @return 结果
+     */
+    public int deleteUserByIds(Long[] userIds);
 }

+ 13 - 1
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysConfigServiceImpl.java

@@ -88,7 +88,7 @@ public class SysConfigServiceImpl implements ISysConfigService
     /**
      * 删除参数配置信息
      * 
-     * @param configId 需要删除的数据ID
+     * @param configId 参数ID
      * @return 结果
      */
     @Override
@@ -97,6 +97,18 @@ public class SysConfigServiceImpl implements ISysConfigService
         return configMapper.deleteConfigById(configId);
     }
 
+    /**
+     * 批量删除参数信息
+     * 
+     * @param configIds 需要删除的参数ID
+     * @return 结果
+     */
+    @Override
+    public int deleteConfigByIds(Long[] configIds)
+    {
+        return configMapper.deleteConfigByIds(configIds);
+    }
+
     /**
      * 校验参数键名是否唯一
      * 

+ 11 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictDataServiceImpl.java

@@ -79,6 +79,17 @@ public class SysDictDataServiceImpl implements ISysDictDataService
         return dictDataMapper.deleteDictDataById(dictCode);
     }
 
+    /**
+     * 批量删除字典数据信息
+     * 
+     * @param dictCodes 需要删除的字典数据ID
+     * @return 结果
+     */
+    public int deleteDictDataByIds(Long[] dictCodes)
+    {
+        return dictDataMapper.deleteDictDataByIds(dictCodes);
+    }
+
     /**
      * 新增保存字典数据信息
      * 

+ 11 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictTypeServiceImpl.java

@@ -83,6 +83,17 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
         return dictTypeMapper.deleteDictTypeById(dictId);
     }
 
+    /**
+     * 批量删除字典类型信息
+     * 
+     * @param dictIds 需要删除的字典ID
+     * @return 结果
+     */
+    public int deleteDictTypeByIds(Long[] dictIds)
+    {
+        return dictTypeMapper.deleteDictTypeByIds(dictIds);
+    }
+
     /**
      * 新增保存字典类型信息
      * 

+ 11 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java

@@ -77,4 +77,15 @@ public class SysNoticeServiceImpl implements ISysNoticeService
     {
         return noticeMapper.deleteNoticeById(noticeId);
     }
+
+    /**
+     * 批量删除公告信息
+     * 
+     * @param noticeIds 需要删除的公告ID
+     * @return 结果
+     */
+    public int deleteNoticeByIds(Long noticeIds)
+    {
+        return noticeMapper.deleteNoticeByIds(noticeIds);
+    }
 }

+ 37 - 1
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysPostServiceImpl.java

@@ -4,9 +4,11 @@ import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.exception.CustomException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.project.system.domain.SysPost;
 import com.ruoyi.project.system.mapper.SysPostMapper;
+import com.ruoyi.project.system.mapper.SysUserPostMapper;
 import com.ruoyi.project.system.service.ISysPostService;
 
 /**
@@ -20,6 +22,9 @@ public class SysPostServiceImpl implements ISysPostService
     @Autowired
     private SysPostMapper postMapper;
 
+    @Autowired
+    private SysUserPostMapper userPostMapper;
+
     /**
      * 查询岗位信息集合
      * 
@@ -66,7 +71,6 @@ public class SysPostServiceImpl implements ISysPostService
         return postMapper.selectPostListByUserId(userId);
     }
 
-
     /**
      * 校验岗位名称是否唯一
      * 
@@ -103,6 +107,18 @@ public class SysPostServiceImpl implements ISysPostService
         return UserConstants.UNIQUE;
     }
 
+    /**
+     * 通过岗位ID查询岗位使用数量
+     * 
+     * @param postId 岗位ID
+     * @return 结果
+     */
+    @Override
+    public int countUserPostById(Long postId)
+    {
+        return userPostMapper.countUserPostById(postId);
+    }
+
     /**
      * 删除岗位信息
      * 
@@ -115,6 +131,26 @@ public class SysPostServiceImpl implements ISysPostService
         return postMapper.deletePostById(postId);
     }
 
+    /**
+     * 批量删除岗位信息
+     * 
+     * @param postIds 需要删除的岗位ID
+     * @return 结果
+     * @throws Exception 异常
+     */
+    public int deletePostByIds(Long[] postIds)
+    {
+        for (Long postId : postIds)
+        {
+            SysPost post = selectPostById(postId);
+            if (countUserPostById(postId) > 0)
+            {
+                throw new CustomException(String.format("%1$s已分配,不能删除", post.getPostName()));
+            }
+        }
+        return postMapper.deletePostByIds(postIds);
+    }
+
     /**
      * 新增保存岗位信息
      * 

+ 36 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysRoleServiceImpl.java

@@ -18,6 +18,7 @@ import com.ruoyi.project.system.domain.SysRoleMenu;
 import com.ruoyi.project.system.mapper.SysRoleDeptMapper;
 import com.ruoyi.project.system.mapper.SysRoleMapper;
 import com.ruoyi.project.system.mapper.SysRoleMenuMapper;
+import com.ruoyi.project.system.mapper.SysUserRoleMapper;
 import com.ruoyi.project.system.service.ISysRoleService;
 
 /**
@@ -34,6 +35,9 @@ public class SysRoleServiceImpl implements ISysRoleService
     @Autowired
     private SysRoleMenuMapper roleMenuMapper;
 
+    @Autowired
+    private SysUserRoleMapper userRoleMapper;
+
     @Autowired
     private SysRoleDeptMapper roleDeptMapper;
 
@@ -152,6 +156,18 @@ public class SysRoleServiceImpl implements ISysRoleService
         }
     }
 
+    /**
+     * 通过角色ID查询角色使用数量
+     * 
+     * @param roleId 角色ID
+     * @return 结果
+     */
+    @Override
+    public int countUserRoleByRoleId(Long roleId)
+    {
+        return userRoleMapper.countUserRoleByRoleId(roleId);
+    }
+
     /**
      * 新增保存角色信息
      * 
@@ -272,4 +288,24 @@ public class SysRoleServiceImpl implements ISysRoleService
     {
         return roleMapper.deleteRoleById(roleId);
     }
+
+    /**
+     * 批量删除角色信息
+     * 
+     * @param roleIds 需要删除的角色ID
+     * @return 结果
+     */
+    public int deleteRoleByIds(Long[] roleIds)
+    {
+        for (Long roleId : roleIds)
+        {
+            checkRoleAllowed(new SysRole(roleId));
+            SysRole role = selectRoleById(roleId);
+            if (countUserRoleByRoleId(roleId) > 0)
+            {
+                throw new CustomException(String.format("%1$s已分配,不能删除", role.getRoleName()));
+            }
+        }
+        return roleMapper.deleteRoleByIds(roleIds);
+    }
 }

+ 15 - 0
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java

@@ -360,4 +360,19 @@ public class SysUserServiceImpl implements ISysUserService
         userPostMapper.deleteUserPostByUserId(userId);
         return userMapper.deleteUserById(userId);
     }
+
+    /**
+     * 批量删除用户信息
+     * 
+     * @param userIds 需要删除的用户ID
+     * @return 结果
+     */
+    public int deleteUserByIds(Long[] userIds)
+    {
+        for (Long userId : userIds)
+        {
+            checkUserAllowed(new SysUser(userId));
+        }
+        return userMapper.deleteUserByIds(userIds);
+    }
 }

+ 1 - 1
ruoyi/src/main/resources/application.yml

@@ -3,7 +3,7 @@ ruoyi:
   # 名称
   name: RuoYi
   # 版本
-  version: 1.0.0
+  version: 1.1.0
   # 版权年份
   copyrightYear: 2019
   # 实例演示开关

+ 1 - 1
ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml

@@ -42,7 +42,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		</where>
 	</select>
 	
-	<delete id="deleteLogininforByIds" parameterType="String">
+	<delete id="deleteLogininforByIds" parameterType="Long">
  		delete from sys_logininfor where info_id in
  		<foreach collection="array" item="infoId" open="(" separator="," close=")">
  			#{infoId}

+ 1 - 1
ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml

@@ -63,7 +63,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		</where>
 	</select>
 	
-	<delete id="deleteOperLogByIds" parameterType="String">
+	<delete id="deleteOperLogByIds" parameterType="Long">
  		delete from sys_oper_log where oper_id in
  		<foreach collection="array" item="operId" open="(" separator="," close=")">
  			#{operId}

+ 7 - 0
ruoyi/src/main/resources/mybatis/system/SysConfigMapper.xml

@@ -102,4 +102,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         delete from sys_config where config_id = #{configId}
     </delete>
     
+    <delete id="deleteConfigByIds" parameterType="Long">
+        delete from sys_config where config_id in 
+        <foreach item="configId" collection="array" open="(" separator="," close=")">
+        	#{configId}
+        </foreach>
+    </delete>
+    
 </mapper>

+ 7 - 0
ruoyi/src/main/resources/mybatis/system/SysDictDataMapper.xml

@@ -62,6 +62,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	<delete id="deleteDictDataById" parameterType="Long">
  		delete from sys_dict_data where dict_code = #{dictCode}
  	</delete>
+ 	
+ 	<delete id="deleteDictDataByIds" parameterType="Long">
+ 		delete from sys_dict_data where dict_code in
+ 		<foreach collection="array" item="dictCode" open="(" separator="," close=")">
+ 			#{dictCode}
+        </foreach> 
+ 	</delete>
 	
 	<update id="updateDictData" parameterType="SysDictData">
  		update sys_dict_data

+ 7 - 0
ruoyi/src/main/resources/mybatis/system/SysDictTypeMapper.xml

@@ -63,6 +63,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	<delete id="deleteDictTypeById" parameterType="Long">
  		delete from sys_dict_type where dict_id = #{dictId}
  	</delete>
+ 	
+ 	<delete id="deleteDictTypeByIds" parameterType="Long">
+ 		delete from sys_dict_type where dict_id in
+ 		<foreach collection="array" item="dictId" open="(" separator="," close=")">
+ 			#{dictId}
+        </foreach> 
+ 	</delete>
 
  	<update id="updateDictType" parameterType="SysDictType">
  		update sys_dict_type

+ 7 - 0
ruoyi/src/main/resources/mybatis/system/SysNoticeMapper.xml

@@ -79,4 +79,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         delete from sys_notice where notice_id = #{noticeId}
     </delete>
     
+    <delete id="deleteNoticeByIds" parameterType="Long">
+        delete from sys_notice where notice_id in 
+        <foreach item="noticeId" collection="array" open="(" separator="," close=")">
+            #{noticeId}
+        </foreach>
+    </delete>
+    
 </mapper>

+ 7 - 0
ruoyi/src/main/resources/mybatis/system/SysPostMapper.xml

@@ -111,5 +111,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	<delete id="deletePostById" parameterType="Long">
 		delete from sys_post where post_id = #{postId}
 	</delete>
+	
+	<delete id="deletePostByIds" parameterType="Long">
+ 		delete from sys_post where post_id in
+ 		<foreach collection="array" item="postId" open="(" separator="," close=")">
+ 			#{postId}
+        </foreach> 
+ 	</delete>
 
 </mapper> 

+ 7 - 0
ruoyi/src/main/resources/mybatis/system/SysRoleMapper.xml

@@ -134,4 +134,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  		delete from sys_role where role_id = #{roleId}
  	</delete>
  	
+ 	<delete id="deleteRoleByIds" parameterType="Long">
+ 	    update sys_role set del_flag = '2' where role_id in
+ 		<foreach collection="array" item="roleId" open="(" separator="," close=")">
+ 			#{roleId}
+        </foreach> 
+ 	</delete>
+ 	
 </mapper> 

+ 7 - 0
ruoyi/src/main/resources/mybatis/system/SysUserMapper.xml

@@ -170,5 +170,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	<delete id="deleteUserById" parameterType="Long">
  		delete from sys_user where user_id = #{userId}
  	</delete>
+ 	
+ 	<delete id="deleteUserByIds" parameterType="Long">
+ 		update sys_user set del_flag = '2' where user_id in
+ 		<foreach collection="array" item="userId" open="(" separator="," close=")">
+ 			#{userId}
+        </foreach> 
+ 	</delete>
 	
 </mapper>