Commit dba723b8fc265ee875fb8d74a986712c237e06e6

Authored by YunaiV
1 parent 74daab06

1. 增加字典数据接口

2. 前端接入全局字典数据
ruoyi-ui/src/api/system/dict/data.js
@@ -58,4 +58,12 @@ export function exportData(query) { @@ -58,4 +58,12 @@ export function exportData(query) {
58 method: 'get', 58 method: 'get',
59 params: query 59 params: query
60 }) 60 })
61 -}  
62 \ No newline at end of file 61 \ No newline at end of file
  62 +}
  63 +
  64 +// 查询全部字典数据列表
  65 +export function listSimpleDictDatas() {
  66 + return request({
  67 + url: '/system/dict-data/list-all-simple',
  68 + method: 'get',
  69 + })
  70 +}
ruoyi-ui/src/permission.js
@@ -18,6 +18,8 @@ router.beforeEach((to, from, next) => { @@ -18,6 +18,8 @@ router.beforeEach((to, from, next) => {
18 NProgress.done() 18 NProgress.done()
19 } else { 19 } else {
20 if (store.getters.roles.length === 0) { 20 if (store.getters.roles.length === 0) {
  21 + // 获取字典数据
  22 + store.dispatch('dict/loadDictDatas')
21 // 判断当前用户是否已拉取完user_info信息 23 // 判断当前用户是否已拉取完user_info信息
22 store.dispatch('GetInfo').then(res => { 24 store.dispatch('GetInfo').then(res => {
23 // 拉取user_info 25 // 拉取user_info
ruoyi-ui/src/store/getters.js
@@ -12,5 +12,7 @@ const getters = { @@ -12,5 +12,7 @@ const getters = {
12 permissions: state => state.user.permissions, 12 permissions: state => state.user.permissions,
13 permission_routes: state => state.permission.routes, 13 permission_routes: state => state.permission.routes,
14 sidebarRouters:state => state.permission.sidebarRouters, 14 sidebarRouters:state => state.permission.sidebarRouters,
  15 + // 数据字典
  16 + dict_datas: state => state.dict.dictDatas
15 } 17 }
16 export default getters 18 export default getters
ruoyi-ui/src/store/index.js
@@ -5,6 +5,7 @@ import user from './modules/user' @@ -5,6 +5,7 @@ import user from './modules/user'
5 import tagsView from './modules/tagsView' 5 import tagsView from './modules/tagsView'
6 import permission from './modules/permission' 6 import permission from './modules/permission'
7 import settings from './modules/settings' 7 import settings from './modules/settings'
  8 +import dict from './modules/dict'
8 import getters from './getters' 9 import getters from './getters'
9 10
10 Vue.use(Vuex) 11 Vue.use(Vuex)
@@ -15,7 +16,8 @@ const store = new Vuex.Store({ @@ -15,7 +16,8 @@ const store = new Vuex.Store({
15 user, 16 user,
16 tagsView, 17 tagsView,
17 permission, 18 permission,
18 - settings 19 + settings,
  20 + dict
19 }, 21 },
20 getters 22 getters
21 }) 23 })
ruoyi-ui/src/store/modules/dict.js 0 → 100644
  1 +import { listSimpleDictDatas } from '@/api/system/dict/data'
  2 +
  3 +const state = {
  4 + /**
  5 + * 数据字典 MAP
  6 + * key:数据字典大类枚举值 dictType
  7 + * dictValue:数据字典小类数值 {dictValue: '', dictLabel: ''} 的数组
  8 + */
  9 + dictDatas: {}
  10 +}
  11 +
  12 +const mutations = {
  13 + SET_DICT_DATAS: (state, dictDatas) => {
  14 + state.dictDatas = dictDatas
  15 + }
  16 +}
  17 +
  18 +const actions = {
  19 + loadDictDatas({ commit }) {
  20 + listSimpleDictDatas().then(response => {
  21 + // 设置数据
  22 + const dictDataMap = {}
  23 + response.data.forEach(dictData => {
  24 + // 获得 dictType 层级
  25 + const enumValueObj = dictDataMap[dictData.dictType]
  26 + if (!enumValueObj) {
  27 + dictDataMap[dictData.dictType] = []
  28 + }
  29 + // 处理 dictValue 层级
  30 + dictDataMap[dictData.dictType].push({
  31 + dictValue: dictData.dictValue,
  32 + dictLabel: dictData.dictLabel
  33 + })
  34 + })
  35 + // 存储到 Store 中
  36 + commit('SET_DICT_DATAS', dictDataMap)
  37 + })
  38 + }
  39 +}
  40 +
  41 +export default {
  42 + namespaced: true,
  43 + state,
  44 + mutations,
  45 + actions
  46 +}
ruoyi-ui/src/store/modules/user.js
@@ -37,6 +37,7 @@ const user = { @@ -37,6 +37,7 @@ const user = {
37 const uuid = userInfo.uuid 37 const uuid = userInfo.uuid
38 return new Promise((resolve, reject) => { 38 return new Promise((resolve, reject) => {
39 login(username, password, code, uuid).then(res => { 39 login(username, password, code, uuid).then(res => {
  40 + res = res.data;
40 setToken(res.token) 41 setToken(res.token)
41 commit('SET_TOKEN', res.token) 42 commit('SET_TOKEN', res.token)
42 resolve() 43 resolve()
@@ -53,7 +54,6 @@ const user = { @@ -53,7 +54,6 @@ const user = {
53 res = res.data; // 读取 data 数据 54 res = res.data; // 读取 data 数据
54 const user = res.user 55 const user = res.user
55 const avatar = user.avatar === "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar; 56 const avatar = user.avatar === "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
56 - debugger  
57 if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 57 if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
58 commit('SET_ROLES', res.roles) 58 commit('SET_ROLES', res.roles)
59 commit('SET_PERMISSIONS', res.permissions) 59 commit('SET_PERMISSIONS', res.permissions)
ruoyi-ui/src/utils/dict.js 0 → 100644
  1 +/**
  2 + * Created by 芋道源码
  3 + *
  4 + * 数据字典工具类
  5 + */
  6 +import store from '@/store'
  7 +
  8 +export const DICT_TYPE = {
  9 + SYS_COMMON_STATUS: 'sys_common_status'
  10 +}
  11 +
  12 +/**
  13 + * 获取 dictType 对应的数据字典数组
  14 + *
  15 + * @param dictType 数据类型
  16 + * @returns {*|Array} 数据字典数组
  17 + */
  18 +export function getDictDatas(dictType) {
  19 + return store.getters.dict_datas[dictType] || []
  20 +}
  21 +
  22 +export function getDictDataLabel(dictType, value) {
  23 + // 获取 dictType 对应的数据字典数组
  24 + const dictDatas = getDictDatas(dictType)
  25 + if (!dictDatas || dictDatas.length === 0) {
  26 + return ''
  27 + }
  28 + // 获取 value 对应的展示名
  29 + value = value + '' // 强制转换成字符串,因为 DictData 小类数值,是字符串
  30 + for (const dictData of dictDatas) {
  31 + if (dictData.dictValue === value) {
  32 + return dictData.dictLabel
  33 + }
  34 + }
  35 + return ''
  36 +}
ruoyi-ui/src/views/login.vue
@@ -99,6 +99,7 @@ export default { @@ -99,6 +99,7 @@ export default {
99 methods: { 99 methods: {
100 getCode() { 100 getCode() {
101 getCodeImg().then(res => { 101 getCodeImg().then(res => {
  102 + res = res.data;
102 this.codeUrl = "data:image/gif;base64," + res.img; 103 this.codeUrl = "data:image/gif;base64," + res.img;
103 this.loginForm.uuid = res.uuid; 104 this.loginForm.uuid = res.uuid;
104 }); 105 });
ruoyi-ui/src/views/system/menu/index.vue
@@ -211,6 +211,8 @@ import Treeselect from "@riophae/vue-treeselect"; @@ -211,6 +211,8 @@ import Treeselect from "@riophae/vue-treeselect";
211 import "@riophae/vue-treeselect/dist/vue-treeselect.css"; 211 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
212 import IconSelect from "@/components/IconSelect"; 212 import IconSelect from "@/components/IconSelect";
213 213
  214 +import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
  215 +
214 export default { 216 export default {
215 name: "Menu", 217 name: "Menu",
216 components: { Treeselect, IconSelect }, 218 components: { Treeselect, IconSelect },
@@ -255,12 +257,6 @@ export default { @@ -255,12 +257,6 @@ export default {
255 }, 257 },
256 created() { 258 created() {
257 this.getList(); 259 this.getList();
258 - this.getDicts("sys_show_hide").then(response => {  
259 - this.visibleOptions = response.data;  
260 - });  
261 - this.getDicts("sys_normal_disable").then(response => {  
262 - this.statusOptions = response.data;  
263 - });  
264 }, 260 },
265 methods: { 261 methods: {
266 // 选择图标 262 // 选择图标
@@ -295,19 +291,9 @@ export default { @@ -295,19 +291,9 @@ export default {
295 this.menuOptions.push(menu); 291 this.menuOptions.push(menu);
296 }); 292 });
297 }, 293 },
298 - // 显示状态字典翻译  
299 - visibleFormat(row, column) {  
300 - if (row.menuType == "3") {  
301 - return "";  
302 - }  
303 - return this.selectDictLabel(this.visibleOptions, row.visible);  
304 - },  
305 // 菜单状态字典翻译 294 // 菜单状态字典翻译
306 statusFormat(row, column) { 295 statusFormat(row, column) {
307 - if (row.menuType == "3") {  
308 - return "";  
309 - }  
310 - return this.selectDictLabel(this.statusOptions, row.status); 296 + return getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, row.status)
311 }, 297 },
312 // 取消按钮 298 // 取消按钮
313 cancel() { 299 cancel() {
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.http 0 → 100644
  1 +### 请求 /menu/list 接口 => 成功
  2 +GET {{baseUrl}}/system/dict-data/list-all-simple
  3 +Authorization: Bearer {{token}}
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.dict;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.modules.system.controller.dict.vo.SysDataDictSimpleVO;
  5 +import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert;
  6 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO;
  7 +import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
  8 +import io.swagger.annotations.Api;
  9 +import io.swagger.annotations.ApiOperation;
  10 +import org.springframework.web.bind.annotation.GetMapping;
  11 +import org.springframework.web.bind.annotation.RequestMapping;
  12 +import org.springframework.web.bind.annotation.RestController;
  13 +
  14 +import javax.annotation.Resource;
  15 +import java.util.List;
  16 +
  17 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  18 +
  19 +@Api(tags = "数据字典 API")
  20 +@RestController
  21 +@RequestMapping("/system/dict-data")
  22 +public class SysDictDataController {
  23 +
  24 + @Resource
  25 + private SysDictDataService dictDataService;
  26 +
  27 + @GetMapping("/list-all-simple")
  28 + @ApiOperation(value = "获得全部字典数据列表", notes = "一般用于管理后台缓存字典数据在本地")
  29 + // 无需添加权限认证,因为前端全局都需要
  30 + public CommonResult<List<SysDataDictSimpleVO>> listSimpleDictDatas() {
  31 + List<SysDictDataDO> list = dictDataService.listDictDatas();
  32 + return success(SysDictDataConvert.INSTANCE.convertList(list));
  33 + }
  34 +
  35 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/SysDataDictSimpleVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.dict.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +@ApiModel("数据字典精简 VO")
  8 +@Data
  9 +public class SysDataDictSimpleVO {
  10 +
  11 + @ApiModelProperty(value = "字典类型", required = true, example = "gender")
  12 + private String dictType;
  13 +
  14 + @ApiModelProperty(value = "字典键值", required = true, example = "1")
  15 + private String dictValue;
  16 +
  17 + @ApiModelProperty(value = "字典标签", required = true, example = "男")
  18 + private String dictLabel;
  19 +
  20 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/SysMenuController.http
1 ### 请求 /menu/list 接口 => 成功 1 ### 请求 /menu/list 接口 => 成功
2 -GET {{baseUrl}}//menu/list 2 +GET {{baseUrl}}/system/menu/list
3 Authorization: Bearer {{token}} 3 Authorization: Bearer {{token}}
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/SysMenuRespVO.java
@@ -19,6 +19,9 @@ public class SysMenuRespVO extends SysMenuBaseVO { @@ -19,6 +19,9 @@ public class SysMenuRespVO extends SysMenuBaseVO {
19 @ApiModelProperty(value = "菜单编号", required = true, example = "1024") 19 @ApiModelProperty(value = "菜单编号", required = true, example = "1024")
20 private Integer menuId; 20 private Integer menuId;
21 21
  22 + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类")
  23 + private Integer status;
  24 +
22 @ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式") 25 @ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
23 private Date createTime; 26 private Date createTime;
24 27
src/main/java/cn/iocoder/dashboard/modules/system/convert/dict/SysDictDataConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.convert.dict;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.controller.dict.vo.SysDataDictSimpleVO;
  4 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO;
  5 +import org.mapstruct.Mapper;
  6 +import org.mapstruct.factory.Mappers;
  7 +
  8 +import java.util.List;
  9 +
  10 +@Mapper
  11 +public interface SysDictDataConvert {
  12 +
  13 + SysDictDataConvert INSTANCE = Mappers.getMapper(SysDictDataConvert.class);
  14 +
  15 + List<SysDataDictSimpleVO> convertList(List<SysDictDataDO> list);
  16 +
  17 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/dict/SysDictDataMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.dict;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO;
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +@Mapper
  8 +public interface SysDictDataMapper extends BaseMapper<SysDictDataDO> {
  9 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictData.java renamed to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/dict/SysDictDataDO.java
@@ -19,7 +19,7 @@ import javax.validation.constraints.Size; @@ -19,7 +19,7 @@ import javax.validation.constraints.Size;
19 @TableName("sys_dict_data") 19 @TableName("sys_dict_data")
20 @Data 20 @Data
21 @EqualsAndHashCode(callSuper = true) 21 @EqualsAndHashCode(callSuper = true)
22 -public class SysDictData extends BaseDO { 22 +public class SysDictDataDO extends BaseDO {
23 23
24 /** 24 /**
25 * 字典编码 25 * 字典编码
@@ -31,7 +31,7 @@ public class SysDictData extends BaseDO { @@ -31,7 +31,7 @@ public class SysDictData extends BaseDO {
31 * 字典排序 31 * 字典排序
32 */ 32 */
33 @Excel(name = "字典排序", cellType = Excel.ColumnType.NUMERIC) 33 @Excel(name = "字典排序", cellType = Excel.ColumnType.NUMERIC)
34 - private Long dictSort; 34 + private Integer dictSort;
35 /** 35 /**
36 * 字典标签 36 * 字典标签
37 */ 37 */
@@ -48,6 +48,8 @@ public class SysDictData extends BaseDO { @@ -48,6 +48,8 @@ public class SysDictData extends BaseDO {
48 private String dictValue; 48 private String dictValue;
49 /** 49 /**
50 * 字典类型 50 * 字典类型
  51 + *
  52 + * 外键 {@link SysDictDataDO#getDictType()}
51 */ 53 */
52 @Excel(name = "字典类型") 54 @Excel(name = "字典类型")
53 @NotBlank(message = "字典类型不能为空") 55 @NotBlank(message = "字典类型不能为空")
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataService.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.service.dict;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * 字典数据 Service 接口
  9 + *
  10 + * @author ruoyi
  11 + */
  12 +public interface SysDictDataService {
  13 +
  14 + List<SysDictDataDO> listDictDatas();
  15 +
  16 +}
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.service.dict.impl;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.dict.SysDictDataMapper;
  4 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO;
  5 +import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
  6 +import org.springframework.stereotype.Service;
  7 +
  8 +import javax.annotation.Resource;
  9 +import java.util.Comparator;
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * 字典数据 Service 实现类
  14 + *
  15 + * @author ruoyi
  16 + */
  17 +@Service
  18 +public class SysDictDataServiceImpl implements SysDictDataService {
  19 +
  20 + private static final Comparator<SysDictDataDO> COMPARATOR_TYPE_AND_SORT = Comparator
  21 + .comparing(SysDictDataDO::getDictType)
  22 + .thenComparingInt(SysDictDataDO::getDictSort);
  23 +
  24 + @Resource
  25 + private SysDictDataMapper dictDataMapper;
  26 +
  27 + @Override
  28 + public List<SysDictDataDO> listDictDatas() {
  29 + List<SysDictDataDO> list = dictDataMapper.selectList(null);
  30 + list.sort(COMPARATOR_TYPE_AND_SORT);
  31 + return list;
  32 + }
  33 +
  34 +}