diff --git a/ruoyi-ui/src/api/system/dict/data.js b/ruoyi-ui/src/api/system/dict/data.js index d3f8c2f20..f4f91e694 100644 --- a/ruoyi-ui/src/api/system/dict/data.js +++ b/ruoyi-ui/src/api/system/dict/data.js @@ -58,4 +58,12 @@ export function exportData(query) { method: 'get', params: query }) -} \ No newline at end of file +} + +// 查询全部字典数据列表 +export function listSimpleDictDatas() { + return request({ + url: '/system/dict-data/list-all-simple', + method: 'get', + }) +} diff --git a/ruoyi-ui/src/permission.js b/ruoyi-ui/src/permission.js index 2c0b1cfb8..ccb20eb78 100644 --- a/ruoyi-ui/src/permission.js +++ b/ruoyi-ui/src/permission.js @@ -18,6 +18,8 @@ router.beforeEach((to, from, next) => { NProgress.done() } else { if (store.getters.roles.length === 0) { + // 获取字典数据 + store.dispatch('dict/loadDictDatas') // 判断当前用户是否已拉取完user_info信息 store.dispatch('GetInfo').then(res => { // 拉取user_info diff --git a/ruoyi-ui/src/store/getters.js b/ruoyi-ui/src/store/getters.js index ea4f90e18..813d838a6 100644 --- a/ruoyi-ui/src/store/getters.js +++ b/ruoyi-ui/src/store/getters.js @@ -12,5 +12,7 @@ const getters = { permissions: state => state.user.permissions, permission_routes: state => state.permission.routes, sidebarRouters:state => state.permission.sidebarRouters, + // 数据字典 + dict_datas: state => state.dict.dictDatas } export default getters diff --git a/ruoyi-ui/src/store/index.js b/ruoyi-ui/src/store/index.js index eceb2cd2b..7e9db3347 100644 --- a/ruoyi-ui/src/store/index.js +++ b/ruoyi-ui/src/store/index.js @@ -5,6 +5,7 @@ import user from './modules/user' import tagsView from './modules/tagsView' import permission from './modules/permission' import settings from './modules/settings' +import dict from './modules/dict' import getters from './getters' Vue.use(Vuex) @@ -15,7 +16,8 @@ const store = new Vuex.Store({ user, tagsView, permission, - settings + settings, + dict }, getters }) diff --git a/ruoyi-ui/src/store/modules/dict.js b/ruoyi-ui/src/store/modules/dict.js new file mode 100644 index 000000000..4774d6d92 --- /dev/null +++ b/ruoyi-ui/src/store/modules/dict.js @@ -0,0 +1,46 @@ +import { listSimpleDictDatas } from '@/api/system/dict/data' + +const state = { + /** + * 数据字典 MAP + * key:数据字典大类枚举值 dictType + * dictValue:数据字典小类数值 {dictValue: '', dictLabel: ''} 的数组 + */ + dictDatas: {} +} + +const mutations = { + SET_DICT_DATAS: (state, dictDatas) => { + state.dictDatas = dictDatas + } +} + +const actions = { + loadDictDatas({ commit }) { + listSimpleDictDatas().then(response => { + // 设置数据 + const dictDataMap = {} + response.data.forEach(dictData => { + // 获得 dictType 层级 + const enumValueObj = dictDataMap[dictData.dictType] + if (!enumValueObj) { + dictDataMap[dictData.dictType] = [] + } + // 处理 dictValue 层级 + dictDataMap[dictData.dictType].push({ + dictValue: dictData.dictValue, + dictLabel: dictData.dictLabel + }) + }) + // 存储到 Store 中 + commit('SET_DICT_DATAS', dictDataMap) + }) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/ruoyi-ui/src/store/modules/user.js b/ruoyi-ui/src/store/modules/user.js index ec95c5faa..82b2b18fa 100644 --- a/ruoyi-ui/src/store/modules/user.js +++ b/ruoyi-ui/src/store/modules/user.js @@ -37,6 +37,7 @@ const user = { const uuid = userInfo.uuid return new Promise((resolve, reject) => { login(username, password, code, uuid).then(res => { + res = res.data; setToken(res.token) commit('SET_TOKEN', res.token) resolve() @@ -53,7 +54,6 @@ const user = { res = res.data; // 读取 data 数据 const user = res.user const avatar = user.avatar === "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar; - debugger if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 commit('SET_ROLES', res.roles) commit('SET_PERMISSIONS', res.permissions) diff --git a/ruoyi-ui/src/utils/dict.js b/ruoyi-ui/src/utils/dict.js new file mode 100644 index 000000000..6e14d32e2 --- /dev/null +++ b/ruoyi-ui/src/utils/dict.js @@ -0,0 +1,36 @@ +/** + * Created by 芋道源码 + * + * 数据字典工具类 + */ +import store from '@/store' + +export const DICT_TYPE = { + SYS_COMMON_STATUS: 'sys_common_status' +} + +/** + * 获取 dictType 对应的数据字典数组 + * + * @param dictType 数据类型 + * @returns {*|Array} 数据字典数组 + */ +export function getDictDatas(dictType) { + return store.getters.dict_datas[dictType] || [] +} + +export function getDictDataLabel(dictType, value) { + // 获取 dictType 对应的数据字典数组 + const dictDatas = getDictDatas(dictType) + if (!dictDatas || dictDatas.length === 0) { + return '' + } + // 获取 value 对应的展示名 + value = value + '' // 强制转换成字符串,因为 DictData 小类数值,是字符串 + for (const dictData of dictDatas) { + if (dictData.dictValue === value) { + return dictData.dictLabel + } + } + return '' +} diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue index 6b2139ea3..7306a0134 100644 --- a/ruoyi-ui/src/views/login.vue +++ b/ruoyi-ui/src/views/login.vue @@ -99,6 +99,7 @@ export default { methods: { getCode() { getCodeImg().then(res => { + res = res.data; this.codeUrl = "data:image/gif;base64," + res.img; this.loginForm.uuid = res.uuid; }); diff --git a/ruoyi-ui/src/views/system/menu/index.vue b/ruoyi-ui/src/views/system/menu/index.vue index b2d535329..4498c7750 100644 --- a/ruoyi-ui/src/views/system/menu/index.vue +++ b/ruoyi-ui/src/views/system/menu/index.vue @@ -211,6 +211,8 @@ import Treeselect from "@riophae/vue-treeselect"; import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import IconSelect from "@/components/IconSelect"; +import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict' + export default { name: "Menu", components: { Treeselect, IconSelect }, @@ -255,12 +257,6 @@ export default { }, created() { this.getList(); - this.getDicts("sys_show_hide").then(response => { - this.visibleOptions = response.data; - }); - this.getDicts("sys_normal_disable").then(response => { - this.statusOptions = response.data; - }); }, methods: { // 选择图标 @@ -295,19 +291,9 @@ export default { this.menuOptions.push(menu); }); }, - // 显示状态字典翻译 - visibleFormat(row, column) { - if (row.menuType == "3") { - return ""; - } - return this.selectDictLabel(this.visibleOptions, row.visible); - }, // 菜单状态字典翻译 statusFormat(row, column) { - if (row.menuType == "3") { - return ""; - } - return this.selectDictLabel(this.statusOptions, row.status); + return getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, row.status) }, // 取消按钮 cancel() { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.http b/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.http new file mode 100644 index 000000000..f7890dc67 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.http @@ -0,0 +1,3 @@ +### 请求 /menu/list 接口 => 成功 +GET {{baseUrl}}/system/dict-data/list-all-simple +Authorization: Bearer {{token}} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.java new file mode 100644 index 000000000..6a816589e --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.java @@ -0,0 +1,35 @@ +package cn.iocoder.dashboard.modules.system.controller.dict; + +import cn.iocoder.dashboard.common.pojo.CommonResult; +import cn.iocoder.dashboard.modules.system.controller.dict.vo.SysDataDictSimpleVO; +import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO; +import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.dashboard.common.pojo.CommonResult.success; + +@Api(tags = "数据字典 API") +@RestController +@RequestMapping("/system/dict-data") +public class SysDictDataController { + + @Resource + private SysDictDataService dictDataService; + + @GetMapping("/list-all-simple") + @ApiOperation(value = "获得全部字典数据列表", notes = "一般用于管理后台缓存字典数据在本地") + // 无需添加权限认证,因为前端全局都需要 + public CommonResult> listSimpleDictDatas() { + List list = dictDataService.listDictDatas(); + return success(SysDictDataConvert.INSTANCE.convertList(list)); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/SysDataDictSimpleVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/SysDataDictSimpleVO.java new file mode 100644 index 000000000..2a3a8a857 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/SysDataDictSimpleVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.dashboard.modules.system.controller.dict.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel("数据字典精简 VO") +@Data +public class SysDataDictSimpleVO { + + @ApiModelProperty(value = "字典类型", required = true, example = "gender") + private String dictType; + + @ApiModelProperty(value = "字典键值", required = true, example = "1") + private String dictValue; + + @ApiModelProperty(value = "字典标签", required = true, example = "男") + private String dictLabel; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/SysMenuController.http b/src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/SysMenuController.http index 9e678025f..c073f7bdc 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/SysMenuController.http +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/SysMenuController.http @@ -1,3 +1,3 @@ ### 请求 /menu/list 接口 => 成功 -GET {{baseUrl}}//menu/list +GET {{baseUrl}}/system/menu/list Authorization: Bearer {{token}} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuRespVO.java index 782ec3ca9..e89e9ae37 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuRespVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuRespVO.java @@ -19,6 +19,9 @@ public class SysMenuRespVO extends SysMenuBaseVO { @ApiModelProperty(value = "菜单编号", required = true, example = "1024") private Integer menuId; + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类") + private Integer status; + @ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式") private Date createTime; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/dict/SysDictDataConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/dict/SysDictDataConvert.java new file mode 100644 index 000000000..923bcbc59 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/dict/SysDictDataConvert.java @@ -0,0 +1,17 @@ +package cn.iocoder.dashboard.modules.system.convert.dict; + +import cn.iocoder.dashboard.modules.system.controller.dict.vo.SysDataDictSimpleVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface SysDictDataConvert { + + SysDictDataConvert INSTANCE = Mappers.getMapper(SysDictDataConvert.class); + + List convertList(List list); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/dict/SysDictDataMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/dict/SysDictDataMapper.java new file mode 100644 index 000000000..4c49406f7 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/dict/SysDictDataMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.dict; + +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysDictDataMapper extends BaseMapper { +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictData.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictDataDO.java similarity index 93% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictData.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictDataDO.java index 59f4a739c..7f198b507 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictData.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictDataDO.java @@ -19,7 +19,7 @@ import javax.validation.constraints.Size; @TableName("sys_dict_data") @Data @EqualsAndHashCode(callSuper = true) -public class SysDictData extends BaseDO { +public class SysDictDataDO extends BaseDO { /** * 字典编码 @@ -31,7 +31,7 @@ public class SysDictData extends BaseDO { * 字典排序 */ @Excel(name = "字典排序", cellType = Excel.ColumnType.NUMERIC) - private Long dictSort; + private Integer dictSort; /** * 字典标签 */ @@ -48,6 +48,8 @@ public class SysDictData extends BaseDO { private String dictValue; /** * 字典类型 + * + * 外键 {@link SysDictDataDO#getDictType()} */ @Excel(name = "字典类型") @NotBlank(message = "字典类型不能为空") diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataService.java new file mode 100644 index 000000000..d1ea39f7b --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataService.java @@ -0,0 +1,16 @@ +package cn.iocoder.dashboard.modules.system.service.dict; + +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO; + +import java.util.List; + +/** + * 字典数据 Service 接口 + * + * @author ruoyi + */ +public interface SysDictDataService { + + List listDictDatas(); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java new file mode 100644 index 000000000..7f654a5ce --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java @@ -0,0 +1,34 @@ +package cn.iocoder.dashboard.modules.system.service.dict.impl; + +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.dict.SysDictDataMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO; +import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Comparator; +import java.util.List; + +/** + * 字典数据 Service 实现类 + * + * @author ruoyi + */ +@Service +public class SysDictDataServiceImpl implements SysDictDataService { + + private static final Comparator COMPARATOR_TYPE_AND_SORT = Comparator + .comparing(SysDictDataDO::getDictType) + .thenComparingInt(SysDictDataDO::getDictSort); + + @Resource + private SysDictDataMapper dictDataMapper; + + @Override + public List listDictDatas() { + List list = dictDataMapper.selectList(null); + list.sort(COMPARATOR_TYPE_AND_SORT); + return list; + } + +}