diff --git a/script/sql/zfjd-refactoring-v1/011-重建虚拟单位树.sql b/script/sql/zfjd-refactoring-v1/011-重建虚拟单位树.sql index 0c7ab53c..d437cd37 100644 --- a/script/sql/zfjd-refactoring-v1/011-重建虚拟单位树.sql +++ b/script/sql/zfjd-refactoring-v1/011-重建虚拟单位树.sql @@ -1,22 +1,23 @@ create table efcode_virtual_unit ( - vir_id varchar(100) not null comment '虚拟单位ID' primary key, - vir_is_virtual varchar(20) null comment '是否是虚拟节点', - vir_tenant_id varchar(20) default '000000' null comment '租户编号', - vir_parent_id varchar(100) default '0' null comment '父部门id', - vir_zone tinyint null comment '类型', - vir_ancestors varchar(500) default '' null comment '虚拟单位祖级ID列表:包含自身', - vir_display_path varchar(1000) null comment '虚拟单位节点的单位路径:包含自身', - vir_include_type varchar(20) null comment '包含类型:查询/统计,查询,统计', - vir_domain varchar(40) null comment '域', - vir_status varchar(40) null comment '状态', - vir_remark varchar(500) null comment '备注', - sys_dept_id varchar(100) null comment '部门id', - srz_organization_id varchar(100) null comment '市认证的组织ID', - order_num int default 0 null comment '显示顺序', - create_dept varchar(100) null comment '创建部门', - create_by bigint null comment '创建者', - create_time datetime null comment '创建时间', - update_by bigint null comment '更新者', - update_time datetime null comment '更新时间' + vir_id varchar(100) not null comment '虚拟单位ID' primary key, + vir_is_virtual varchar(20) null comment '是否是虚拟节点', + vir_parent_id varchar(100) default '0' null comment '父部门id', + vir_name varchar(100) null comment '名称', + vir_zone tinyint null comment '类型', + vir_ancestors varchar(500) default '' null comment '虚拟单位祖级ID列表:包含自身', + vir_display_path varchar(1000) null comment '虚拟单位节点的单位路径:包含自身', + vir_include_type varchar(20) null comment '包含类型:查询/统计,查询,统计', + vir_domain varchar(40) null comment '域', + vir_status varchar(40) null comment '状态', + vir_show_at_business varchar(40) null comment '是否在业务中显示', + vir_remark varchar(500) null comment '备注', + sys_dept_id varchar(100) null comment '部门id', + srz_organization_id varchar(100) null comment '市认证的组织ID', + order_num int default 0 null comment '显示顺序', + create_dept varchar(100) null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间' ) comment '虚拟单位树' row_format = DYNAMIC; diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java new file mode 100644 index 00000000..24b07e38 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java @@ -0,0 +1,105 @@ +package com.zdxt.enforcementcode.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo; +import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo; +import com.zdxt.enforcementcode.service.IEfcodeVirtualUnitService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 虚拟单位树 + * + * @author Lion Li + * @date 2026-05-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/enforcementcode/virtualUnit") +public class EfcodeVirtualUnitController extends BaseController { + + private final IEfcodeVirtualUnitService efcodeVirtualUnitService; + + /** + * 查询虚拟单位树列表 + */ + @SaCheckPermission("enforcementcode:virtualUnit:list") + @GetMapping("/list") + public TableDataInfo list(EfcodeVirtualUnitBo bo, PageQuery pageQuery) { + return efcodeVirtualUnitService.queryPageList(bo, pageQuery); + } + + /** + * 导出虚拟单位树列表 + */ + @SaCheckPermission("enforcementcode:virtualUnit:export") + @Log(title = "虚拟单位树", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(EfcodeVirtualUnitBo bo, HttpServletResponse response) { + List list = efcodeVirtualUnitService.queryList(bo); + ExcelUtil.exportExcel(list, "虚拟单位树", EfcodeVirtualUnitVo.class, response); + } + + /** + * 获取虚拟单位树详细信息 + * + * @param virId 主键 + */ + @SaCheckPermission("enforcementcode:virtualUnit:query") + @GetMapping("/{virId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String virId) { + return R.ok(efcodeVirtualUnitService.queryById(virId)); + } + + /** + * 新增虚拟单位树 + */ + @SaCheckPermission("enforcementcode:virtualUnit:add") + @Log(title = "虚拟单位树", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody EfcodeVirtualUnitBo bo) { + return toAjax(efcodeVirtualUnitService.insertByBo(bo)); + } + + /** + * 修改虚拟单位树 + */ + @SaCheckPermission("enforcementcode:virtualUnit:edit") + @Log(title = "虚拟单位树", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody EfcodeVirtualUnitBo bo) { + return toAjax(efcodeVirtualUnitService.updateByBo(bo)); + } + + /** + * 删除虚拟单位树 + * + * @param virIds 主键串 + */ + @SaCheckPermission("enforcementcode:virtualUnit:remove") + @Log(title = "虚拟单位树", businessType = BusinessType.DELETE) + @DeleteMapping("/{virIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] virIds) { + return toAjax(efcodeVirtualUnitService.deleteWithValidByIds(List.of(virIds), true)); + } +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/EfcodeVirtualUnit.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/EfcodeVirtualUnit.java new file mode 100644 index 00000000..f2e8c7e2 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/EfcodeVirtualUnit.java @@ -0,0 +1,102 @@ +package com.zdxt.enforcementcode.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 虚拟单位树对象 efcode_virtual_unit + * + * @author Lion Li + * @date 2026-05-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("efcode_virtual_unit") +public class EfcodeVirtualUnit extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 虚拟单位ID + */ + @TableId(value = "vir_id") + private String virId; + + /** + * 是否是虚拟节点 + */ + private String virIsVirtual; + + + /** + * 父部门id + */ + private String virParentId; + + /** + * 名称 + */ + private String virName; + + /** + * 类型 + */ + private Long virZone; + + /** + * 虚拟单位祖级ID列表:包含自身 + */ + private String virAncestors; + + /** + * 虚拟单位节点的单位路径:包含自身 + */ + private String virDisplayPath; + + /** + * 包含类型:查询/统计,查询,统计 + */ + private String virIncludeType; + + /** + * 域 + */ + private String virDomain; + + /** + * 状态 + */ + private String virStatus; + + /** + * 是否在业务中显示 + */ + private String virShowAtBusiness; + + /** + * 备注 + */ + private String virRemark; + + /** + * 部门id + */ + private String sysDeptId; + + /** + * 市认证的组织ID + */ + private String srzOrganizationId; + + /** + * 显示顺序 + */ + private Long orderNum; + + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/EfcodeVirtualUnitBo.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/EfcodeVirtualUnitBo.java new file mode 100644 index 00000000..cb45d666 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/EfcodeVirtualUnitBo.java @@ -0,0 +1,105 @@ +package com.zdxt.enforcementcode.domain.bo; + +import com.zdxt.enforcementcode.domain.EfcodeVirtualUnit; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 虚拟单位树业务对象 efcode_virtual_unit + * + * @author Lion Li + * @date 2026-05-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = EfcodeVirtualUnit.class, reverseConvertGenerate = false) +public class EfcodeVirtualUnitBo extends BaseEntity { + + /** + * 虚拟单位ID + */ + @NotBlank(message = "虚拟单位ID不能为空", groups = { EditGroup.class }) + private String virId; + + /** + * 是否是虚拟节点 + */ + private String virIsVirtual; + + /** + * 租户编号 + */ + private String virTenantId; + + /** + * 父部门id + */ + private String virParentId; + + /** + * 名称 + */ + private String virName; + + /** + * 类型 + */ + private Long virZone; + + /** + * 虚拟单位祖级ID列表:包含自身 + */ + private String virAncestors; + + /** + * 虚拟单位节点的单位路径:包含自身 + */ + private String virDisplayPath; + + /** + * 包含类型:查询/统计,查询,统计 + */ + private String virIncludeType; + + /** + * 域 + */ + private String virDomain; + + /** + * 状态 + */ + private String virStatus; + + /** + * 是否在业务中显示 + */ + private String virShowAtBusiness; + + /** + * 备注 + */ + private String virRemark; + + /** + * 部门id + */ + private String sysDeptId; + + /** + * 市认证的组织ID + */ + private String srzOrganizationId; + + /** + * 显示顺序 + */ + private Long orderNum; + + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeVirtualUnitVo.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeVirtualUnitVo.java new file mode 100644 index 00000000..707c5c14 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeVirtualUnitVo.java @@ -0,0 +1,128 @@ +package com.zdxt.enforcementcode.domain.vo; + +import com.zdxt.enforcementcode.domain.EfcodeVirtualUnit; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 虚拟单位树视图对象 efcode_virtual_unit + * + * @author Lion Li + * @date 2026-05-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = EfcodeVirtualUnit.class) +public class EfcodeVirtualUnitVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 虚拟单位ID + */ + @ExcelProperty(value = "虚拟单位ID") + private String virId; + + /** + * 是否是虚拟节点 + */ + @ExcelProperty(value = "是否是虚拟节点") + private String virIsVirtual; + + /** + * 租户编号 + */ + @ExcelProperty(value = "租户编号") + private String virTenantId; + + /** + * 父部门id + */ + @ExcelProperty(value = "父部门id") + private String virParentId; + + /** + * 名称 + */ + @ExcelProperty(value = "名称") + private String virName; + + /** + * 类型 + */ + @ExcelProperty(value = "类型") + private Long virZone; + + /** + * 虚拟单位祖级ID列表:包含自身 + */ + @ExcelProperty(value = "虚拟单位祖级ID列表:包含自身") + private String virAncestors; + + /** + * 虚拟单位节点的单位路径:包含自身 + */ + @ExcelProperty(value = "虚拟单位节点的单位路径:包含自身") + private String virDisplayPath; + + /** + * 包含类型:查询/统计,查询,统计 + */ + @ExcelProperty(value = "包含类型:查询/统计,查询,统计") + private String virIncludeType; + + /** + * 域 + */ + @ExcelProperty(value = "域") + private String virDomain; + + /** + * 状态 + */ + @ExcelProperty(value = "状态") + private String virStatus; + + /** + * 是否在业务中显示 + */ + @ExcelProperty(value = "是否在业务中显示") + private String virShowAtBusiness; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String virRemark; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private String sysDeptId; + + /** + * 市认证的组织ID + */ + @ExcelProperty(value = "市认证的组织ID") + private String srzOrganizationId; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "显示顺序") + private Long orderNum; + + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/SrzDeptVo.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/SrzDeptVo.java index 0ea65c60..5b565392 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/SrzDeptVo.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/SrzDeptVo.java @@ -7,6 +7,7 @@ import org.dromara.common.excel.annotation.ExcelDictFormat; import org.dromara.common.excel.convert.ExcelDictConvert; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import lombok.EqualsAndHashCode; import java.io.Serial; import java.io.Serializable; @@ -21,25 +22,14 @@ import java.util.Date; * @date 2026-05-06 */ @Data +@EqualsAndHashCode(callSuper = true) @ExcelIgnoreUnannotated @AutoMapper(target = SrzDept.class) -public class SrzDeptVo implements Serializable { +public class SrzDeptVo extends SrzDeptMinVo { @Serial private static final long serialVersionUID = 1L; - /** - * 机构ID - */ - @ExcelProperty(value = "机构ID") - private String organizationid; - - /** - * 机构名称 - */ - @ExcelProperty(value = "机构名称") - private String name; - /** * 机构代码 */ @@ -64,12 +54,6 @@ public class SrzDeptVo implements Serializable { @ExcelProperty(value = "部门路径") private String zzdisplaypath; - /** - * 是否叶子节点 - */ - @ExcelProperty(value = "是否叶子节点") - private String zzisleaf; - /** * 是否删除 */ @@ -88,18 +72,6 @@ public class SrzDeptVo implements Serializable { @ExcelProperty(value = "系统ID") private String systemid; - /** - * 机构层级 - */ - @ExcelProperty(value = "机构层级") - private String zzlevel; - - /** - * 机构父节点 - */ - @ExcelProperty(value = "机构父节点") - private String parentid; - /** * 排序 */ diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeVirtualUnitMapper.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeVirtualUnitMapper.java new file mode 100644 index 00000000..09057fe6 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeVirtualUnitMapper.java @@ -0,0 +1,15 @@ +package com.zdxt.enforcementcode.mapper; + +import com.zdxt.enforcementcode.domain.EfcodeVirtualUnit; +import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 虚拟单位树Mapper接口 + * + * @author Lion Li + * @date 2026-05-07 + */ +public interface EfcodeVirtualUnitMapper extends BaseMapperPlus { + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java new file mode 100644 index 00000000..6c100aed --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java @@ -0,0 +1,68 @@ +package com.zdxt.enforcementcode.service; + +import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo; +import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 虚拟单位树Service接口 + * + * @author Lion Li + * @date 2026-05-07 + */ +public interface IEfcodeVirtualUnitService { + + /** + * 查询虚拟单位树 + * + * @param virId 主键 + * @return 虚拟单位树 + */ + EfcodeVirtualUnitVo queryById(String virId); + + /** + * 分页查询虚拟单位树列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 虚拟单位树分页列表 + */ + TableDataInfo queryPageList(EfcodeVirtualUnitBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的虚拟单位树列表 + * + * @param bo 查询条件 + * @return 虚拟单位树列表 + */ + List queryList(EfcodeVirtualUnitBo bo); + + /** + * 新增虚拟单位树 + * + * @param bo 虚拟单位树 + * @return 是否新增成功 + */ + Boolean insertByBo(EfcodeVirtualUnitBo bo); + + /** + * 修改虚拟单位树 + * + * @param bo 虚拟单位树 + * @return 是否修改成功 + */ + Boolean updateByBo(EfcodeVirtualUnitBo bo); + + /** + * 校验并批量删除虚拟单位树信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java new file mode 100644 index 00000000..9a55b7a3 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java @@ -0,0 +1,144 @@ +package com.zdxt.enforcementcode.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo; +import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo; +import com.zdxt.enforcementcode.domain.EfcodeVirtualUnit; +import com.zdxt.enforcementcode.mapper.EfcodeVirtualUnitMapper; +import com.zdxt.enforcementcode.service.IEfcodeVirtualUnitService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 虚拟单位树Service业务层处理 + * + * @author Lion Li + * @date 2026-05-07 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class EfcodeVirtualUnitServiceImpl implements IEfcodeVirtualUnitService { + + private final EfcodeVirtualUnitMapper baseMapper; + + /** + * 查询虚拟单位树 + * + * @param virId 主键 + * @return 虚拟单位树 + */ + @Override + public EfcodeVirtualUnitVo queryById(String virId){ + return baseMapper.selectVoById(virId); + } + + /** + * 分页查询虚拟单位树列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 虚拟单位树分页列表 + */ + @Override + public TableDataInfo queryPageList(EfcodeVirtualUnitBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的虚拟单位树列表 + * + * @param bo 查询条件 + * @return 虚拟单位树列表 + */ + @Override + public List queryList(EfcodeVirtualUnitBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(EfcodeVirtualUnitBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(EfcodeVirtualUnit::getVirId); + lqw.eq(StringUtils.isNotBlank(bo.getVirIsVirtual()), EfcodeVirtualUnit::getVirIsVirtual, bo.getVirIsVirtual()); + lqw.eq(StringUtils.isNotBlank(bo.getVirParentId()), EfcodeVirtualUnit::getVirParentId, bo.getVirParentId()); + lqw.eq(bo.getVirZone() != null, EfcodeVirtualUnit::getVirZone, bo.getVirZone()); + lqw.eq(StringUtils.isNotBlank(bo.getVirAncestors()), EfcodeVirtualUnit::getVirAncestors, bo.getVirAncestors()); + lqw.eq(StringUtils.isNotBlank(bo.getVirDisplayPath()), EfcodeVirtualUnit::getVirDisplayPath, bo.getVirDisplayPath()); + lqw.eq(StringUtils.isNotBlank(bo.getVirIncludeType()), EfcodeVirtualUnit::getVirIncludeType, bo.getVirIncludeType()); + lqw.eq(StringUtils.isNotBlank(bo.getVirDomain()), EfcodeVirtualUnit::getVirDomain, bo.getVirDomain()); + lqw.eq(StringUtils.isNotBlank(bo.getVirStatus()), EfcodeVirtualUnit::getVirStatus, bo.getVirStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getVirShowAtBusiness()), EfcodeVirtualUnit::getVirShowAtBusiness, bo.getVirShowAtBusiness()); + lqw.eq(StringUtils.isNotBlank(bo.getVirRemark()), EfcodeVirtualUnit::getVirRemark, bo.getVirRemark()); + lqw.eq(StringUtils.isNotBlank(bo.getSysDeptId()), EfcodeVirtualUnit::getSysDeptId, bo.getSysDeptId()); + lqw.eq(StringUtils.isNotBlank(bo.getSrzOrganizationId()), EfcodeVirtualUnit::getSrzOrganizationId, bo.getSrzOrganizationId()); + lqw.eq(bo.getOrderNum() != null, EfcodeVirtualUnit::getOrderNum, bo.getOrderNum()); + return lqw; + } + + /** + * 新增虚拟单位树 + * + * @param bo 虚拟单位树 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(EfcodeVirtualUnitBo bo) { + EfcodeVirtualUnit add = MapstructUtils.convert(bo, EfcodeVirtualUnit.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setVirId(add.getVirId()); + } + return flag; + } + + /** + * 修改虚拟单位树 + * + * @param bo 虚拟单位树 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(EfcodeVirtualUnitBo bo) { + EfcodeVirtualUnit update = MapstructUtils.convert(bo, EfcodeVirtualUnit.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(EfcodeVirtualUnit entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除虚拟单位树信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml b/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml new file mode 100644 index 00000000..d96e93f9 --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml @@ -0,0 +1,6 @@ + + + + diff --git a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java index 03decca3..ab036442 100644 --- a/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java +++ b/zdxt-modules/zdxt-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java @@ -114,4 +114,9 @@ public class SysDeptVo implements Serializable { private List children = new ArrayList<>(); private String zzDisplayPath; + + /** + * 排序号 + */ + private String sequence; } diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml index 2d02e2f5..270b8269 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml @@ -174,6 +174,7 @@ tenant: - rule_list - srz_dept - srz_user + - efcode_virtual_unit # MyBatisPlus配置 # https://baomidou.com/config/ diff --git a/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/service/test/InitVirtualUnitTest.java b/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/service/test/InitVirtualUnitTest.java new file mode 100644 index 00000000..9d3654fc --- /dev/null +++ b/zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/service/test/InitVirtualUnitTest.java @@ -0,0 +1,344 @@ +package com.zdxt.service.test; + +import cn.dev33.satoken.context.mock.SaTokenContextMockUtil; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.zdxt.enforcementcode.domain.EfcodeVirtualUnit; +import com.zdxt.enforcementcode.mapper.EfcodeVirtualUnitMapper; +import org.dromara.ZdxtAdminApplication; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.service.ISysDictTypeService; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 初始化虚拟单位树 + *

+ * 将 selectDeptTreeListReBuildByZone 中的虚拟化节点转为实际节点, + * 连同真实部门节点一起存入 efcode_virtual_unit 表。 + *

+ */ +@SpringBootTest(classes = ZdxtAdminApplication.class) +@ActiveProfiles({"dev", "dev-cust-zrb"}) +@AutoConfigureMockMvc +@DisplayName("初始化虚拟单位树") +public class InitVirtualUnitTest { + + @Autowired + private SysDeptMapper sysDeptMapper; + + @Autowired + private ISysDictTypeService dictTypeService; + + @Autowired + private EfcodeVirtualUnitMapper efcodeVirtualUnitMapper; + + private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e"; + private static final String TENANT_ID = "000000"; + + @BeforeEach + public void setUp() { + SaTokenContextMockUtil.setMockContext(); + + MockHttpServletRequest mockRequest = new MockHttpServletRequest(); + mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest)); + + LoginUser loginUser = new LoginUser(); + loginUser.setUserId(1L); + loginUser.setUserType("sys_user"); + loginUser.setTenantId(TENANT_ID); + loginUser.setUsername("test_admin"); + loginUser.setNickname("测试管理员"); + loginUser.setDeptId("103"); + loginUser.setDeptName("测试部门"); + loginUser.setRolePermission(new HashSet<>()); + loginUser.setMenuPermission(new HashSet<>()); + + SaLoginParameter param = new SaLoginParameter(); + param.setExtra(LoginHelper.CLIENT_KEY, TEST_CLIENT_ID); + LoginHelper.login(loginUser, param); + } + + @AfterEach + public void tearDown() { + try { + StpUtil.logout(); + } catch (Exception ignored) { + } + RequestContextHolder.resetRequestAttributes(); + SaTokenContextMockUtil.clearContext(); + } + + @DisplayName("初始化虚拟单位树数据到 efcode_virtual_unit 表") + @Test + public void initVirtualUnitTree() { + // 与 SysUserController.deptTreeReBuildByZone 使用相同的 zone 列表 + List zones = Arrays.asList(1, 2, 3, 4, 5, 6, 16, 15); + + // 1. 查询所有部门(按zone过滤) + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysDept::getDelFlag, SystemConstants.NORMAL); + lqw.orderByAsc(SysDept::getParentId); + lqw.orderByAsc(SysDept::getOrderNum); + lqw.orderByAsc(SysDept::getDeptId); + lqw.in(SysDept::getZone, zones); + List depts = new ArrayList<>(sysDeptMapper.selectVoList(lqw)); + + if (CollUtil.isEmpty(depts)) { + System.out.println("未查询到任何部门数据,退出"); + return; + } + System.out.println("查询到部门总数: " + depts.size()); + + // 构建 deptId -> organizationId 映射(用于设置 srz_organization_id) + Map deptOrgIdMap = sysDeptMapper.selectList(Wrappers.lambdaQuery() + .select(SysDept::getDeptId, SysDept::getOrganizationId) + .in(SysDept::getZone, zones) + .eq(SysDept::getDelFlag, SystemConstants.NORMAL) + ).stream().collect(Collectors.toMap( + SysDept::getDeptId, + d -> d.getOrganizationId() != null ? d.getOrganizationId() : "", + (a, b) -> a + )); + + // 用于收集所有待插入的虚拟单位节点 + List allUnits = new ArrayList<>(); + // id -> name 映射,用于构建 displayPath + Map idNameMap = new LinkedHashMap<>(); + + // 2. 构建虚拟根节点 "深圳市" + EfcodeVirtualUnit rootUnit = buildVirtualUnit("_root_", "深圳市", null, 0L); + allUnits.add(rootUnit); + idNameMap.put(rootUnit.getVirId(), "深圳市"); + + // 3. 获取字典数据 role_tree_zone + List dictDataList = dictTypeService.selectDictDataByType("role_tree_zone"); + if (CollUtil.isEmpty(dictDataList)) { + System.out.println("未获取到 role_tree_zone 字典数据,退出"); + return; + } + + // 3.1 添加 "市直"(dictValue=1) 和 "区"(dictValue=2) 虚拟节点 + // dictValue -> 虚拟节点virId 的映射,用于后续绑定父节点 + Map zoneVirIdMap = new HashMap<>(); + for (SysDictDataVo dict : dictDataList) { + if ("1".equals(dict.getDictValue()) || "2".equals(dict.getDictValue())) { + EfcodeVirtualUnit zoneUnit = buildVirtualUnit( + rootUnit.getVirId(), dict.getDictLabel(), + Long.parseLong(dict.getDictValue()), Long.parseLong(dict.getDictValue())); + allUnits.add(zoneUnit); + zoneVirIdMap.put(dict.getDictValue(), zoneUnit.getVirId()); + idNameMap.put(zoneUnit.getVirId(), dict.getDictLabel()); + } + } + + // 4. 按 zone 重新绑定部门的父节点(同 selectDeptTreeListReBuildByZone 逻辑) + String shizhiVirId = zoneVirIdMap.get("1"); + String quVirId = zoneVirIdMap.get("2"); + depts.forEach(d -> { + if (Objects.equals(d.getZone(), 1)) { + d.setParentId(shizhiVirId); + } + if (Objects.equals(d.getZone(), 2)) { + d.setParentId(quVirId); + } + if (Objects.equals(d.getZone(), 15) || Objects.equals(d.getZone(), 16)) { + d.setParentId(shizhiVirId); + } + }); + + // 5. 收集区(zone=2)的 id->name 映射 + Map districtMap = depts.stream() + .filter(d -> Objects.equals(d.getZone(), 2)) + .collect(Collectors.toMap(SysDeptVo::getDeptId, SysDeptVo::getDeptName)); + + // 收集 zone=3/5/6 的部门ID + List checkDeptIds = depts.stream() + .filter(d -> Objects.equals(d.getZone(), 3) || Objects.equals(d.getZone(), 5) || Objects.equals(d.getZone(), 6)) + .map(SysDeptVo::getDeptId) + .collect(Collectors.toList()); + + // 6. 为每个区创建 "区直" 虚拟节点,并将 zone=3/5/6 的部门挂到对应区直下 + districtMap.forEach((pid, districtName) -> { + EfcodeVirtualUnit quzhiUnit = buildVirtualUnit(pid, "区直", null, 0L); + String quzhiId = quzhiUnit.getVirId(); + allUnits.add(quzhiUnit); + idNameMap.put(quzhiId, "区直"); + + for (SysDeptVo dept : depts) { + if (Objects.equals(dept.getZone(), 3) || Objects.equals(dept.getZone(), 6) || Objects.equals(dept.getZone(), 5)) { + if (checkDeptIds.contains(dept.getParentId())) { + // 父部门也是区直类型(zone=3/5/6),保持原有父子关系 + } else if (StringUtils.isNotEmpty(dept.getAncestors()) && dept.getAncestors().contains(pid)) { + dept.setParentId(quzhiId); + } else if (StringUtils.isEmpty(dept.getAncestors()) + || districtMap.values().stream().noneMatch(v -> dept.getAncestors().contains(v))) { + if (dept.getDeptName() != null && districtName.length() >= 2 + && dept.getDeptName().contains(districtName.substring(0, 2))) { + dept.setParentId(quzhiId); + } + } + } + } + }); + + // 7. 将实际部门节点转为 EfcodeVirtualUnit + // 7.1 先为每个部门生成 UUID,并建立 deptId -> UUID 映射 + Map deptIdToVirIdMap = new HashMap<>(); + for (SysDeptVo dept : depts) { + String virId = UUID.randomUUID().toString().replace("-", ""); + deptIdToVirIdMap.put(dept.getDeptId(), virId); + // idNameMap 同时存 deptId 和 virId 两个 key,确保 ancestors/displayPath 构建时能找到名称 + idNameMap.put(dept.getDeptId(), dept.getDeptName()); + idNameMap.put(virId, dept.getDeptName()); + } + + // 7.2 更新已有虚拟节点的 parentId(如"区直"节点的 parentId 还是原始 deptId,需替换为 UUID) + for (EfcodeVirtualUnit existingUnit : allUnits) { + String pid = existingUnit.getVirParentId(); + if (deptIdToVirIdMap.containsKey(pid)) { + existingUnit.setVirParentId(deptIdToVirIdMap.get(pid)); + } + } + + // 7.3 构建实际部门节点,parentId 如果指向其他部门则替换为对应 UUID + // 收集所有已知的有效 virId(虚拟节点 + 部门映射) + Set knownVirIds = allUnits.stream() + .map(EfcodeVirtualUnit::getVirId) + .collect(Collectors.toSet()); + knownVirIds.addAll(deptIdToVirIdMap.values()); + + for (SysDeptVo dept : depts) { + EfcodeVirtualUnit unit = new EfcodeVirtualUnit(); + unit.setVirId(deptIdToVirIdMap.get(dept.getDeptId())); + unit.setVirIsVirtual("否"); + // parentId: 优先映射为对应部门的UUID,否则检查是否为已知虚拟节点virId + String parentId = dept.getParentId(); + if (deptIdToVirIdMap.containsKey(parentId)) { + parentId = deptIdToVirIdMap.get(parentId); + } else if (!knownVirIds.contains(parentId)) { + // parentId 无法映射为有效virId,从原始 ancestors 中查找最近的有效祖级 + String fallback = null; + if (StringUtils.isNotEmpty(dept.getAncestors())) { + String[] ancestorArr = dept.getAncestors().split(","); + for (int j = ancestorArr.length - 1; j >= 0; j--) { + String aid = ancestorArr[j].trim(); + if (deptIdToVirIdMap.containsKey(aid)) { + fallback = deptIdToVirIdMap.get(aid); + break; + } + } + } + // 如果仍找不到,按 zone 降级到虚拟父节点 + if (fallback == null) { + if (Objects.equals(dept.getZone(), 2)) { + fallback = quVirId; + } else if (Objects.equals(dept.getZone(), 1) || Objects.equals(dept.getZone(), 15) || Objects.equals(dept.getZone(), 16)) { + fallback = shizhiVirId; + } else { + fallback = rootUnit.getVirId(); + } + } + parentId = fallback; + } + unit.setVirParentId(parentId); + unit.setVirName(dept.getDeptName()); + unit.setVirZone(dept.getZone() != null ? Long.valueOf(dept.getZone()) : null); + unit.setVirStatus("启用"); + unit.setVirIncludeType("全部"); + unit.setVirShowAtBusiness("是"); + unit.setSysDeptId(dept.getDeptId()); + unit.setSrzOrganizationId(deptOrgIdMap.getOrDefault(dept.getDeptId(), "")); + unit.setOrderNum(StringUtils.isNotEmpty(dept.getSequence()) ? Long.valueOf(dept.getSequence()) : 0L); + allUnits.add(unit); + } + + // 8. 构建 ancestors 和 displayPath + Map unitMap = allUnits.stream() + .collect(Collectors.toMap(EfcodeVirtualUnit::getVirId, u -> u, (a, b) -> a)); + + for (EfcodeVirtualUnit unit : allUnits) { + // 8.1 构建 vir_ancestors:向上追溯所有祖级virId + 自身 virId + List ancestorIds = new ArrayList<>(); + String parentId = unit.getVirParentId(); + while (parentId != null && !"_root_".equals(parentId)) { + EfcodeVirtualUnit parentUnit = unitMap.get(parentId); + if (parentUnit != null) { + ancestorIds.add(0, parentId); + parentId = parentUnit.getVirParentId(); + } else { + break; + } + } + ancestorIds.add(unit.getVirId()); + unit.setVirAncestors(String.join(",", ancestorIds)); + + // 8.2 构建 vir_display_path:基于 ancestors 中每个 virId 查找名称 + String displayPath = ancestorIds.stream() + .map(id -> idNameMap.getOrDefault(id, "")) + .collect(Collectors.joining("/")); + unit.setVirDisplayPath(displayPath); + } + + // 9. 清空旧数据后批量插入 + long existCount = efcodeVirtualUnitMapper.selectCount(Wrappers.lambdaQuery()); + if (existCount > 0) { + System.out.println("清空旧数据,共 " + existCount + " 条"); + efcodeVirtualUnitMapper.delete(Wrappers.lambdaQuery()); + } + + // 分批插入(每批500条) + int batchSize = 500; + int total = allUnits.size(); + int inserted = 0; + for (int i = 0; i < total; i += batchSize) { + List batch = allUnits.subList(i, Math.min(i + batchSize, total)); + efcodeVirtualUnitMapper.insertBatch(batch); + inserted += batch.size(); + } + + System.out.println("========== 初始化完成 =========="); + System.out.println("虚拟节点数: " + allUnits.stream().filter(u -> "1".equals(u.getVirIsVirtual())).count()); + System.out.println("实际部门节点数: " + allUnits.stream().filter(u -> "0".equals(u.getVirIsVirtual())).count()); + System.out.println("总插入数: " + inserted); + } + + /** + * 构建虚拟节点 + */ + private EfcodeVirtualUnit buildVirtualUnit(String parentId, String name, Long zone, Long orderNum) { + EfcodeVirtualUnit unit = new EfcodeVirtualUnit(); + unit.setVirId(UUID.randomUUID().toString().replace("-", "")); + unit.setVirIsVirtual("是"); + unit.setVirParentId(parentId); + unit.setVirName(name); + unit.setVirZone(zone); + unit.setVirStatus("启用"); + unit.setVirIncludeType("全部"); + unit.setVirShowAtBusiness("是"); + unit.setSysDeptId(null); + unit.setSrzOrganizationId(null); + unit.setOrderNum(orderNum != null ? orderNum : 0L); + return unit; + } +}