Commit ea4c9e498164f992582634471ddb47a056aad0c1
1 parent
dba723b8
1. 修改 MenuDO 的字段,menuId 改成 id,menuName 改成 name
2. 添加 Menu 的创建、修改、删除接口
Showing
29 changed files
with
503 additions
and
237 deletions
ruoyi-ui/src/api/system/menu.js
| ... | ... | @@ -10,9 +10,9 @@ export function listMenu(query) { |
| 10 | 10 | } |
| 11 | 11 | |
| 12 | 12 | // 查询菜单详细 |
| 13 | -export function getMenu(menuId) { | |
| 13 | +export function getMenu(id) { | |
| 14 | 14 | return request({ |
| 15 | - url: '/system/menu/' + menuId, | |
| 15 | + url: '/system/menu/get?id=' + id, | |
| 16 | 16 | method: 'get' |
| 17 | 17 | }) |
| 18 | 18 | } |
| ... | ... | @@ -36,7 +36,7 @@ export function roleMenuTreeselect(roleId) { |
| 36 | 36 | // 新增菜单 |
| 37 | 37 | export function addMenu(data) { |
| 38 | 38 | return request({ |
| 39 | - url: '/system/menu', | |
| 39 | + url: '/system/menu/create', | |
| 40 | 40 | method: 'post', |
| 41 | 41 | data: data |
| 42 | 42 | }) |
| ... | ... | @@ -45,16 +45,16 @@ export function addMenu(data) { |
| 45 | 45 | // 修改菜单 |
| 46 | 46 | export function updateMenu(data) { |
| 47 | 47 | return request({ |
| 48 | - url: '/system/menu', | |
| 49 | - method: 'put', | |
| 48 | + url: '/system/menu/update', | |
| 49 | + method: 'post', | |
| 50 | 50 | data: data |
| 51 | 51 | }) |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | // 删除菜单 |
| 55 | -export function delMenu(menuId) { | |
| 55 | +export function delMenu(id) { | |
| 56 | 56 | return request({ |
| 57 | - url: '/system/menu/' + menuId, | |
| 58 | - method: 'delete' | |
| 57 | + url: '/system/menu/delete?id=' + id, | |
| 58 | + method: 'post' | |
| 59 | 59 | }) |
| 60 | -} | |
| 61 | 60 | \ No newline at end of file |
| 61 | +} | ... | ... |
ruoyi-ui/src/store/modules/dict.js
ruoyi-ui/src/store/modules/permission.js
ruoyi-ui/src/utils/constants.js
0 → 100644
| 1 | +/** | |
| 2 | + * Created by 芋道源码 | |
| 3 | + * | |
| 4 | + * 枚举类 | |
| 5 | + */ | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 全局通用状态枚举 | |
| 9 | + */ | |
| 10 | +export const SysCommonStatusEnum = { | |
| 11 | + ENABLE: 0, // 开启 | |
| 12 | + DISABLE: 1 // 禁用 | |
| 13 | +} | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * 菜单的类型枚举 | |
| 17 | + */ | |
| 18 | +export const SysMenuTypeEnum = { | |
| 19 | + DIR : 1, // 目录 | |
| 20 | + MENU: 2, // 菜单 | |
| 21 | + BUTTON: 3 // 按钮 | |
| 22 | +} | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * 角色的类型枚举 | |
| 26 | + */ | |
| 27 | +export const RoleTypeEnum = { | |
| 28 | + SYSTEM: 1, // 内置角色 | |
| 29 | + CUSTOM: 2 // 自定义角色 | |
| 30 | +} | ... | ... |
ruoyi-ui/src/utils/dict.js
| ... | ... | @@ -6,7 +6,8 @@ |
| 6 | 6 | import store from '@/store' |
| 7 | 7 | |
| 8 | 8 | export const DICT_TYPE = { |
| 9 | - SYS_COMMON_STATUS: 'sys_common_status' | |
| 9 | + SYS_COMMON_STATUS: 'sys_common_status', | |
| 10 | + SYS_MENU_TYPE: 'menu_type' | |
| 10 | 11 | } |
| 11 | 12 | |
| 12 | 13 | /** |
| ... | ... | @@ -28,8 +29,8 @@ export function getDictDataLabel(dictType, value) { |
| 28 | 29 | // 获取 value 对应的展示名 |
| 29 | 30 | value = value + '' // 强制转换成字符串,因为 DictData 小类数值,是字符串 |
| 30 | 31 | for (const dictData of dictDatas) { |
| 31 | - if (dictData.dictValue === value) { | |
| 32 | - return dictData.dictLabel | |
| 32 | + if (dictData.value === value) { | |
| 33 | + return dictData.label | |
| 33 | 34 | } |
| 34 | 35 | } |
| 35 | 36 | return '' | ... | ... |
ruoyi-ui/src/views/system/menu/index.vue
| 1 | 1 | <template> |
| 2 | 2 | <div class="app-container"> |
| 3 | 3 | <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch"> |
| 4 | - <el-form-item label="菜单名称" prop="menuName"> | |
| 4 | + <el-form-item label="菜单名称" prop="name"> | |
| 5 | 5 | <el-input |
| 6 | - v-model="queryParams.menuName" | |
| 6 | + v-model="queryParams.name" | |
| 7 | 7 | placeholder="请输入菜单名称" |
| 8 | 8 | clearable |
| 9 | 9 | size="small" |
| ... | ... | @@ -42,10 +42,10 @@ |
| 42 | 42 | <el-table |
| 43 | 43 | v-loading="loading" |
| 44 | 44 | :data="menuList" |
| 45 | - row-key="menuId" | |
| 45 | + row-key="id" | |
| 46 | 46 | :tree-props="{children: 'children', hasChildren: 'hasChildren'}" |
| 47 | 47 | > |
| 48 | - <el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column> | |
| 48 | + <el-table-column prop="name" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column> | |
| 49 | 49 | <el-table-column prop="icon" label="图标" align="center" width="100"> |
| 50 | 50 | <template slot-scope="scope"> |
| 51 | 51 | <svg-icon :icon-class="scope.row.icon" /> |
| ... | ... | @@ -102,16 +102,18 @@ |
| 102 | 102 | </el-form-item> |
| 103 | 103 | </el-col> |
| 104 | 104 | <el-col :span="24"> |
| 105 | - <el-form-item label="菜单类型" prop="menuType"> | |
| 106 | - <el-radio-group v-model="form.menuType"> | |
| 107 | - <el-radio label="1">目录</el-radio> | |
| 108 | - <el-radio label="2">菜单</el-radio> | |
| 109 | - <el-radio label="3">按钮</el-radio> | |
| 105 | + <el-form-item label="菜单类型" prop="type"> | |
| 106 | + <el-radio-group v-model="form.type"> | |
| 107 | + <el-radio | |
| 108 | + v-for="dict in menuTypeDictDatas" | |
| 109 | + :key="dict.value" | |
| 110 | + :label="dict.value" | |
| 111 | + >{{dict.label}}</el-radio> | |
| 110 | 112 | </el-radio-group> |
| 111 | 113 | </el-form-item> |
| 112 | 114 | </el-col> |
| 113 | 115 | <el-col :span="24"> |
| 114 | - <el-form-item v-if="form.menuType != '3'" label="菜单图标"> | |
| 116 | + <el-form-item v-if="form.type != '3'" label="菜单图标"> | |
| 115 | 117 | <el-popover |
| 116 | 118 | placement="bottom-start" |
| 117 | 119 | width="460" |
| ... | ... | @@ -133,65 +135,38 @@ |
| 133 | 135 | </el-form-item> |
| 134 | 136 | </el-col> |
| 135 | 137 | <el-col :span="12"> |
| 136 | - <el-form-item label="菜单名称" prop="menuName"> | |
| 137 | - <el-input v-model="form.menuName" placeholder="请输入菜单名称" /> | |
| 138 | + <el-form-item label="菜单名称" prop="name"> | |
| 139 | + <el-input v-model="form.name" placeholder="请输入菜单名称" /> | |
| 138 | 140 | </el-form-item> |
| 139 | 141 | </el-col> |
| 140 | 142 | <el-col :span="12"> |
| 141 | - <el-form-item label="显示排序" prop="orderNum"> | |
| 142 | - <el-input-number v-model="form.orderNum" controls-position="right" :min="0" /> | |
| 143 | - </el-form-item> | |
| 144 | - </el-col> | |
| 145 | - <el-col :span="12"> | |
| 146 | - <el-form-item v-if="form.menuType != '3'" label="是否外链"> | |
| 147 | - <el-radio-group v-model="form.isFrame"> | |
| 148 | - <el-radio label="0">是</el-radio> | |
| 149 | - <el-radio label="1">否</el-radio> | |
| 150 | - </el-radio-group> | |
| 143 | + <el-form-item label="显示排序" prop="sort"> | |
| 144 | + <el-input-number v-model="form.sort" controls-position="right" :min="0" /> | |
| 151 | 145 | </el-form-item> |
| 152 | 146 | </el-col> |
| 153 | 147 | <el-col :span="12"> |
| 154 | - <el-form-item v-if="form.menuType != '3'" label="路由地址" prop="path"> | |
| 148 | + <el-form-item v-if="form.type != '3'" label="路由地址" prop="path"> | |
| 155 | 149 | <el-input v-model="form.path" placeholder="请输入路由地址" /> |
| 156 | 150 | </el-form-item> |
| 157 | 151 | </el-col> |
| 158 | - <el-col :span="12" v-if="form.menuType == '2'"> | |
| 152 | + <el-col :span="12" v-if="form.type == '2'"> | |
| 159 | 153 | <el-form-item label="组件路径" prop="component"> |
| 160 | 154 | <el-input v-model="form.component" placeholder="请输入组件路径" /> |
| 161 | 155 | </el-form-item> |
| 162 | 156 | </el-col> |
| 163 | 157 | <el-col :span="12"> |
| 164 | - <el-form-item v-if="form.menuType != '1'" label="权限标识"> | |
| 158 | + <el-form-item v-if="form.type != '1'" label="权限标识"> | |
| 165 | 159 | <el-input v-model="form.perms" placeholder="请权限标识" maxlength="50" /> |
| 166 | 160 | </el-form-item> |
| 167 | 161 | </el-col> |
| 168 | 162 | <el-col :span="12"> |
| 169 | - <el-form-item v-if="form.menuType != '3'" label="显示状态"> | |
| 170 | - <el-radio-group v-model="form.visible"> | |
| 171 | - <el-radio | |
| 172 | - v-for="dict in visibleOptions" | |
| 173 | - :key="dict.dictValue" | |
| 174 | - :label="dict.dictValue" | |
| 175 | - >{{dict.dictLabel}}</el-radio> | |
| 176 | - </el-radio-group> | |
| 177 | - </el-form-item> | |
| 178 | - </el-col> | |
| 179 | - <el-col :span="12"> | |
| 180 | - <el-form-item v-if="form.menuType != '3'" label="菜单状态"> | |
| 163 | + <el-form-item v-if="form.type != '3'" label="菜单状态"> | |
| 181 | 164 | <el-radio-group v-model="form.status"> |
| 182 | 165 | <el-radio |
| 183 | - v-for="dict in statusOptions" | |
| 184 | - :key="dict.dictValue" | |
| 185 | - :label="dict.dictValue" | |
| 186 | - >{{dict.dictLabel}}</el-radio> | |
| 187 | - </el-radio-group> | |
| 188 | - </el-form-item> | |
| 189 | - </el-col> | |
| 190 | - <el-col :span="12"> | |
| 191 | - <el-form-item v-if="form.menuType == '2'" label="是否缓存"> | |
| 192 | - <el-radio-group v-model="form.isCache"> | |
| 193 | - <el-radio label="0">缓存</el-radio> | |
| 194 | - <el-radio label="1">不缓存</el-radio> | |
| 166 | + v-for="dict in statusDictDatas" | |
| 167 | + :key="dict.value" | |
| 168 | + :label="dict.value" | |
| 169 | + >{{dict.label}}</el-radio> | |
| 195 | 170 | </el-radio-group> |
| 196 | 171 | </el-form-item> |
| 197 | 172 | </el-col> |
| ... | ... | @@ -211,6 +186,7 @@ import Treeselect from "@riophae/vue-treeselect"; |
| 211 | 186 | import "@riophae/vue-treeselect/dist/vue-treeselect.css"; |
| 212 | 187 | import IconSelect from "@/components/IconSelect"; |
| 213 | 188 | |
| 189 | +import { SysMenuTypeEnum, SysCommonStatusEnum } from '@/utils/constants' | |
| 214 | 190 | import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict' |
| 215 | 191 | |
| 216 | 192 | export default { |
| ... | ... | @@ -230,29 +206,34 @@ export default { |
| 230 | 206 | title: "", |
| 231 | 207 | // 是否显示弹出层 |
| 232 | 208 | open: false, |
| 233 | - // 显示状态数据字典 | |
| 234 | - visibleOptions: [], | |
| 235 | 209 | // 菜单状态数据字典 |
| 236 | 210 | statusOptions: [], |
| 237 | 211 | // 查询参数 |
| 238 | 212 | queryParams: { |
| 239 | - menuName: undefined, | |
| 213 | + name: undefined, | |
| 240 | 214 | visible: undefined |
| 241 | 215 | }, |
| 242 | 216 | // 表单参数 |
| 243 | 217 | form: {}, |
| 244 | 218 | // 表单校验 |
| 245 | 219 | rules: { |
| 246 | - menuName: [ | |
| 220 | + name: [ | |
| 247 | 221 | { required: true, message: "菜单名称不能为空", trigger: "blur" } |
| 248 | 222 | ], |
| 249 | - orderNum: [ | |
| 223 | + sort: [ | |
| 250 | 224 | { required: true, message: "菜单顺序不能为空", trigger: "blur" } |
| 251 | 225 | ], |
| 252 | 226 | path: [ |
| 253 | 227 | { required: true, message: "路由地址不能为空", trigger: "blur" } |
| 254 | 228 | ] |
| 255 | - } | |
| 229 | + }, | |
| 230 | + | |
| 231 | + // 枚举 | |
| 232 | + MenuTypeEnum: SysMenuTypeEnum, | |
| 233 | + CommonStatusEnum: SysCommonStatusEnum, | |
| 234 | + // 数据字典 | |
| 235 | + menuTypeDictDatas: getDictDatas(DICT_TYPE.SYS_MENU_TYPE), | |
| 236 | + statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS) | |
| 256 | 237 | }; |
| 257 | 238 | }, |
| 258 | 239 | created() { |
| ... | ... | @@ -267,7 +248,7 @@ export default { |
| 267 | 248 | getList() { |
| 268 | 249 | this.loading = true; |
| 269 | 250 | listMenu(this.queryParams).then(response => { |
| 270 | - this.menuList = this.handleTree(response.data, "menuId"); | |
| 251 | + this.menuList = this.handleTree(response.data, "id"); | |
| 271 | 252 | this.loading = false; |
| 272 | 253 | }); |
| 273 | 254 | }, |
| ... | ... | @@ -277,8 +258,8 @@ export default { |
| 277 | 258 | delete node.children; |
| 278 | 259 | } |
| 279 | 260 | return { |
| 280 | - id: node.menuId, | |
| 281 | - label: node.menuName, | |
| 261 | + id: node.id, | |
| 262 | + label: node.name, | |
| 282 | 263 | children: node.children |
| 283 | 264 | }; |
| 284 | 265 | }, |
| ... | ... | @@ -286,8 +267,8 @@ export default { |
| 286 | 267 | getTreeselect() { |
| 287 | 268 | listMenu().then(response => { |
| 288 | 269 | this.menuOptions = []; |
| 289 | - const menu = { menuId: 0, menuName: '主类目', children: [] }; | |
| 290 | - menu.children = this.handleTree(response.data, "menuId"); | |
| 270 | + const menu = { id: 0, name: '主类目', children: [] }; | |
| 271 | + menu.children = this.handleTree(response.data, "id"); | |
| 291 | 272 | this.menuOptions.push(menu); |
| 292 | 273 | }); |
| 293 | 274 | }, |
| ... | ... | @@ -303,15 +284,12 @@ export default { |
| 303 | 284 | // 表单重置 |
| 304 | 285 | reset() { |
| 305 | 286 | this.form = { |
| 306 | - menuId: undefined, | |
| 287 | + id: undefined, | |
| 307 | 288 | parentId: 0, |
| 308 | - menuName: undefined, | |
| 289 | + name: undefined, | |
| 309 | 290 | icon: undefined, |
| 310 | - menuType: "1", | |
| 311 | - orderNum: undefined, | |
| 312 | - isFrame: "1", | |
| 313 | - isCache: "0", | |
| 314 | - visible: "0", | |
| 291 | + type: "1", | |
| 292 | + sort: undefined, | |
| 315 | 293 | status: "0" |
| 316 | 294 | }; |
| 317 | 295 | this.resetForm("form"); |
| ... | ... | @@ -329,8 +307,8 @@ export default { |
| 329 | 307 | handleAdd(row) { |
| 330 | 308 | this.reset(); |
| 331 | 309 | this.getTreeselect(); |
| 332 | - if (row != null && row.menuId) { | |
| 333 | - this.form.parentId = row.menuId; | |
| 310 | + if (row != null && row.id) { | |
| 311 | + this.form.parentId = row.id; | |
| 334 | 312 | } else { |
| 335 | 313 | this.form.parentId = 0; |
| 336 | 314 | } |
| ... | ... | @@ -341,7 +319,7 @@ export default { |
| 341 | 319 | handleUpdate(row) { |
| 342 | 320 | this.reset(); |
| 343 | 321 | this.getTreeselect(); |
| 344 | - getMenu(row.menuId).then(response => { | |
| 322 | + getMenu(row.id).then(response => { | |
| 345 | 323 | this.form = response.data; |
| 346 | 324 | this.open = true; |
| 347 | 325 | this.title = "修改菜单"; |
| ... | ... | @@ -351,7 +329,24 @@ export default { |
| 351 | 329 | submitForm: function() { |
| 352 | 330 | this.$refs["form"].validate(valid => { |
| 353 | 331 | if (valid) { |
| 354 | - if (this.form.menuId != undefined) { | |
| 332 | + // 若权限类型为菜单时,进行 route 的校验,避免后续拼接出来的路由无法跳转 | |
| 333 | + if (this.form.type === ResourceTypeEnum.MENU) { | |
| 334 | + // 如果是外链,则不进行校验 | |
| 335 | + const route = this.resourceForm.route | |
| 336 | + if (route.indexOf('http://') === -1 || route.indexOf('https://') === -1) { | |
| 337 | + // 父权限为根节点,route 必须以 / 开头 | |
| 338 | + if (this.resourceForm.pid === 0 && route.charAt(0) !== '/') { | |
| 339 | + this.messageSuccess('前端必须以 / 开头') | |
| 340 | + return | |
| 341 | + } else if (this.resourceForm.pid !== 0 && route.charAt(0) === '/') { | |
| 342 | + this.messageSuccess('前端不能以 / 开头') | |
| 343 | + return | |
| 344 | + } | |
| 345 | + } | |
| 346 | + } | |
| 347 | + | |
| 348 | + // 提交 | |
| 349 | + if (this.form.id !== undefined) { | |
| 355 | 350 | updateMenu(this.form).then(response => { |
| 356 | 351 | this.msgSuccess("修改成功"); |
| 357 | 352 | this.open = false; |
| ... | ... | @@ -369,12 +364,12 @@ export default { |
| 369 | 364 | }, |
| 370 | 365 | /** 删除按钮操作 */ |
| 371 | 366 | handleDelete(row) { |
| 372 | - this.$confirm('是否确认删除名称为"' + row.menuName + '"的数据项?', "警告", { | |
| 367 | + this.$confirm('是否确认删除名称为"' + row.name + '"的数据项?', "警告", { | |
| 373 | 368 | confirmButtonText: "确定", |
| 374 | 369 | cancelButtonText: "取消", |
| 375 | 370 | type: "warning" |
| 376 | 371 | }).then(function() { |
| 377 | - return delMenu(row.menuId); | |
| 372 | + return delMenu(row.id); | |
| 378 | 373 | }).then(() => { |
| 379 | 374 | this.getList(); |
| 380 | 375 | this.msgSuccess("删除成功"); | ... | ... |
ruoyi-ui/src/views/system/role/index.vue
| ... | ... | @@ -437,7 +437,7 @@ export default { |
| 437 | 437 | roleKey: undefined, |
| 438 | 438 | roleSort: 0, |
| 439 | 439 | status: "0", |
| 440 | - menuIds: [], | |
| 440 | + ids: [], | |
| 441 | 441 | deptIds: [], |
| 442 | 442 | menuCheckStrictly: true, |
| 443 | 443 | deptCheckStrictly: true, |
| ... | ... | @@ -535,14 +535,14 @@ export default { |
| 535 | 535 | this.$refs["form"].validate(valid => { |
| 536 | 536 | if (valid) { |
| 537 | 537 | if (this.form.roleId != undefined) { |
| 538 | - this.form.menuIds = this.getMenuAllCheckedKeys(); | |
| 538 | + this.form.ids = this.getMenuAllCheckedKeys(); | |
| 539 | 539 | updateRole(this.form).then(response => { |
| 540 | 540 | this.msgSuccess("修改成功"); |
| 541 | 541 | this.open = false; |
| 542 | 542 | this.getList(); |
| 543 | 543 | }); |
| 544 | 544 | } else { |
| 545 | - this.form.menuIds = this.getMenuAllCheckedKeys(); | |
| 545 | + this.form.ids = this.getMenuAllCheckedKeys(); | |
| 546 | 546 | addRole(this.form).then(response => { |
| 547 | 547 | this.msgSuccess("新增成功"); |
| 548 | 548 | this.open = false; |
| ... | ... | @@ -592,4 +592,4 @@ export default { |
| 592 | 592 | } |
| 593 | 593 | } |
| 594 | 594 | }; |
| 595 | -</script> | |
| 596 | 595 | \ No newline at end of file |
| 596 | +</script> | ... | ... |
ruoyi-ui/src/views/tool/gen/editTable.vue
ruoyi-ui/src/views/tool/gen/genInfoForm.vue
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/SysAuthMenuRespVO.java
| 1 | 1 | package cn.iocoder.dashboard.modules.system.controller.auth.vo; |
| 2 | 2 | |
| 3 | 3 | import io.swagger.annotations.ApiModel; |
| 4 | +import io.swagger.annotations.ApiModelProperty; | |
| 4 | 5 | import lombok.AllArgsConstructor; |
| 5 | 6 | import lombok.Builder; |
| 6 | 7 | import lombok.Data; |
| ... | ... | @@ -15,32 +16,22 @@ import java.util.List; |
| 15 | 16 | @Builder |
| 16 | 17 | public class SysAuthMenuRespVO { |
| 17 | 18 | |
| 18 | - /** | |
| 19 | - * 菜单编号 | |
| 20 | - */ | |
| 21 | - private Long menuId; | |
| 22 | - /** | |
| 23 | - * 父菜单编号 | |
| 24 | - */ | |
| 19 | + @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") | |
| 20 | + private Long id; | |
| 21 | + | |
| 22 | + @ApiModelProperty(value = "父菜单 ID", required = true, example = "1024") | |
| 25 | 23 | private Long parentId; |
| 26 | 24 | |
| 27 | - /** | |
| 28 | - * 菜单名称 | |
| 29 | - */ | |
| 30 | - private String menuName; | |
| 25 | + @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") | |
| 26 | + private String name; | |
| 31 | 27 | |
| 32 | - /** | |
| 33 | - * 路由地址 | |
| 34 | - */ | |
| 28 | + @ApiModelProperty(value = "路由地址", example = "post", notes = "仅菜单类型为菜单或者目录时,才需要传") | |
| 35 | 29 | private String path; |
| 36 | - /** | |
| 37 | - * 组件地址 | |
| 38 | - */ | |
| 30 | + | |
| 31 | + @ApiModelProperty(value = "组件路径", example = "system/post/index", notes = "仅菜单类型为菜单时,才需要传") | |
| 39 | 32 | private String component; |
| 40 | 33 | |
| 41 | - /** | |
| 42 | - * 菜单图标 | |
| 43 | - */ | |
| 34 | + @ApiModelProperty(value = "菜单图标", example = "/menu/list", notes = "仅菜单类型为菜单或者目录时,才需要传") | |
| 44 | 35 | private String icon; |
| 45 | 36 | |
| 46 | 37 | /** | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/SysDataDictSimpleVO.java
| ... | ... | @@ -12,9 +12,9 @@ public class SysDataDictSimpleVO { |
| 12 | 12 | private String dictType; |
| 13 | 13 | |
| 14 | 14 | @ApiModelProperty(value = "字典键值", required = true, example = "1") |
| 15 | - private String dictValue; | |
| 15 | + private String value; | |
| 16 | 16 | |
| 17 | 17 | @ApiModelProperty(value = "字典标签", required = true, example = "男") |
| 18 | - private String dictLabel; | |
| 18 | + private String label; | |
| 19 | 19 | |
| 20 | 20 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/SysMenuController.java
| 1 | 1 | package cn.iocoder.dashboard.modules.system.controller.permission; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.dashboard.common.pojo.CommonResult; |
| 4 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO; | |
| 4 | 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; |
| 5 | 6 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; |
| 7 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO; | |
| 8 | +import cn.iocoder.dashboard.modules.system.convert.permission.SysMenuConvert; | |
| 9 | +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | |
| 6 | 10 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; |
| 7 | 11 | import io.swagger.annotations.Api; |
| 8 | -import org.springframework.web.bind.annotation.GetMapping; | |
| 9 | -import org.springframework.web.bind.annotation.RequestMapping; | |
| 10 | -import org.springframework.web.bind.annotation.RestController; | |
| 12 | +import io.swagger.annotations.ApiOperation; | |
| 13 | +import org.springframework.validation.annotation.Validated; | |
| 14 | +import org.springframework.web.bind.annotation.*; | |
| 11 | 15 | |
| 12 | 16 | import javax.annotation.Resource; |
| 13 | 17 | import java.util.List; |
| ... | ... | @@ -22,24 +26,21 @@ public class SysMenuController { |
| 22 | 26 | @Resource |
| 23 | 27 | private SysMenuService menuService; |
| 24 | 28 | |
| 25 | - /** | |
| 26 | - * 获取菜单列表 | |
| 27 | - */ | |
| 29 | + @ApiOperation("获取菜单列表") | |
| 28 | 30 | // @PreAuthorize("@ss.hasPermi('system:menu:list')") |
| 29 | 31 | @GetMapping("/list") |
| 30 | 32 | public CommonResult<List<SysMenuRespVO>> list(SysMenuListReqVO reqVO) { |
| 31 | 33 | return success(menuService.listMenus(reqVO)); |
| 32 | 34 | } |
| 33 | -// | |
| 34 | -// /** | |
| 35 | -// * 根据菜单编号获取详细信息 | |
| 36 | -// */ | |
| 35 | + | |
| 36 | + @ApiOperation("获取菜单信息") | |
| 37 | + @GetMapping("/get") | |
| 37 | 38 | // @PreAuthorize("@ss.hasPermi('system:menu:query')") |
| 38 | -// @GetMapping(value = "/{menuId}") | |
| 39 | -// public AjaxResult getInfo(@PathVariable Long menuId) { | |
| 40 | -// return AjaxResult.success(menuService.selectMenuById(menuId)); | |
| 41 | -// } | |
| 42 | -// | |
| 39 | + public CommonResult<SysMenuRespVO> getMenu(Long id) { | |
| 40 | + SysMenuDO menu = menuService.getMenu(id); | |
| 41 | + return success(SysMenuConvert.INSTANCE.convert(menu)); | |
| 42 | + } | |
| 43 | + | |
| 43 | 44 | // /** |
| 44 | 45 | // * 获取菜单下拉树列表 |
| 45 | 46 | // */ |
| ... | ... | @@ -63,57 +64,31 @@ public class SysMenuController { |
| 63 | 64 | // ajax.put("menus", menuService.buildMenuTreeSelect(menus)); |
| 64 | 65 | // return ajax; |
| 65 | 66 | // } |
| 66 | -// | |
| 67 | -// /** | |
| 68 | -// * 新增菜单 | |
| 69 | -// */ | |
| 67 | + | |
| 68 | + @ApiOperation("新增菜单") | |
| 70 | 69 | // @PreAuthorize("@ss.hasPermi('system:menu:add')") |
| 71 | 70 | // @Log(title = "菜单管理", businessType = BusinessType.INSERT) |
| 72 | -// @PostMapping | |
| 73 | -// public AjaxResult add(@Validated @RequestBody SysMenu menu) { | |
| 74 | -// if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) { | |
| 75 | -// return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); | |
| 76 | -// } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) | |
| 77 | -// && !StringUtils.startsWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS)) { | |
| 78 | -// return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); | |
| 79 | -// } | |
| 80 | -// menu.setCreateBy(SecurityUtils.getUsername()); | |
| 81 | -// return toAjax(menuService.insertMenu(menu)); | |
| 82 | -// } | |
| 83 | -// | |
| 84 | -// /** | |
| 85 | -// * 修改菜单 | |
| 86 | -// */ | |
| 71 | + @PostMapping("/create") | |
| 72 | + public CommonResult<Long> createMenu(@Validated @RequestBody SysMenuCreateReqVO reqVO) { | |
| 73 | + Long menuId = menuService.createMenu(reqVO); | |
| 74 | + return success(menuId); | |
| 75 | + } | |
| 76 | + | |
| 77 | + @ApiOperation("修改菜单") | |
| 87 | 78 | // @PreAuthorize("@ss.hasPermi('system:menu:edit')") |
| 88 | 79 | // @Log(title = "菜单管理", businessType = BusinessType.UPDATE) |
| 89 | -// @PutMapping | |
| 90 | -// public AjaxResult edit(@Validated @RequestBody SysMenu menu) { | |
| 91 | -// if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) { | |
| 92 | -// return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); | |
| 93 | -// } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) | |
| 94 | -// && !StringUtils.startsWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS)) { | |
| 95 | -// return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); | |
| 96 | -// } else if (menu.getMenuId().equals(menu.getParentId())) { | |
| 97 | -// return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); | |
| 98 | -// } | |
| 99 | -// menu.setUpdateBy(SecurityUtils.getUsername()); | |
| 100 | -// return toAjax(menuService.updateMenu(menu)); | |
| 101 | -// } | |
| 102 | -// | |
| 103 | -// /** | |
| 104 | -// * 删除菜单 | |
| 105 | -// */ | |
| 106 | -// @PreAuthorize("@ss.hasPermi('system:menu:remove')") | |
| 80 | + @PostMapping("/update") | |
| 81 | + public CommonResult<Boolean> updateMenu(@Validated @RequestBody SysMenuUpdateReqVO reqVO) { | |
| 82 | + menuService.updateMenu(reqVO); | |
| 83 | + return success(true); | |
| 84 | + } | |
| 85 | + | |
| 86 | + @ApiOperation("删除菜单") | |
| 107 | 87 | // @Log(title = "菜单管理", businessType = BusinessType.DELETE) |
| 108 | 88 | // @DeleteMapping("/{menuId}") |
| 109 | -// public AjaxResult remove(@PathVariable("menuId") Long menuId) { | |
| 110 | -// if (menuService.hasChildByMenuId(menuId)) { | |
| 111 | -// return AjaxResult.error("存在子菜单,不允许删除"); | |
| 112 | -// } | |
| 113 | -// if (menuService.checkMenuExistRole(menuId)) { | |
| 114 | -// return AjaxResult.error("菜单已分配,不允许删除"); | |
| 115 | -// } | |
| 116 | -// return toAjax(menuService.deleteMenuById(menuId)); | |
| 117 | -// } | |
| 89 | + public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) { | |
| 90 | + menuService.deleteMenu(id); | |
| 91 | + return success(true); | |
| 92 | + } | |
| 118 | 93 | |
| 119 | 94 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuBaseVO.java
| ... | ... | @@ -17,15 +17,15 @@ public class SysMenuBaseVO { |
| 17 | 17 | @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") |
| 18 | 18 | @NotBlank(message = "菜单名称不能为空") |
| 19 | 19 | @Size(max = 50, message = "菜单名称长度不能超过50个字符") |
| 20 | - private String menuName; | |
| 20 | + private String name; | |
| 21 | 21 | |
| 22 | 22 | @ApiModelProperty(value = "权限标识", example = "sys:menu:add", notes = "仅菜单类型为按钮时,才需要传递") |
| 23 | 23 | @Size(max = 100) |
| 24 | 24 | private String permission; |
| 25 | 25 | |
| 26 | - @ApiModelProperty(value = "类型", required = true, example = "1", notes = "参见 MenuTypeEnum 枚举类") | |
| 26 | + @ApiModelProperty(value = "类型", required = true, example = "1", notes = "参见 SysMenuTypeEnum 枚举类") | |
| 27 | 27 | @NotBlank(message = "菜单类型不能为空") |
| 28 | - private Integer menuType; | |
| 28 | + private Integer type; | |
| 29 | 29 | |
| 30 | 30 | @ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024") |
| 31 | 31 | @NotBlank(message = "显示顺序不能为空") | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuListReqVO.java
| ... | ... | @@ -14,7 +14,7 @@ public class SysMenuListReqVO { |
| 14 | 14 | @ApiModelProperty(value = "菜单名称", example = "芋道", notes = "模糊匹配") |
| 15 | 15 | private String menuName; |
| 16 | 16 | |
| 17 | - @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类") | |
| 17 | + @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类") | |
| 18 | 18 | private Integer status; |
| 19 | 19 | |
| 20 | 20 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuRespVO.java
| ... | ... | @@ -17,9 +17,9 @@ import java.util.Date; |
| 17 | 17 | public class SysMenuRespVO extends SysMenuBaseVO { |
| 18 | 18 | |
| 19 | 19 | @ApiModelProperty(value = "菜单编号", required = true, example = "1024") |
| 20 | - private Integer menuId; | |
| 20 | + private Integer id; | |
| 21 | 21 | |
| 22 | - @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类") | |
| 22 | + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 SysCommonStatusEnum 枚举类") | |
| 23 | 23 | private Integer status; |
| 24 | 24 | |
| 25 | 25 | @ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式") | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuUpdateReqVO.java
src/main/java/cn/iocoder/dashboard/modules/system/convert/auth/SysAuthConvert.java
| 1 | 1 | package cn.iocoder.dashboard.modules.system.convert.auth; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.dashboard.framework.security.core.LoginUser; |
| 4 | -import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthPermissionInfoRespVO; | |
| 5 | 4 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthMenuRespVO; |
| 5 | +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthPermissionInfoRespVO; | |
| 6 | 6 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 7 | 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; |
| 8 | 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; |
| 9 | +import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum; | |
| 9 | 10 | import cn.iocoder.dashboard.util.collection.CollectionUtils; |
| 10 | 11 | import org.mapstruct.Mapper; |
| 11 | 12 | import org.mapstruct.Mapping; |
| 12 | 13 | import org.mapstruct.factory.Mappers; |
| 14 | +import org.slf4j.LoggerFactory; | |
| 13 | 15 | |
| 14 | -import java.util.List; | |
| 16 | +import java.util.*; | |
| 15 | 17 | |
| 16 | 18 | @Mapper |
| 17 | 19 | public interface SysAuthConvert { |
| ... | ... | @@ -31,4 +33,36 @@ public interface SysAuthConvert { |
| 31 | 33 | |
| 32 | 34 | SysAuthMenuRespVO convertTreeNode(SysMenuDO menu); |
| 33 | 35 | |
| 36 | + /** | |
| 37 | + * 将菜单列表,构建成菜单树 | |
| 38 | + * | |
| 39 | + * @param menuList 菜单列表 | |
| 40 | + * @return 菜单树 | |
| 41 | + */ | |
| 42 | + default List<SysAuthMenuRespVO> buildMenuTree(List<SysMenuDO> menuList) { | |
| 43 | + // 排序,保证菜单的有序性 | |
| 44 | + menuList.sort(Comparator.comparing(SysMenuDO::getSort)); | |
| 45 | + // 构建菜单树 | |
| 46 | + // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 | |
| 47 | + Map<Long, SysAuthMenuRespVO> treeNodeMap = new LinkedHashMap<>(); | |
| 48 | + menuList.forEach(menu -> treeNodeMap.put(menu.getId(), SysAuthConvert.INSTANCE.convertTreeNode(menu))); | |
| 49 | + // 处理父子关系 | |
| 50 | + treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(MenuIdEnum.ROOT.getId())).forEach((childNode) -> { | |
| 51 | + // 获得父节点 | |
| 52 | + SysAuthMenuRespVO parentNode = treeNodeMap.get(childNode.getParentId()); | |
| 53 | + if (parentNode == null) { | |
| 54 | + LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", | |
| 55 | + childNode.getId(), childNode.getParentId()); | |
| 56 | + return; | |
| 57 | + } | |
| 58 | + // 将自己添加到父节点中 | |
| 59 | + if (parentNode.getChildren() == null) { | |
| 60 | + parentNode.setChildren(new ArrayList<>()); | |
| 61 | + } | |
| 62 | + parentNode.getChildren().add(childNode); | |
| 63 | + }); | |
| 64 | + // 获得到所有的根节点 | |
| 65 | + return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId())); | |
| 66 | + } | |
| 67 | + | |
| 34 | 68 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/convert/permission/SysMenuConvert.java
| 1 | 1 | package cn.iocoder.dashboard.modules.system.convert.permission; |
| 2 | 2 | |
| 3 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO; | |
| 3 | 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; |
| 5 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO; | |
| 4 | 6 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 5 | 7 | import org.mapstruct.Mapper; |
| 6 | 8 | import org.mapstruct.factory.Mappers; |
| ... | ... | @@ -14,4 +16,10 @@ public interface SysMenuConvert { |
| 14 | 16 | |
| 15 | 17 | List<SysMenuRespVO> convertList(List<SysMenuDO> list); |
| 16 | 18 | |
| 19 | + SysMenuDO convert(SysMenuCreateReqVO bean); | |
| 20 | + | |
| 21 | + SysMenuDO convert(SysMenuUpdateReqVO bean); | |
| 22 | + | |
| 23 | + SysMenuRespVO convert(SysMenuDO bean); | |
| 24 | + | |
| 17 | 25 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/permission/SysMenuMapper.java
| 1 | 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 4 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |
| 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| 5 | 6 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 7 | |
| 7 | 8 | @Mapper |
| 8 | 9 | public interface SysMenuMapper extends BaseMapper<SysMenuDO> { |
| 10 | + | |
| 11 | + default SysMenuDO selectByParentIdAndName(Long parentId, String name) { | |
| 12 | + return selectOne(new QueryWrapper<SysMenuDO>().eq("parent_id", parentId) | |
| 13 | + .eq("name", name)); | |
| 14 | + } | |
| 15 | + | |
| 16 | + default Integer selectCountByParentId(Long parentId) { | |
| 17 | + return selectCount(new QueryWrapper<SysMenuDO>().eq("parent_id", parentId)); | |
| 18 | + } | |
| 19 | + | |
| 9 | 20 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictDataDO.java
| ... | ... | @@ -26,30 +26,30 @@ public class SysDictDataDO extends BaseDO { |
| 26 | 26 | */ |
| 27 | 27 | @TableId |
| 28 | 28 | @Excel(name = "字典编码", cellType = Excel.ColumnType.NUMERIC) |
| 29 | - private Long dictCode; | |
| 29 | + private Long id; | |
| 30 | 30 | /** |
| 31 | 31 | * 字典排序 |
| 32 | 32 | */ |
| 33 | 33 | @Excel(name = "字典排序", cellType = Excel.ColumnType.NUMERIC) |
| 34 | - private Integer dictSort; | |
| 34 | + private Integer sort; | |
| 35 | 35 | /** |
| 36 | 36 | * 字典标签 |
| 37 | 37 | */ |
| 38 | 38 | @Excel(name = "字典标签") |
| 39 | 39 | @NotBlank(message = "字典标签不能为空") |
| 40 | 40 | @Size(max = 100, message = "字典标签长度不能超过100个字符") |
| 41 | - private String dictLabel; | |
| 41 | + private String label; | |
| 42 | 42 | /** |
| 43 | - * 字典键值 | |
| 43 | + * 字典值 | |
| 44 | 44 | */ |
| 45 | 45 | @Excel(name = "字典键值") |
| 46 | 46 | @NotBlank(message = "字典键值不能为空") |
| 47 | 47 | @Size(max = 100, message = "字典键值长度不能超过100个字符") |
| 48 | - private String dictValue; | |
| 48 | + private String value; | |
| 49 | 49 | /** |
| 50 | 50 | * 字典类型 |
| 51 | 51 | * |
| 52 | - * 外键 {@link SysDictDataDO#getDictType()} | |
| 52 | + * 冗余 {@link SysDictDataDO#getDictType()} | |
| 53 | 53 | */ |
| 54 | 54 | @Excel(name = "字典类型") |
| 55 | 55 | @NotBlank(message = "字典类型不能为空") | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictTypeDO.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict; |
| 3 | 3 | import cn.iocoder.dashboard.common.enums.CommonStatusEnum; |
| 4 | 4 | import cn.iocoder.dashboard.framework.excel.Excel; |
| 5 | 5 | import cn.iocoder.dashboard.framework.mybatis.core.BaseDO; |
| 6 | +import com.baomidou.mybatisplus.annotation.TableField; | |
| 6 | 7 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | 8 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | 9 | import lombok.Data; |
| ... | ... | @@ -26,24 +27,22 @@ public class SysDictTypeDO extends BaseDO { |
| 26 | 27 | */ |
| 27 | 28 | @TableId |
| 28 | 29 | @Excel(name = "字典主键", cellType = Excel.ColumnType.NUMERIC) |
| 29 | - private Long dictId; | |
| 30 | - | |
| 30 | + private Long id; | |
| 31 | 31 | /** |
| 32 | 32 | * 字典名称 |
| 33 | 33 | */ |
| 34 | 34 | @Excel(name = "字典名称") |
| 35 | 35 | @NotBlank(message = "字典名称不能为空") |
| 36 | 36 | @Size(max = 100, message = "字典类型名称长度不能超过100个字符") |
| 37 | - private String dictName; | |
| 38 | - | |
| 37 | + private String name; | |
| 39 | 38 | /** |
| 40 | 39 | * 字典类型 |
| 41 | 40 | */ |
| 41 | + @TableField("dict_type") | |
| 42 | 42 | @Excel(name = "字典类型") |
| 43 | 43 | @NotBlank(message = "字典类型不能为空") |
| 44 | 44 | @Size(max = 100, message = "字典类型类型长度不能超过100个字符") |
| 45 | - private String dictType; | |
| 46 | - | |
| 45 | + private String type; | |
| 47 | 46 | /** |
| 48 | 47 | * 状态 |
| 49 | 48 | * | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/permission/SysMenuDO.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission; |
| 3 | 3 | import cn.iocoder.dashboard.common.enums.CommonStatusEnum; |
| 4 | 4 | import cn.iocoder.dashboard.framework.mybatis.core.BaseDO; |
| 5 | 5 | import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; |
| 6 | +import com.baomidou.mybatisplus.annotation.TableField; | |
| 6 | 7 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | 8 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | 9 | import lombok.Data; |
| ... | ... | @@ -22,11 +23,11 @@ public class SysMenuDO extends BaseDO { |
| 22 | 23 | * 菜单ID |
| 23 | 24 | */ |
| 24 | 25 | @TableId |
| 25 | - private Long menuId; | |
| 26 | + private Long id; | |
| 26 | 27 | /** |
| 27 | 28 | * 菜单名称 |
| 28 | 29 | */ |
| 29 | - private String menuName; | |
| 30 | + private String name; | |
| 30 | 31 | /** |
| 31 | 32 | * 权限标识 |
| 32 | 33 | * |
| ... | ... | @@ -43,7 +44,8 @@ public class SysMenuDO extends BaseDO { |
| 43 | 44 | * |
| 44 | 45 | * 枚举 {@link MenuTypeEnum} |
| 45 | 46 | */ |
| 46 | - private Integer menuType; | |
| 47 | + @TableField("menu_type") | |
| 48 | + private Integer type; | |
| 47 | 49 | /** |
| 48 | 50 | * 显示顺序 |
| 49 | 51 | */ | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java
| ... | ... | @@ -18,4 +18,12 @@ public interface SysErrorCodeConstants { |
| 18 | 18 | ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); |
| 19 | 19 | ErrorCode TOKEN_PARSE_FAIL = new ErrorCode(1002001001, "Token 解析失败"); |
| 20 | 20 | |
| 21 | + // ========== 菜单模块 1002002000 ========== | |
| 22 | + ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1002002000, "已经存在该名字的菜单"); | |
| 23 | + ErrorCode MENU_PARENT_NOT_EXISTS = new ErrorCode(1002002001, "父菜单不存在"); | |
| 24 | + ErrorCode MENU_PARENT_ERROR = new ErrorCode(1002002002, "不能设置自己为父菜单"); | |
| 25 | + ErrorCode MENU_NOT_EXISTS = new ErrorCode(1002002003, "菜单不存在"); | |
| 26 | + ErrorCode MENU_EXISTS_CHILDREN = new ErrorCode(1002002004, "存在子菜单,无法删除"); | |
| 27 | + ErrorCode MENU_PARENT_NOT_MENU = new ErrorCode(1002002005, "父菜单的类型必须是菜单"); | |
| 28 | + | |
| 21 | 29 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java
| ... | ... | @@ -12,7 +12,6 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMe |
| 12 | 12 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; |
| 13 | 13 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; |
| 14 | 14 | import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO; |
| 15 | -import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum; | |
| 16 | 15 | import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; |
| 17 | 16 | import cn.iocoder.dashboard.modules.system.enums.user.UserStatus; |
| 18 | 17 | import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService; |
| ... | ... | @@ -38,7 +37,10 @@ import org.springframework.stereotype.Service; |
| 38 | 37 | import org.springframework.util.Assert; |
| 39 | 38 | |
| 40 | 39 | import javax.annotation.Resource; |
| 41 | -import java.util.*; | |
| 40 | +import java.util.Date; | |
| 41 | +import java.util.HashSet; | |
| 42 | +import java.util.List; | |
| 43 | +import java.util.Set; | |
| 42 | 44 | |
| 43 | 45 | import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; |
| 44 | 46 | import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; |
| ... | ... | @@ -243,36 +245,12 @@ public class SysAuthServiceImpl implements SysAuthService { |
| 243 | 245 | |
| 244 | 246 | @Override |
| 245 | 247 | public List<SysAuthMenuRespVO> listMenus(Long userId, Set<Long> roleIds) { |
| 248 | + // 获得用户拥有的菜单列表 | |
| 246 | 249 | List<SysMenuDO> menuList = permissionService.listRoleMenusFromCache(roleIds, |
| 247 | - SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), | |
| 248 | - SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); | |
| 250 | + SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型 | |
| 251 | + SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的 | |
| 249 | 252 | // 转换成 Tree 结构返回 |
| 250 | - return buildRouterTree(menuList); | |
| 251 | - } | |
| 252 | - | |
| 253 | - private static List<SysAuthMenuRespVO> buildRouterTree(List<SysMenuDO> menuList) { | |
| 254 | - // 排序,保证菜单的有序性 | |
| 255 | - menuList.sort(Comparator.comparing(SysMenuDO::getSort)); | |
| 256 | - // 构建菜单树 | |
| 257 | - // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 | |
| 258 | - Map<Long, SysAuthMenuRespVO> treeNodeMap = new LinkedHashMap<>(); | |
| 259 | - menuList.forEach(menu -> treeNodeMap.put(menu.getMenuId(), SysAuthConvert.INSTANCE.convertTreeNode(menu))); | |
| 260 | - // 处理父子关系 | |
| 261 | - treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(MenuIdEnum.ROOT.getId())).forEach((childNode) -> { | |
| 262 | - // 获得父节点 | |
| 263 | - SysAuthMenuRespVO parentNode = treeNodeMap.get(childNode.getParentId()); | |
| 264 | - if (parentNode == null) { | |
| 265 | - log.error("[buildRouterTree][resource({}) 找不到父资源({})]", childNode.getMenuId(), childNode.getParentId()); | |
| 266 | - return; | |
| 267 | - } | |
| 268 | - // 将自己添加到父节点中 | |
| 269 | - if (parentNode.getChildren() == null) { | |
| 270 | - parentNode.setChildren(new ArrayList<>()); | |
| 271 | - } | |
| 272 | - parentNode.getChildren().add(childNode); | |
| 273 | - }); | |
| 274 | - // 获得到所有的根节点 | |
| 275 | - return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId())); | |
| 253 | + return SysAuthConvert.INSTANCE.buildMenuTree(menuList); | |
| 276 | 254 | } |
| 277 | 255 | |
| 278 | 256 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java
| ... | ... | @@ -19,7 +19,7 @@ public class SysDictDataServiceImpl implements SysDictDataService { |
| 19 | 19 | |
| 20 | 20 | private static final Comparator<SysDictDataDO> COMPARATOR_TYPE_AND_SORT = Comparator |
| 21 | 21 | .comparing(SysDictDataDO::getDictType) |
| 22 | - .thenComparingInt(SysDictDataDO::getDictSort); | |
| 22 | + .thenComparingInt(SysDictDataDO::getSort); | |
| 23 | 23 | |
| 24 | 24 | @Resource |
| 25 | 25 | private SysDictDataMapper dictDataMapper; | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuService.java
| 1 | 1 | package cn.iocoder.dashboard.modules.system.service.permission; |
| 2 | 2 | |
| 3 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO; | |
| 3 | 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; |
| 4 | 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; |
| 6 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO; | |
| 5 | 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 6 | 8 | |
| 7 | 9 | import java.util.Collection; |
| ... | ... | @@ -9,6 +11,8 @@ import java.util.List; |
| 9 | 11 | |
| 10 | 12 | /** |
| 11 | 13 | * 菜单 Service 接口 |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 12 | 16 | */ |
| 13 | 17 | public interface SysMenuService { |
| 14 | 18 | |
| ... | ... | @@ -49,4 +53,34 @@ public interface SysMenuService { |
| 49 | 53 | List<SysMenuDO> listMenusFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes, |
| 50 | 54 | Collection<Integer> menusStatuses); |
| 51 | 55 | |
| 56 | + /* | |
| 57 | + * 创建菜单 | |
| 58 | + * | |
| 59 | + * @param reqVO 菜单信息 | |
| 60 | + * @return 创建出来的菜单编号 | |
| 61 | + */ | |
| 62 | + Long createMenu(SysMenuCreateReqVO reqVO); | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * 更新菜单 | |
| 66 | + * | |
| 67 | + * @param reqVO 菜单信息 | |
| 68 | + */ | |
| 69 | + void updateMenu(SysMenuUpdateReqVO reqVO); | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * 删除菜单 | |
| 73 | + * | |
| 74 | + * @param id 菜单编号 | |
| 75 | + */ | |
| 76 | + void deleteMenu(Long id); | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * 获得菜单 | |
| 80 | + * | |
| 81 | + * @param id 菜单编号 | |
| 82 | + * @return 菜单 | |
| 83 | + */ | |
| 84 | + SysMenuDO getMenu(Long id); | |
| 85 | + | |
| 52 | 86 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionService.java
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java
| 1 | 1 | package cn.iocoder.dashboard.modules.system.service.permission.impl; |
| 2 | 2 | |
| 3 | +import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; | |
| 4 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO; | |
| 3 | 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; |
| 4 | 6 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; |
| 7 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO; | |
| 5 | 8 | import cn.iocoder.dashboard.modules.system.convert.permission.SysMenuConvert; |
| 6 | 9 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysMenuMapper; |
| 7 | 10 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 11 | +import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum; | |
| 12 | +import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; | |
| 8 | 13 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; |
| 14 | +import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; | |
| 9 | 15 | import cn.iocoder.dashboard.util.collection.CollectionUtils; |
| 10 | 16 | import com.google.common.collect.ImmutableMap; |
| 11 | 17 | import com.google.common.collect.ImmutableMultimap; |
| ... | ... | @@ -21,8 +27,12 @@ import java.util.List; |
| 21 | 27 | import java.util.Map; |
| 22 | 28 | import java.util.stream.Collectors; |
| 23 | 29 | |
| 30 | +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; | |
| 31 | + | |
| 24 | 32 | /** |
| 25 | 33 | * 菜单 Service 实现 |
| 34 | + * | |
| 35 | + * @author 芋道源码 | |
| 26 | 36 | */ |
| 27 | 37 | @Service |
| 28 | 38 | @Slf4j |
| ... | ... | @@ -46,6 +56,8 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 46 | 56 | |
| 47 | 57 | @Resource |
| 48 | 58 | private SysMenuMapper menuMapper; |
| 59 | + @Resource | |
| 60 | + private SysPermissionService permissionService; | |
| 49 | 61 | |
| 50 | 62 | /** |
| 51 | 63 | * 初始化 {@link #menuCache} 和 {@link #permMenuCache} 缓存 |
| ... | ... | @@ -57,7 +69,7 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 57 | 69 | ImmutableMap.Builder<Long, SysMenuDO> menuCacheBuilder = ImmutableMap.builder(); |
| 58 | 70 | ImmutableMultimap.Builder<String, SysMenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); |
| 59 | 71 | menuList.forEach(menuDO -> { |
| 60 | - menuCacheBuilder.put(menuDO.getMenuId(), menuDO); | |
| 72 | + menuCacheBuilder.put(menuDO.getId(), menuDO); | |
| 61 | 73 | permMenuCacheBuilder.put(menuDO.getPermission(), menuDO); |
| 62 | 74 | }); |
| 63 | 75 | menuCache = menuCacheBuilder.build(); |
| ... | ... | @@ -79,7 +91,7 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 79 | 91 | return Collections.emptyList(); |
| 80 | 92 | } |
| 81 | 93 | // 创建新数组,避免缓存被修改 |
| 82 | - return menuCache.values().stream().filter(menu -> menuTypes.contains(menu.getMenuType()) | |
| 94 | + return menuCache.values().stream().filter(menu -> menuTypes.contains(menu.getType()) | |
| 83 | 95 | && menusStatuses.contains(menu.getStatus())) |
| 84 | 96 | .collect(Collectors.toList()); |
| 85 | 97 | } |
| ... | ... | @@ -91,10 +103,186 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 91 | 103 | if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) { |
| 92 | 104 | return Collections.emptyList(); |
| 93 | 105 | } |
| 94 | - return menuCache.values().stream().filter(menu -> menuIds.contains(menu.getMenuId()) | |
| 95 | - && menuTypes.contains(menu.getMenuType()) | |
| 106 | + return menuCache.values().stream().filter(menu -> menuIds.contains(menu.getId()) | |
| 107 | + && menuTypes.contains(menu.getType()) | |
| 96 | 108 | && menusStatuses.contains(menu.getStatus())) |
| 97 | 109 | .collect(Collectors.toList()); |
| 98 | 110 | } |
| 99 | 111 | |
| 112 | + @Override | |
| 113 | + public Long createMenu(SysMenuCreateReqVO reqVO) { | |
| 114 | + // 校验父菜单存在 | |
| 115 | + checkParentResource(reqVO.getParentId(), null); | |
| 116 | + // 校验菜单(自己) | |
| 117 | + checkResource(reqVO.getParentId(), reqVO.getName(), null); | |
| 118 | + // 插入数据库 | |
| 119 | + SysMenuDO menu = SysMenuConvert.INSTANCE.convert(reqVO); | |
| 120 | + initMenuProperty(menu); | |
| 121 | + menuMapper.insert(menu); | |
| 122 | + // 返回 | |
| 123 | + return menu.getId(); | |
| 124 | + } | |
| 125 | + | |
| 126 | + @Override | |
| 127 | + public void updateMenu(SysMenuUpdateReqVO reqVO) { | |
| 128 | + // 校验更新的菜单是否存在 | |
| 129 | + if (menuMapper.selectById(reqVO.getId()) == null) { | |
| 130 | + throw ServiceExceptionUtil.exception(MENU_NOT_EXISTS); | |
| 131 | + } | |
| 132 | + // 校验父菜单存在 | |
| 133 | + checkParentResource(reqVO.getParentId(), reqVO.getId()); | |
| 134 | + // 校验菜单(自己) | |
| 135 | + checkResource(reqVO.getParentId(), reqVO.getName(), reqVO.getId()); | |
| 136 | + // 更新到数据库 | |
| 137 | + SysMenuDO updateObject = SysMenuConvert.INSTANCE.convert(reqVO); | |
| 138 | + initMenuProperty(updateObject); | |
| 139 | + menuMapper.updateById(updateObject); | |
| 140 | + } | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * 删除菜单 | |
| 144 | + * | |
| 145 | + * @param menuId 菜单编号 | |
| 146 | + */ | |
| 147 | + public void deleteMenu(Long menuId) { | |
| 148 | + // 校验更新的菜单是否存在 | |
| 149 | + if (menuMapper.selectById(menuId) == null) { | |
| 150 | + throw ServiceExceptionUtil.exception(MENU_NOT_EXISTS); | |
| 151 | + } | |
| 152 | + // 校验是否还有子菜单 | |
| 153 | + if (menuMapper.selectCountByParentId(menuId) > 0) { | |
| 154 | + throw ServiceExceptionUtil.exception(MENU_EXISTS_CHILDREN); | |
| 155 | + } | |
| 156 | + // 校验删除的菜单是否存在 | |
| 157 | + if (menuMapper.selectById(menuId) == null) { | |
| 158 | + throw ServiceExceptionUtil.exception(MENU_NOT_EXISTS); | |
| 159 | + } | |
| 160 | + // 标记删除 | |
| 161 | + menuMapper.deleteById(menuId); | |
| 162 | + // 删除授予给角色的权限 | |
| 163 | + permissionService.deleteRolesMenuByMenuId(menuId); | |
| 164 | + } | |
| 165 | + | |
| 166 | + @Override | |
| 167 | + public SysMenuDO getMenu(Long id) { | |
| 168 | + return menuMapper.selectById(id); | |
| 169 | + } | |
| 170 | + | |
| 171 | +// /** | |
| 172 | +// * 获得菜单列表 | |
| 173 | +// * | |
| 174 | +// * @param menuIds 菜单编号列表 | |
| 175 | +// * @return 菜单列表 | |
| 176 | +// */ | |
| 177 | +// public List<ResourceBO> listResources(List<Integer> menuIds) { | |
| 178 | +// List<ResourceDO> menuDOs = menuMapper.selectBatchIds(menuIds); | |
| 179 | +// return ResourceConvert.INSTANCE.convertList(menuDOs); | |
| 180 | +// } | |
| 181 | +// | |
| 182 | +// /** | |
| 183 | +// * 获得菜单全列表 | |
| 184 | +// * | |
| 185 | +// * @return 菜单全列表 | |
| 186 | +// */ | |
| 187 | +// public List<ResourceBO> listResources() { | |
| 188 | +// List<ResourceDO> menuDOs = menuMapper.selectList(null); | |
| 189 | +// return ResourceConvert.INSTANCE.convertList(menuDOs); | |
| 190 | +// } | |
| 191 | +// | |
| 192 | +// /** | |
| 193 | +// * 获得指定类型的菜单列表 | |
| 194 | +// * | |
| 195 | +// * @param type 菜单类型,允许空 | |
| 196 | +// * @return 菜单列表 | |
| 197 | +// */ | |
| 198 | +// public List<ResourceBO> listResourcesByType(Integer type) { | |
| 199 | +// List<ResourceDO> menuDOs = menuMapper.selectListByType(type); | |
| 200 | +// return ResourceConvert.INSTANCE.convertList(menuDOs); | |
| 201 | +// } | |
| 202 | +// | |
| 203 | +// /** | |
| 204 | +// * 获得角色拥有的菜单列表 | |
| 205 | +// * | |
| 206 | +// * @param roleIds 角色编号 | |
| 207 | +// * @param type 菜单类型,允许空 | |
| 208 | +// * @return 菜单列表 | |
| 209 | +// */ | |
| 210 | +// public List<ResourceBO> listRoleResourcesByType(Collection<Integer> roleIds, Integer type) { | |
| 211 | +// List<RoleResourceDO> roleResourceDOs = roleResourceMapper.selectListByRoleIds(roleIds); | |
| 212 | +// if (CollectionUtils.isEmpty(roleResourceDOs)) { | |
| 213 | +// return Collections.emptyList(); | |
| 214 | +// } | |
| 215 | +// List<ResourceDO> menuDOs = menuMapper.selectListByIdsAndType( | |
| 216 | +// CollectionUtils.convertSet(roleResourceDOs, RoleResourceDO::getResourceId), type); | |
| 217 | +// return ResourceConvert.INSTANCE.convertList(menuDOs); | |
| 218 | +// } | |
| 219 | +// | |
| 220 | + /** | |
| 221 | + * 校验父菜单是否合法 | |
| 222 | + * | |
| 223 | + * 1. 不能设置自己为父菜单 | |
| 224 | + * 2. 父菜单不存在 | |
| 225 | + * 3. 父菜单必须是 {@link MenuTypeEnum#MENU} 菜单类型 | |
| 226 | + * | |
| 227 | + * @param parentId 父菜单编号 | |
| 228 | + * @param childId 当前菜单编号 | |
| 229 | + */ | |
| 230 | + private void checkParentResource(Long parentId, Long childId) { | |
| 231 | + if (parentId == null || MenuIdEnum.ROOT.getId().equals(parentId)) { | |
| 232 | + return; | |
| 233 | + } | |
| 234 | + // 不能设置自己为父菜单 | |
| 235 | + if (parentId.equals(childId)) { | |
| 236 | + throw ServiceExceptionUtil.exception(MENU_PARENT_ERROR); | |
| 237 | + } | |
| 238 | + SysMenuDO menu = menuMapper.selectById(parentId); | |
| 239 | + // 父菜单不存在 | |
| 240 | + if (menu == null) { | |
| 241 | + throw ServiceExceptionUtil.exception(MENU_PARENT_NOT_EXISTS); | |
| 242 | + } | |
| 243 | + // 父菜单必须是目录类型 | |
| 244 | + if (!MenuTypeEnum.DIR.getType().equals(menu.getType())) { | |
| 245 | + throw ServiceExceptionUtil.exception(MENU_PARENT_NOT_MENU); | |
| 246 | + } | |
| 247 | + } | |
| 248 | + | |
| 249 | + /** | |
| 250 | + * 校验菜单是否合法 | |
| 251 | + * | |
| 252 | + * 1. 校验相同父菜单编号下,是否存在相同的菜单名 | |
| 253 | + * | |
| 254 | + * @param name 菜单名字 | |
| 255 | + * @param parentId 父菜单编号 | |
| 256 | + * @param id 菜单编号 | |
| 257 | + */ | |
| 258 | + private void checkResource(Long parentId, String name, Long id) { | |
| 259 | + SysMenuDO menu = menuMapper.selectByParentIdAndName(parentId, name); | |
| 260 | + if (menu == null) { | |
| 261 | + return; | |
| 262 | + } | |
| 263 | + // 如果 menuId 为空,说明不用比较是否为相同 menuId 的菜单 | |
| 264 | + if (id == null) { | |
| 265 | + throw ServiceExceptionUtil.exception(MENU_NAME_DUPLICATE); | |
| 266 | + } | |
| 267 | + if (!menu.getId().equals(id)) { | |
| 268 | + throw ServiceExceptionUtil.exception(MENU_NAME_DUPLICATE); | |
| 269 | + } | |
| 270 | + } | |
| 271 | + | |
| 272 | + /** | |
| 273 | + * 初始化菜单的通用属性。 | |
| 274 | + * | |
| 275 | + * 例如说,只有目录或者菜单类型的菜单,才设置 icon | |
| 276 | + * | |
| 277 | + * @param menu 菜单 | |
| 278 | + */ | |
| 279 | + private void initMenuProperty(SysMenuDO menu) { | |
| 280 | + // 菜单为按钮类型时,无需 component、icon、path 属性,进行置空 | |
| 281 | + if (MenuTypeEnum.BUTTON.getType().equals(menu.getType())) { | |
| 282 | + menu.setComponent(""); | |
| 283 | + menu.setIcon(""); | |
| 284 | + menu.setPath(""); | |
| 285 | + } | |
| 286 | + } | |
| 287 | + | |
| 100 | 288 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java
| ... | ... | @@ -107,4 +107,9 @@ public class SysPermissionServiceImpl implements SysPermissionService { |
| 107 | 107 | return roleDept != null ? roleDept.getRoleId() : null; |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | + @Override | |
| 111 | + public void deleteRolesMenuByMenuId(Long menuId) { | |
| 112 | + // TODO 实现我 | |
| 113 | + } | |
| 114 | + | |
| 110 | 115 | } | ... | ... |