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,9 +10,9 @@ export function listMenu(query) { | ||
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | // 查询菜单详细 | 12 | // 查询菜单详细 |
| 13 | -export function getMenu(menuId) { | 13 | +export function getMenu(id) { |
| 14 | return request({ | 14 | return request({ |
| 15 | - url: '/system/menu/' + menuId, | 15 | + url: '/system/menu/get?id=' + id, |
| 16 | method: 'get' | 16 | method: 'get' |
| 17 | }) | 17 | }) |
| 18 | } | 18 | } |
| @@ -36,7 +36,7 @@ export function roleMenuTreeselect(roleId) { | @@ -36,7 +36,7 @@ export function roleMenuTreeselect(roleId) { | ||
| 36 | // 新增菜单 | 36 | // 新增菜单 |
| 37 | export function addMenu(data) { | 37 | export function addMenu(data) { |
| 38 | return request({ | 38 | return request({ |
| 39 | - url: '/system/menu', | 39 | + url: '/system/menu/create', |
| 40 | method: 'post', | 40 | method: 'post', |
| 41 | data: data | 41 | data: data |
| 42 | }) | 42 | }) |
| @@ -45,16 +45,16 @@ export function addMenu(data) { | @@ -45,16 +45,16 @@ export function addMenu(data) { | ||
| 45 | // 修改菜单 | 45 | // 修改菜单 |
| 46 | export function updateMenu(data) { | 46 | export function updateMenu(data) { |
| 47 | return request({ | 47 | return request({ |
| 48 | - url: '/system/menu', | ||
| 49 | - method: 'put', | 48 | + url: '/system/menu/update', |
| 49 | + method: 'post', | ||
| 50 | data: data | 50 | data: data |
| 51 | }) | 51 | }) |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | // 删除菜单 | 54 | // 删除菜单 |
| 55 | -export function delMenu(menuId) { | 55 | +export function delMenu(id) { |
| 56 | return request({ | 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 | \ No newline at end of file | 60 | \ No newline at end of file |
| 61 | +} |
ruoyi-ui/src/store/modules/dict.js
| @@ -28,8 +28,8 @@ const actions = { | @@ -28,8 +28,8 @@ const actions = { | ||
| 28 | } | 28 | } |
| 29 | // 处理 dictValue 层级 | 29 | // 处理 dictValue 层级 |
| 30 | dictDataMap[dictData.dictType].push({ | 30 | dictDataMap[dictData.dictType].push({ |
| 31 | - dictValue: dictData.dictValue, | ||
| 32 | - dictLabel: dictData.dictLabel | 31 | + value: dictData.value, |
| 32 | + label: dictData.label | ||
| 33 | }) | 33 | }) |
| 34 | }) | 34 | }) |
| 35 | // 存储到 Store 中 | 35 | // 存储到 Store 中 |
ruoyi-ui/src/store/modules/permission.js
| @@ -44,7 +44,7 @@ function filterAsyncRouter(asyncRouterMap, isRewrite = false) { | @@ -44,7 +44,7 @@ function filterAsyncRouter(asyncRouterMap, isRewrite = false) { | ||
| 44 | // 将 ruoyi 后端原有耦合前端的逻辑,迁移到此处 | 44 | // 将 ruoyi 后端原有耦合前端的逻辑,迁移到此处 |
| 45 | // 处理 meta 属性 | 45 | // 处理 meta 属性 |
| 46 | route.meta = { | 46 | route.meta = { |
| 47 | - title: route.menuName, | 47 | + title: route.name, |
| 48 | icon: route.icon | 48 | icon: route.icon |
| 49 | } | 49 | } |
| 50 | // 处理 component 属性 | 50 | // 处理 component 属性 |
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,7 +6,8 @@ | ||
| 6 | import store from '@/store' | 6 | import store from '@/store' |
| 7 | 7 | ||
| 8 | export const DICT_TYPE = { | 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,8 +29,8 @@ export function getDictDataLabel(dictType, value) { | ||
| 28 | // 获取 value 对应的展示名 | 29 | // 获取 value 对应的展示名 |
| 29 | value = value + '' // 强制转换成字符串,因为 DictData 小类数值,是字符串 | 30 | value = value + '' // 强制转换成字符串,因为 DictData 小类数值,是字符串 |
| 30 | for (const dictData of dictDatas) { | 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 | return '' | 36 | return '' |
ruoyi-ui/src/views/system/menu/index.vue
| 1 | <template> | 1 | <template> |
| 2 | <div class="app-container"> | 2 | <div class="app-container"> |
| 3 | <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch"> | 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 | <el-input | 5 | <el-input |
| 6 | - v-model="queryParams.menuName" | 6 | + v-model="queryParams.name" |
| 7 | placeholder="请输入菜单名称" | 7 | placeholder="请输入菜单名称" |
| 8 | clearable | 8 | clearable |
| 9 | size="small" | 9 | size="small" |
| @@ -42,10 +42,10 @@ | @@ -42,10 +42,10 @@ | ||
| 42 | <el-table | 42 | <el-table |
| 43 | v-loading="loading" | 43 | v-loading="loading" |
| 44 | :data="menuList" | 44 | :data="menuList" |
| 45 | - row-key="menuId" | 45 | + row-key="id" |
| 46 | :tree-props="{children: 'children', hasChildren: 'hasChildren'}" | 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 | <el-table-column prop="icon" label="图标" align="center" width="100"> | 49 | <el-table-column prop="icon" label="图标" align="center" width="100"> |
| 50 | <template slot-scope="scope"> | 50 | <template slot-scope="scope"> |
| 51 | <svg-icon :icon-class="scope.row.icon" /> | 51 | <svg-icon :icon-class="scope.row.icon" /> |
| @@ -102,16 +102,18 @@ | @@ -102,16 +102,18 @@ | ||
| 102 | </el-form-item> | 102 | </el-form-item> |
| 103 | </el-col> | 103 | </el-col> |
| 104 | <el-col :span="24"> | 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 | </el-radio-group> | 112 | </el-radio-group> |
| 111 | </el-form-item> | 113 | </el-form-item> |
| 112 | </el-col> | 114 | </el-col> |
| 113 | <el-col :span="24"> | 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 | <el-popover | 117 | <el-popover |
| 116 | placement="bottom-start" | 118 | placement="bottom-start" |
| 117 | width="460" | 119 | width="460" |
| @@ -133,65 +135,38 @@ | @@ -133,65 +135,38 @@ | ||
| 133 | </el-form-item> | 135 | </el-form-item> |
| 134 | </el-col> | 136 | </el-col> |
| 135 | <el-col :span="12"> | 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 | </el-form-item> | 140 | </el-form-item> |
| 139 | </el-col> | 141 | </el-col> |
| 140 | <el-col :span="12"> | 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 | </el-form-item> | 145 | </el-form-item> |
| 152 | </el-col> | 146 | </el-col> |
| 153 | <el-col :span="12"> | 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 | <el-input v-model="form.path" placeholder="请输入路由地址" /> | 149 | <el-input v-model="form.path" placeholder="请输入路由地址" /> |
| 156 | </el-form-item> | 150 | </el-form-item> |
| 157 | </el-col> | 151 | </el-col> |
| 158 | - <el-col :span="12" v-if="form.menuType == '2'"> | 152 | + <el-col :span="12" v-if="form.type == '2'"> |
| 159 | <el-form-item label="组件路径" prop="component"> | 153 | <el-form-item label="组件路径" prop="component"> |
| 160 | <el-input v-model="form.component" placeholder="请输入组件路径" /> | 154 | <el-input v-model="form.component" placeholder="请输入组件路径" /> |
| 161 | </el-form-item> | 155 | </el-form-item> |
| 162 | </el-col> | 156 | </el-col> |
| 163 | <el-col :span="12"> | 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 | <el-input v-model="form.perms" placeholder="请权限标识" maxlength="50" /> | 159 | <el-input v-model="form.perms" placeholder="请权限标识" maxlength="50" /> |
| 166 | </el-form-item> | 160 | </el-form-item> |
| 167 | </el-col> | 161 | </el-col> |
| 168 | <el-col :span="12"> | 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 | <el-radio-group v-model="form.status"> | 164 | <el-radio-group v-model="form.status"> |
| 182 | <el-radio | 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 | </el-radio-group> | 170 | </el-radio-group> |
| 196 | </el-form-item> | 171 | </el-form-item> |
| 197 | </el-col> | 172 | </el-col> |
| @@ -211,6 +186,7 @@ import Treeselect from "@riophae/vue-treeselect"; | @@ -211,6 +186,7 @@ import Treeselect from "@riophae/vue-treeselect"; | ||
| 211 | import "@riophae/vue-treeselect/dist/vue-treeselect.css"; | 186 | import "@riophae/vue-treeselect/dist/vue-treeselect.css"; |
| 212 | import IconSelect from "@/components/IconSelect"; | 187 | import IconSelect from "@/components/IconSelect"; |
| 213 | 188 | ||
| 189 | +import { SysMenuTypeEnum, SysCommonStatusEnum } from '@/utils/constants' | ||
| 214 | import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict' | 190 | import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict' |
| 215 | 191 | ||
| 216 | export default { | 192 | export default { |
| @@ -230,29 +206,34 @@ export default { | @@ -230,29 +206,34 @@ export default { | ||
| 230 | title: "", | 206 | title: "", |
| 231 | // 是否显示弹出层 | 207 | // 是否显示弹出层 |
| 232 | open: false, | 208 | open: false, |
| 233 | - // 显示状态数据字典 | ||
| 234 | - visibleOptions: [], | ||
| 235 | // 菜单状态数据字典 | 209 | // 菜单状态数据字典 |
| 236 | statusOptions: [], | 210 | statusOptions: [], |
| 237 | // 查询参数 | 211 | // 查询参数 |
| 238 | queryParams: { | 212 | queryParams: { |
| 239 | - menuName: undefined, | 213 | + name: undefined, |
| 240 | visible: undefined | 214 | visible: undefined |
| 241 | }, | 215 | }, |
| 242 | // 表单参数 | 216 | // 表单参数 |
| 243 | form: {}, | 217 | form: {}, |
| 244 | // 表单校验 | 218 | // 表单校验 |
| 245 | rules: { | 219 | rules: { |
| 246 | - menuName: [ | 220 | + name: [ |
| 247 | { required: true, message: "菜单名称不能为空", trigger: "blur" } | 221 | { required: true, message: "菜单名称不能为空", trigger: "blur" } |
| 248 | ], | 222 | ], |
| 249 | - orderNum: [ | 223 | + sort: [ |
| 250 | { required: true, message: "菜单顺序不能为空", trigger: "blur" } | 224 | { required: true, message: "菜单顺序不能为空", trigger: "blur" } |
| 251 | ], | 225 | ], |
| 252 | path: [ | 226 | path: [ |
| 253 | { required: true, message: "路由地址不能为空", trigger: "blur" } | 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 | created() { | 239 | created() { |
| @@ -267,7 +248,7 @@ export default { | @@ -267,7 +248,7 @@ export default { | ||
| 267 | getList() { | 248 | getList() { |
| 268 | this.loading = true; | 249 | this.loading = true; |
| 269 | listMenu(this.queryParams).then(response => { | 250 | listMenu(this.queryParams).then(response => { |
| 270 | - this.menuList = this.handleTree(response.data, "menuId"); | 251 | + this.menuList = this.handleTree(response.data, "id"); |
| 271 | this.loading = false; | 252 | this.loading = false; |
| 272 | }); | 253 | }); |
| 273 | }, | 254 | }, |
| @@ -277,8 +258,8 @@ export default { | @@ -277,8 +258,8 @@ export default { | ||
| 277 | delete node.children; | 258 | delete node.children; |
| 278 | } | 259 | } |
| 279 | return { | 260 | return { |
| 280 | - id: node.menuId, | ||
| 281 | - label: node.menuName, | 261 | + id: node.id, |
| 262 | + label: node.name, | ||
| 282 | children: node.children | 263 | children: node.children |
| 283 | }; | 264 | }; |
| 284 | }, | 265 | }, |
| @@ -286,8 +267,8 @@ export default { | @@ -286,8 +267,8 @@ export default { | ||
| 286 | getTreeselect() { | 267 | getTreeselect() { |
| 287 | listMenu().then(response => { | 268 | listMenu().then(response => { |
| 288 | this.menuOptions = []; | 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 | this.menuOptions.push(menu); | 272 | this.menuOptions.push(menu); |
| 292 | }); | 273 | }); |
| 293 | }, | 274 | }, |
| @@ -303,15 +284,12 @@ export default { | @@ -303,15 +284,12 @@ export default { | ||
| 303 | // 表单重置 | 284 | // 表单重置 |
| 304 | reset() { | 285 | reset() { |
| 305 | this.form = { | 286 | this.form = { |
| 306 | - menuId: undefined, | 287 | + id: undefined, |
| 307 | parentId: 0, | 288 | parentId: 0, |
| 308 | - menuName: undefined, | 289 | + name: undefined, |
| 309 | icon: undefined, | 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 | status: "0" | 293 | status: "0" |
| 316 | }; | 294 | }; |
| 317 | this.resetForm("form"); | 295 | this.resetForm("form"); |
| @@ -329,8 +307,8 @@ export default { | @@ -329,8 +307,8 @@ export default { | ||
| 329 | handleAdd(row) { | 307 | handleAdd(row) { |
| 330 | this.reset(); | 308 | this.reset(); |
| 331 | this.getTreeselect(); | 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 | } else { | 312 | } else { |
| 335 | this.form.parentId = 0; | 313 | this.form.parentId = 0; |
| 336 | } | 314 | } |
| @@ -341,7 +319,7 @@ export default { | @@ -341,7 +319,7 @@ export default { | ||
| 341 | handleUpdate(row) { | 319 | handleUpdate(row) { |
| 342 | this.reset(); | 320 | this.reset(); |
| 343 | this.getTreeselect(); | 321 | this.getTreeselect(); |
| 344 | - getMenu(row.menuId).then(response => { | 322 | + getMenu(row.id).then(response => { |
| 345 | this.form = response.data; | 323 | this.form = response.data; |
| 346 | this.open = true; | 324 | this.open = true; |
| 347 | this.title = "修改菜单"; | 325 | this.title = "修改菜单"; |
| @@ -351,7 +329,24 @@ export default { | @@ -351,7 +329,24 @@ export default { | ||
| 351 | submitForm: function() { | 329 | submitForm: function() { |
| 352 | this.$refs["form"].validate(valid => { | 330 | this.$refs["form"].validate(valid => { |
| 353 | if (valid) { | 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 | updateMenu(this.form).then(response => { | 350 | updateMenu(this.form).then(response => { |
| 356 | this.msgSuccess("修改成功"); | 351 | this.msgSuccess("修改成功"); |
| 357 | this.open = false; | 352 | this.open = false; |
| @@ -369,12 +364,12 @@ export default { | @@ -369,12 +364,12 @@ export default { | ||
| 369 | }, | 364 | }, |
| 370 | /** 删除按钮操作 */ | 365 | /** 删除按钮操作 */ |
| 371 | handleDelete(row) { | 366 | handleDelete(row) { |
| 372 | - this.$confirm('是否确认删除名称为"' + row.menuName + '"的数据项?', "警告", { | 367 | + this.$confirm('是否确认删除名称为"' + row.name + '"的数据项?', "警告", { |
| 373 | confirmButtonText: "确定", | 368 | confirmButtonText: "确定", |
| 374 | cancelButtonText: "取消", | 369 | cancelButtonText: "取消", |
| 375 | type: "warning" | 370 | type: "warning" |
| 376 | }).then(function() { | 371 | }).then(function() { |
| 377 | - return delMenu(row.menuId); | 372 | + return delMenu(row.id); |
| 378 | }).then(() => { | 373 | }).then(() => { |
| 379 | this.getList(); | 374 | this.getList(); |
| 380 | this.msgSuccess("删除成功"); | 375 | this.msgSuccess("删除成功"); |
ruoyi-ui/src/views/system/role/index.vue
| @@ -437,7 +437,7 @@ export default { | @@ -437,7 +437,7 @@ export default { | ||
| 437 | roleKey: undefined, | 437 | roleKey: undefined, |
| 438 | roleSort: 0, | 438 | roleSort: 0, |
| 439 | status: "0", | 439 | status: "0", |
| 440 | - menuIds: [], | 440 | + ids: [], |
| 441 | deptIds: [], | 441 | deptIds: [], |
| 442 | menuCheckStrictly: true, | 442 | menuCheckStrictly: true, |
| 443 | deptCheckStrictly: true, | 443 | deptCheckStrictly: true, |
| @@ -535,14 +535,14 @@ export default { | @@ -535,14 +535,14 @@ export default { | ||
| 535 | this.$refs["form"].validate(valid => { | 535 | this.$refs["form"].validate(valid => { |
| 536 | if (valid) { | 536 | if (valid) { |
| 537 | if (this.form.roleId != undefined) { | 537 | if (this.form.roleId != undefined) { |
| 538 | - this.form.menuIds = this.getMenuAllCheckedKeys(); | 538 | + this.form.ids = this.getMenuAllCheckedKeys(); |
| 539 | updateRole(this.form).then(response => { | 539 | updateRole(this.form).then(response => { |
| 540 | this.msgSuccess("修改成功"); | 540 | this.msgSuccess("修改成功"); |
| 541 | this.open = false; | 541 | this.open = false; |
| 542 | this.getList(); | 542 | this.getList(); |
| 543 | }); | 543 | }); |
| 544 | } else { | 544 | } else { |
| 545 | - this.form.menuIds = this.getMenuAllCheckedKeys(); | 545 | + this.form.ids = this.getMenuAllCheckedKeys(); |
| 546 | addRole(this.form).then(response => { | 546 | addRole(this.form).then(response => { |
| 547 | this.msgSuccess("新增成功"); | 547 | this.msgSuccess("新增成功"); |
| 548 | this.open = false; | 548 | this.open = false; |
| @@ -592,4 +592,4 @@ export default { | @@ -592,4 +592,4 @@ export default { | ||
| 592 | } | 592 | } |
| 593 | } | 593 | } |
| 594 | }; | 594 | }; |
| 595 | -</script> | ||
| 596 | \ No newline at end of file | 595 | \ No newline at end of file |
| 596 | +</script> |
ruoyi-ui/src/views/tool/gen/editTable.vue
| @@ -167,7 +167,7 @@ export default { | @@ -167,7 +167,7 @@ export default { | ||
| 167 | }); | 167 | }); |
| 168 | /** 查询菜单下拉列表 */ | 168 | /** 查询菜单下拉列表 */ |
| 169 | getMenuTreeselect().then(response => { | 169 | getMenuTreeselect().then(response => { |
| 170 | - this.menus = this.handleTree(response.data, "menuId"); | 170 | + this.menus = this.handleTree(response.data, "id"); |
| 171 | }); | 171 | }); |
| 172 | } | 172 | } |
| 173 | }, | 173 | }, |
ruoyi-ui/src/views/tool/gen/genInfoForm.vue
| @@ -219,8 +219,8 @@ export default { | @@ -219,8 +219,8 @@ export default { | ||
| 219 | delete node.children; | 219 | delete node.children; |
| 220 | } | 220 | } |
| 221 | return { | 221 | return { |
| 222 | - id: node.menuId, | ||
| 223 | - label: node.menuName, | 222 | + id: node.id, |
| 223 | + label: node.name, | ||
| 224 | children: node.children | 224 | children: node.children |
| 225 | }; | 225 | }; |
| 226 | } | 226 | } |
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/SysAuthMenuRespVO.java
| 1 | package cn.iocoder.dashboard.modules.system.controller.auth.vo; | 1 | package cn.iocoder.dashboard.modules.system.controller.auth.vo; |
| 2 | 2 | ||
| 3 | import io.swagger.annotations.ApiModel; | 3 | import io.swagger.annotations.ApiModel; |
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 4 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 5 | import lombok.Builder; | 6 | import lombok.Builder; |
| 6 | import lombok.Data; | 7 | import lombok.Data; |
| @@ -15,32 +16,22 @@ import java.util.List; | @@ -15,32 +16,22 @@ import java.util.List; | ||
| 15 | @Builder | 16 | @Builder |
| 16 | public class SysAuthMenuRespVO { | 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 | private Long parentId; | 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 | private String path; | 29 | private String path; |
| 36 | - /** | ||
| 37 | - * 组件地址 | ||
| 38 | - */ | 30 | + |
| 31 | + @ApiModelProperty(value = "组件路径", example = "system/post/index", notes = "仅菜单类型为菜单时,才需要传") | ||
| 39 | private String component; | 32 | private String component; |
| 40 | 33 | ||
| 41 | - /** | ||
| 42 | - * 菜单图标 | ||
| 43 | - */ | 34 | + @ApiModelProperty(value = "菜单图标", example = "/menu/list", notes = "仅菜单类型为菜单或者目录时,才需要传") |
| 44 | private String icon; | 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,9 +12,9 @@ public class SysDataDictSimpleVO { | ||
| 12 | private String dictType; | 12 | private String dictType; |
| 13 | 13 | ||
| 14 | @ApiModelProperty(value = "字典键值", required = true, example = "1") | 14 | @ApiModelProperty(value = "字典键值", required = true, example = "1") |
| 15 | - private String dictValue; | 15 | + private String value; |
| 16 | 16 | ||
| 17 | @ApiModelProperty(value = "字典标签", required = true, example = "男") | 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 | package cn.iocoder.dashboard.modules.system.controller.permission; | 1 | package cn.iocoder.dashboard.modules.system.controller.permission; |
| 2 | 2 | ||
| 3 | import cn.iocoder.dashboard.common.pojo.CommonResult; | 3 | import cn.iocoder.dashboard.common.pojo.CommonResult; |
| 4 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO; | ||
| 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; | 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; |
| 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; | 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 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; | 10 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; |
| 7 | import io.swagger.annotations.Api; | 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 | import javax.annotation.Resource; | 16 | import javax.annotation.Resource; |
| 13 | import java.util.List; | 17 | import java.util.List; |
| @@ -22,24 +26,21 @@ public class SysMenuController { | @@ -22,24 +26,21 @@ public class SysMenuController { | ||
| 22 | @Resource | 26 | @Resource |
| 23 | private SysMenuService menuService; | 27 | private SysMenuService menuService; |
| 24 | 28 | ||
| 25 | - /** | ||
| 26 | - * 获取菜单列表 | ||
| 27 | - */ | 29 | + @ApiOperation("获取菜单列表") |
| 28 | // @PreAuthorize("@ss.hasPermi('system:menu:list')") | 30 | // @PreAuthorize("@ss.hasPermi('system:menu:list')") |
| 29 | @GetMapping("/list") | 31 | @GetMapping("/list") |
| 30 | public CommonResult<List<SysMenuRespVO>> list(SysMenuListReqVO reqVO) { | 32 | public CommonResult<List<SysMenuRespVO>> list(SysMenuListReqVO reqVO) { |
| 31 | return success(menuService.listMenus(reqVO)); | 33 | return success(menuService.listMenus(reqVO)); |
| 32 | } | 34 | } |
| 33 | -// | ||
| 34 | -// /** | ||
| 35 | -// * 根据菜单编号获取详细信息 | ||
| 36 | -// */ | 35 | + |
| 36 | + @ApiOperation("获取菜单信息") | ||
| 37 | + @GetMapping("/get") | ||
| 37 | // @PreAuthorize("@ss.hasPermi('system:menu:query')") | 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,57 +64,31 @@ public class SysMenuController { | ||
| 63 | // ajax.put("menus", menuService.buildMenuTreeSelect(menus)); | 64 | // ajax.put("menus", menuService.buildMenuTreeSelect(menus)); |
| 64 | // return ajax; | 65 | // return ajax; |
| 65 | // } | 66 | // } |
| 66 | -// | ||
| 67 | -// /** | ||
| 68 | -// * 新增菜单 | ||
| 69 | -// */ | 67 | + |
| 68 | + @ApiOperation("新增菜单") | ||
| 70 | // @PreAuthorize("@ss.hasPermi('system:menu:add')") | 69 | // @PreAuthorize("@ss.hasPermi('system:menu:add')") |
| 71 | // @Log(title = "菜单管理", businessType = BusinessType.INSERT) | 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 | // @PreAuthorize("@ss.hasPermi('system:menu:edit')") | 78 | // @PreAuthorize("@ss.hasPermi('system:menu:edit')") |
| 88 | // @Log(title = "菜单管理", businessType = BusinessType.UPDATE) | 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 | // @Log(title = "菜单管理", businessType = BusinessType.DELETE) | 87 | // @Log(title = "菜单管理", businessType = BusinessType.DELETE) |
| 108 | // @DeleteMapping("/{menuId}") | 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,15 +17,15 @@ public class SysMenuBaseVO { | ||
| 17 | @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") | 17 | @ApiModelProperty(value = "菜单名称", required = true, example = "芋道") |
| 18 | @NotBlank(message = "菜单名称不能为空") | 18 | @NotBlank(message = "菜单名称不能为空") |
| 19 | @Size(max = 50, message = "菜单名称长度不能超过50个字符") | 19 | @Size(max = 50, message = "菜单名称长度不能超过50个字符") |
| 20 | - private String menuName; | 20 | + private String name; |
| 21 | 21 | ||
| 22 | @ApiModelProperty(value = "权限标识", example = "sys:menu:add", notes = "仅菜单类型为按钮时,才需要传递") | 22 | @ApiModelProperty(value = "权限标识", example = "sys:menu:add", notes = "仅菜单类型为按钮时,才需要传递") |
| 23 | @Size(max = 100) | 23 | @Size(max = 100) |
| 24 | private String permission; | 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 | @NotBlank(message = "菜单类型不能为空") | 27 | @NotBlank(message = "菜单类型不能为空") |
| 28 | - private Integer menuType; | 28 | + private Integer type; |
| 29 | 29 | ||
| 30 | @ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024") | 30 | @ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024") |
| 31 | @NotBlank(message = "显示顺序不能为空") | 31 | @NotBlank(message = "显示顺序不能为空") |
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuListReqVO.java
| @@ -14,7 +14,7 @@ public class SysMenuListReqVO { | @@ -14,7 +14,7 @@ public class SysMenuListReqVO { | ||
| 14 | @ApiModelProperty(value = "菜单名称", example = "芋道", notes = "模糊匹配") | 14 | @ApiModelProperty(value = "菜单名称", example = "芋道", notes = "模糊匹配") |
| 15 | private String menuName; | 15 | private String menuName; |
| 16 | 16 | ||
| 17 | - @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类") | 17 | + @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类") |
| 18 | private Integer status; | 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,9 +17,9 @@ import java.util.Date; | ||
| 17 | public class SysMenuRespVO extends SysMenuBaseVO { | 17 | public class SysMenuRespVO extends SysMenuBaseVO { |
| 18 | 18 | ||
| 19 | @ApiModelProperty(value = "菜单编号", required = true, example = "1024") | 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 | private Integer status; | 23 | private Integer status; |
| 24 | 24 | ||
| 25 | @ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式") | 25 | @ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式") |
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuUpdateReqVO.java
| @@ -13,6 +13,6 @@ public class SysMenuUpdateReqVO extends SysMenuBaseVO { | @@ -13,6 +13,6 @@ public class SysMenuUpdateReqVO extends SysMenuBaseVO { | ||
| 13 | 13 | ||
| 14 | @ApiModelProperty(value = "菜单编号", required = true, example = "1024") | 14 | @ApiModelProperty(value = "菜单编号", required = true, example = "1024") |
| 15 | @NotNull(message = "菜单编号不能为空") | 15 | @NotNull(message = "菜单编号不能为空") |
| 16 | - private Integer menuId; | 16 | + private Long id; |
| 17 | 17 | ||
| 18 | } | 18 | } |
src/main/java/cn/iocoder/dashboard/modules/system/convert/auth/SysAuthConvert.java
| 1 | package cn.iocoder.dashboard.modules.system.convert.auth; | 1 | package cn.iocoder.dashboard.modules.system.convert.auth; |
| 2 | 2 | ||
| 3 | import cn.iocoder.dashboard.framework.security.core.LoginUser; | 3 | import cn.iocoder.dashboard.framework.security.core.LoginUser; |
| 4 | -import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthPermissionInfoRespVO; | ||
| 5 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthMenuRespVO; | 4 | import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthMenuRespVO; |
| 5 | +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthPermissionInfoRespVO; | ||
| 6 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | 6 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; | 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; |
| 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; | 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; |
| 9 | +import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum; | ||
| 9 | import cn.iocoder.dashboard.util.collection.CollectionUtils; | 10 | import cn.iocoder.dashboard.util.collection.CollectionUtils; |
| 10 | import org.mapstruct.Mapper; | 11 | import org.mapstruct.Mapper; |
| 11 | import org.mapstruct.Mapping; | 12 | import org.mapstruct.Mapping; |
| 12 | import org.mapstruct.factory.Mappers; | 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 | @Mapper | 18 | @Mapper |
| 17 | public interface SysAuthConvert { | 19 | public interface SysAuthConvert { |
| @@ -31,4 +33,36 @@ public interface SysAuthConvert { | @@ -31,4 +33,36 @@ public interface SysAuthConvert { | ||
| 31 | 33 | ||
| 32 | SysAuthMenuRespVO convertTreeNode(SysMenuDO menu); | 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 | package cn.iocoder.dashboard.modules.system.convert.permission; | 1 | package cn.iocoder.dashboard.modules.system.convert.permission; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO; | ||
| 3 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; | 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; |
| 5 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO; | ||
| 4 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | 6 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 5 | import org.mapstruct.Mapper; | 7 | import org.mapstruct.Mapper; |
| 6 | import org.mapstruct.factory.Mappers; | 8 | import org.mapstruct.factory.Mappers; |
| @@ -14,4 +16,10 @@ public interface SysMenuConvert { | @@ -14,4 +16,10 @@ public interface SysMenuConvert { | ||
| 14 | 16 | ||
| 15 | List<SysMenuRespVO> convertList(List<SysMenuDO> list); | 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 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; | 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; |
| 2 | 2 | ||
| 3 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | 3 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 4 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| 5 | import org.apache.ibatis.annotations.Mapper; | 6 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 7 | ||
| 7 | @Mapper | 8 | @Mapper |
| 8 | public interface SysMenuMapper extends BaseMapper<SysMenuDO> { | 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,30 +26,30 @@ public class SysDictDataDO extends BaseDO { | ||
| 26 | */ | 26 | */ |
| 27 | @TableId | 27 | @TableId |
| 28 | @Excel(name = "字典编码", cellType = Excel.ColumnType.NUMERIC) | 28 | @Excel(name = "字典编码", cellType = Excel.ColumnType.NUMERIC) |
| 29 | - private Long dictCode; | 29 | + private Long id; |
| 30 | /** | 30 | /** |
| 31 | * 字典排序 | 31 | * 字典排序 |
| 32 | */ | 32 | */ |
| 33 | @Excel(name = "字典排序", cellType = Excel.ColumnType.NUMERIC) | 33 | @Excel(name = "字典排序", cellType = Excel.ColumnType.NUMERIC) |
| 34 | - private Integer dictSort; | 34 | + private Integer sort; |
| 35 | /** | 35 | /** |
| 36 | * 字典标签 | 36 | * 字典标签 |
| 37 | */ | 37 | */ |
| 38 | @Excel(name = "字典标签") | 38 | @Excel(name = "字典标签") |
| 39 | @NotBlank(message = "字典标签不能为空") | 39 | @NotBlank(message = "字典标签不能为空") |
| 40 | @Size(max = 100, message = "字典标签长度不能超过100个字符") | 40 | @Size(max = 100, message = "字典标签长度不能超过100个字符") |
| 41 | - private String dictLabel; | 41 | + private String label; |
| 42 | /** | 42 | /** |
| 43 | - * 字典键值 | 43 | + * 字典值 |
| 44 | */ | 44 | */ |
| 45 | @Excel(name = "字典键值") | 45 | @Excel(name = "字典键值") |
| 46 | @NotBlank(message = "字典键值不能为空") | 46 | @NotBlank(message = "字典键值不能为空") |
| 47 | @Size(max = 100, message = "字典键值长度不能超过100个字符") | 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 | @Excel(name = "字典类型") | 54 | @Excel(name = "字典类型") |
| 55 | @NotBlank(message = "字典类型不能为空") | 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,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict; | ||
| 3 | import cn.iocoder.dashboard.common.enums.CommonStatusEnum; | 3 | import cn.iocoder.dashboard.common.enums.CommonStatusEnum; |
| 4 | import cn.iocoder.dashboard.framework.excel.Excel; | 4 | import cn.iocoder.dashboard.framework.excel.Excel; |
| 5 | import cn.iocoder.dashboard.framework.mybatis.core.BaseDO; | 5 | import cn.iocoder.dashboard.framework.mybatis.core.BaseDO; |
| 6 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
| 6 | import com.baomidou.mybatisplus.annotation.TableId; | 7 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | import com.baomidou.mybatisplus.annotation.TableName; | 8 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | import lombok.Data; | 9 | import lombok.Data; |
| @@ -26,24 +27,22 @@ public class SysDictTypeDO extends BaseDO { | @@ -26,24 +27,22 @@ public class SysDictTypeDO extends BaseDO { | ||
| 26 | */ | 27 | */ |
| 27 | @TableId | 28 | @TableId |
| 28 | @Excel(name = "字典主键", cellType = Excel.ColumnType.NUMERIC) | 29 | @Excel(name = "字典主键", cellType = Excel.ColumnType.NUMERIC) |
| 29 | - private Long dictId; | ||
| 30 | - | 30 | + private Long id; |
| 31 | /** | 31 | /** |
| 32 | * 字典名称 | 32 | * 字典名称 |
| 33 | */ | 33 | */ |
| 34 | @Excel(name = "字典名称") | 34 | @Excel(name = "字典名称") |
| 35 | @NotBlank(message = "字典名称不能为空") | 35 | @NotBlank(message = "字典名称不能为空") |
| 36 | @Size(max = 100, message = "字典类型名称长度不能超过100个字符") | 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 | @Excel(name = "字典类型") | 42 | @Excel(name = "字典类型") |
| 43 | @NotBlank(message = "字典类型不能为空") | 43 | @NotBlank(message = "字典类型不能为空") |
| 44 | @Size(max = 100, message = "字典类型类型长度不能超过100个字符") | 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,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission; | ||
| 3 | import cn.iocoder.dashboard.common.enums.CommonStatusEnum; | 3 | import cn.iocoder.dashboard.common.enums.CommonStatusEnum; |
| 4 | import cn.iocoder.dashboard.framework.mybatis.core.BaseDO; | 4 | import cn.iocoder.dashboard.framework.mybatis.core.BaseDO; |
| 5 | import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; | 5 | import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; |
| 6 | +import com.baomidou.mybatisplus.annotation.TableField; | ||
| 6 | import com.baomidou.mybatisplus.annotation.TableId; | 7 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | import com.baomidou.mybatisplus.annotation.TableName; | 8 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | import lombok.Data; | 9 | import lombok.Data; |
| @@ -22,11 +23,11 @@ public class SysMenuDO extends BaseDO { | @@ -22,11 +23,11 @@ public class SysMenuDO extends BaseDO { | ||
| 22 | * 菜单ID | 23 | * 菜单ID |
| 23 | */ | 24 | */ |
| 24 | @TableId | 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,7 +44,8 @@ public class SysMenuDO extends BaseDO { | ||
| 43 | * | 44 | * |
| 44 | * 枚举 {@link MenuTypeEnum} | 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,4 +18,12 @@ public interface SysErrorCodeConstants { | ||
| 18 | ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); | 18 | ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); |
| 19 | ErrorCode TOKEN_PARSE_FAIL = new ErrorCode(1002001001, "Token 解析失败"); | 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,7 +12,6 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMe | ||
| 12 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; | 12 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; |
| 13 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; | 13 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; |
| 14 | import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO; | 14 | import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO; |
| 15 | -import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum; | ||
| 16 | import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; | 15 | import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; |
| 17 | import cn.iocoder.dashboard.modules.system.enums.user.UserStatus; | 16 | import cn.iocoder.dashboard.modules.system.enums.user.UserStatus; |
| 18 | import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService; | 17 | import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService; |
| @@ -38,7 +37,10 @@ import org.springframework.stereotype.Service; | @@ -38,7 +37,10 @@ import org.springframework.stereotype.Service; | ||
| 38 | import org.springframework.util.Assert; | 37 | import org.springframework.util.Assert; |
| 39 | 38 | ||
| 40 | import javax.annotation.Resource; | 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 | import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; | 45 | import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; |
| 44 | import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; | 46 | import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; |
| @@ -243,36 +245,12 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -243,36 +245,12 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 243 | 245 | ||
| 244 | @Override | 246 | @Override |
| 245 | public List<SysAuthMenuRespVO> listMenus(Long userId, Set<Long> roleIds) { | 247 | public List<SysAuthMenuRespVO> listMenus(Long userId, Set<Long> roleIds) { |
| 248 | + // 获得用户拥有的菜单列表 | ||
| 246 | List<SysMenuDO> menuList = permissionService.listRoleMenusFromCache(roleIds, | 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 | // 转换成 Tree 结构返回 | 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,7 +19,7 @@ public class SysDictDataServiceImpl implements SysDictDataService { | ||
| 19 | 19 | ||
| 20 | private static final Comparator<SysDictDataDO> COMPARATOR_TYPE_AND_SORT = Comparator | 20 | private static final Comparator<SysDictDataDO> COMPARATOR_TYPE_AND_SORT = Comparator |
| 21 | .comparing(SysDictDataDO::getDictType) | 21 | .comparing(SysDictDataDO::getDictType) |
| 22 | - .thenComparingInt(SysDictDataDO::getDictSort); | 22 | + .thenComparingInt(SysDictDataDO::getSort); |
| 23 | 23 | ||
| 24 | @Resource | 24 | @Resource |
| 25 | private SysDictDataMapper dictDataMapper; | 25 | private SysDictDataMapper dictDataMapper; |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuService.java
| 1 | package cn.iocoder.dashboard.modules.system.service.permission; | 1 | package cn.iocoder.dashboard.modules.system.service.permission; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuCreateReqVO; | ||
| 3 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; | 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; |
| 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; | 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; |
| 6 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO; | ||
| 5 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 6 | 8 | ||
| 7 | import java.util.Collection; | 9 | import java.util.Collection; |
| @@ -9,6 +11,8 @@ import java.util.List; | @@ -9,6 +11,8 @@ import java.util.List; | ||
| 9 | 11 | ||
| 10 | /** | 12 | /** |
| 11 | * 菜单 Service 接口 | 13 | * 菜单 Service 接口 |
| 14 | + * | ||
| 15 | + * @author 芋道源码 | ||
| 12 | */ | 16 | */ |
| 13 | public interface SysMenuService { | 17 | public interface SysMenuService { |
| 14 | 18 | ||
| @@ -49,4 +53,34 @@ public interface SysMenuService { | @@ -49,4 +53,34 @@ public interface SysMenuService { | ||
| 49 | List<SysMenuDO> listMenusFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes, | 53 | List<SysMenuDO> listMenusFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes, |
| 50 | Collection<Integer> menusStatuses); | 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
| @@ -48,4 +48,11 @@ public interface SysPermissionService { | @@ -48,4 +48,11 @@ public interface SysPermissionService { | ||
| 48 | */ | 48 | */ |
| 49 | Long getDeptRoleId(Long deptId); | 49 | Long getDeptRoleId(Long deptId); |
| 50 | 50 | ||
| 51 | + /** | ||
| 52 | + * 删除授予给角色的菜单们 | ||
| 53 | + * | ||
| 54 | + * @param menuId 菜单编号 | ||
| 55 | + */ | ||
| 56 | + void deleteRolesMenuByMenuId(Long menuId); | ||
| 57 | + | ||
| 51 | } | 58 | } |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java
| 1 | package cn.iocoder.dashboard.modules.system.service.permission.impl; | 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 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; | 5 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuListReqVO; |
| 4 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; | 6 | import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuRespVO; |
| 7 | +import cn.iocoder.dashboard.modules.system.controller.permission.vo.SysMenuUpdateReqVO; | ||
| 5 | import cn.iocoder.dashboard.modules.system.convert.permission.SysMenuConvert; | 8 | import cn.iocoder.dashboard.modules.system.convert.permission.SysMenuConvert; |
| 6 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysMenuMapper; | 9 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysMenuMapper; |
| 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | 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 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; | 13 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; |
| 14 | +import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; | ||
| 9 | import cn.iocoder.dashboard.util.collection.CollectionUtils; | 15 | import cn.iocoder.dashboard.util.collection.CollectionUtils; |
| 10 | import com.google.common.collect.ImmutableMap; | 16 | import com.google.common.collect.ImmutableMap; |
| 11 | import com.google.common.collect.ImmutableMultimap; | 17 | import com.google.common.collect.ImmutableMultimap; |
| @@ -21,8 +27,12 @@ import java.util.List; | @@ -21,8 +27,12 @@ import java.util.List; | ||
| 21 | import java.util.Map; | 27 | import java.util.Map; |
| 22 | import java.util.stream.Collectors; | 28 | import java.util.stream.Collectors; |
| 23 | 29 | ||
| 30 | +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; | ||
| 31 | + | ||
| 24 | /** | 32 | /** |
| 25 | * 菜单 Service 实现 | 33 | * 菜单 Service 实现 |
| 34 | + * | ||
| 35 | + * @author 芋道源码 | ||
| 26 | */ | 36 | */ |
| 27 | @Service | 37 | @Service |
| 28 | @Slf4j | 38 | @Slf4j |
| @@ -46,6 +56,8 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -46,6 +56,8 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 46 | 56 | ||
| 47 | @Resource | 57 | @Resource |
| 48 | private SysMenuMapper menuMapper; | 58 | private SysMenuMapper menuMapper; |
| 59 | + @Resource | ||
| 60 | + private SysPermissionService permissionService; | ||
| 49 | 61 | ||
| 50 | /** | 62 | /** |
| 51 | * 初始化 {@link #menuCache} 和 {@link #permMenuCache} 缓存 | 63 | * 初始化 {@link #menuCache} 和 {@link #permMenuCache} 缓存 |
| @@ -57,7 +69,7 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -57,7 +69,7 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 57 | ImmutableMap.Builder<Long, SysMenuDO> menuCacheBuilder = ImmutableMap.builder(); | 69 | ImmutableMap.Builder<Long, SysMenuDO> menuCacheBuilder = ImmutableMap.builder(); |
| 58 | ImmutableMultimap.Builder<String, SysMenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); | 70 | ImmutableMultimap.Builder<String, SysMenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); |
| 59 | menuList.forEach(menuDO -> { | 71 | menuList.forEach(menuDO -> { |
| 60 | - menuCacheBuilder.put(menuDO.getMenuId(), menuDO); | 72 | + menuCacheBuilder.put(menuDO.getId(), menuDO); |
| 61 | permMenuCacheBuilder.put(menuDO.getPermission(), menuDO); | 73 | permMenuCacheBuilder.put(menuDO.getPermission(), menuDO); |
| 62 | }); | 74 | }); |
| 63 | menuCache = menuCacheBuilder.build(); | 75 | menuCache = menuCacheBuilder.build(); |
| @@ -79,7 +91,7 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -79,7 +91,7 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 79 | return Collections.emptyList(); | 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 | && menusStatuses.contains(menu.getStatus())) | 95 | && menusStatuses.contains(menu.getStatus())) |
| 84 | .collect(Collectors.toList()); | 96 | .collect(Collectors.toList()); |
| 85 | } | 97 | } |
| @@ -91,10 +103,186 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -91,10 +103,186 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 91 | if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) { | 103 | if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) { |
| 92 | return Collections.emptyList(); | 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 | && menusStatuses.contains(menu.getStatus())) | 108 | && menusStatuses.contains(menu.getStatus())) |
| 97 | .collect(Collectors.toList()); | 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,4 +107,9 @@ public class SysPermissionServiceImpl implements SysPermissionService { | ||
| 107 | return roleDept != null ? roleDept.getRoleId() : null; | 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 | } |