diff --git a/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/config/AuthConfigure.java b/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/config/AuthConfigure.java index 60ff38ff..1202a148 100644 --- a/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/config/AuthConfigure.java +++ b/snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/core/config/AuthConfigure.java @@ -12,7 +12,6 @@ */ package vip.xiaonuo.auth.core.config; -import cn.dev33.satoken.interceptor.SaAnnotationInterceptor; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.stp.StpInterface; import cn.dev33.satoken.stp.StpLogic; diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/org/service/BizOrgService.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/org/service/BizOrgService.java index 853e0c17..93203dd6 100644 --- a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/org/service/BizOrgService.java +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/org/service/BizOrgService.java @@ -85,6 +85,22 @@ public interface BizOrgService extends IService { **/ BizOrg queryEntity(String id); + /** + * 获取缓存的所有机构 + * + * @author xuyuxiang + * @date 2022/7/25 19:42 + **/ + List getCachedAllOrgList(); + + /** + * 根据机构全名称获取机构id,有则返回,无则创建 + * + * @author xuyuxiang + * @date 2023/3/7 15:44 + **/ + String getOrgIdByOrgFullNameWithCreate(String orgFullName); + /** * 获取机构树选择器 * diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/org/service/impl/BizOrgServiceImpl.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/org/service/impl/BizOrgServiceImpl.java index 4c84f3fb..da4627d3 100644 --- a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/org/service/impl/BizOrgServiceImpl.java +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/org/service/impl/BizOrgServiceImpl.java @@ -40,6 +40,7 @@ import vip.xiaonuo.biz.modular.position.entity.BizPosition; import vip.xiaonuo.biz.modular.position.service.BizPositionService; import vip.xiaonuo.biz.modular.user.entity.BizUser; import vip.xiaonuo.biz.modular.user.service.BizUserService; +import vip.xiaonuo.common.cache.CommonCacheOperator; import vip.xiaonuo.common.enums.CommonSortOrderEnum; import vip.xiaonuo.common.exception.CommonException; import vip.xiaonuo.common.listener.CommonDataChangeEventCenter; @@ -47,6 +48,7 @@ import vip.xiaonuo.common.page.CommonPageRequest; import vip.xiaonuo.sys.api.SysRoleApi; import javax.annotation.Resource; +import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -60,6 +62,11 @@ import java.util.stream.Collectors; @Service public class BizOrgServiceImpl extends ServiceImpl implements BizOrgService { + public static final String ORG_CACHE_ALL_KEY = "sys-org:all"; + + @Resource + private CommonCacheOperator commonCacheOperator; + @Resource private SysRoleApi sysRoleApi; @@ -196,7 +203,7 @@ public class BizOrgServiceImpl extends ServiceImpl impleme throw new CommonException("您没有权限删除这些机构,机构id:{}", orgIdList); } List allOrgList = this.list(); - // 获取所有子组织 + // 获取所有子机构 List toDeleteOrgIdList = CollectionUtil.newArrayList(); orgIdList.forEach(orgId -> toDeleteOrgIdList.addAll(this.getChildListById(allOrgList, orgId, true).stream() .map(BizOrg::getId).collect(Collectors.toList()))); @@ -249,6 +256,74 @@ public class BizOrgServiceImpl extends ServiceImpl impleme return bizOrg; } + @Override + public List getCachedAllOrgList() { + // 从缓存中取 + Object cacheValue = commonCacheOperator.get(ORG_CACHE_ALL_KEY); + if(ObjectUtil.isNotEmpty(cacheValue)) { + return JSONUtil.toList(JSONUtil.parseArray(cacheValue), BizOrg.class); + } + List orgList = this.list(new LambdaQueryWrapper().orderByAsc(BizOrg::getSortCode)); + if(ObjectUtil.isNotEmpty(orgList)) { + // 更新到缓存 + commonCacheOperator.put(ORG_CACHE_ALL_KEY, orgList); + } + return orgList; + } + + @Override + public String getOrgIdByOrgFullNameWithCreate(String orgFullName) { + List cachedAllOrgList = this.getCachedAllOrgList(); + List> treeList = TreeUtil.build(cachedAllOrgList.stream().map(bizOrg -> + new TreeNode<>(bizOrg.getId(), bizOrg.getParentId(), bizOrg.getName(), bizOrg.getSortCode())) + .collect(Collectors.toList()), "0"); + return findOrgIdByOrgName("0", StrUtil.split(orgFullName, StrUtil.DASHED).iterator(), cachedAllOrgList, treeList); + } + + public String findOrgIdByOrgName(String parentId, Iterator iterator, List cachedAllOrgList, List> treeList) { + String orgName = iterator.next(); + if(ObjectUtil.isNotEmpty(treeList)) { + List> findList = treeList.stream().filter(tree -> tree.getName().equals(orgName)).collect(Collectors.toList()); + if(ObjectUtil.isNotEmpty(findList)) { + if(iterator.hasNext()) { + return findOrgIdByOrgName(findList.get(0).getId(), iterator, cachedAllOrgList, findList.get(0).getChildren()); + } else { + return findList.get(0).getId(); + } + } + } + String orgId = this.doCreateOrg(parentId, orgName, cachedAllOrgList); + if(iterator.hasNext()) { + return findOrgIdByOrgName(orgId, iterator, cachedAllOrgList, CollectionUtil.newArrayList()); + } else { + return orgId; + } + } + + /** + * 执行创建机构 + * + * @author xuyuxiang + * @date 2023/3/8 9:38 + **/ + public String doCreateOrg(String parentId, String orgName, List cachedAllOrgList) { + //创建该机构 + BizOrg bizOrg = new BizOrg(); + bizOrg.setName(orgName); + bizOrg.setCode(RandomUtil.randomString(10)); + bizOrg.setParentId(parentId); + bizOrg.setCategory(parentId.equals("0")?BizOrgCategoryEnum.COMPANY.getValue():BizOrgCategoryEnum.DEPT.getValue()); + bizOrg.setSortCode(99); + this.save(bizOrg); + // 发布增加事件 + CommonDataChangeEventCenter.doAddWithData(BizDataTypeEnum.ORG.getValue(), JSONUtil.createArray().put(bizOrg)); + // 将该机构加入缓存 + cachedAllOrgList.add(bizOrg); + // 更新缓存 + commonCacheOperator.put(ORG_CACHE_ALL_KEY, cachedAllOrgList); + return bizOrg.getId(); + } + /* ====机构部分所需要用到的选择器==== */ @Override @@ -316,6 +391,13 @@ public class BizOrgServiceImpl extends ServiceImpl impleme /* ====以下为各种递归方法==== */ + public List getParentAndChildListById(List originDataList, String id, boolean includeSelf) { + List parentListById = this.getParentListById(originDataList, id, false); + List childListById = this.getChildListById(originDataList, id, true); + parentListById.addAll(childListById); + return parentListById; + } + public List getChildListById(List originDataList, String id, boolean includeSelf) { List resultList = CollectionUtil.newArrayList(); execRecursionFindChild(originDataList, id, resultList); diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/position/service/BizPositionService.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/position/service/BizPositionService.java index 06e7d76d..c4d4c909 100644 --- a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/position/service/BizPositionService.java +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/position/service/BizPositionService.java @@ -76,6 +76,14 @@ public interface BizPositionService extends IService { **/ BizPosition queryEntity(String id); + /** + * 根据机构id和岗位名称获取岗位id,有则返回,无则创建 + * + * @author xuyuxiang + * @date 2022/8/15 14:55 + **/ + String getPositionIdByPositionNameWithCreate(String orgId, String positionName); + /* ====岗位部分所需要用到的选择器==== */ /** diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/position/service/impl/BizPositionServiceImpl.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/position/service/impl/BizPositionServiceImpl.java index 9025491c..ffb381ae 100644 --- a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/position/service/impl/BizPositionServiceImpl.java +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/position/service/impl/BizPositionServiceImpl.java @@ -204,6 +204,11 @@ public class BizPositionServiceImpl extends ServiceImpl downloadImportUserTemplate(HttpServletResponse response) throws IOException { + bizUserService.downloadImportUserTemplate(response); + return CommonResult.ok(); + } + + /** + * 人员导入 + * + * @author xuyuxiang + * @date 2022/4/24 20:00 + */ + @ApiOperationSupport(order = 12) @ApiOperation("人员导入") @CommonLog("人员导入") - @SaCheckPermission("/biz/user/import") @PostMapping("/biz/user/import") - public CommonResult importUser(@RequestPart("file") @ApiParam(value="文件", required = true) MultipartFile file) { - bizUserService.importUser(file); - return CommonResult.ok(); + public CommonResult importUser(@RequestPart("file") @ApiParam(value="文件", required = true) MultipartFile file) { + return CommonResult.data(bizUserService.importUser(file)); } /** @@ -233,15 +247,28 @@ public class BizUserController { * @author xuyuxiang * @date 2022/4/24 20:00 */ - @ApiOperationSupport(order = 12) + @ApiOperationSupport(order = 13) @ApiOperation("人员导出") @CommonLog("人员导出") - @SaCheckPermission("/biz/user/export") @GetMapping(value = "/biz/user/export", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) public void exportUser(BizUserExportParam bizUserExportParam, HttpServletResponse response) throws IOException { bizUserService.exportUser(bizUserExportParam, response); } + /** + * 按模板导出人员个人信息 + * + * @author xuyuxiang + * @date 2022/4/24 20:00 + */ + @ApiOperationSupport(order = 14) + @ApiOperation("导出人员个人信息") + @CommonLog("导出人员个人信息") + @GetMapping(value = "/biz/user/exportUserInfo", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public void exportUserInfo(BizUserIdParam bizUserIdParam, HttpServletResponse response) throws IOException { + bizUserService.exportUserInfo(bizUserIdParam, response); + } + /* ====人员部分所需要用到的选择器==== */ /** @@ -250,7 +277,7 @@ public class BizUserController { * @author xuyuxiang * @date 2022/4/24 20:00 */ - @ApiOperationSupport(order = 13) + @ApiOperationSupport(order = 15) @ApiOperation("获取机构树选择器") @SaCheckPermission("/biz/user/orgTreeSelector") @GetMapping("/biz/user/orgTreeSelector") @@ -264,7 +291,7 @@ public class BizUserController { * @author xuyuxiang * @date 2022/4/24 20:00 */ - @ApiOperationSupport(order = 14) + @ApiOperationSupport(order = 16) @ApiOperation("获取机构列表选择器") @SaCheckPermission("/biz/user/orgListSelector") @GetMapping("/biz/user/orgListSelector") @@ -278,7 +305,7 @@ public class BizUserController { * @author xuyuxiang * @date 2022/4/24 20:00 */ - @ApiOperationSupport(order = 15) + @ApiOperationSupport(order = 17) @ApiOperation("获取岗位选择器") @SaCheckPermission("/biz/user/positionSelector") @GetMapping("/biz/user/positionSelector") @@ -292,7 +319,7 @@ public class BizUserController { * @author xuyuxiang * @date 2022/4/24 20:00 */ - @ApiOperationSupport(order = 16) + @ApiOperationSupport(order = 18) @ApiOperation("获取角色选择器") @SaCheckPermission("/biz/user/roleSelector") @GetMapping("/biz/user/roleSelector") @@ -306,7 +333,7 @@ public class BizUserController { * @author xuyuxiang * @date 2022/4/24 20:00 */ - @ApiOperationSupport(order = 17) + @ApiOperationSupport(order = 19) @ApiOperation("获取人员选择器") @SaCheckPermission("/biz/user/userSelector") @GetMapping("/biz/user/userSelector") diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/BizUserExportParam.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/BizUserExportParam.java index 03bf76b4..d3b65779 100644 --- a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/BizUserExportParam.java +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/BizUserExportParam.java @@ -16,8 +16,10 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; +import java.util.List; + /** - * 用户导出参数 + * 人员导出参数 * * @author xuyuxiang * @date 2022/7/26 16:00 @@ -26,11 +28,15 @@ import lombok.Setter; @Setter public class BizUserExportParam { - /** 用户状态 */ - @ApiModelProperty(value = "用户状态") + /** 人员状态 */ + @ApiModelProperty(value = "人员状态") private String userStatus; /** 账号、姓名、手机号关键词 */ @ApiModelProperty(value = "账号、姓名、手机号关键词") private String searchKey; + + /** 人员id集合 */ + @ApiModelProperty(value = "人员id集合") + private List userIdList; } diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/BizUserImportParam.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/BizUserImportParam.java new file mode 100644 index 00000000..00069cf2 --- /dev/null +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/BizUserImportParam.java @@ -0,0 +1,120 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.biz.modular.user.param; + +import lombok.Getter; +import lombok.Setter; + +/** + * 人员导入参数 + * + * @author xuyuxiang + * @date 2022/7/8 13:22 + **/ +@Getter +@Setter +public class BizUserImportParam { + + /** 账号 */ + private String account; + + /** 姓名 */ + private String name; + + /** 组织名称 */ + private String orgName; + + /** 职位名称 */ + private String positionName; + + /** 手机 */ + private String phone; + + /** 邮箱 */ + private String email; + + /** 主管名称 */ + private String directorName; + + /** 员工编号 */ + private String empNo; + + /** 入职日期 */ + private String entryDate; + + /** 职级 */ + private String positionLevel; + + /** 昵称 */ + private String nickname; + + /** 性别 */ + private String gender; + + /** 年龄 */ + private String age; + + /** 出生日期 */ + private String birthday; + + /** 民族 */ + private String nation; + + /** 籍贯 */ + private String nativePlace; + + /** 家庭住址 */ + private String homeAddress; + + /** 通信地址 */ + private String mailingAddress; + + /** 证件类型 */ + private String idCardType; + + /** 证件号码 */ + private String idCardNumber; + + /** 文化程度 */ + private String cultureLevel; + + /** 政治面貌 */ + private String politicalOutlook; + + /** 毕业院校 */ + private String college; + + /** 学历 */ + private String education; + + /** 学制 */ + private String eduLength; + + /** 学位 */ + private String degree; + + /** 家庭电话 */ + private String homeTel; + + /** 办公电话 */ + private String officeTel; + + /** 紧急联系人 */ + private String emergencyContact; + + /** 紧急联系人电话 */ + private String emergencyPhone; + + /** 紧急联系人地址 */ + private String emergencyAddress; +} diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/result/BizUserExportResult.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/result/BizUserExportResult.java index 9555a8e4..1bd67637 100644 --- a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/result/BizUserExportResult.java +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/result/BizUserExportResult.java @@ -10,16 +10,20 @@ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip */ -package vip.xiaonuo.biz.modular.user.result; +package vip.xiaonuo.sys.modular.user.result; -import cn.afterturn.easypoi.excel.annotation.Excel; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.HeadStyle; +import com.alibaba.excel.enums.poi.FillPatternTypeEnum; import lombok.Getter; import lombok.Setter; import java.util.Date; /** - * 用户导出结果集 + * 人员导出结果集 * * @author xuyuxiang * @date 2022/7/8 13:22 @@ -28,170 +32,216 @@ import java.util.Date; @Setter public class BizUserExportResult { - /** 头像 */ - private String avatar; + /** 机构分组 */ + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40) + @ExcelProperty({"人员信息", "机构分组"}) + private String groupName; - /** 头像字节数组 */ - @Excel(name = "头像", type = 2, imageType = 2) - private byte[] avatarByte; + /** 头像 */ + @ColumnWidth(8) + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "头像"}) + private byte[] avatar; /** 账号 */ - @Excel(name = "账号") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "账号"}) private String account; /** 姓名 */ - @Excel(name = "姓名") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "姓名"}) private String name; /** 昵称 */ - @Excel(name = "姓名") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "昵称"}) private String nickname; /** 性别 */ - @Excel(name = "性别") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "性别"}) private String gender; /** 年龄 */ - @Excel(name = "年龄") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "年龄"}) private String age; /** 出生日期 */ - @Excel(name = "出生日期") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "出生日期"}) private String birthday; /** 民族 */ - @Excel(name = "民族") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "民族"}) private String nation; /** 籍贯 */ - @Excel(name = "籍贯") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "籍贯"}) private String nativePlace; /** 家庭住址 */ - @Excel(name = "家庭住址") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "家庭住址"}) private String homeAddress; /** 通信地址 */ - @Excel(name = "通信地址") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "通信地址"}) private String mailingAddress; /** 证件类型 */ - @Excel(name = "证件类型") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "证件类型"}) private String idCardType; /** 证件号码 */ - @Excel(name = "证件号码") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "证件号码"}) private String idCardNumber; /** 文化程度 */ - @Excel(name = "文化程度") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "文化程度"}) private String cultureLevel; /** 政治面貌 */ - @Excel(name = "政治面貌") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "政治面貌"}) private String politicalOutlook; /** 毕业院校 */ - @Excel(name = "毕业院校") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "毕业院校"}) private String college; /** 学历 */ - @Excel(name = "学历") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "学历"}) private String education; /** 学制 */ - @Excel(name = "学制") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "学制"}) private String eduLength; /** 学位 */ - @Excel(name = "学位") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "学位"}) private String degree; /** 手机 */ - @Excel(name = "手机") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "手机"}) private String phone; /** 邮箱 */ - @Excel(name = "邮箱") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "邮箱"}) private String email; /** 家庭电话 */ - @Excel(name = "家庭电话") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "家庭电话"}) private String homeTel; /** 办公电话 */ - @Excel(name = "办公电话") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "办公电话"}) private String officeTel; /** 紧急联系人 */ - @Excel(name = "紧急联系人") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "紧急联系人"}) private String emergencyContact; /** 紧急联系人电话 */ - @Excel(name = "紧急联系人电话") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "紧急联系人电话"}) private String emergencyPhone; /** 紧急联系人地址 */ - @Excel(name = "紧急联系人地址") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 29) + @ExcelProperty({"人员信息", "基本信息", "紧急联系人地址"}) private String emergencyAddress; /** 员工编号 */ - @Excel(name = "员工编号") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 34) + @ExcelProperty({"人员信息", "员工信息", "员工编号"}) private String empNo; /** 入职日期 */ - @Excel(name = "入职日期") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 34) + @ExcelProperty({"人员信息", "员工信息", "入职日期"}) private String entryDate; /** 组织名称 */ - @Excel(name = "组织名称") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 34) + @ExcelProperty({"人员信息", "员工信息", "组织名称"}) private String orgName; /** 职位名称 */ - @Excel(name = "职位名称") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 34) + @ExcelProperty({"人员信息", "员工信息", "职位名称"}) private String positionName; /** 主管名称 */ - @Excel(name = "主管名称") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 34) + @ExcelProperty({"人员信息", "员工信息", "主管名称"}) private String directorName; /** 职级 */ - @Excel(name = "职级") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 34) + @ExcelProperty({"人员信息", "员工信息", "职级"}) private String positionLevel; /** 上次登录ip */ - @Excel(name = "上次登录ip") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @ExcelProperty({"人员信息", "系统信息", "上次登录ip"}) private String lastLoginIp; /** 上次登录地点 */ - @Excel(name = "上次登录地点") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @ExcelProperty({"人员信息", "系统信息", "上次登录地点"}) private String lastLoginAddress; /** 上次登录时间 */ - @Excel(name = "上次登录时间", format = "yyyy-MM-dd HH:mm:ss") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @DateTimeFormat("yyyy-MM-dd HH:mm:ss") + @ExcelProperty({"人员信息", "系统信息", "上次登录时间"}) private Date lastLoginTime; /** 上次登录设备 */ - @Excel(name = "上次登录设备") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @ExcelProperty({"人员信息", "系统信息", "上次登录设备"}) private String lastLoginDevice; /** 最新登录ip */ - @Excel(name = "最新登录ip") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @ExcelProperty({"人员信息", "系统信息", "最新登录ip"}) private String latestLoginIp; /** 最新登录地点 */ - @Excel(name = "最新登录地点") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @ExcelProperty({"人员信息", "系统信息", "最新登录地点"}) private String latestLoginAddress; /** 最新登录时间 */ - @Excel(name = "最新登录时间", format = "yyyy-MM-dd HH:mm:ss") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @DateTimeFormat("yyyy-MM-dd HH:mm:ss") + @ExcelProperty({"人员信息", "系统信息", "最新登录时间"}) private Date latestLoginTime; /** 最新登录设备 */ - @Excel(name = "最新登录设备") + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @ExcelProperty({"人员信息", "系统信息", "最新登录设备"}) private String latestLoginDevice; - /** 用户状态 */ - @Excel(name = "用户状态", replace = { "正常_ENABLE", "停用_DISABLED" }) + /** 人员状态 */ + @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 42) + @ExcelProperty({"人员信息", "系统信息", "人员状态"}) private String userStatus; } diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/BizUserService.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/BizUserService.java index 45ca085d..e0ccd324 100644 --- a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/BizUserService.java +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/BizUserService.java @@ -13,6 +13,7 @@ package vip.xiaonuo.biz.modular.user.service; import cn.hutool.core.lang.tree.Tree; +import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import org.springframework.web.multipart.MultipartFile; @@ -122,22 +123,38 @@ public interface BizUserService extends IService { **/ void grantRole(BizUserGrantRoleParam bizUserGrantRoleParam); + /** + * 下载用户导入模板 + * + * @author xuyuxiang + * @date 2022/8/8 13:16 + **/ + void downloadImportUserTemplate(HttpServletResponse response) throws IOException; + /** * 人员导入 * * @author xuyuxiang * @date 2022/8/8 13:16 **/ - void importUser(MultipartFile file); + JSONObject importUser(MultipartFile file); /** - * 人员导出 + * 用户导出 * * @author xuyuxiang * @date 2022/8/8 13:16 **/ void exportUser(BizUserExportParam bizUserExportParam, HttpServletResponse response) throws IOException; + /** + * 导出用户个人信息 + * + * @author xuyuxiang + * @date 2022/8/8 13:16 + **/ + void exportUserInfo(BizUserIdParam bizUserIdParam, HttpServletResponse response) throws IOException; + /* ====人员部分所需要用到的选择器==== */ /** diff --git a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/impl/BizUserServiceImpl.java b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/impl/BizUserServiceImpl.java index cc21c6a8..0e4e5818 100644 --- a/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/impl/BizUserServiceImpl.java +++ b/snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/impl/BizUserServiceImpl.java @@ -12,28 +12,46 @@ */ package vip.xiaonuo.biz.modular.user.service.impl; -import cn.afterturn.easypoi.excel.ExcelExportUtil; -import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.cache.manager.POICacheManager; +import cn.afterturn.easypoi.entity.ImageEntity; +import cn.afterturn.easypoi.word.WordExportUtil; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollStreamUtil; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.img.ImgUtil; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.TreeNode; import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.PhoneUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.apache.poi.ss.usermodel.Workbook; +import com.fhs.trans.service.impl.TransService; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -48,10 +66,10 @@ import vip.xiaonuo.biz.modular.user.entity.BizUser; import vip.xiaonuo.biz.modular.user.enums.BizUserStatusEnum; import vip.xiaonuo.biz.modular.user.mapper.BizUserMapper; import vip.xiaonuo.biz.modular.user.param.*; -import vip.xiaonuo.biz.modular.user.result.BizUserExportResult; import vip.xiaonuo.biz.modular.user.result.BizUserRoleResult; import vip.xiaonuo.biz.modular.user.service.BizUserService; import vip.xiaonuo.common.enums.CommonSortOrderEnum; +import vip.xiaonuo.common.excel.CommonExcelCustomMergeStrategy; import vip.xiaonuo.common.exception.CommonException; import vip.xiaonuo.common.listener.CommonDataChangeEventCenter; import vip.xiaonuo.common.page.CommonPageRequest; @@ -59,13 +77,17 @@ import vip.xiaonuo.common.util.*; import vip.xiaonuo.dev.api.DevConfigApi; import vip.xiaonuo.sys.api.SysRoleApi; import vip.xiaonuo.sys.api.SysUserApi; +import vip.xiaonuo.sys.modular.user.result.BizUserExportResult; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -80,6 +102,9 @@ public class BizUserServiceImpl extends ServiceImpl impl private static final String SNOWY_SYS_DEFAULT_PASSWORD_KEY = "SNOWY_SYS_DEFAULT_PASSWORD"; + @Resource + private TransService transService; + @Resource private DevConfigApi devConfigApi; @@ -188,7 +213,7 @@ public class BizUserServiceImpl extends ServiceImpl impl boolean updateSuperAdminAccount = bizUser.getAccount().equals(BizBuildInEnum.BUILD_IN_USER_ACCOUNT.getValue()) && !bizUserEditParam.getAccount().equals(BizBuildInEnum.BUILD_IN_USER_ACCOUNT.getValue()); if(updateSuperAdminAccount) { - throw new CommonException("不可修改系统内置超管用户账号"); + throw new CommonException("不可修改系统内置超管人员账号"); } BeanUtil.copyProperties(bizUserEditParam, bizUser); this.updateById(bizUser); @@ -244,7 +269,7 @@ public class BizUserServiceImpl extends ServiceImpl impl boolean containsSuperAdminAccount = this.listByIds(bizUserIdList).stream().map(BizUser::getAccount) .collect(Collectors.toSet()).contains(BizBuildInEnum.BUILD_IN_USER_ACCOUNT.getValue()); if(containsSuperAdminAccount) { - throw new CommonException("不可删除系统内置超管用户"); + throw new CommonException("不可删除系统内置超管人员"); } // 获取这些人员的的机构id集合 Set userOrgIdList = this.listByIds(bizUserIdList).stream().map(BizUser::getOrgId).collect(Collectors.toSet()); @@ -264,19 +289,19 @@ public class BizUserServiceImpl extends ServiceImpl impl this.update(new LambdaUpdateWrapper().in(BizUser::getDirectorId, bizUserIdList).set(BizUser::getDirectorId, null)); // 清除【将这些人员作为兼任岗位的主管】的信息 - this.list(new LambdaQueryWrapper() .isNotNull(BizUser::getPositionJson)).forEach(sysUser -> { - List handledJsonObjectList = JSONUtil.toList(JSONUtil.parseArray(sysUser.getPositionJson()), + this.list(new LambdaQueryWrapper() .isNotNull(BizUser::getPositionJson)).forEach(bizUser -> { + List handledJsonObjectList = JSONUtil.toList(JSONUtil.parseArray(bizUser.getPositionJson()), JSONObject.class).stream().peek(jsonObject -> { String directorId = jsonObject.getStr("directorId"); if (ObjectUtil.isNotEmpty(directorId) && bizUserIdList.contains(directorId)) { jsonObject.remove("directorId"); } }).collect(Collectors.toList()); - this.update(new LambdaUpdateWrapper().eq(BizUser::getId, sysUser.getId()) + this.update(new LambdaUpdateWrapper().eq(BizUser::getId, bizUser.getId()) .set(BizUser::getPositionJson, JSONUtil.toJsonStr(handledJsonObjectList))); }); - // 清除【将这些用户作为主管】的机构的主管信息 + // 清除【将这些人员作为主管】的机构的主管信息 bizOrgService.update(new LambdaUpdateWrapper().in(BizOrg::getDirectorId, bizUserIdList).set(BizOrg::getDirectorId, null)); // 执行删除 @@ -374,8 +399,176 @@ public class BizUserServiceImpl extends ServiceImpl impl } @Override - public void importUser(MultipartFile file) { - // TODO 待完善 + public void downloadImportUserTemplate(HttpServletResponse response) throws IOException { + try { + InputStream inputStream = POICacheManager.getFile("userImportTemplate.xlsx"); + byte[] bytes = IoUtil.readBytes(inputStream); + CommonDownloadUtil.download("SNOWY2.0系统B端人员导入模板.xlsx", bytes, response); + } catch (Exception e) { + e.printStackTrace(); + CommonResponseUtil.renderError(response, "导出失败"); + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public JSONObject importUser(MultipartFile file) { + try { + int successCount = 0; + int errorCount = 0; + JSONArray errorDetail = JSONUtil.createArray(); + // 创建临时文件 + File tempFile = FileUtil.writeBytes(file.getBytes(), FileUtil.file(FileUtil.getTmpDir() + + FileUtil.FILE_SEPARATOR + "userImportTemplate.xlsx")); + // 读取excel + List bizUserImportParamList = EasyExcel.read(tempFile).head(BizUserImportParam.class).sheet() + .headRowNumber(2).doReadSync(); + List allUserList = this.list(); + for (int i = 0; i < bizUserImportParamList.size(); i++) { + JSONObject jsonObject = this.doImport(allUserList, bizUserImportParamList.get(i), i); + if(jsonObject.getBool("success")) { + successCount += 1; + } else{ + errorCount += 1; + errorDetail.add(jsonObject); + } + } + return JSONUtil.createObj() + .set("totalCount", bizUserImportParamList.size()) + .set("successCount", successCount) + .set("errorCount", errorCount) + .set("errorDetail", errorDetail); + } catch (Exception e) { + e.printStackTrace(); + throw new CommonException("文件导入失败"); + } + } + + /** + * 执行导入 + * + * @author xuyuxiang + * @date 2023/3/7 13:22 + **/ + public JSONObject doImport(List allUserList, BizUserImportParam bizUserImportParam, int i) { + String account = bizUserImportParam.getAccount(); + String name = bizUserImportParam.getName(); + String orgFullName = bizUserImportParam.getOrgName(); + String positionFullName = bizUserImportParam.getPositionName(); + // 校验必填参数 + if(ObjectUtil.hasEmpty(account, name, orgFullName, positionFullName)) { + return JSONUtil.createObj().set("index", i + 1).set("success", false).set("msg", "必填字段存在空值"); + } else { + try { + // 机构名称 + String orgName = CollectionUtil.getLast(StrUtil.split(orgFullName, StrUtil.DASHED)); + // 职位名称 + String positionName = CollectionUtil.getLast(StrUtil.split(positionFullName, StrUtil.DASHED)); + // 机构id + String orgId = bizOrgService.getOrgIdByOrgFullNameWithCreate(orgFullName); + // 职位id + String positionId = bizPositionService.getPositionIdByPositionNameWithCreate(orgId, positionName); + + // 查找账号对应索引 + int index = CollStreamUtil.toList(allUserList, BizUser::getAccount).indexOf(account); + BizUser bizUser = new BizUser(); + boolean isAdd = false; + if(index == -1) { + isAdd = true; + } else { + bizUser = allUserList.get(index); + } + + // 获取手机号和邮箱 + String phone = bizUserImportParam.getPhone(); + String email = bizUserImportParam.getEmail(); + + // 判断手机号是否跟系统现有的重复 + if(ObjectUtil.isNotEmpty(phone)) { + if(isAdd) { + boolean repeatPhone = allUserList.stream().anyMatch(tempBizUser -> ObjectUtil + .isNotEmpty(tempBizUser.getPhone()) && tempBizUser.getPhone().equals(phone)); + if(repeatPhone) { + // 新增人员手机号重复则不导入该手机号 + bizUserImportParam.setPhone(null); + } + } else { + String finalExistUserId = bizUser.getId(); + boolean repeatPhone = allUserList.stream().anyMatch(tempBizUser -> ObjectUtil + .isNotEmpty(tempBizUser.getPhone()) && tempBizUser.getPhone() + .equals(phone) && !tempBizUser.getId().equals(finalExistUserId)); + if(repeatPhone) { + // 更新人员手机号重复则使用原手机号 + bizUser.setPhone(bizUser.getPhone()); + } + } + } + // 判断邮箱是否跟系统现有的重复 + if(ObjectUtil.isNotEmpty(email)) { + if(isAdd) { + boolean repeatEmail = allUserList.stream().anyMatch(tempBizUser -> ObjectUtil + .isNotEmpty(tempBizUser.getEmail()) && tempBizUser.getEmail().equals(email)); + if(repeatEmail) { + // 新增邮箱重复则不导入该邮箱 + bizUserImportParam.setEmail(null); + } + } else { + String finalExistUserId = bizUser.getId(); + boolean repeatEmail = allUserList.stream().anyMatch(tempBizUser -> ObjectUtil + .isNotEmpty(tempBizUser.getEmail()) && tempBizUser.getEmail() + .equals(email) && !tempBizUser.getId().equals(finalExistUserId)); + if(repeatEmail) { + // 更新人员手机号重复则使用原邮箱 + bizUser.setEmail(bizUser.getEmail()); + } + } + } + // 拷贝属性 + BeanUtil.copyProperties(bizUserImportParam, bizUser); + + // 设置机构id和职位id + bizUser.setOrgId(orgId); + bizUser.setPositionId(positionId); + + // 设置机构名称和职位名称(暂时无作用) + bizUser.setOrgName(orgName); + bizUser.setPositionName(positionName); + + // 发布事件 + if(isAdd) { + // 设置id + bizUser.setId(IdWorker.getIdStr()); + // 设置默认头像 + bizUser.setAvatar(CommonAvatarUtil.generateImg(bizUser.getName())); + // 设置默认密码 + bizUser.setPassword(CommonCryptogramUtil.doHashValue(devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_PASSWORD_KEY))); + // 设置排序码 + bizUser.setSortCode(99); + // 设置状态 + bizUser.setUserStatus(BizUserStatusEnum.ENABLE.getValue()); + // 发布增加事件 + CommonDataChangeEventCenter.doAddWithData(BizDataTypeEnum.USER.getValue(), JSONUtil.createArray().put(bizUser)); + // 更新全部人员 + allUserList.add(bizUser); + } else { + // 发布更新事件 + CommonDataChangeEventCenter.doUpdateWithData(BizDataTypeEnum.USER.getValue(), JSONUtil.createArray().put(bizUser)); + // 删除指定索引元素 + allUserList.remove(index); + // 插入指定索引元素 + allUserList.add(index, bizUser); + } + + // 保存或更新 + this.saveOrUpdate(bizUser); + + // 返回成功 + return JSONUtil.createObj().set("success", true); + } catch (Exception e) { + e.printStackTrace(); + return JSONUtil.createObj().set("success", false).set("index", i + 1).set("msg", "数据导入异常"); + } + } } @Override @@ -383,27 +576,124 @@ public class BizUserServiceImpl extends ServiceImpl impl File tempFile = null; try { QueryWrapper queryWrapper = new QueryWrapper<>(); - if(ObjectUtil.isNotEmpty(bizUserExportParam.getSearchKey())) { - queryWrapper.lambda().like(BizUser::getAccount, bizUserExportParam.getSearchKey()).or() - .like(BizUser::getName, bizUserExportParam.getSearchKey()); - } - if(ObjectUtil.isNotEmpty(bizUserExportParam.getUserStatus())) { - queryWrapper.lambda().eq(BizUser::getUserStatus, bizUserExportParam.getUserStatus()); - } - String fileName = "SNOWY2.0系统B端人员信息清单"; - List bizUserExportResultList =this.list(queryWrapper).stream() - .map(bizUser -> BeanUtil.copyProperties(bizUser, BizUserExportResult.class)).peek(bizUserExportResult -> { - if (ObjectUtil.isNotEmpty(bizUserExportResult.getAvatar())) { - bizUserExportResult.setAvatarByte(ImgUtil.toBytes(ImgUtil.toImage(StrUtil - .split(bizUserExportResult.getAvatar(), StrUtil.COMMA).get(1)), ImgUtil.IMAGE_TYPE_PNG)); + if(ObjectUtil.isNotEmpty(bizUserExportParam.getUserIdList())) { + queryWrapper.lambda().in(BizUser::getId, bizUserExportParam.getUserIdList()); + } else { + if (ObjectUtil.isNotEmpty(bizUserExportParam.getSearchKey())) { + queryWrapper.lambda().like(BizUser::getAccount, bizUserExportParam.getSearchKey()) + .or().like(BizUser::getName, bizUserExportParam.getSearchKey()) + .or().like(BizUser::getPhone, bizUserExportParam.getSearchKey()); } - }).collect(Collectors.toList()); - Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(fileName, "B端人员"), - BizUserExportResult.class, bizUserExportResultList); - tempFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName + ".xls"); - BufferedOutputStream outputStream = FileUtil.getOutputStream(tempFile); - workbook.write(outputStream); - outputStream.close(); + if (ObjectUtil.isNotEmpty(bizUserExportParam.getUserStatus())) { + queryWrapper.lambda().eq(BizUser::getUserStatus, bizUserExportParam.getUserStatus()); + } + } + String fileName = "SNOWY2.0系统B端人员信息清单.xlsx"; + List bizUserList = this.list(queryWrapper); + if(ObjectUtil.isEmpty(bizUserList)) { + throw new CommonException("无数据可导出"); + } + transService.transBatch(bizUserList); + bizUserList = CollectionUtil.sort(bizUserList, Comparator.comparing(BizUser::getOrgId)); + List bizUserExportResultList = bizUserList.stream() + .map(bizUser -> { + BizUserExportResult bizUserExportResult = new BizUserExportResult(); + BeanUtil.copyProperties(bizUser, bizUserExportResult); + bizUserExportResult.setGroupName(ObjectUtil.isNotEmpty(bizUserExportResult.getOrgName())? + bizUserExportResult.getOrgName():"无组织"); + // 状态枚举转为文字 + bizUserExportResult.setUserStatus(bizUserExportResult.getUserStatus() + .equalsIgnoreCase(BizUserStatusEnum.ENABLE.getValue())?"正常":"停用"); + // 将base64转为byte数组 + if (ObjectUtil.isNotEmpty(bizUser.getAvatar())) { + bizUserExportResult.setAvatar(ImgUtil.toBytes(ImgUtil.toImage(StrUtil + .split(bizUser.getAvatar(), StrUtil.COMMA).get(1)), ImgUtil.IMAGE_TYPE_PNG)); + } + return bizUserExportResult; + }).collect(Collectors.toList()); + // 创建临时文件 + tempFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName); + + // 头的策略 + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontHeightInPoints((short) 14); + headWriteCellStyle.setWriteFont(headWriteFont); + // 水平垂直居中 + headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); + headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + // 内容的策略 + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定 + contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + // 内容背景白色 + contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); + WriteFont contentWriteFont = new WriteFont(); + + // 内容字体大小 + contentWriteFont.setFontHeightInPoints((short) 12); + contentWriteCellStyle.setWriteFont(contentWriteFont); + + //设置边框样式,细实线 + contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); + contentWriteCellStyle.setBorderTop(BorderStyle.THIN); + contentWriteCellStyle.setBorderRight(BorderStyle.THIN); + contentWriteCellStyle.setBorderBottom(BorderStyle.THIN); + + // 水平垂直居中 + contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT); + contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 + HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, + contentWriteCellStyle); + + // 写excel + EasyExcel.write(tempFile.getPath(), BizUserExportResult.class) + // 自定义样式 + .registerWriteHandler(horizontalCellStyleStrategy) + // 自动列宽 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 机构分组合并单元格 + .registerWriteHandler(new CommonExcelCustomMergeStrategy(bizUserExportResultList.stream().map(BizUserExportResult::getGroupName) + .collect(Collectors.toList()), 0)) + // 设置第一行字体 + .registerWriteHandler(new CellWriteHandler() { + @Override + public void afterCellDispose(CellWriteHandlerContext context) { + WriteCellData cellData = context.getFirstCellData(); + WriteCellStyle writeCellStyle = cellData.getOrCreateStyle(); + Integer rowIndex = context.getRowIndex(); + if(rowIndex == 0) { + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontName("宋体"); + headWriteFont.setBold(true); + headWriteFont.setFontHeightInPoints((short) 16); + writeCellStyle.setWriteFont(headWriteFont); + } + } + }) + // 设置表头行高 + .registerWriteHandler(new AbstractRowHeightStyleStrategy() { + @Override + protected void setHeadColumnHeight(Row row, int relativeRowIndex) { + if(relativeRowIndex == 0) { + // 表头第一行 + row.setHeightInPoints(34); + } else { + // 表头其他行 + row.setHeightInPoints(30); + } + } + @Override + protected void setContentColumnHeight(Row row, int relativeRowIndex) { + // 内容行 + row.setHeightInPoints(20); + } + }) + .sheet("人员信息") + .doWrite(bizUserExportResultList); CommonDownloadUtil.download(tempFile, response); } catch (Exception e) { e.printStackTrace(); @@ -413,6 +703,66 @@ public class BizUserServiceImpl extends ServiceImpl impl } } + @Override + public void exportUserInfo(BizUserIdParam bizUserIdParam, HttpServletResponse response) throws IOException { + File destTemplateFile = null; + File resultFile = null; + try { + BizUser bizUser = this.queryEntity(bizUserIdParam.getId()); + transService.transOne(bizUser); + // 读取模板流 + InputStream inputStream = POICacheManager.getFile("userExportTemplate.docx"); + // 创建一个临时模板 + destTemplateFile = FileUtil.writeFromStream(inputStream, FileUtil.file(FileUtil.getTmpDir() + + File.separator + "userExportTemplate.docx")); + // 构造填充的参数 + Map map = BeanUtil.beanToMap(bizUser); + String avatarBase64; + if(ObjectUtil.isNotEmpty(bizUser.getAvatar())) { + avatarBase64 = bizUser.getAvatar(); + } else { + avatarBase64 = CommonAvatarUtil.generateImg(bizUser.getName()); + } + // 头像 + ImageEntity imageEntity = new ImageEntity(ImgUtil.toBytes(ImgUtil.toImage(StrUtil + .split(avatarBase64, StrUtil.COMMA).get(1)), ImgUtil.IMAGE_TYPE_PNG), 120, 160); + map.put("avatar", imageEntity); + if(ObjectUtil.isNotEmpty(bizUser.getBirthday())) { + try { + // 年龄 + long age = cn.hutool.core.date.DateUtil.betweenYear(cn.hutool.core.date.DateUtil.parseDate(bizUser.getBirthday()), DateTime.now(), true); + if(age != 0) { + map.put("age", age + "岁"); + } + } catch (Exception ignored) { + } + } + // 导出时间 + map.put("exportDateTime", DateUtil.format(DateTime.now(), DatePattern.CHINESE_DATE_PATTERN)); + // 生成doc + XWPFDocument doc = WordExportUtil.exportWord07(destTemplateFile.getAbsolutePath(), map); + // 生成临时导出文件 + resultFile = FileUtil.file(FileUtil.getTmpDir() + File.separator + "SNOWY2.0系统B端人员信息_" + bizUser.getName() + ".docx"); + // 写入 + BufferedOutputStream outputStream = FileUtil.getOutputStream(resultFile); + doc.write(outputStream); + outputStream.close(); + // 下载 + CommonDownloadUtil.download(resultFile, response); + } catch (Exception e) { + e.printStackTrace(); + CommonResponseUtil.renderError(response, "导出失败"); + } finally { + // 删除临时文件 + if(ObjectUtil.isNotEmpty(destTemplateFile)) { + FileUtil.del(destTemplateFile); + } + if(ObjectUtil.isNotEmpty(resultFile)) { + FileUtil.del(resultFile); + } + } + } + @Override public BizUser queryEntity(String id) { BizUser bizUser = this.getById(id); diff --git a/snowy-plugin/snowy-plugin-biz/src/main/resources/userExportTemplate.docx b/snowy-plugin/snowy-plugin-biz/src/main/resources/userExportTemplate.docx new file mode 100644 index 00000000..95ab65f8 Binary files /dev/null and b/snowy-plugin/snowy-plugin-biz/src/main/resources/userExportTemplate.docx differ diff --git a/snowy-plugin/snowy-plugin-biz/src/main/resources/userImportTemplate.xlsx b/snowy-plugin/snowy-plugin-biz/src/main/resources/userImportTemplate.xlsx new file mode 100644 index 00000000..b4a787e1 Binary files /dev/null and b/snowy-plugin/snowy-plugin-biz/src/main/resources/userImportTemplate.xlsx differ diff --git a/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/org/service/SysOrgService.java b/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/org/service/SysOrgService.java index a6217572..0bc20bc9 100644 --- a/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/org/service/SysOrgService.java +++ b/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/org/service/SysOrgService.java @@ -94,7 +94,7 @@ public interface SysOrgService extends IService { List getCachedAllOrgList(); /** - * 根据机构全名称获取机构id,有则返回,无则创建 + * 根据组织全名称获取组织id,有则返回,无则创建 * * @author xuyuxiang * @date 2023/3/7 15:44 diff --git a/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/org/service/impl/SysOrgServiceImpl.java b/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/org/service/impl/SysOrgServiceImpl.java index 96e9a974..e4e0e198 100644 --- a/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/org/service/impl/SysOrgServiceImpl.java +++ b/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/org/service/impl/SysOrgServiceImpl.java @@ -253,13 +253,13 @@ public class SysOrgServiceImpl extends ServiceImpl impleme } /** - * 执行创建机构 + * 执行创建组织 * * @author xuyuxiang * @date 2023/3/8 9:38 **/ public String doCreateOrg(String parentId, String orgName, List cachedAllOrgList) { - //创建该机构 + //创建该组织 SysOrg sysOrg = new SysOrg(); sysOrg.setName(orgName); sysOrg.setCode(RandomUtil.randomString(10)); @@ -269,7 +269,7 @@ public class SysOrgServiceImpl extends ServiceImpl impleme this.save(sysOrg); // 发布增加事件 CommonDataChangeEventCenter.doAddWithData(SysDataTypeEnum.ORG.getValue(), JSONUtil.createArray().put(sysOrg)); - // 将该机构加入缓存 + // 将该组织加入缓存 cachedAllOrgList.add(sysOrg); // 更新缓存 commonCacheOperator.put(ORG_CACHE_ALL_KEY, cachedAllOrgList); @@ -313,7 +313,7 @@ public class SysOrgServiceImpl extends ServiceImpl impleme return sysUserService.getCachedAllUserSelectorList(); } else { if(ObjectUtil.isNotEmpty(sysOrgSelectorUserParam.getOrgId())) { - // 如果机构id不为空,则查询该机构所在顶级机构下的所有人 + // 如果组织id不为空,则查询该组织所在顶级组织下的所有人 List parentAndChildOrgIdList = CollStreamUtil.toList(this.getParentAndChildListById(this .getCachedAllOrgList(), sysOrgSelectorUserParam.getOrgId(), true), SysOrg::getId); if (ObjectUtil.isNotEmpty(parentAndChildOrgIdList)) { diff --git a/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/position/service/SysPositionService.java b/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/position/service/SysPositionService.java index 815cd249..c3d5f4cc 100644 --- a/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/position/service/SysPositionService.java +++ b/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/position/service/SysPositionService.java @@ -85,7 +85,7 @@ public interface SysPositionService extends IService { SysPosition getById(List originDataList, String id); /** - * 根据机构id和职位名称获取职位id,有则返回,无则创建 + * 根据组织id和职位名称获取职位id,有则返回,无则创建 * * @author xuyuxiang * @date 2022/8/15 14:55