Pārlūkot izejas kodu

【修改】新增用户字典表

lichen 1 gadu atpakaļ
vecāks
revīzija
31165f0fa3
18 mainītis faili ar 1226 papildinājumiem un 3 dzēšanām
  1. 0 1
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
  2. 109 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/DictDataTenantController.java
  3. 105 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/DictTypeTenantController.java
  4. 48 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/data/DictDataTenantPageReqVO.java
  5. 54 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/data/DictDataTenantRespVO.java
  6. 44 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/data/DictDataTenantSaveReqVO.java
  7. 37 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/type/DictTypeTenantPageReqVO.java
  8. 42 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/type/DictTypeTenantRespVO.java
  9. 34 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/type/DictTypeTenantSaveReqVO.java
  10. 60 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dictTenant/DictDataTenantDO.java
  11. 51 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dictTenant/DictTypeTenantDO.java
  12. 72 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dictTenant/DictDataTenantMapper.java
  13. 48 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dictTenant/DictTypeTenantMapper.java
  14. 117 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dictTenant/DictDataTenantService.java
  15. 187 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dictTenant/DictDataTenantServiceImpl.java
  16. 73 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dictTenant/DictTypeTenantService.java
  17. 143 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dictTenant/DictTypeTenantServiceImpl.java
  18. 2 2
      yudao-ui/yudao-ui-admin-vue2/.env.dev

+ 0 - 1
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java

@@ -70,7 +70,6 @@ public interface ErrorCodeConstants {
     ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1_002_007_001, "当前字典数据不存在");
     ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1_002_007_002, "字典数据({})不处于开启状态,不允许选择");
     ErrorCode DICT_DATA_VALUE_DUPLICATE = new ErrorCode(1_002_007_003, "已经存在该值的字典数据");
-
     // ========== 通知公告 1-002-008-000 ==========
     ErrorCode NOTICE_NOT_FOUND = new ErrorCode(1_002_008_001, "当前通知公告不存在");
 

+ 109 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/DictDataTenantController.java

