Merge branch 'dev-klw' into test
* dev-klw: 清理与ztcloud中重复的代码,改为 jar 包方式引用 ztcloud # Conflicts: # zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/sms/dto/send/SmsSendSingleToUserReqDTO.java # zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/sms/SmsCallbackController.java # zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/mq/message/sms/SmsSendMessage.java
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>zt-module-system</artifactId>
|
||||
<artifactId>zt-module-system-dsc</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
@@ -24,6 +24,13 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.zt.plat.module.system.api.dept;
|
||||
|
||||
import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.CompanyDeptInfo;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.framework.datapermission.core.annotation.CompanyDataPermissionIgnore;
|
||||
import com.zt.plat.framework.datapermission.core.annotation.DeptDataPermissionIgnore;
|
||||
import com.zt.plat.module.system.api.dept.dto.CompanyDeptInfoRespDTO;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptDetailRespDTO;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptListReqDTO;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptRespDTO;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptSaveReqDTO;
|
||||
import com.zt.plat.module.system.api.dept.dto.DeptSimpleRespDTO;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
|
||||
import com.zt.plat.module.system.service.dept.DeptService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController // 提供 RESTful API 接口,给 Feign 调用
|
||||
@Validated
|
||||
public class DeptApiImpl implements DeptApi {
|
||||
|
||||
@Resource
|
||||
private DeptService deptService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> createDept(DeptSaveReqDTO createReqVO) {
|
||||
DeptSaveReqVO reqVO = BeanUtils.toBean(createReqVO, DeptSaveReqVO.class);
|
||||
Long deptId = deptService.createDept(reqVO);
|
||||
return success(deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateDept(DeptSaveReqDTO updateReqVO) {
|
||||
DeptSaveReqVO reqVO = BeanUtils.toBean(updateReqVO, DeptSaveReqVO.class);
|
||||
deptService.updateDept(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> deleteDept(Long id) {
|
||||
deptService.deleteDept(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptDetailRespDTO>> getDeptList(DeptListReqDTO reqVO) {
|
||||
DeptListReqVO listReqVO = BeanUtils.toBean(reqVO, DeptListReqVO.class);
|
||||
List<DeptDO> depts = deptService.getDeptList(listReqVO);
|
||||
return success(BeanUtils.toBean(depts, DeptDetailRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptSimpleRespDTO>> getSimpleDeptList() {
|
||||
List<DeptDO> depts = deptService.getDeptList(
|
||||
new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
return success(BeanUtils.toBean(depts, DeptSimpleRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptSimpleRespDTO>> getSimpleCompanyList() {
|
||||
List<DeptDO> companies = deptService.getUserCompanyList();
|
||||
return success(BeanUtils.toBean(companies, DeptSimpleRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptSimpleRespDTO>> getAllCompanyList() {
|
||||
List<DeptDO> allCompanies = deptService.getAllCompanyList();
|
||||
// 还需要把用户归属的公司加上
|
||||
List<DeptDO> userCompanyList = deptService.getUserCompanyList();
|
||||
allCompanies.addAll(userCompanyList);
|
||||
// 去重
|
||||
List<DeptDO> companies = allCompanies.stream().distinct().toList();
|
||||
return success(BeanUtils.toBean(companies, DeptSimpleRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@CompanyDataPermissionIgnore
|
||||
@DeptDataPermissionIgnore
|
||||
public CommonResult<DeptRespDTO> getDept(Long id) {
|
||||
DeptDO dept = deptService.getDept(id);
|
||||
return success(BeanUtils.toBean(dept, DeptRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptRespDTO>> getDeptList(Collection<Long> ids) {
|
||||
List<DeptDO> depts = deptService.getDeptList(ids);
|
||||
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> validateDeptList(Collection<Long> ids) {
|
||||
deptService.validateDeptList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptRespDTO>> getChildDeptList(Long id) {
|
||||
List<DeptDO> depts = deptService.getChildDeptList(id);
|
||||
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Set<CompanyDeptInfoRespDTO>> getCompanyDeptInfoListByUserId(Long userId) {
|
||||
Set<CompanyDeptInfo> companyDeptInfos = deptService.getCompanyDeptInfoListByUserId(userId);
|
||||
return success(BeanUtils.toBean(companyDeptInfos, CompanyDeptInfoRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DeptRespDTO>> upFindCompanyNode(Long deptId) {
|
||||
List<DeptDO> depts = deptService.upFindCompanyNode(deptId);
|
||||
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
|
||||
}
|
||||
|
||||
// ========== 数据同步专用接口 ==========
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> syncDept(DeptSaveReqDTO syncReqDTO) {
|
||||
DeptSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, DeptSaveReqVO.class);
|
||||
deptService.syncDept(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package com.zt.plat.module.system.controller.admin.portal;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.framework.excel.core.util.ExcelUtils;
|
||||
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
|
||||
import com.zt.plat.module.infra.api.file.FileApi;
|
||||
import com.zt.plat.module.infra.api.file.dto.FileRespDTO;
|
||||
import com.zt.plat.module.system.controller.admin.portal.vo.PortalPageReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.portal.vo.PortalRespVO;
|
||||
import com.zt.plat.module.system.controller.admin.portal.vo.PortalSaveReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.portal.PortalDO;
|
||||
import com.zt.plat.module.system.service.portal.PortalService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
import static com.zt.plat.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
/**
|
||||
* 门户网站 Controller
|
||||
*
|
||||
* @author 中铜数字供应链平台
|
||||
*/
|
||||
@Tag(name = "管理后台 - 门户网站")
|
||||
@RestController
|
||||
@RequestMapping("/system/portal")
|
||||
@Validated
|
||||
public class PortalController {
|
||||
|
||||
@Resource
|
||||
private PortalService portalService;
|
||||
|
||||
@Resource
|
||||
private FileApi fileApi;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建门户网站")
|
||||
@PreAuthorize("@ss.hasPermission('system:portal:create')")
|
||||
public CommonResult<Long> createPortal(@Valid @RequestBody PortalSaveReqVO createReqVO) {
|
||||
return success(portalService.createPortal(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新门户网站")
|
||||
@PreAuthorize("@ss.hasPermission('system:portal:update')")
|
||||
public CommonResult<Boolean> updatePortal(@Valid @RequestBody PortalSaveReqVO updateReqVO) {
|
||||
portalService.updatePortal(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除门户网站")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:portal:delete')")
|
||||
public CommonResult<Boolean> deletePortal(@RequestParam("id") Long id) {
|
||||
portalService.deletePortal(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得门户网站")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:portal:query')")
|
||||
public CommonResult<PortalRespVO> getPortal(@RequestParam("id") Long id) {
|
||||
PortalDO portal = portalService.getPortal(id);
|
||||
return success(BeanUtils.toBean(portal, PortalRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得门户网站分页")
|
||||
@PreAuthorize("@ss.hasPermission('system:portal:query')")
|
||||
public CommonResult<PageResult<PortalRespVO>> getPortalPage(@Valid PortalPageReqVO pageReqVO) {
|
||||
PageResult<PortalDO> pageResult = portalService.getPortalPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, PortalRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出门户网站 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:portal:export')")
|
||||
public void exportPortalExcel(@Valid PortalPageReqVO pageReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
List<PortalDO> list = portalService.getPortalPage(pageReqVO).getList();
|
||||
// 导出 Excel
|
||||
List<PortalRespVO> data = BeanUtils.toBean(list, PortalRespVO.class);
|
||||
ExcelUtils.write(response, "门户网站.xls", "数据", PortalRespVO.class, data);
|
||||
}
|
||||
/**
|
||||
* 获取当前用户可访问的门户列表
|
||||
* 此接口无需权限验证,因为已经通过登录验证,
|
||||
* 返回的门户列表已经根据用户权限进行了过滤
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取我的门户列表")
|
||||
@PermitAll
|
||||
@TenantIgnore
|
||||
public CommonResult<List<PortalRespVO>> getMyPortalList() {
|
||||
Long userId = null;
|
||||
try {
|
||||
userId = getLoginUserId();
|
||||
} catch (Exception ignored) {
|
||||
// 未登录时获取公开门户
|
||||
}
|
||||
List<PortalDO> portals = (userId == null)
|
||||
? portalService.getPublicPortalList()
|
||||
: portalService.getPortalListByUserId(userId);
|
||||
return success(BeanUtils.toBean(portals, PortalRespVO.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 匿名获取公开门户的图标文件信息
|
||||
* 仅允许访问门户中已配置的图标文件
|
||||
*/
|
||||
@GetMapping("/public-icon-files")
|
||||
@Operation(summary = "获取公开门户图标文件信息")
|
||||
@PermitAll
|
||||
@TenantIgnore
|
||||
public CommonResult<List<FileRespDTO>> getPublicPortalIconFiles(@RequestParam("fileIds") List<Long> fileIds) {
|
||||
if (fileIds == null || fileIds.isEmpty()) {
|
||||
return success(java.util.Collections.emptyList());
|
||||
}
|
||||
|
||||
List<PortalDO> portals = portalService.getPublicPortalList();
|
||||
Set<Long> allowedFileIds = new HashSet<>();
|
||||
for (PortalDO portal : portals) {
|
||||
if (portal.getIconType() == null || portal.getIconType() != 2) {
|
||||
continue;
|
||||
}
|
||||
if (!StringUtils.hasText(portal.getIconFileId())) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
allowedFileIds.add(Long.parseLong(portal.getIconFileId()));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// ignore invalid fileId
|
||||
}
|
||||
}
|
||||
|
||||
List<FileRespDTO> result = new ArrayList<>();
|
||||
for (Long fileId : fileIds) {
|
||||
if (!allowedFileIds.contains(fileId)) {
|
||||
continue;
|
||||
}
|
||||
CommonResult<FileRespDTO> fileResult = fileApi.getFileInfo(fileId);
|
||||
if (fileResult != null && fileResult.isSuccess() && fileResult.getData() != null) {
|
||||
result.add(fileResult.getData());
|
||||
}
|
||||
}
|
||||
return success(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.impl;//package com.zt.plat.module.system.framework.sms.core.client.impl;
|
||||
//
|
||||
//import cn.hutool.core.codec.Base64;
|
||||
//import cn.hutool.core.lang.Assert;
|
||||
//import cn.hutool.core.util.StrUtil;
|
||||
//import cn.hutool.crypto.digest.DigestUtil;
|
||||
//import cn.hutool.json.JSONObject;
|
||||
//import cn.hutool.json.JSONUtil;
|
||||
//import com.zt.plat.framework.common.core.KeyValue;
|
||||
//import com.zt.plat.framework.common.util.http.HttpUtils;
|
||||
//import com.zt.plat.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||
//import com.zt.plat.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||
//import com.zt.plat.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||
//import com.zt.plat.module.system.framework.sms.core.property.SmsChannelProperties;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//
|
||||
//import java.util.Collections;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//
|
||||
///**
|
||||
// * 中国移动云MAS短信客户端实现类
|
||||
// *
|
||||
// * @author zt-team
|
||||
// * @since 2025-01-19
|
||||
// */
|
||||
//@Slf4j
|
||||
//public class CmccMasSmsClient extends AbstractSmsClient {
|
||||
//
|
||||
// private static final String URL = "https://112.35.10.201:28888/sms/submit";
|
||||
// private static final String RESPONSE_SUCCESS = "success";
|
||||
//
|
||||
// public CmccMasSmsClient(SmsChannelProperties properties) {
|
||||
// super(properties);
|
||||
// Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
|
||||
// Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
||||
// validateCmccMasConfig(properties);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 参数校验中国移动云MAS的配置
|
||||
// *
|
||||
// * 原因是:中国移动云MAS需要三个参数:ecName、apId、secretKey
|
||||
// *
|
||||
// * 解决方案:考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 ecName 和 apId 拼接到 apiKey 字段中,格式为 "ecName apId"。
|
||||
// * secretKey 存储在 apiSecret 字段中。
|
||||
// *
|
||||
// * @param properties 配置
|
||||
// */
|
||||
// private static void validateCmccMasConfig(SmsChannelProperties properties) {
|
||||
// String combineKey = properties.getApiKey();
|
||||
// Assert.notEmpty(combineKey, "apiKey 不能为空");
|
||||
// String[] keys = combineKey.trim().split(" ");
|
||||
// Assert.isTrue(keys.length == 2, "中国移动云MAS apiKey 配置格式错误,请配置为 [ecName apId]");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取 ecName(企业名称)
|
||||
// */
|
||||
// private String getEcName() {
|
||||
// return StrUtil.subBefore(properties.getApiKey(), " ", true);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取 apId(应用ID)
|
||||
// */
|
||||
// private String getApId() {
|
||||
// return StrUtil.subAfter(properties.getApiKey(), " ", true);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取 secretKey(密钥)
|
||||
// */
|
||||
// private String getSecretKey() {
|
||||
// return properties.getApiSecret();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 发送短信
|
||||
// *
|
||||
// * @param logId 日志ID
|
||||
// * @param mobile 手机号
|
||||
// * @param apiTemplateId 模板ID(本平台不使用模板,传入内容)
|
||||
// * @param templateParams 模板参数
|
||||
// * @return 发送结果
|
||||
// */
|
||||
// @Override
|
||||
// public SmsSendRespDTO sendSms(Long logId, String mobile, String apiTemplateId,
|
||||
// List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||
//
|
||||
// // 1. 构建短信内容
|
||||
// String content = buildContent(apiTemplateId, templateParams);
|
||||
//
|
||||
// // 2. 计算MAC校验值
|
||||
// String mac = calculateMac(mobile, content);
|
||||
//
|
||||
// // 3. 构建请求参数
|
||||
// JSONObject requestBody = new JSONObject();
|
||||
// requestBody.set("ecName", getEcName()); // 企业名称
|
||||
// requestBody.set("apId", getApId()); // 应用ID
|
||||
// requestBody.set("secretKey", getSecretKey()); // 密钥
|
||||
// requestBody.set("sign", properties.getSignature()); // 签名编码
|
||||
// requestBody.set("mobiles", mobile);
|
||||
// requestBody.set("content", content);
|
||||
// requestBody.set("addSerial", "");
|
||||
// requestBody.set("mac", mac);
|
||||
//
|
||||
// log.info("[sendSms][发送短信 {}]", JSONUtil.toJsonStr(requestBody));
|
||||
//
|
||||
// // 4. Base64编码请求体
|
||||
// String encodedBody = Base64.encode(requestBody.toString());
|
||||
// log.info("[sendSms][Base64编码后: {}]", encodedBody);
|
||||
//
|
||||
// // 5. 构建请求头(需要JWT Token)
|
||||
// Map<String, String> headers = new HashMap<>();
|
||||
// headers.put("Authorization", "Bearer " + getJwtToken());
|
||||
// headers.put("Content-Type", "text/plain");
|
||||
//
|
||||
// // 6. 发起请求
|
||||
// String responseBody = HttpUtils.post(URL, headers, encodedBody);
|
||||
// JSONObject response = JSONUtil.parseObj(responseBody);
|
||||
//
|
||||
// log.info("[sendSms][收到响应 - {}]", response);
|
||||
//
|
||||
// // 7. 解析响应
|
||||
// return new SmsSendRespDTO()
|
||||
// .setSuccess(response.getBool("success", false))
|
||||
// .setSerialNo(response.getStr("msgGroup"))
|
||||
// .setApiCode(response.getStr("rspcod"))
|
||||
// .setApiMsg(response.getStr("message", "未知错误"));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 解析短信接收状态回调
|
||||
// *
|
||||
// * @param text 回调文本
|
||||
// * @return 接收状态列表
|
||||
// */
|
||||
// @Override
|
||||
// public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable {
|
||||
// // TODO: 根据移动云MAS回调格式实现
|
||||
// log.warn("[parseSmsReceiveStatus][暂未实现短信状态回调解析]");
|
||||
// return Collections.emptyList();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 查询短信模板
|
||||
// *
|
||||
// * @param apiTemplateId 模板ID
|
||||
// * @return 模板信息
|
||||
// */
|
||||
// @Override
|
||||
// public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
|
||||
// // 移动云MAS不使用模板机制,直接发送内容
|
||||
// log.debug("[getSmsTemplate][中国移动云MAS不支持模板查询]");
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 计算MAC校验值
|
||||
// * 算法:MD5(ecName + apId + secretKey + mobiles + content + sign + addSerial)
|
||||
// *
|
||||
// * @param mobile 手机号
|
||||
// * @param content 短信内容
|
||||
// * @return MAC校验值
|
||||
// */
|
||||
// private String calculateMac(String mobile, String content) {
|
||||
// String rawString = getEcName() // ecName
|
||||
// + getApId() // apId
|
||||
// + getSecretKey() // secretKey
|
||||
// + mobile // mobiles
|
||||
// + content // content
|
||||
// + properties.getSignature() // sign
|
||||
// + ""; // addSerial
|
||||
//
|
||||
// String mac = DigestUtil.md5Hex(rawString).toLowerCase();
|
||||
// log.debug("[calculateMac][原始字符串长度: {}, MAC: {}]", rawString.length(), mac);
|
||||
// return mac;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 构建短信内容
|
||||
// *
|
||||
// * @param apiTemplateId 模板ID
|
||||
// * @param templateParams 模板参数
|
||||
// * @return 短信内容
|
||||
// */
|
||||
// private String buildContent(String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
|
||||
// // 简单实现:直接返回模板ID作为内容
|
||||
// // 实际使用时需要根据业务需求构建短信内容
|
||||
// if (templateParams == null || templateParams.isEmpty()) {
|
||||
// return apiTemplateId;
|
||||
// }
|
||||
//
|
||||
// // 替换模板参数,支持 {{key}} 格式
|
||||
// String content = apiTemplateId;
|
||||
// for (KeyValue<String, Object> param : templateParams) {
|
||||
// String placeholder = "{{" + param.getKey() + "}}";
|
||||
// String value = String.valueOf(param.getValue());
|
||||
// content = content.replace(placeholder, value);
|
||||
// }
|
||||
// return content;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取JWT Token
|
||||
// * TODO: 实现Token获取逻辑,可能需要:
|
||||
// * 1. 调用认证接口获取Token
|
||||
// * 2. 缓存Token并在过期前自动刷新
|
||||
// * 3. 处理Token失效情况
|
||||
// *
|
||||
// * @return JWT Token
|
||||
// */
|
||||
// private String getJwtToken() {
|
||||
// // 临时实现:从配置中读取或调用认证接口获取
|
||||
// // 实际生产环境需要实现完整的Token管理机制
|
||||
// String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.example.token";
|
||||
// log.warn("[getJwtToken][使用临时Token,生产环境需实现完整的Token获取机制]");
|
||||
// return token;
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.impl;
|
||||
|
||||
import com.zt.plat.module.system.framework.sms.core.client.SmsClient;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.SmsClientFactory;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.SmsChannelEnum;
|
||||
import com.zt.plat.module.system.framework.sms.core.property.SmsChannelProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* 短信客户端工厂接口
|
||||
*
|
||||
* @author zzf
|
||||
*/
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class SmsClientFactoryImpl implements SmsClientFactory {
|
||||
|
||||
/**
|
||||
* 短信客户端 Map
|
||||
* key:渠道编号,使用 {@link SmsChannelProperties#getId()}
|
||||
*/
|
||||
private final ConcurrentMap<Long, AbstractSmsClient> channelIdClients = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 短信客户端 Map
|
||||
* key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()}
|
||||
*
|
||||
* 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。
|
||||
* 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients}
|
||||
*/
|
||||
private final ConcurrentMap<String, AbstractSmsClient> channelCodeClients = new ConcurrentHashMap<>();
|
||||
|
||||
public SmsClientFactoryImpl() {
|
||||
// 初始化 channelCodeClients 集合
|
||||
Arrays.stream(SmsChannelEnum.values()).forEach(channel -> {
|
||||
// 创建一个空的 SmsChannelProperties 对象
|
||||
SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode())
|
||||
.setApiKey("default default").setApiSecret("default");
|
||||
// 创建 Sms 客户端
|
||||
AbstractSmsClient smsClient = createSmsClient(properties);
|
||||
channelCodeClients.put(channel.getCode(), smsClient);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsClient getSmsClient(Long channelId) {
|
||||
return channelIdClients.get(channelId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsClient getSmsClient(String channelCode) {
|
||||
return channelCodeClients.get(channelCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsClient createOrUpdateSmsClient(SmsChannelProperties properties) {
|
||||
AbstractSmsClient client = channelIdClients.get(properties.getId());
|
||||
if (client == null) {
|
||||
client = this.createSmsClient(properties);
|
||||
client.init();
|
||||
channelIdClients.put(client.getId(), client);
|
||||
} else {
|
||||
client.refresh(properties);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
private AbstractSmsClient createSmsClient(SmsChannelProperties properties) {
|
||||
SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode());
|
||||
Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
|
||||
// 创建客户端
|
||||
switch (channelEnum) {
|
||||
case ALIYUN: return new AliyunSmsClient(properties);
|
||||
case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
|
||||
case TENCENT: return new TencentSmsClient(properties);
|
||||
case HUAWEI: return new HuaweiSmsClient(properties);
|
||||
case QINIU: return new QiniuSmsClient(properties);
|
||||
// case CMCC_MAS: return new CmccMasSmsClient(properties);
|
||||
case HL95: return new Hl95SmsClient(properties);
|
||||
case ZLE: return new ZleSmsClient(properties);
|
||||
}
|
||||
// 创建失败,错误日志 + 抛出异常
|
||||
log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
|
||||
throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.enums;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 短信渠道枚举
|
||||
*
|
||||
* @author zzf
|
||||
* @since 2021/1/25 10:56
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SmsChannelEnum {
|
||||
|
||||
DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"),
|
||||
ALIYUN("ALIYUN", "阿里云"),
|
||||
TENCENT("TENCENT", "腾讯云"),
|
||||
HUAWEI("HUAWEI", "华为云"),
|
||||
QINIU("QINIU", "七牛云"),
|
||||
HL95("HL95", "鸿联九五"),
|
||||
// CMCC_MAS("CMCC_MAS", "中国移动云MAS"),
|
||||
ZLE("ZLE", "中铝e办"),
|
||||
;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final String code;
|
||||
/**
|
||||
* 名字
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
public static SmsChannelEnum getByCode(String code) {
|
||||
return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.zt.plat.module.system.job.sync;
|
||||
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import com.zt.plat.framework.tenant.core.job.TenantJob;
|
||||
import com.zt.plat.module.system.service.sync.SyncIWorkOrgChangeService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 用于定时同步 iWork 当日变更的组织数据
|
||||
* 同步时间:每日23:00
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SyncIWorkOrgChangeJob {
|
||||
|
||||
@Resource
|
||||
private SyncIWorkOrgChangeService syncIWorkOrgChangeService;
|
||||
|
||||
/**
|
||||
* 执行定时任务
|
||||
* 配置执行频率:每日23:00时执行一次
|
||||
* cron表达式:0 0 23 * * ?
|
||||
*/
|
||||
@XxlJob("syncIWorkOrgChangeJob")
|
||||
@TenantJob
|
||||
public void execute() {
|
||||
log.info("[syncIWorkOrgChangeJob][开始执行同步 iWork 当日变更组织任务]");
|
||||
try {
|
||||
int processedCount = syncIWorkOrgChangeService.process();
|
||||
if (processedCount > 0) {
|
||||
log.info("[syncIWorkOrgChangeJob][同步任务执行完成,处理了 {} 条记录]", processedCount);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[syncIWorkOrgChangeJob][同步任务执行失败]", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.zt.plat.module.system.service.portal;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.system.controller.admin.portal.vo.PortalPageReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.portal.vo.PortalSaveReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.portal.PortalDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 门户网站 Service 接口
|
||||
*
|
||||
* @author 中铜数字供应链平台
|
||||
*/
|
||||
public interface PortalService {
|
||||
|
||||
/**
|
||||
* 创建门户
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createPortal(PortalSaveReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新门户
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updatePortal(PortalSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除门户
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void deletePortal(Long id);
|
||||
|
||||
/**
|
||||
* 获得门户
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 门户
|
||||
*/
|
||||
PortalDO getPortal(Long id);
|
||||
|
||||
/**
|
||||
* 获得门户分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 门户分页
|
||||
*/
|
||||
PageResult<PortalDO> getPortalPage(PortalPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得用户有权限访问的门户列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 门户列表
|
||||
*/
|
||||
List<PortalDO> getPortalListByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 获得公开门户列表(无需登录)
|
||||
*
|
||||
* @return 门户列表
|
||||
*/
|
||||
List<PortalDO> getPublicPortalList();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.zt.plat.module.system.service.portal;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.system.controller.admin.permission.vo.menu.MenuSaveVO;
|
||||
import com.zt.plat.module.system.controller.admin.portal.vo.PortalPageReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.portal.vo.PortalSaveReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.portal.PortalDO;
|
||||
import com.zt.plat.module.system.dal.mysql.portal.PortalMapper;
|
||||
import com.zt.plat.module.system.enums.permission.MenuTypeEnum;
|
||||
import com.zt.plat.module.system.service.permission.MenuService;
|
||||
import com.zt.plat.module.system.service.permission.PermissionService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.module.system.enums.ErrorCodeConstants.PORTAL_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 门户网站 Service 实现类
|
||||
*
|
||||
* @author 中铜数字供应链平台
|
||||
*/
|
||||
@Service
|
||||
public class PortalServiceImpl implements PortalService {
|
||||
|
||||
@Resource
|
||||
private PortalMapper portalMapper;
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Resource
|
||||
private MenuService menuService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createPortal(PortalSaveReqVO createReqVO) {
|
||||
// 1. 创建门户
|
||||
PortalDO portal = BeanUtils.toBean(createReqVO, PortalDO.class);
|
||||
portalMapper.insert(portal);
|
||||
|
||||
// 2. 自动创建对应的菜单权限
|
||||
if (createReqVO.getParentMenuId() != null&& StringUtils.hasText(createReqVO.getPermission())) {
|
||||
syncMenuPermission(portal, createReqVO.getParentMenuId(), null);
|
||||
}
|
||||
|
||||
return portal.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updatePortal(PortalSaveReqVO updateReqVO) {
|
||||
// 1. 校验是否存在
|
||||
PortalDO oldPortal = validatePortalExists(updateReqVO.getId());
|
||||
|
||||
// 2. 更新门户
|
||||
PortalDO updateObj = BeanUtils.toBean(updateReqVO, PortalDO.class);
|
||||
portalMapper.updateById(updateObj);
|
||||
|
||||
// 3. 自动更新对应的菜单权限
|
||||
if (updateReqVO.getParentMenuId() != null) {
|
||||
syncMenuPermission(updateObj, updateReqVO.getParentMenuId(), oldPortal.getPermission());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deletePortal(Long id) {
|
||||
// 1. 校验是否存在
|
||||
PortalDO portal = validatePortalExists(id);
|
||||
|
||||
// 2. 删除门户
|
||||
portalMapper.deleteById(id);
|
||||
|
||||
// 3. 自动删除对应的菜单权限
|
||||
deleteMenuPermission(portal.getPermission());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PortalDO getPortal(Long id) {
|
||||
return portalMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<PortalDO> getPortalPage(PortalPageReqVO pageReqVO) {
|
||||
return portalMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PortalDO> getPortalListByUserId(Long userId) {
|
||||
// 1. 获取用户的角色ID列表
|
||||
Set<Long> roleIds = permissionService.getUserRoleIdListByUserIdFromCache(userId);
|
||||
if (roleIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 2. 获取角色对应的菜单ID列表
|
||||
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(roleIds);
|
||||
if (menuIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 3. 获取菜单列表并提取权限标识
|
||||
List<MenuDO> menus = menuService.getMenuList(menuIds);
|
||||
List<String> permissions = menus.stream()
|
||||
.map(MenuDO::getPermission)
|
||||
.filter(permission -> permission != null && !permission.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (permissions.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 4. 根据权限标识查询门户列表
|
||||
return portalMapper.selectListByPermissions(permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PortalDO> getPublicPortalList() {
|
||||
return portalMapper.selectListByPermissions(Collections.emptyList());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public PortalDO validatePortalExists(Long id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
PortalDO portal = portalMapper.selectById(id);
|
||||
if (portal == null) {
|
||||
throw exception(PORTAL_NOT_EXISTS);
|
||||
}
|
||||
return portal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步菜单权限
|
||||
* - 如果菜单权限不存在,则创建
|
||||
* - 如果菜单权限已存在,则更新
|
||||
*
|
||||
* @param portal 门户对象
|
||||
* @param parentMenuId 父菜单 ID
|
||||
* @param oldPermission 旧的权限标识(用于更新场景)
|
||||
*/
|
||||
private void syncMenuPermission(PortalDO portal, Long parentMenuId, String oldPermission) {
|
||||
// 1. 如果权限标识发生变化,先删除旧的菜单权限
|
||||
if (oldPermission != null && !oldPermission.equals(portal.getPermission())) {
|
||||
deleteMenuPermission(oldPermission);
|
||||
}
|
||||
|
||||
// 2. 查询是否已存在该权限的菜单
|
||||
List<Long> existMenuIds = menuService.getMenuIdListByPermissionFromCache(portal.getPermission());
|
||||
|
||||
// 3. 构建菜单对象
|
||||
MenuSaveVO menuVO = new MenuSaveVO();
|
||||
menuVO.setName("访问" + portal.getName());
|
||||
menuVO.setPermission(portal.getPermission());
|
||||
menuVO.setType(MenuTypeEnum.BUTTON.getType());
|
||||
menuVO.setSort(portal.getSort());
|
||||
menuVO.setParentId(parentMenuId);
|
||||
menuVO.setStatus(portal.getStatus());
|
||||
menuVO.setVisible(false); // 按钮权限不显示在菜单中
|
||||
|
||||
// 4. 如果菜单已存在则更新,否则创建
|
||||
if (!CollectionUtils.isEmpty(existMenuIds)) {
|
||||
menuVO.setId(existMenuIds.get(0));
|
||||
menuService.updateMenu(menuVO);
|
||||
} else {
|
||||
menuService.createMenu(menuVO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单权限
|
||||
*
|
||||
* @param permission 权限标识
|
||||
*/
|
||||
private void deleteMenuPermission(String permission) {
|
||||
if (permission == null || permission.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Long> menuIds = menuService.getMenuIdListByPermissionFromCache(permission);
|
||||
if (!CollectionUtils.isEmpty(menuIds)) {
|
||||
menuIds.forEach(menuService::deleteMenu);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.zt.plat.module.system.service.sync;
|
||||
|
||||
/**
|
||||
* 定时同步 iWork 组织变更服务
|
||||
*/
|
||||
public interface SyncIWorkOrgChangeService {
|
||||
|
||||
/**
|
||||
* 执行同步
|
||||
* @return 拉取记录数量
|
||||
*/
|
||||
int process();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.zt.plat.module.system.service.sync;
|
||||
|
||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFullSyncReqVO;
|
||||
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFullSyncRespVO;
|
||||
import com.zt.plat.module.system.service.integration.iwork.IWorkSyncService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Service
|
||||
public class SyncIWorkOrgChangeServiceImpl implements SyncIWorkOrgChangeService {
|
||||
|
||||
@Resource
|
||||
private IWorkSyncService iWorkSyncService;
|
||||
|
||||
@Override
|
||||
public int process() {
|
||||
IWorkFullSyncReqVO reqVO = new IWorkFullSyncReqVO();
|
||||
reqVO.setPageSize(10);
|
||||
ZoneId zone = ZoneId.of("Asia/Shanghai");
|
||||
String startOfToday = LocalDate.now(zone)
|
||||
.atStartOfDay(zone)
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
reqVO.setModified(startOfToday);
|
||||
IWorkFullSyncRespVO subcompanyResp = iWorkSyncService.fullSyncSubcompanies(reqVO);
|
||||
IWorkFullSyncRespVO departmentResp = iWorkSyncService.fullSyncDepartments(reqVO);
|
||||
return countPulled(subcompanyResp) + countPulled(departmentResp);
|
||||
}
|
||||
|
||||
private int countPulled(IWorkFullSyncRespVO respVO) {
|
||||
if (respVO == null || respVO.getBatches() == null) {
|
||||
return 0;
|
||||
}
|
||||
return respVO.getBatches().stream()
|
||||
.mapToInt(batch -> batch.getPulled() == null ? 0 : batch.getPulled())
|
||||
.sum();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
package com.zt.plat.module.system.service.sync;
|
||||
|
||||
import com.zt.plat.framework.security.core.LoginUser;
|
||||
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.zt.plat.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserCreateRequestVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserCreateResponseVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserDeleteRequestVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserDeleteResponseVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserGetRequestVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserGetResponseVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserListRequestVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserListResponseVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserUpdateRequestVO;
|
||||
import com.zt.plat.module.system.controller.admin.sync.vo.user.UserUpdateResponseVO;
|
||||
import com.zt.plat.module.system.controller.admin.user.vo.user.UserSaveReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.zt.plat.module.system.dal.mysql.dept.UserPostMapper;
|
||||
import com.zt.plat.module.system.service.dept.PostService;
|
||||
import com.zt.plat.module.system.service.user.AdminUserService;
|
||||
import com.zt.plat.module.system.service.userdept.UserDeptService;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.zt.plat.framework.test.core.util.RandomUtils.randomLongId;
|
||||
import static com.zt.plat.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class UserSyncServiceImplTest extends BaseMockitoUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private UserSyncServiceImpl userSyncService;
|
||||
|
||||
@Mock
|
||||
private AdminUserService adminUserService;
|
||||
@Mock
|
||||
private PostService postService;
|
||||
@Mock
|
||||
private UserPostMapper userPostMapper;
|
||||
|
||||
@Mock
|
||||
private UserDeptService userDeptService;
|
||||
|
||||
private MockedStatic<SecurityFrameworkUtils> securityFrameworkUtilsMock;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
securityFrameworkUtilsMock = Mockito.mockStatic(SecurityFrameworkUtils.class);
|
||||
LoginUser mockLoginUser = new LoginUser();
|
||||
mockLoginUser.setTenantId(1L);
|
||||
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(mockLoginUser);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
securityFrameworkUtilsMock.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateUser_WithPostName() {
|
||||
// Arrange
|
||||
UserCreateRequestVO requestVO = randomPojo(UserCreateRequestVO.class, vo -> {
|
||||
vo.setPostName("岗位A");
|
||||
vo.setDeptIds(null);
|
||||
});
|
||||
Long newUserId = randomLongId();
|
||||
Long postId = randomLongId();
|
||||
when(postService.getOrCreatePostByName(requestVO.getPostName())).thenReturn(postId);
|
||||
when(adminUserService.createUser(any(UserSaveReqVO.class))).thenReturn(newUserId);
|
||||
|
||||
// Act
|
||||
UserCreateResponseVO response = userSyncService.createUser(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("0", response.getResultCode());
|
||||
assertEquals("success", response.getMessage());
|
||||
assertEquals(String.valueOf(newUserId), response.getUid());
|
||||
assertEquals(requestVO.getBimRequestId(), response.getBimRequestId());
|
||||
|
||||
ArgumentCaptor<UserSaveReqVO> captor = ArgumentCaptor.forClass(UserSaveReqVO.class);
|
||||
verify(adminUserService).createUser(captor.capture());
|
||||
assertNotNull(captor.getValue().getPostIds());
|
||||
assertTrue(captor.getValue().getPostIds().contains(postId));
|
||||
verify(postService).getOrCreatePostByName(requestVO.getPostName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateUser_WithoutPostName() {
|
||||
// Arrange
|
||||
UserCreateRequestVO requestVO = randomPojo(UserCreateRequestVO.class, vo -> {
|
||||
vo.setPostName(null);
|
||||
vo.setDeptIds(null);
|
||||
});
|
||||
Long newUserId = randomLongId();
|
||||
when(adminUserService.createUser(any(UserSaveReqVO.class))).thenReturn(newUserId);
|
||||
|
||||
// Act
|
||||
UserCreateResponseVO response = userSyncService.createUser(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("0", response.getResultCode());
|
||||
assertEquals("success", response.getMessage());
|
||||
assertEquals(String.valueOf(newUserId), response.getUid());
|
||||
assertEquals(requestVO.getBimRequestId(), response.getBimRequestId());
|
||||
|
||||
ArgumentCaptor<UserSaveReqVO> captor = ArgumentCaptor.forClass(UserSaveReqVO.class);
|
||||
verify(adminUserService).createUser(captor.capture());
|
||||
assertTrue(captor.getValue().getPostIds() == null || captor.getValue().getPostIds().isEmpty());
|
||||
verify(postService, never()).getOrCreatePostByName(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteUser_Success() {
|
||||
// Arrange
|
||||
UserDeleteRequestVO requestVO = randomPojo(UserDeleteRequestVO.class);
|
||||
AdminUserDO existingUser = randomPojo(AdminUserDO.class);
|
||||
|
||||
// Act
|
||||
UserDeleteResponseVO response = userSyncService.deleteUser(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("0", response.getResultCode());
|
||||
assertEquals("success", response.getMessage());
|
||||
verify(adminUserService).deleteUser(requestVO.getBimUid());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteUser_NotFound() {
|
||||
// Arrange
|
||||
UserDeleteRequestVO requestVO = randomPojo(UserDeleteRequestVO.class);
|
||||
when(adminUserService.getUserByUsername(requestVO.getBimRemoteUser())).thenReturn(null);
|
||||
|
||||
// Act
|
||||
UserDeleteResponseVO response = userSyncService.deleteUser(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("500", response.getResultCode());
|
||||
assertEquals("用户不存在", response.getMessage());
|
||||
verify(adminUserService, never()).deleteUser(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateUser_Success() {
|
||||
// Arrange
|
||||
UserUpdateRequestVO requestVO = randomPojo(UserUpdateRequestVO.class, o -> o.setDeptIds(Set.of(randomLongId(), randomLongId())));
|
||||
AdminUserDO existingUser = randomPojo(AdminUserDO.class);
|
||||
existingUser.setStatus(0); // Active
|
||||
when(adminUserService.getUser(requestVO.getBimUid())).thenReturn(existingUser);
|
||||
|
||||
// Act
|
||||
UserUpdateResponseVO response = userSyncService.updateUser(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("0", response.getResultCode());
|
||||
assertEquals("success", response.getMessage());
|
||||
assertTrue(response.get__ENABLE__());
|
||||
|
||||
verify(userDeptService).deleteUserDeptByUserId(existingUser.getId());
|
||||
verify(userDeptService).batchCreateUserDept(anyList());
|
||||
verify(adminUserService).updateUser(any(UserSaveReqVO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateUser_NotFound() {
|
||||
// Arrange
|
||||
UserUpdateRequestVO requestVO = randomPojo(UserUpdateRequestVO.class);
|
||||
when(adminUserService.getUser(requestVO.getBimUid())).thenReturn(null);
|
||||
|
||||
// Act
|
||||
UserUpdateResponseVO response = userSyncService.updateUser(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("500", response.getResultCode());
|
||||
assertEquals("用户不存在", response.getMessage());
|
||||
assertFalse(response.get__ENABLE__());
|
||||
verify(adminUserService, never()).updateUser(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetUserById_Success() {
|
||||
// Arrange
|
||||
UserGetRequestVO requestVO = new UserGetRequestVO();
|
||||
Long userId = randomLongId();
|
||||
requestVO.setBimUid(String.valueOf(userId));
|
||||
AdminUserDO user = randomPojo(AdminUserDO.class);
|
||||
user.setId(userId);
|
||||
when(adminUserService.getUser(userId)).thenReturn(user);
|
||||
|
||||
// Act
|
||||
UserGetResponseVO response = userSyncService.getUserById(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("0", response.getResultCode());
|
||||
assertEquals("success", response.getMessage());
|
||||
assertNotNull(response.getAccount());
|
||||
assertEquals(user.getId(), response.getAccount().get("uid"));
|
||||
assertEquals(user.getUsername(), response.getAccount().get("username"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetUserById_NotFound() {
|
||||
// Arrange
|
||||
UserGetRequestVO requestVO = new UserGetRequestVO();
|
||||
Long userId = randomLongId();
|
||||
requestVO.setBimUid(String.valueOf(userId));
|
||||
when(adminUserService.getUser(userId)).thenReturn(null);
|
||||
|
||||
// Act
|
||||
UserGetResponseVO response = userSyncService.getUserById(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("500", response.getResultCode());
|
||||
assertEquals("用户不存在", response.getMessage());
|
||||
assertNull(response.getAccount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetUserById_InvalidId() {
|
||||
// Arrange
|
||||
UserGetRequestVO requestVO = new UserGetRequestVO();
|
||||
requestVO.setBimUid("invalid-id");
|
||||
|
||||
// Act
|
||||
UserGetResponseVO response = userSyncService.getUserById(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("500", response.getResultCode());
|
||||
assertEquals("参数错误", response.getMessage());
|
||||
assertNull(response.getAccount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testListUserIds() {
|
||||
// Arrange
|
||||
UserListRequestVO requestVO = randomPojo(UserListRequestVO.class);
|
||||
AdminUserDO user1 = randomPojo(AdminUserDO.class);
|
||||
AdminUserDO user2 = randomPojo(AdminUserDO.class);
|
||||
when(adminUserService.getUserListByStatus(0)).thenReturn(List.of(user1, user2));
|
||||
|
||||
// Act
|
||||
UserListResponseVO response = userSyncService.listUserIds(requestVO);
|
||||
|
||||
// Assert
|
||||
assertNotNull(response);
|
||||
assertEquals("0", response.getResultCode());
|
||||
assertEquals("success", response.getMessage());
|
||||
assertEquals(2, response.getUserIdList().size());
|
||||
assertTrue(response.getUserIdList().contains(String.valueOf(user1.getId())));
|
||||
assertTrue(response.getUserIdList().contains(String.valueOf(user2.getId())));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user