1. 去除强制的业务字段 insert 非空校验
2. 修复同步用户错误 3. 同步日志支持接口重跑 4. 新增部门树加载效果优化接口 5. 修复部分 post API 参数注解错误的问题
This commit is contained in:
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,6 +45,21 @@ public class BeanUtils {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <S, T> Set<T> toBean(Set<S> source, Class<T> targetType) {
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return CollectionUtils.convertSet(source, s -> toBean(s, targetType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <S, T> Set<T> toBean(Set<S> source, Class<T> targetType, Consumer<T> peek) {
|
||||||
|
Set<T> set = toBean(source, targetType);
|
||||||
|
if (set != null) {
|
||||||
|
set.forEach(peek);
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
public static <S, T> PageResult<T> toBean(PageResult<S> source, Class<T> targetType) {
|
public static <S, T> PageResult<T> toBean(PageResult<S> source, Class<T> targetType) {
|
||||||
return toBean(source, targetType, null);
|
return toBean(source, targetType, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import java.lang.reflect.Field;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.USER_NOT_SET_DEPT;
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,10 +158,11 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
|
|||||||
Set<Long> postIds = new HashSet<>(JSONUtil.parseArray(
|
Set<Long> postIds = new HashSet<>(JSONUtil.parseArray(
|
||||||
loginUser.getInfo().getOrDefault(LoginUser.INFO_KEY_POST_IDS, "[]")
|
loginUser.getInfo().getOrDefault(LoginUser.INFO_KEY_POST_IDS, "[]")
|
||||||
).toList(Long.class));
|
).toList(Long.class));
|
||||||
|
// 阻碍部分场景的使用,不强制校验
|
||||||
// 如果 visitCompanyId 不存在,不能进行业务办理
|
// 如果 visitCompanyId 不存在,不能进行业务办理
|
||||||
if (Objects.isNull(visitCompanyId) || Objects.isNull(visitDeptId)) {
|
// if (Objects.isNull(visitCompanyId) || Objects.isNull(visitDeptId)) {
|
||||||
throw exception(USER_NOT_SET_DEPT);
|
// throw exception(USER_NOT_SET_DEPT);
|
||||||
}
|
// }
|
||||||
businessBaseDO.setCompanyId(visitCompanyId);
|
businessBaseDO.setCompanyId(visitCompanyId);
|
||||||
businessBaseDO.setCompanyName(loginUser.getVisitCompanyName());
|
businessBaseDO.setCompanyName(loginUser.getVisitCompanyName());
|
||||||
businessBaseDO.setDeptId(visitDeptId);
|
businessBaseDO.setDeptId(visitDeptId);
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ public interface DeptApi {
|
|||||||
@Operation(summary = "删除部门")
|
@Operation(summary = "删除部门")
|
||||||
CommonResult<Boolean> deleteDept(@RequestParam("id") Long id);
|
CommonResult<Boolean> deleteDept(@RequestParam("id") Long id);
|
||||||
|
|
||||||
@GetMapping(PREFIX + "/list-all")
|
@PostMapping(PREFIX + "/list-all")
|
||||||
@Operation(summary = "获得部门列表")
|
@Operation(summary = "获得部门列表")
|
||||||
CommonResult<List<DeptDetailRespDTO>> getDeptList(@RequestParam DeptListReqDTO reqVO);
|
CommonResult<List<DeptDetailRespDTO>> getDeptList(@RequestBody DeptListReqDTO reqVO);
|
||||||
|
|
||||||
@GetMapping(PREFIX + "/simple-list")
|
@GetMapping(PREFIX + "/simple-list")
|
||||||
@Operation(summary = "获得部门精简信息列表")
|
@Operation(summary = "获得部门精简信息列表")
|
||||||
@@ -77,4 +77,9 @@ public interface DeptApi {
|
|||||||
@Parameter(name = "id", description = "部门编号", example = "1024", required = true)
|
@Parameter(name = "id", description = "部门编号", example = "1024", required = true)
|
||||||
CommonResult<List<DeptRespDTO>> getChildDeptList(@RequestParam("id") Long id);
|
CommonResult<List<DeptRespDTO>> getChildDeptList(@RequestParam("id") Long id);
|
||||||
|
|
||||||
|
@GetMapping(PREFIX + "/company-dept-info")
|
||||||
|
@Operation(summary = "获得指定用户的公司部门信息")
|
||||||
|
@Parameter(name = "userId", description = "用户编号", example = "1", required = true)
|
||||||
|
CommonResult<Set<CompanyDeptInfoRespDTO>> getCompanyDeptInfoListByUserId(@RequestParam("userId") Long userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.api.dept.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公司部门信息 Response DTO
|
||||||
|
*
|
||||||
|
* @author ZT
|
||||||
|
*/
|
||||||
|
@Schema(description = "RPC 服务 - 公司部门信息 Response DTO")
|
||||||
|
@Data
|
||||||
|
public class CompanyDeptInfoRespDTO {
|
||||||
|
|
||||||
|
@Schema(description = "公司编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Long companyId;
|
||||||
|
|
||||||
|
@Schema(description = "公司名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
|
||||||
|
private String companyName;
|
||||||
|
|
||||||
|
@Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Long deptId;
|
||||||
|
|
||||||
|
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部")
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,8 +9,8 @@ import cn.iocoder.yudao.module.system.enums.ApiConstants;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.cloud.openfeign.SpringQueryMap;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||||
@Tag(name = "RPC 服务 - 操作日志")
|
@Tag(name = "RPC 服务 - 操作日志")
|
||||||
@@ -18,8 +18,8 @@ public interface OperateLogApi extends OperateLogCommonApi {
|
|||||||
|
|
||||||
String PREFIX = ApiConstants.PREFIX + "/operate-log";
|
String PREFIX = ApiConstants.PREFIX + "/operate-log";
|
||||||
|
|
||||||
@GetMapping(PREFIX + "/page")
|
@PostMapping(PREFIX + "/page")
|
||||||
@Operation(summary = "获取指定模块的指定数据的操作日志分页")
|
@Operation(summary = "获取指定模块的指定数据的操作日志分页")
|
||||||
CommonResult<PageResult<OperateLogRespDTO>> getOperateLogPage(@SpringQueryMap OperateLogPageReqDTO pageReqDTO);
|
CommonResult<PageResult<OperateLogRespDTO>> getOperateLogPage(@RequestBody OperateLogPageReqDTO pageReqDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public interface SmsCodeApi {
|
|||||||
@Operation(summary = "验证短信验证码,并进行使用")
|
@Operation(summary = "验证短信验证码,并进行使用")
|
||||||
CommonResult<Boolean> useSmsCode(@Valid @RequestBody SmsCodeUseReqDTO reqDTO);
|
CommonResult<Boolean> useSmsCode(@Valid @RequestBody SmsCodeUseReqDTO reqDTO);
|
||||||
|
|
||||||
@GetMapping(PREFIX + "/validate")
|
@PostMapping(PREFIX + "/validate")
|
||||||
@Operation(summary = "检查验证码是否有效")
|
@Operation(summary = "检查验证码是否有效")
|
||||||
CommonResult<Boolean> validateSmsCode(@Valid @RequestBody SmsCodeValidateReqDTO reqDTO);
|
CommonResult<Boolean> validateSmsCode(@Valid @RequestBody SmsCodeValidateReqDTO reqDTO);
|
||||||
|
|
||||||
|
|||||||
@@ -52,9 +52,9 @@ public interface SocialClientApi {
|
|||||||
CommonResult<SocialWxPhoneNumberInfoRespDTO> getWxMaPhoneNumberInfo(@RequestParam("userType") Integer userType,
|
CommonResult<SocialWxPhoneNumberInfoRespDTO> getWxMaPhoneNumberInfo(@RequestParam("userType") Integer userType,
|
||||||
@RequestParam("phoneCode") String phoneCode);
|
@RequestParam("phoneCode") String phoneCode);
|
||||||
|
|
||||||
@GetMapping(PREFIX + "/get-wxa-qrcode")
|
@PostMapping(PREFIX + "/get-wxa-qrcode")
|
||||||
@Operation(summary = "获得小程序二维码")
|
@Operation(summary = "获得小程序二维码")
|
||||||
CommonResult<byte[]> getWxaQrcode(@SpringQueryMap SocialWxQrcodeReqDTO reqVO);
|
CommonResult<byte[]> getWxaQrcode(@RequestBody SocialWxQrcodeReqDTO reqVO);
|
||||||
|
|
||||||
@GetMapping(PREFIX + "/get-wxa-subscribe-template-list")
|
@GetMapping(PREFIX + "/get-wxa-subscribe-template-list")
|
||||||
@Operation(summary = "获得微信小程订阅模板")
|
@Operation(summary = "获得微信小程订阅模板")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.api.dept;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.CompanyDeptInfo;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.system.api.dept.dto.*;
|
import cn.iocoder.yudao.module.system.api.dept.dto.*;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
|
||||||
@@ -14,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
@@ -88,4 +90,10 @@ public class DeptApiImpl implements DeptApi {
|
|||||||
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,23 @@ public class DeptController {
|
|||||||
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
|
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/top-level-list")
|
||||||
|
@Operation(summary = "获取顶级部门列表", description = "用于懒加载,只返回没有父部门的顶级部门")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||||
|
public CommonResult<List<DeptSimpleRespVO>> getTopLevelDeptList() {
|
||||||
|
List<DeptDO> list = deptService.getTopLevelDeptList();
|
||||||
|
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/children")
|
||||||
|
@Operation(summary = "根据父部门ID获取子部门列表", description = "用于懒加载,根据父部门ID返回直接子部门")
|
||||||
|
@Parameter(name = "parentId", description = "父部门ID", required = true, example = "1024")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||||
|
public CommonResult<List<DeptSimpleRespVO>> getChildrenDeptList(@RequestParam("parentId") Long parentId) {
|
||||||
|
List<DeptDO> list = deptService.getDirectChildDeptList(parentId);
|
||||||
|
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/get")
|
@GetMapping("/get")
|
||||||
@Operation(summary = "获得部门信息")
|
@Operation(summary = "获得部门信息")
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
|
|||||||
@@ -49,4 +49,13 @@ public class SyncLogController {
|
|||||||
return success(BeanUtils.toBean(pageResult, SyncLogRespVO.class));
|
return success(BeanUtils.toBean(pageResult, SyncLogRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/rerun")
|
||||||
|
@Operation(summary = "重新执行异常的同步接口")
|
||||||
|
@Parameter(name = "id", description = "日志编号", required = true, example = "1024")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:sync-log:rerun')")
|
||||||
|
public CommonResult<Boolean> rerunSyncLog(@RequestParam("id") Long id) {
|
||||||
|
boolean success = syncLogService.rerunSyncLog(id);
|
||||||
|
return success(success);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,34 @@ public interface DeptMapper extends BaseMapperX<DeptDO> {
|
|||||||
UpdateWrapper<DeptDO> wrapper = new UpdateWrapper<>();
|
UpdateWrapper<DeptDO> wrapper = new UpdateWrapper<>();
|
||||||
wrapper.in("id", ids).set("tenant_id", tenantId);
|
wrapper.in("id", ids).set("tenant_id", tenantId);
|
||||||
update(null, wrapper);
|
update(null, wrapper);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据父部门ID和状态查询部门列表
|
||||||
|
*
|
||||||
|
* @param parentId 父部门ID
|
||||||
|
* @param status 状态
|
||||||
|
* @return 部门列表
|
||||||
|
*/
|
||||||
|
default List<DeptDO> selectList(Long parentId, Integer status) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<DeptDO>()
|
||||||
|
.eqIfPresent(DeptDO::getParentId, parentId)
|
||||||
|
.eqIfPresent(DeptDO::getStatus, status)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据父部门ID和状态查询子部门列表
|
||||||
|
*
|
||||||
|
* @param parentId 父部门ID
|
||||||
|
* @param status 状态
|
||||||
|
* @return 子部门列表
|
||||||
|
*/
|
||||||
|
default List<DeptDO> selectListByParentId(Long parentId, Integer status) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<DeptDO>()
|
||||||
|
.eq(DeptDO::getParentId, parentId)
|
||||||
|
.eqIfPresent(DeptDO::getStatus, status)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,4 +118,21 @@ public interface DeptService {
|
|||||||
List<DeptDO> getUserCompanyList();
|
List<DeptDO> getUserCompanyList();
|
||||||
|
|
||||||
Set<CompanyDeptInfo> getCompanyDeptInfoListByUserId(Long userId);
|
Set<CompanyDeptInfo> getCompanyDeptInfoListByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取顶级部门列表
|
||||||
|
* 用于懒加载,只返回没有父部门的顶级部门
|
||||||
|
*
|
||||||
|
* @return 顶级部门列表
|
||||||
|
*/
|
||||||
|
List<DeptDO> getTopLevelDeptList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据父部门ID获取直接子部门列表
|
||||||
|
* 用于懒加载,只返回指定父部门的直接子部门
|
||||||
|
*
|
||||||
|
* @param parentId 父部门ID
|
||||||
|
* @return 直接子部门列表
|
||||||
|
*/
|
||||||
|
List<DeptDO> getDirectChildDeptList(Long parentId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,4 +311,19 @@ public class DeptServiceImpl implements DeptService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DeptDO> getTopLevelDeptList() {
|
||||||
|
// 获取顶级部门:没有父部门的部门(parentId为null或0)
|
||||||
|
return deptMapper.selectList(DeptDO.PARENT_ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DeptDO> getDirectChildDeptList(Long parentId) {
|
||||||
|
if (parentId == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
// 根据父部门ID获取直接子部门,只返回启用状态的部门
|
||||||
|
return deptMapper.selectListByParentId(parentId, CommonStatusEnum.ENABLE.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,4 +99,12 @@ public interface SyncLogService {
|
|||||||
String exceptionStack, String responseData, String encryptedResponse,
|
String exceptionStack, String responseData, String encryptedResponse,
|
||||||
String businessResult);
|
String businessResult);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新执行异常的同步接口
|
||||||
|
*
|
||||||
|
* @param logId 日志ID
|
||||||
|
* @return 重跑是否成功
|
||||||
|
*/
|
||||||
|
boolean rerunSyncLog(Long logId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,32 @@ package cn.iocoder.yudao.module.system.service.sync;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.SyncLogPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.SyncLogPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.org.OrgCreateRequestVO;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.org.OrgDeleteRequestVO;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.org.OrgUpdateRequestVO;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.user.UserCreateRequestVO;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.user.UserDeleteRequestVO;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.user.UserUpdateRequestVO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.sync.SyncLogDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.sync.SyncLogDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.sync.SyncLogMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.sync.SyncLogMapper;
|
||||||
import cn.iocoder.yudao.module.system.enums.sync.SyncLogStatusEnum;
|
import cn.iocoder.yudao.module.system.enums.sync.SyncLogStatusEnum;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步接口日志 Service 实现类
|
* 同步接口日志 Service 实现类
|
||||||
|
*
|
||||||
|
* 注意:系统现已调整为允许用户名重复,相关影响如下:
|
||||||
|
* 1. 移除了用户创建和更新时的用户名唯一性校验
|
||||||
|
* 2. 用户删除操作改为通过用户ID进行,而非用户名
|
||||||
|
* 3. 登录认证仍使用用户名,但可能需要额外的区分机制(如租户ID)
|
||||||
*
|
*
|
||||||
* @author ZT
|
* @author ZT
|
||||||
*/
|
*/
|
||||||
@@ -24,6 +38,10 @@ public class SyncLogServiceImpl implements SyncLogService {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SyncLogMapper syncLogMapper;
|
private SyncLogMapper syncLogMapper;
|
||||||
|
@Resource
|
||||||
|
private OrgSyncService orgSyncService;
|
||||||
|
@Resource
|
||||||
|
private UserSyncService userSyncService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createSyncLog(SyncLogDO syncLog) {
|
public Long createSyncLog(SyncLogDO syncLog) {
|
||||||
@@ -145,4 +163,145 @@ public class SyncLogServiceImpl implements SyncLogService {
|
|||||||
updateSyncLog(syncLog);
|
updateSyncLog(syncLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rerunSyncLog(Long logId) {
|
||||||
|
// 获取原始日志
|
||||||
|
SyncLogDO originalLog = getSyncLog(logId);
|
||||||
|
if (originalLog == null) {
|
||||||
|
log.warn("同步日志不存在,无法重跑,logId: {}", logId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是失败的日志
|
||||||
|
if (SyncLogStatusEnum.SUCCESS.getStatus().equals(originalLog.getStatus())) {
|
||||||
|
log.warn("同步日志状态为成功,无需重跑,logId: {}", logId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有解密后的请求数据
|
||||||
|
if (originalLog.getDecryptedRequest() == null || originalLog.getDecryptedRequest().trim().isEmpty()) {
|
||||||
|
log.warn("同步日志缺少解密后的请求数据,无法重跑,logId: {}", logId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 重置相关状态,准备重新执行
|
||||||
|
SyncLogDO updateLog = new SyncLogDO();
|
||||||
|
updateLog.setId(logId);
|
||||||
|
updateLog.setResponseTime(LocalDateTime.now());
|
||||||
|
updateLog.setErrorCode(null);
|
||||||
|
updateLog.setErrorMessage(null);
|
||||||
|
updateLog.setExceptionStack(null);
|
||||||
|
updateLog.setResponseData(null);
|
||||||
|
updateLog.setEncryptedResponse(null);
|
||||||
|
updateLog.setBusinessResult(null);
|
||||||
|
|
||||||
|
// 根据服务名称重新执行业务逻辑
|
||||||
|
boolean success = rerunBusinessLogic(originalLog.getServiceName(),
|
||||||
|
originalLog.getDecryptedRequest(), logId);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
log.info("同步接口重跑成功,logId: {}", logId);
|
||||||
|
} else {
|
||||||
|
log.error("同步接口重跑失败,logId: {}", logId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("重跑同步接口异常,logId: {}", logId, e);
|
||||||
|
// 记录重跑异常
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SYSTEM_ERROR.getStatus(),
|
||||||
|
"RERUN_ERROR", "重跑过程中发生异常: " + e.getMessage(), getStackTrace(e), null, null, "500");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据服务名称重新执行业务逻辑
|
||||||
|
*/
|
||||||
|
private boolean rerunBusinessLogic(String serviceName, String decryptedRequest, Long logId) {
|
||||||
|
try {
|
||||||
|
switch (serviceName) {
|
||||||
|
// 只支持写操作(创建、更新、删除)的重跑,查询操作通常是幂等的不需要重跑
|
||||||
|
case "OrgCreateService":
|
||||||
|
OrgCreateRequestVO orgCreateReq = JSON.parseObject(decryptedRequest, OrgCreateRequestVO.class);
|
||||||
|
var orgCreateResp = orgSyncService.createOrg(orgCreateReq);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
|
||||||
|
null, null, null, JSON.toJSONString(orgCreateResp), null, orgCreateResp.getResultCode());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "OrgDeleteService":
|
||||||
|
OrgDeleteRequestVO orgDeleteReq = JSON.parseObject(decryptedRequest, OrgDeleteRequestVO.class);
|
||||||
|
var orgDeleteResp = orgSyncService.deleteOrg(orgDeleteReq);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
|
||||||
|
null, null, null, JSON.toJSONString(orgDeleteResp), null, orgDeleteResp.getResultCode());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "OrgUpdateService":
|
||||||
|
OrgUpdateRequestVO orgUpdateReq = JSON.parseObject(decryptedRequest, OrgUpdateRequestVO.class);
|
||||||
|
var orgUpdateResp = orgSyncService.updateOrg(orgUpdateReq);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
|
||||||
|
null, null, null, JSON.toJSONString(orgUpdateResp), null, orgUpdateResp.getResultCode());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "UserCreateService":
|
||||||
|
UserCreateRequestVO userCreateReq = JSON.parseObject(decryptedRequest, UserCreateRequestVO.class);
|
||||||
|
var userCreateResp = userSyncService.createUser(userCreateReq);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
|
||||||
|
null, null, null, JSON.toJSONString(userCreateResp), null, userCreateResp.getResultCode());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "UserDeleteService":
|
||||||
|
UserDeleteRequestVO userDeleteReq = JSON.parseObject(decryptedRequest, UserDeleteRequestVO.class);
|
||||||
|
var userDeleteResp = userSyncService.deleteUser(userDeleteReq);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
|
||||||
|
null, null, null, JSON.toJSONString(userDeleteResp), null, userDeleteResp.getResultCode());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "UserUpdateService":
|
||||||
|
UserUpdateRequestVO userUpdateReq = JSON.parseObject(decryptedRequest, UserUpdateRequestVO.class);
|
||||||
|
var userUpdateResp = userSyncService.updateUser(userUpdateReq);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
|
||||||
|
null, null, null, JSON.toJSONString(userUpdateResp), null, userUpdateResp.getResultCode());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 查询类服务不支持重跑,因为它们通常是幂等的且没有副作用
|
||||||
|
case "SchemaService":
|
||||||
|
case "QueryOrgByIdService":
|
||||||
|
case "QueryAllOrgIdsService":
|
||||||
|
case "QueryUserByIdService":
|
||||||
|
case "QueryAllUserIdsService":
|
||||||
|
log.warn("查询类服务不支持重跑: {}", serviceName);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SYSTEM_ERROR.getStatus(),
|
||||||
|
"QUERY_SERVICE_NOT_RERUNABLE", "查询类服务不支持重跑", null, null, null, "400");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.warn("不支持的服务类型重跑: {}", serviceName);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SYSTEM_ERROR.getStatus(),
|
||||||
|
"UNSUPPORTED_SERVICE", "不支持的服务类型重跑", null, null, null, "500");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("重跑业务逻辑异常,serviceName: {}", serviceName, e);
|
||||||
|
logRequestComplete(logId, SyncLogStatusEnum.SYSTEM_ERROR.getStatus(),
|
||||||
|
"RERUN_ERROR", e.getMessage(), getStackTrace(e), null, null, "500");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取异常堆栈信息
|
||||||
|
*/
|
||||||
|
private String getStackTrace(Exception e) {
|
||||||
|
try {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
e.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,15 @@ import java.util.*;
|
|||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户同步服务实现类
|
||||||
|
*
|
||||||
|
* 注意:系统现已调整为允许用户名重复,相关调整:
|
||||||
|
* 1. deleteUser 方法改为通过用户ID直接查找和删除用户,而非通过用户名
|
||||||
|
* 2. 用户创建时不再校验用户名唯一性
|
||||||
|
*
|
||||||
|
* @author ZT
|
||||||
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class UserSyncServiceImpl implements UserSyncService {
|
public class UserSyncServiceImpl implements UserSyncService {
|
||||||
@Resource
|
@Resource
|
||||||
@@ -60,7 +69,8 @@ public class UserSyncServiceImpl implements UserSyncService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDeleteResponseVO deleteUser(UserDeleteRequestVO requestVO) {
|
public UserDeleteResponseVO deleteUser(UserDeleteRequestVO requestVO) {
|
||||||
AdminUserDO user = adminUserService.getUserByUsername(requestVO.getBimRemoteUser());
|
// 由于用户名可能重复,直接通过 ID 查找和删除用户
|
||||||
|
AdminUserDO user = adminUserService.getUser(requestVO.getBimUid());
|
||||||
UserDeleteResponseVO resp = new UserDeleteResponseVO();
|
UserDeleteResponseVO resp = new UserDeleteResponseVO();
|
||||||
resp.setBimRequestId(requestVO.getBimRequestId());
|
resp.setBimRequestId(requestVO.getBimRequestId());
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 后台用户 Service 实现类
|
* 后台用户 Service 实现类
|
||||||
|
*
|
||||||
|
* 注意:系统现已调整为允许用户名重复,已移除用户名唯一性校验。
|
||||||
|
* 这意味着:
|
||||||
|
* 1. 用户创建和更新时不再检查用户名是否重复
|
||||||
|
* 2. 通过用户名查询可能返回多个用户中的第一个
|
||||||
|
* 3. 建议在需要精确查找时使用用户ID或其他唯一标识
|
||||||
*
|
*
|
||||||
* @author ZT
|
* @author ZT
|
||||||
*/
|
*/
|
||||||
@@ -416,8 +422,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
|||||||
return DataPermissionUtils.executeIgnore(() -> {
|
return DataPermissionUtils.executeIgnore(() -> {
|
||||||
// 校验用户存在
|
// 校验用户存在
|
||||||
AdminUserDO user = validateUserExists(id);
|
AdminUserDO user = validateUserExists(id);
|
||||||
// 校验用户名唯一
|
// 校验用户名唯一 - 注释掉,允许用户名重复
|
||||||
validateUsernameUnique(id, username);
|
// validateUsernameUnique(id, username);
|
||||||
// 校验手机号唯一
|
// 校验手机号唯一
|
||||||
validateMobileUnique(id, mobile);
|
validateMobileUnique(id, mobile);
|
||||||
// 校验邮箱唯一
|
// 校验邮箱唯一
|
||||||
|
|||||||
Reference in New Issue
Block a user