@@ -0,0 +1,109 @@
+package cn.iocoder.yudao.module.system.controller.admin.dictTenant;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSimpleRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data.DictDataTenantPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data.DictDataTenantRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data.DictDataTenantSaveReqVO;
+
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictDataTenantDO;
+import cn.iocoder.yudao.module.system.service.dictTenant.DictDataTenantService;
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+
+
+@Tag(name = "管理后台 - 租户字典数据")
+@RestController
+@RequestMapping("/tenant/dictTenant-data")
+@Validated
+public class DictDataTenantController {
+
+    @Resource
+    private DictDataTenantService dictDataTenantService;
+
+    @PostMapping("/create")
+    @Operation(summary = "新增租户字典数据")
+    @PreAuthorize("@ss.hasPermission('tenant:dictTenant-data:create')")
+    public CommonResult<Long> createDictData(@Valid @RequestBody DictDataTenantSaveReqVO createReqVO) {
+        return success(dictDataTenantService.createDictData(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "修改租户字典数据")
+    @PreAuthorize("@ss.hasPermission('tenant:dictTenant-data:update')")
+    public CommonResult<Boolean> updateDictData(@Valid @RequestBody DictDataTenantSaveReqVO updateReqVO) {
+        dictDataTenantService.updateDictData(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除租户字典数据")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('tenant:dictTenant-data:delete')")
+    public CommonResult<Boolean> deleteDictData(@RequestParam("id") Long id) {
+        dictDataTenantService.deleteDictData(id);
+        return success(true);
+    }
+
+    @GetMapping(value = {"/list-all-simple", "simple-list"})
+    @Operation(summary = "获得全部字典数据列表", description = "一般用于管理后台缓存字典数据在本地")
+    // 无需添加权限认证,因为前端全局都需要
+    public CommonResult<List<DictDataSimpleRespVO>> getSimpleDictDataList() {
+        List<DictDataTenantDO> list = dictDataTenantService.getDictDataList(
+                CommonStatusEnum.ENABLE.getStatus(), null);
+        return success(BeanUtils.toBean(list, DictDataSimpleRespVO.class));
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得租户字典数据")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('tenant:dictTenant-data:query')")
+    public CommonResult<DictDataTenantRespVO> getDictData(@RequestParam("id") Long id) {
+        DictDataTenantDO dictData = dictDataTenantService.getDictData(id);
+        return success(BeanUtils.toBean(dictData, DictDataTenantRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得租户字典数据分页")
+    @PreAuthorize("@ss.hasPermission('tenant:dictTenant-data:query')")
+    public CommonResult<PageResult<DictDataTenantRespVO>> getDictDataPage(@Valid DictDataTenantPageReqVO pageReqVO) {
+        PageResult<DictDataTenantDO> pageResult = dictDataTenantService.getDictDataPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, DictDataTenantRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出租户字典数据 Excel")
+    @PreAuthorize("@ss.hasPermission('tenant:dictTenant-data:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportDictDataExcel(@Valid DictDataTenantPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<DictDataTenantDO> list = dictDataTenantService.getDictDataPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "租户字典数据.xls", "数据", DictDataTenantRespVO.class,
+                        BeanUtils.toBean(list, DictDataTenantRespVO.class));
+    }
+
+}

+ 105 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/DictTypeTenantController.java

@@ -0,0 +1,105 @@
+package cn.iocoder.yudao.module.system.controller.admin.dictTenant;
+
+import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeSimpleRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type.DictTypeTenantPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type.DictTypeTenantRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type.DictTypeTenantSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictTypeTenantDO;
+import cn.iocoder.yudao.module.system.service.dictTenant.DictTypeTenantService;
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+
+@Tag(name = "管理后台 - 租户字典类型")
+@RestController
+@RequestMapping("/tenant/dict-type")
+@Validated
+public class DictTypeTenantController {
+
+    @Resource
+    private DictTypeTenantService dictTypeTenantService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建租户字典类型")
+    @PreAuthorize("@ss.hasPermission('tenant:dict-type:create')")
+    public CommonResult<Long> createDictType(@Valid @RequestBody DictTypeTenantSaveReqVO createReqVO) {
+        return success(dictTypeTenantService.createDictType(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新租户字典类型")
+    @PreAuthorize("@ss.hasPermission('tenant:dict-type:update')")
+    public CommonResult<Boolean> updateDictType(@Valid @RequestBody DictTypeTenantSaveReqVO updateReqVO) {
+        dictTypeTenantService.updateDictType(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除租户字典类型")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('tenant:dict-type:delete')")
+    public CommonResult<Boolean> deleteDictType(@RequestParam("id") Long id) {
+        dictTypeTenantService.deleteDictType(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得租户字典类型")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('tenant:dict-type:query')")
+    public CommonResult<DictTypeTenantRespVO> getDictType(@RequestParam("id") Long id) {
+        DictTypeTenantDO dictType = dictTypeTenantService.getDictType(id);
+        return success(BeanUtils.toBean(dictType, DictTypeTenantRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得租户字典类型分页")
+    @PreAuthorize("@ss.hasPermission('tenant:dict-type:query')")
+    public CommonResult<PageResult<DictTypeTenantRespVO>> getDictTypePage(@Valid DictTypeTenantPageReqVO pageReqVO) {
+        PageResult<DictTypeTenantDO> pageResult = dictTypeTenantService.getDictTypePage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, DictTypeTenantRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出租户字典类型 Excel")
+    @PreAuthorize("@ss.hasPermission('tenant:dict-type:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportDictTypeExcel(@Valid DictTypeTenantPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<DictTypeTenantDO> list = dictTypeTenantService.getDictTypePage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "租户字典类型.xls", "数据", DictTypeTenantRespVO.class,
+                        BeanUtils.toBean(list, DictTypeTenantRespVO.class));
+    }
+
+    @GetMapping(value = {"/list-all-simple", "simple-list"})
+    @Operation(summary = "获得全部字典类型列表", description = "包括开启 + 禁用的字典类型,主要用于前端的下拉选项")
+    // 无需添加权限认证,因为前端全局都需要
+    public CommonResult<List<DictTypeSimpleRespVO>> getSimpleDictTypeList() {
+        List<DictTypeTenantDO> list = dictTypeTenantService.getDictTypeList();
+        return success(BeanUtils.toBean(list, DictTypeSimpleRespVO.class));
+    }
+}

+ 48 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/data/DictDataTenantPageReqVO.java

@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data;
+
+import lombok.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 租户字典数据分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DictDataTenantPageReqVO extends PageParam {
+
+    @Schema(description = "字典数据编号", example = "1024")
+    private Long id;
+
+    @Schema(description = "字典排序")
+    private Integer sort;
+
+    @Schema(description = "字典标签")
+    private String label;
+
+    @Schema(description = "字典键值")
+    private String value;
+
+    @Schema(description = "字典类型", example = "2")
+    private String dictType;
+
+    @Schema(description = "状态(0正常 1停用)", example = "2")
+    private Integer status;
+
+    @Schema(description = "颜色类型", example = "2")
+    private String colorType;
+
+    @Schema(description = "css 样式")
+    private String cssClass;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 54 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/data/DictDataTenantRespVO.java

@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 租户字典数据 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class DictDataTenantRespVO {
+
+    @Schema(description = "字典编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "25421")
+    @ExcelProperty("字典编码")
+    private Long id;
+
+    @Schema(description = "字典排序", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("字典排序")
+    private Integer sort;
+
+    @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("字典标签")
+    private String label;
+
+    @Schema(description = "字典键值", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("字典键值")
+    private String value;
+
+    @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty("字典类型")
+    private String dictType;
+
+    @Schema(description = "状态(0正常 1停用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty("状态(0正常 1停用)")
+    private Integer status;
+
+    @Schema(description = "颜色类型", example = "2")
+    @ExcelProperty("颜色类型")
+    private String colorType;
+
+    @Schema(description = "css 样式")
+    @ExcelProperty("css 样式")
+    private String cssClass;
+
+    @Schema(description = "备注", example = "随便")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 44 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/data/DictDataTenantSaveReqVO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - 租户字典数据新增/修改 Request VO")
+@Data
+public class DictDataTenantSaveReqVO {
+
+    @Schema(description = "字典编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "25421")
+    private Long id;
+
+    @Schema(description = "字典排序", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "字典排序不能为空")
+    private Integer sort;
+
+    @Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "字典标签不能为空")
+    private String label;
+
+    @Schema(description = "字典键值", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "字典键值不能为空")
+    private String value;
+
+    @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotEmpty(message = "字典类型不能为空")
+    private String dictType;
+
+    @Schema(description = "状态(0正常 1停用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotNull(message = "状态(0正常 1停用)不能为空")
+    private Integer status;
+
+    @Schema(description = "颜色类型", example = "2")
+    private String colorType;
+
+    @Schema(description = "css 样式")
+    private String cssClass;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+}

+ 37 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/type/DictTypeTenantPageReqVO.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type;
+
+import lombok.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 租户字典类型分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DictTypeTenantPageReqVO extends PageParam {
+
+    @Schema(description = "字典名称", example = "张三")
+    private String name;
+
+    @Schema(description = "字典类型", example = "1")
+    private String type;
+
+    @Schema(description = "状态(0正常 1停用)", example = "2")
+    private Integer status;
+
+    @Schema(description = "备注", example = "你说的对")
+    private String remark;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+    @Schema(description = "删除时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] deletedTime;
+
+}

+ 42 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/type/DictTypeTenantRespVO.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 租户字典类型 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class DictTypeTenantRespVO {
+
+    @Schema(description = "字典主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "10945")
+    @ExcelProperty("字典主键")
+    private Long id;
+
+    @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+    @ExcelProperty("字典名称")
+    private String name;
+
+    @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("字典类型")
+    private String type;
+
+    @Schema(description = "状态(0正常 1停用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty("状态(0正常 1停用)")
+    private Integer status;
+
+    @Schema(description = "备注", example = "你说的对")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "删除时间")
+    @ExcelProperty("删除时间")
+    private LocalDateTime deletedTime;
+
+}

+ 34 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dictTenant/vo/type/DictTypeTenantSaveReqVO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import javax.validation.constraints.*;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 租户字典类型新增/修改 Request VO")
+@Data
+public class DictTypeTenantSaveReqVO {
+
+    @Schema(description = "字典主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "10945")
+    private Long id;
+
+    @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
+    @NotEmpty(message = "字典名称不能为空")
+    private String name;
+
+    @Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotEmpty(message = "字典类型不能为空")
+    private String type;
+
+    @Schema(description = "状态(0正常 1停用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotNull(message = "状态(0正常 1停用)不能为空")
+    private Integer status;
+
+    @Schema(description = "备注", example = "你说的对")
+    private String remark;
+
+    @Schema(description = "删除时间")
+    private LocalDateTime deletedTime;
+
+}

+ 60 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dictTenant/DictDataTenantDO.java

@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.system.dal.dataobject.dictTenant;
+
+import lombok.*;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 租户字典数据 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("tenant_dict_data")
+@KeySequence("tenant_dict_data_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DictDataTenantDO extends BaseDO {
+
+    /**
+     * 字典编码
+     */
+    @TableId
+    private Long id;
+    /**
+     * 字典排序
+     */
+    private Integer sort;
+    /**
+     * 字典标签
+     */
+    private String label;
+    /**
+     * 字典键值
+     */
+    private String value;
+    /**
+     * 字典类型
+     */
+    private String dictType;
+    /**
+     * 状态(0正常 1停用)
+     */
+    private Integer status;
+    /**
+     * 颜色类型
+     */
+    private String colorType;
+    /**
+     * css 样式
+     */
+    private String cssClass;
+    /**
+     * 备注
+     */
+    private String remark;
+
+}

+ 51 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dictTenant/DictTypeTenantDO.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.system.dal.dataobject.dictTenant;
+
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 租户字典类型 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("tenant_dict_type")
+@KeySequence("tenant_dict_type_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DictTypeTenantDO extends BaseDO {
+
+    /**
+     * 字典主键
+     */
+    @TableId
+    private Long id;
+    /**
+     * 字典名称
+     */
+    private String name;
+    /**
+     * 字典类型
+     */
+    private String type;
+    /**
+     * 状态(0正常 1停用)
+     */
+    private Integer status;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 删除时间
+     */
+    private LocalDateTime deletedTime;
+
+}

+ 72 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dictTenant/DictDataTenantMapper.java

@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.module.system.dal.mysql.dictTenant;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+
+
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data.DictDataTenantPageReqVO;
+
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictDataTenantDO;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+
+/**
+ * 租户字典数据 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface DictDataTenantMapper extends BaseMapperX<DictDataTenantDO> {
+
+    default PageResult<DictDataTenantDO> selectPage(DictDataTenantPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<DictDataTenantDO>()
+                .eqIfPresent(DictDataTenantDO::getSort, reqVO.getSort())
+                .eqIfPresent(DictDataTenantDO::getLabel, reqVO.getLabel())
+                .eqIfPresent(DictDataTenantDO::getValue, reqVO.getValue())
+                .eqIfPresent(DictDataTenantDO::getDictType, reqVO.getDictType())
+                .eqIfPresent(DictDataTenantDO::getStatus, reqVO.getStatus())
+                .eqIfPresent(DictDataTenantDO::getColorType, reqVO.getColorType())
+                .eqIfPresent(DictDataTenantDO::getCssClass, reqVO.getCssClass())
+                .eqIfPresent(DictDataTenantDO::getRemark, reqVO.getRemark())
+                .betweenIfPresent(DictDataTenantDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(DictDataTenantDO::getId));
+    }
+
+    default List<DictDataTenantDO> selectListByStatusAndDictType(Integer status, String dictType) {
+        return selectList(new LambdaQueryWrapperX<DictDataTenantDO>()
+                .eqIfPresent(DictDataTenantDO::getStatus, status)
+                .eqIfPresent(DictDataTenantDO::getDictType, dictType));
+    }
+
+    default DictDataTenantDO selectByDictTypeAndValue(String dictType, String value) {
+        return selectOne(DictDataTenantDO::getDictType, dictType, DictDataTenantDO::getValue, value);
+    }
+
+    default DictDataTenantDO selectByDictTypeAndLabel(String dictType, String label) {
+        return selectOne(DictDataTenantDO::getDictType, dictType, DictDataTenantDO::getLabel, label);
+    }
+
+    default List<DictDataTenantDO> selectByDictTypeAndValues(String dictType, Collection<String> values) {
+        return selectList(new LambdaQueryWrapper<DictDataTenantDO>().eq(DictDataTenantDO::getDictType, dictType)
+                .in(DictDataTenantDO::getValue, values));
+    }
+
+    default long selectCountByDictType(String dictType) {
+        return selectCount(DictDataTenantDO::getDictType, dictType);
+    }
+
+    default PageResult<DictDataTenantDO> selectPage(cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<DictDataTenantDO>()
+                .likeIfPresent(DictDataTenantDO::getLabel, reqVO.getLabel())
+                .eqIfPresent(DictDataTenantDO::getDictType, reqVO.getDictType())
+                .eqIfPresent(DictDataTenantDO::getStatus, reqVO.getStatus())
+                .orderByDesc(Arrays.asList(DictDataTenantDO::getDictType, DictDataTenantDO::getSort)));
+    }
+
+}

+ 48 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dictTenant/DictTypeTenantMapper.java

@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.system.dal.mysql.dictTenant;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type.DictTypeTenantPageReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictTypeTenantDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Update;
+
+import java.time.LocalDateTime;
+
+
+/**
+ * 租户字典类型 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface DictTypeTenantMapper extends BaseMapperX<DictTypeTenantDO> {
+
+    default PageResult<DictTypeTenantDO> selectPage(DictTypeTenantPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<DictTypeTenantDO>()
+                .likeIfPresent(DictTypeTenantDO::getName, reqVO.getName())
+                .eqIfPresent(DictTypeTenantDO::getType, reqVO.getType())
+                .eqIfPresent(DictTypeTenantDO::getStatus, reqVO.getStatus())
+                .eqIfPresent(DictTypeTenantDO::getRemark, reqVO.getRemark())
+                .betweenIfPresent(DictTypeTenantDO::getCreateTime, reqVO.getCreateTime())
+                .betweenIfPresent(DictTypeTenantDO::getDeletedTime, reqVO.getDeletedTime())
+                .orderByDesc(DictTypeTenantDO::getId));
+    }
+
+    default DictTypeTenantDO selectByType(String type) {
+        return selectOne(DictTypeTenantDO::getType, type);
+    }
+
+    default DictTypeTenantDO selectByName(String name) {
+        return selectOne(DictTypeTenantDO::getName, name);
+    }
+
+    @Update("UPDATE system_dict_type SET deleted = 1, deleted_time = #{deletedTime} WHERE id = #{id}")
+    void updateToDelete(@Param("id") Long id, @Param("deletedTime") LocalDateTime deletedTime);
+
+
+}

+ 117 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dictTenant/DictDataTenantService.java

@@ -0,0 +1,117 @@
+package cn.iocoder.yudao.module.system.service.dictTenant;
+
+import javax.validation.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data.DictDataTenantPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data.DictDataTenantSaveReqVO;
+
+
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictDataTenantDO;
+import org.springframework.lang.Nullable;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 租户字典数据 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface DictDataTenantService {
+
+    /**
+     * 创建租户字典数据
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createDictData(@Valid DictDataTenantSaveReqVO createReqVO);
+
+    /**
+     * 更新租户字典数据
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateDictData(@Valid DictDataTenantPageReqVO updateReqVO);
+
+    /**
+     * 删除租户字典数据
+     *
+     * @param id 编号
+     */
+    void deleteDictData(Long id);
+
+    /**
+     * 获得字典数据列表
+     *
+     * @param status   状态
+     * @param dictType 字典类型
+     * @return 字典数据全列表
+     */
+    List<DictDataTenantDO> getDictDataList(@Nullable Integer status, @Nullable String dictType);
+
+    /**
+     * 获得租户字典数据
+     *
+     * @param id 编号
+     * @return 租户字典数据
+     */
+    DictDataTenantDO getDictData(Long id);
+
+    /**
+     * 获得租户字典数据分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 租户字典数据分页
+     */
+    PageResult<DictDataTenantDO> getDictDataPage(DictDataTenantPageReqVO pageReqVO);
+
+
+
+    /**
+     * 获得指定字典类型的数据数量
+     *
+     * @param dictType 字典类型
+     * @return 数据数量
+     */
+    long getDictDataCountByDictType(String dictType);
+
+    /**
+     * 校验字典数据们是否有效。如下情况,视为无效:
+     * 1. 字典数据不存在
+     * 2. 字典数据被禁用
+     *
+     * @param dictType 字典类型
+     * @param values   字典数据值的数组
+     */
+    void validateDictDataList(String dictType, Collection<String> values);
+
+    /**
+     * 获得指定的字典数据
+     *
+     * @param dictType 字典类型
+     * @param value    字典数据值
+     * @return 字典数据
+     */
+    DictDataTenantDO getDictData(String dictType, String value);
+
+    /**
+     * 解析获得指定的字典数据,从缓存中
+     *
+     * @param dictType 字典类型
+     * @param label    字典数据标签
+     * @return 字典数据
+     */
+    DictDataTenantDO parseDictData(String dictType, String label);
+
+    /**
+     * 获得指定数据类型的字典数据列表
+     *
+     * @param dictType 字典类型
+     * @return 字典数据列表
+     */
+    List<DictDataTenantDO> getDictDataListByDictType(String dictType);
+
+}

+ 187 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dictTenant/DictDataTenantServiceImpl.java

@@ -0,0 +1,187 @@
+package cn.iocoder.yudao.module.system.service.dictTenant;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data.DictDataTenantPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.data.DictDataTenantSaveReqVO;
+
+import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictDataTenantDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictTypeTenantDO;
+import cn.iocoder.yudao.module.system.dal.mysql.dictTenant.DictDataTenantMapper;
+import com.google.common.annotations.VisibleForTesting;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
+
+
+/**
+ * 租户字典数据 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class DictDataTenantServiceImpl implements DictDataTenantService {
+
+    /**
+     * 排序 dictType > sort
+     */
+    private static final Comparator<DictDataTenantDO> COMPARATOR_TYPE_AND_SORT = Comparator
+            .comparing(DictDataTenantDO::getDictType)
+            .thenComparingInt(DictDataTenantDO::getSort);
+
+    @Resource
+    private DictDataTenantMapper dictDataTenantMapper;
+
+    @Resource
+    private DictTypeTenantService dictTypeTenantService;
+
+
+    @Override
+    public List<DictDataTenantDO> getDictDataList(Integer status, String dictType) {
+        List<DictDataTenantDO> list = dictDataTenantMapper.selectListByStatusAndDictType(status, dictType);
+        list.sort(COMPARATOR_TYPE_AND_SORT);
+        return list;
+    }
+
+
+    @Override
+    public DictDataTenantDO getDictData(Long id) {
+        return dictDataTenantMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<DictDataTenantDO> getDictDataPage(DictDataTenantPageReqVO pageReqVO) {
+        return dictDataTenantMapper.selectPage(pageReqVO);
+    }
+
+
+    @Override
+    public Long createDictData(DictDataTenantSaveReqVO createReqVO) {
+        // 校验字典类型有效
+        validateDictTypeExists(createReqVO.getDictType());
+        // 校验字典数据的值的唯一性
+        validateDictDataValueUnique(null, createReqVO.getDictType(), createReqVO.getValue());
+
+        // 插入字典类型
+        DictDataTenantDO dictData = BeanUtils.toBean(createReqVO, DictDataTenantDO.class);
+        dictDataTenantMapper.insert(dictData);
+        return dictData.getId();
+    }
+
+    @Override
+    public void updateDictData(DictDataTenantPageReqVO updateReqVO) {
+        // 校验自己存在
+        validateDictDataExists(updateReqVO.getId());
+        // 校验字典类型有效
+        validateDictTypeExists(updateReqVO.getDictType());
+        // 校验字典数据的值的唯一性
+        validateDictDataValueUnique(updateReqVO.getId(), updateReqVO.getDictType(), updateReqVO.getValue());
+
+        // 更新字典类型
+        DictDataTenantDO updateObj = BeanUtils.toBean(updateReqVO, DictDataTenantDO.class);
+        dictDataTenantMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteDictData(Long id) {
+        // 校验是否存在
+        validateDictDataExists(id);
+
+        // 删除字典数据
+        dictDataTenantMapper.deleteById(id);
+    }
+
+    @Override
+    public long getDictDataCountByDictType(String dictType) {
+        return dictDataTenantMapper.selectCountByDictType(dictType);
+    }
+
+    @VisibleForTesting
+    public void validateDictDataValueUnique(Long id, String dictType, String value) {
+        DictDataTenantDO dictData = dictDataTenantMapper.selectByDictTypeAndValue(dictType, value);
+        if (dictData == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的字典数据
+        if (id == null) {
+            throw exception(DICT_DATA_VALUE_DUPLICATE);
+        }
+        if (!dictData.getId().equals(id)) {
+            throw exception(DICT_DATA_VALUE_DUPLICATE);
+        }
+    }
+
+    @VisibleForTesting
+    public void validateDictDataExists(Long id) {
+        if (id == null) {
+            return;
+        }
+        DictDataTenantDO dictData = dictDataTenantMapper.selectById(id);
+        if (dictData == null) {
+            throw exception(DICT_DATA_NOT_EXISTS);
+        }
+    }
+
+    @VisibleForTesting
+    public void validateDictTypeExists(String type) {
+        DictTypeTenantDO dictType = dictTypeTenantService.getDictType(type);
+        if (dictType == null) {
+            throw exception(DICT_TYPE_NOT_EXISTS);
+        }
+        if (!CommonStatusEnum.ENABLE.getStatus().equals(dictType.getStatus())) {
+            throw exception(DICT_TYPE_NOT_ENABLE);
+        }
+    }
+
+    @Override
+    public void validateDictDataList(String dictType, Collection<String> values) {
+        if (CollUtil.isEmpty(values)) {
+            return;
+        }
+        Map<String, DictDataTenantDO> dictDataMap = CollectionUtils.convertMap(
+                dictDataTenantMapper.selectByDictTypeAndValues(dictType, values), DictDataTenantDO::getValue);
+        // 校验
+        values.forEach(value -> {
+            DictDataTenantDO dictData = dictDataMap.get(value);
+            if (dictData == null) {
+                throw exception(DICT_DATA_NOT_EXISTS);
+            }
+            if (!CommonStatusEnum.ENABLE.getStatus().equals(dictData.getStatus())) {
+                throw exception(DICT_DATA_NOT_ENABLE, dictData.getLabel());
+            }
+        });
+    }
+
+    @Override
+    public DictDataTenantDO getDictData(String dictType, String value) {
+        return dictDataTenantMapper.selectByDictTypeAndValue(dictType, value);
+    }
+
+    @Override
+    public DictDataTenantDO parseDictData(String dictType, String label) {
+        return dictDataTenantMapper.selectByDictTypeAndLabel(dictType, label);
+    }
+
+    @Override
+    public List<DictDataTenantDO> getDictDataListByDictType(String dictType) {
+        List<DictDataTenantDO> list = dictDataTenantMapper.selectList(DictDataTenantDO::getDictType, dictType);
+        list.sort(Comparator.comparing(DictDataTenantDO::getSort));
+        return list;
+    }
+
+}

+ 73 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dictTenant/DictTypeTenantService.java

@@ -0,0 +1,73 @@
+package cn.iocoder.yudao.module.system.service.dictTenant;
+
+import javax.validation.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type.DictTypeTenantPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type.DictTypeTenantSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictTypeTenantDO;
+
+import java.util.List;
+
+/**
+ * 租户字典类型 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface DictTypeTenantService {
+
+    /**
+     * 创建租户字典类型
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createDictType(@Valid DictTypeTenantSaveReqVO createReqVO);
+
+    /**
+     * 更新租户字典类型
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateDictType(@Valid DictTypeTenantSaveReqVO updateReqVO);
+
+    /**
+     * 删除租户字典类型
+     *
+     * @param id 编号
+     */
+    void deleteDictType(Long id);
+
+    /**
+     * 获得租户字典类型
+     *
+     * @param id 编号
+     * @return 租户字典类型
+     */
+    DictTypeTenantDO getDictType(Long id);
+
+    /**
+     * 获得字典类型详情
+     *
+     * @param type 字典类型
+     * @return 字典类型详情
+     */
+    DictTypeTenantDO getDictType(String type);
+
+    /**
+     * 获得租户字典类型分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 租户字典类型分页
+     */
+    PageResult<DictTypeTenantDO> getDictTypePage(DictTypeTenantPageReqVO pageReqVO);
+
+    /**
+     * 获得全部字典类型列表
+     *
+     * @return 字典类型列表
+     */
+    List<DictTypeTenantDO> getDictTypeList();
+
+}

+ 143 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dictTenant/DictTypeTenantServiceImpl.java

@@ -0,0 +1,143 @@
+package cn.iocoder.yudao.module.system.service.dictTenant;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type.DictTypeTenantPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.dictTenant.vo.type.DictTypeTenantSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dictTenant.DictTypeTenantDO;
+import cn.iocoder.yudao.module.system.dal.mysql.dictTenant.DictTypeTenantMapper;
+import com.google.common.annotations.VisibleForTesting;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
+
+/**
+ * 租户字典类型 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class DictTypeTenantServiceImpl implements DictTypeTenantService {
+
+    @Resource
+    private DictTypeTenantMapper dictTypeTenantMapper;
+    @Resource
+    private DictDataTenantService dictDataTenantService;
+
+    @Override
+    public Long createDictType(DictTypeTenantSaveReqVO createReqVO) {
+        // 校验字典类型的名字的唯一性
+        validateDictTypeNameUnique(null, createReqVO.getName());
+        // 校验字典类型的类型的唯一性
+        validateDictTypeUnique(null, createReqVO.getType());
+
+        // 插入字典类型
+        DictTypeTenantDO dictType = BeanUtils.toBean(createReqVO, DictTypeTenantDO.class);
+        dictType.setDeletedTime(LocalDateTimeUtils.EMPTY); // 唯一索引,避免 null 值
+        dictTypeTenantMapper.insert(dictType);
+        return dictType.getId();
+    }
+
+    @Override
+    public void updateDictType(DictTypeTenantSaveReqVO updateReqVO) {
+        // 校验自己存在
+        validateDictTypeExists(updateReqVO.getId());
+        // 校验字典类型的名字的唯一性
+        validateDictTypeNameUnique(updateReqVO.getId(), updateReqVO.getName());
+        // 校验字典类型的类型的唯一性
+        validateDictTypeUnique(updateReqVO.getId(), updateReqVO.getType());
+        // 更新
+        DictTypeTenantDO updateObj = BeanUtils.toBean(updateReqVO, DictTypeTenantDO.class);
+        dictTypeTenantMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteDictType(Long id) {
+        // 校验是否存在
+        DictTypeTenantDO dictType = validateDictTypeExists(id);
+        // 校验是否有字典数据
+        if (dictDataTenantService.getDictDataCountByDictType(dictType.getType()) > 0) {
+            throw exception(DICT_TYPE_HAS_CHILDREN);
+        }
+        // 删除
+        dictTypeTenantMapper.deleteById(id);
+    }
+
+
+    @Override
+    public DictTypeTenantDO getDictType(Long id) {
+        return dictTypeTenantMapper.selectById(id);
+    }
+
+    @Override
+    public DictTypeTenantDO getDictType(String type) {
+        return dictTypeTenantMapper.selectByType(type);
+    }
+
+    @Override
+    public PageResult<DictTypeTenantDO> getDictTypePage(DictTypeTenantPageReqVO pageReqVO) {
+        return dictTypeTenantMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<DictTypeTenantDO> getDictTypeList() {
+        return dictTypeTenantMapper.selectList();
+    }
+
+
+    @VisibleForTesting
+    void validateDictTypeNameUnique(Long id, String name) {
+        DictTypeTenantDO dictType = dictTypeTenantMapper.selectByName(name);
+        if (dictType == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的字典类型
+        if (id == null) {
+            throw exception(DICT_TYPE_NAME_DUPLICATE);
+        }
+        if (!dictType.getId().equals(id)) {
+            throw exception(DICT_TYPE_NAME_DUPLICATE);
+        }
+    }
+
+    @VisibleForTesting
+    void validateDictTypeUnique(Long id, String type) {
+        if (StrUtil.isEmpty(type)) {
+            return;
+        }
+        DictTypeTenantDO dictType = dictTypeTenantMapper.selectByType(type);
+        if (dictType == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的字典类型
+        if (id == null) {
+            throw exception(DICT_TYPE_TYPE_DUPLICATE);
+        }
+        if (!dictType.getId().equals(id)) {
+            throw exception(DICT_TYPE_TYPE_DUPLICATE);
+        }
+    }
+
+    @VisibleForTesting
+    DictTypeTenantDO validateDictTypeExists(Long id) {
+        if (id == null) {
+            return null;
+        }
+        DictTypeTenantDO dictType = dictTypeTenantMapper.selectById(id);
+        if (dictType == null) {
+            throw exception(DICT_TYPE_NOT_EXISTS);
+        }
+        return dictType;
+    }
+}

+ 2 - 2
yudao-ui/yudao-ui-admin-vue2/.env.dev

@@ -5,8 +5,8 @@ ENV = 'development'
 VUE_APP_TITLE = 芋道管理系统
 
 # 芋道管理系统/开发环境
-# VUE_APP_BASE_API = 'http://localhost:48080'
- VUE_APP_BASE_API = 'http://192.168.100.249:48080'
+ VUE_APP_BASE_API = 'http://localhost:48080'
+# VUE_APP_BASE_API = 'http://192.168.100.249:48080'
 # VUE_APP_BASE_API = 'http://192.168.100.234:48080'