From 4f71fd1006419d3b8d5c6ec416a07016dbd1ae92 Mon Sep 17 00:00:00 2001 From: xuyuxiang Date: Mon, 13 Mar 2023 16:10:41 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=9B=B4=E6=96=B0=E3=80=91=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=8A=A0=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E7=AD=89=E5=8A=9F=E8=83=BD=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/core/config/AuthConfigure.java | 1 - .../modular/org/service/BizOrgService.java | 16 + .../org/service/impl/BizOrgServiceImpl.java | 84 +++- .../position/service/BizPositionService.java | 8 + .../service/impl/BizPositionServiceImpl.java | 5 + .../user/controller/BizUserController.java | 55 ++- .../user/param/BizUserExportParam.java | 12 +- .../user/param/BizUserImportParam.java | 120 +++++ .../user/result/BizUserExportResult.java | 148 ++++--- .../modular/user/service/BizUserService.java | 21 +- .../user/service/impl/BizUserServiceImpl.java | 414 ++++++++++++++++-- .../main/resources/userExportTemplate.docx | Bin 0 -> 16840 bytes .../main/resources/userImportTemplate.xlsx | Bin 0 -> 11200 bytes .../modular/org/service/SysOrgService.java | 2 +- .../org/service/impl/SysOrgServiceImpl.java | 8 +- .../position/service/SysPositionService.java | 2 +- 16 files changed, 788 insertions(+), 108 deletions(-) create mode 100644 snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/BizUserImportParam.java create mode 100644 snowy-plugin/snowy-plugin-biz/src/main/resources/userExportTemplate.docx create mode 100644 snowy-plugin/snowy-plugin-biz/src/main/resources/userImportTemplate.xlsx 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 0000000000000000000000000000000000000000..95ab65f80a58621e02d6906d1f481e21015598cb GIT binary patch literal 16840 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 literal 0 HcmV?d00001 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