feat:监护人维护人脸流程
This commit is contained in:
1 parent
0149da2823
commit
be37903a1a
15 files changed
+592
-13
No files matched your search
@@ -0,0 +1,3 @@
|
||||
-- 为人脸审核记录补充拒绝原因,供审核详情页面展示。
|
||||
ALTER TABLE sys_user_face
|
||||
ADD COLUMN reject_reason varchar(500) DEFAULT NULL COMMENT '审核拒绝原因' AFTER process_time;
|
||||
@@ -43,6 +43,7 @@ CREATE TABLE `sys_user_face`
|
||||
process_id varchar(256) COMMENT '流程id',
|
||||
process_status varchar(10) COMMENT '审核状体',
|
||||
process_time datetime COMMENT '审核时间',
|
||||
reject_reason varchar(500) DEFAULT NULL COMMENT '审核拒绝原因',
|
||||
face_img varchar(256) NOT NULL COMMENT '人脸图片',
|
||||
create_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
@@ -809,4 +810,4 @@ CREATE TABLE integral_transaction
|
||||
del_flag char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
|
||||
tenant_id bigint DEFAULT NULL COMMENT '租户ID',
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE = InnoDB COMMENT ='积分记录';
|
||||
) ENGINE = InnoDB COMMENT ='积分记录';
|
||||
+5
@@ -15,6 +15,11 @@ public class SysUserFaceDto extends SysUserFaceEntity implements BaseIsIncludeTr
|
||||
|
||||
private List<Long> userIds;
|
||||
|
||||
/**
|
||||
* 审核状态集合
|
||||
*/
|
||||
private List<String> processStatuses;
|
||||
|
||||
private List<Long> deptIds;
|
||||
|
||||
private String isGlobalFace;
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.bsd.pjcloud.admin.api.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 监护人代被监护人提交人脸审核。
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "监护人代被监护人提交人脸审核")
|
||||
public class SysUserFaceGuardianWardCreateDto {
|
||||
|
||||
@NotNull(message = "被监护人不能为空")
|
||||
@Schema(description = "被监护人用户ID")
|
||||
private Long wardUserId;
|
||||
|
||||
@NotEmpty(message = "请上传人脸图片")
|
||||
@Size(min = 1, max = 2, message = "请上传1至2张人脸图片")
|
||||
@Schema(description = "人脸图片地址,最多2张")
|
||||
private List<@NotBlank(message = "人脸图片地址不能为空") String> faceImgs;
|
||||
}
|
||||
+7
-1
@@ -67,6 +67,12 @@ public class SysUserFaceEntity extends Model<SysUserFaceEntity> {
|
||||
@Schema(description = "审核时间")
|
||||
private LocalDateTime processTime;
|
||||
|
||||
/**
|
||||
* 审核拒绝原因
|
||||
*/
|
||||
@Schema(description = "审核拒绝原因")
|
||||
private String rejectReason;
|
||||
|
||||
/**
|
||||
* 人脸图片
|
||||
*/
|
||||
@@ -114,4 +120,4 @@ public class SysUserFaceEntity extends Model<SysUserFaceEntity> {
|
||||
*/
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.bsd.pjcloud.admin.api.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 被监护人选择项。
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "被监护人选择项")
|
||||
public class SysUserFaceGuardianWardOptionVo {
|
||||
|
||||
/**
|
||||
* 被监护人用户ID
|
||||
*/
|
||||
@Schema(description = "被监护人用户ID")
|
||||
private Long wardUserId;
|
||||
|
||||
/**
|
||||
* 被监护人姓名
|
||||
*/
|
||||
@Schema(description = "被监护人姓名")
|
||||
private String wardName;
|
||||
|
||||
/**
|
||||
* 被监护人头像
|
||||
*/
|
||||
@Schema(description = "被监护人头像")
|
||||
private String wardAvatar;
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.bsd.pjcloud.admin.api.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 被监护人人脸审核撤回结果。
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "被监护人人脸审核撤回结果")
|
||||
public class SysUserFaceGuardianWardWithdrawVo {
|
||||
|
||||
/**
|
||||
* 被监护人用户ID
|
||||
*/
|
||||
@Schema(description = "被监护人用户ID")
|
||||
private Long wardUserId;
|
||||
|
||||
/**
|
||||
* 被监护人姓名
|
||||
*/
|
||||
@Schema(description = "被监护人姓名")
|
||||
private String wardName;
|
||||
|
||||
/**
|
||||
* 撤回后用于重新编辑的人脸图片
|
||||
*/
|
||||
@Schema(description = "撤回后用于重新编辑的人脸图片")
|
||||
private String faceImg;
|
||||
}
|
||||
+60
@@ -8,7 +8,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.admin.api.dto.SysUserFaceDto;
|
||||
import com.bsd.pjcloud.admin.api.dto.SysUserFaceGuardianWardCreateDto;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUserFaceEntity;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceGuardianWardOptionVo;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceGuardianWardWithdrawVo;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceVo;
|
||||
import com.bsd.pjcloud.admin.service.SysUserFaceService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
@@ -29,6 +32,7 @@ import org.springframework.http.HttpHeaders;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
@@ -88,6 +92,62 @@ public class SysUserFaceController {
|
||||
return R.ok(sysUserFaceService.create(dto));
|
||||
}
|
||||
|
||||
/**
|
||||
* 监护人代被监护人提交人脸审核。
|
||||
*/
|
||||
@Operation(summary = "监护人提交被监护人人脸", description = "仅监护关系中的监护人可提交,所有图片必须进入审核流程")
|
||||
@SysLog("监护人提交被监护人人脸")
|
||||
@ApiCryptoAes
|
||||
@PostMapping("/app/guardian-ward")
|
||||
@Idempotent(expireTime = 10, info = "正在处理中,请勿重复操作")
|
||||
public R<List<Long>> createGuardianWardFaces(@Valid @RequestBody SysUserFaceGuardianWardCreateDto dto) {
|
||||
return R.ok(sysUserFaceService.createGuardianWardFaces(dto));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前监护人名下可选择的有效被监护人。
|
||||
*/
|
||||
@Operation(summary = "查询被监护人选择项", description = "仅返回当前监护人名下有效被监护人的姓名和头像")
|
||||
@ApiCryptoAes
|
||||
@GetMapping("/app/guardian-ward/options")
|
||||
public R<List<SysUserFaceGuardianWardOptionVo>> listGuardianWardOptions() {
|
||||
return R.ok(sysUserFaceService.listGuardianWardOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询当前监护人名下被监护人的人脸审核记录。
|
||||
*/
|
||||
@Operation(summary = "查询被监护人人脸审核记录", description = "查询当前用户全部有效被监护人的审核记录,并返回被监护人姓名")
|
||||
@ApiCryptoAes
|
||||
@GetMapping("/app/guardian-ward/page")
|
||||
public R<Page<SysUserFaceVo>> pageGuardianWardFaces(@ParameterObject Page page,
|
||||
@RequestParam(required = false) Long wardUserId,
|
||||
@RequestParam(required = false) String processStatus) {
|
||||
return R.ok(sysUserFaceService.pageGuardianWardFaces(page, wardUserId, processStatus));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前监护人名下被监护人的人脸审核详情。
|
||||
*/
|
||||
@Operation(summary = "查询被监护人人脸审核详情", description = "仅被监护人的有效监护人可以查看")
|
||||
@ApiCryptoAes
|
||||
@GetMapping("/app/guardian-ward/detail")
|
||||
public R<SysUserFaceVo> getGuardianWardFaceDetail(@RequestParam Long id) {
|
||||
return R.ok(sysUserFaceService.getGuardianWardFaceDetail(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回并删除当前监护人名下被监护人仍在审核中的人脸记录。
|
||||
*/
|
||||
@Operation(summary = "撤回被监护人人脸审核", description = "仅审核中的记录可以撤回,撤回后删除旧记录并返回原图供重新编辑")
|
||||
@SysLog("撤回被监护人人脸审核")
|
||||
@ApiCryptoAes
|
||||
@PutMapping("/app/guardian-ward/cancel")
|
||||
@Idempotent(expireTime = 3, info = "正在处理中,请勿重复操作")
|
||||
public R<SysUserFaceGuardianWardWithdrawVo> cancelGuardianWardFace(@RequestParam Long id) {
|
||||
return R.ok(sysUserFaceService.cancelGuardianWardFace(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "app修改人脸样本表", description = "修改人脸样本表")
|
||||
@SysLog("修改人脸样本表")
|
||||
@ApiCryptoAes
|
||||
|
||||
+16
-1
@@ -27,6 +27,12 @@ public interface SysUserFaceMapper extends PjcloudBaseMapper<SysUserFaceEntity>
|
||||
|
||||
Long selectAllCount();
|
||||
|
||||
/**
|
||||
* 联表查询单条人脸记录及用户姓名。
|
||||
*
|
||||
* @param id 人脸记录ID
|
||||
* @return 人脸记录详情
|
||||
*/
|
||||
default SysUserFaceVo join(Long id) {
|
||||
MPJLambdaWrapper<SysUserFaceEntity> wrapper = new MPJLambdaWrapper<SysUserFaceEntity>()
|
||||
.selectAll(SysUserFaceEntity.class)
|
||||
@@ -36,6 +42,13 @@ public interface SysUserFaceMapper extends PjcloudBaseMapper<SysUserFaceEntity>
|
||||
return selectJoinOne(SysUserFaceVo.class, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 联表分页查询人脸记录,并按用户和审核状态条件过滤。
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param dto 人脸查询条件
|
||||
* @return 人脸记录分页数据
|
||||
*/
|
||||
default Page<SysUserFaceVo> pageJoin(Page page, SysUserFaceDto dto) {
|
||||
MPJLambdaWrapper<SysUserFaceEntity> wrapper = new MPJLambdaWrapper<SysUserFaceEntity>()
|
||||
.selectAll(SysUserFaceEntity.class)
|
||||
@@ -49,6 +62,8 @@ public interface SysUserFaceMapper extends PjcloudBaseMapper<SysUserFaceEntity>
|
||||
.eq(ObjectUtil.isNotEmpty(dto.getUserId()), SysUserFaceEntity::getUserId, dto.getUserId())
|
||||
.eq(ObjectUtil.isNotEmpty(dto.getProcessStatus()), SysUserFaceEntity::getProcessStatus,
|
||||
dto.getProcessStatus())
|
||||
.in(ObjectUtil.isNotEmpty(dto.getProcessStatuses()), SysUserFaceEntity::getProcessStatus,
|
||||
dto.getProcessStatuses())
|
||||
.in(ObjectUtil.isNotEmpty(dto.getUserIds()), SysUserFaceEntity::getUserId, dto.getUserIds())
|
||||
.orderByDesc(SysUserFaceEntity::getCreateTime)
|
||||
.orderByDesc(SysUserFaceEntity::getUserId);
|
||||
@@ -69,4 +84,4 @@ public interface SysUserFaceMapper extends PjcloudBaseMapper<SysUserFaceEntity>
|
||||
}
|
||||
return selectJoinPage(page, SysUserFaceVo.class, wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
-1
@@ -3,18 +3,60 @@ package com.bsd.pjcloud.admin.service;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bsd.pjcloud.admin.api.dto.SysUserFaceDto;
|
||||
import com.bsd.pjcloud.admin.api.dto.SysUserFaceGuardianWardCreateDto;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUserFaceEntity;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceGuardianWardOptionVo;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceGuardianWardWithdrawVo;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceVo;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import com.bsd.pjcloud.flow.task.dto.ProcessNodeRecordAssignUserParamDto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public interface SysUserFaceService extends IService<SysUserFaceEntity> {
|
||||
|
||||
Long create(SysUserFaceEntity sysUserFace);
|
||||
|
||||
/**
|
||||
* 监护人代被监护人提交人脸,并强制进入审核流程。
|
||||
*
|
||||
* @param dto 被监护人及人脸图片
|
||||
* @return 新增的人脸记录ID
|
||||
*/
|
||||
List<Long> createGuardianWardFaces(SysUserFaceGuardianWardCreateDto dto);
|
||||
|
||||
/**
|
||||
* 查询当前监护人名下可选择的有效被监护人。
|
||||
*
|
||||
* @return 被监护人选择项列表
|
||||
*/
|
||||
List<SysUserFaceGuardianWardOptionVo> listGuardianWardOptions();
|
||||
|
||||
/**
|
||||
* 分页查询当前监护人名下全部或指定被监护人的人脸审核记录。
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param wardUserId 被监护人用户ID,为空时查询全部被监护人
|
||||
* @param processStatus 审核状态
|
||||
* @return 人脸审核记录分页数据
|
||||
*/
|
||||
Page<SysUserFaceVo> pageGuardianWardFaces(Page page, Long wardUserId, String processStatus);
|
||||
|
||||
/**
|
||||
* 查询当前监护人名下被监护人的人脸审核详情。
|
||||
*
|
||||
* @param id 人脸审核记录ID
|
||||
* @return 人脸审核详情
|
||||
*/
|
||||
SysUserFaceVo getGuardianWardFaceDetail(Long id);
|
||||
|
||||
/**
|
||||
* 撤回并删除当前监护人名下被监护人仍在审核中的人脸记录。
|
||||
*/
|
||||
SysUserFaceGuardianWardWithdrawVo cancelGuardianWardFace(Long id);
|
||||
|
||||
void edit(SysUserFaceEntity sysUserFace);
|
||||
|
||||
Boolean editGlobalFace(SysUserFaceDto dto);
|
||||
@@ -36,4 +78,4 @@ public interface SysUserFaceService extends IService<SysUserFaceEntity> {
|
||||
* 审批回调
|
||||
*/
|
||||
void applyCallback(ProcessNodeRecordAssignUserParamDto dto);
|
||||
}
|
||||
}
|
||||
+19
@@ -7,6 +7,8 @@ import com.bsd.pjcloud.admin.api.dto.user.SysUserRelationUpdateDto;
|
||||
import com.bsd.pjcloud.admin.api.entity.user.SysUserRelationEntity;
|
||||
import com.bsd.pjcloud.admin.api.vo.user.SysUserRelationGraphVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SysUserRelationService extends IService<SysUserRelationEntity> {
|
||||
|
||||
/**
|
||||
@@ -17,6 +19,23 @@ public interface SysUserRelationService extends IService<SysUserRelationEntity>
|
||||
*/
|
||||
SysUserRelationGraphVo getRelationGraph(Long userId);
|
||||
|
||||
/**
|
||||
* 判断指定用户之间是否存在有效的监护人到被监护人关系。
|
||||
*
|
||||
* @param guardianUserId 监护人用户ID
|
||||
* @param wardUserId 被监护人用户ID
|
||||
* @return 是否存在有效监护关系
|
||||
*/
|
||||
boolean hasActiveGuardianWardRelation(Long guardianUserId, Long wardUserId);
|
||||
|
||||
/**
|
||||
* 查询指定监护人当前所有有效的被监护人用户ID。
|
||||
*
|
||||
* @param guardianUserId 监护人用户ID
|
||||
* @return 被监护人用户ID列表
|
||||
*/
|
||||
List<Long> listActiveGuardianWardUserIds(Long guardianUserId);
|
||||
|
||||
/**
|
||||
* 创建用户并建立关系,新用户作为关系主语
|
||||
*
|
||||
|
||||
+257
-6
@@ -1,28 +1,34 @@
|
||||
package com.bsd.pjcloud.admin.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.admin.api.dto.SysUserFaceDto;
|
||||
import com.bsd.pjcloud.admin.api.dto.SysUserFaceGuardianWardCreateDto;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysDept;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUserFaceEntity;
|
||||
import com.bsd.pjcloud.admin.api.utils.DataUtil;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceGuardianWardOptionVo;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceGuardianWardWithdrawVo;
|
||||
import com.bsd.pjcloud.admin.api.vo.SysUserFaceVo;
|
||||
import com.bsd.pjcloud.admin.api.vo.UserVO;
|
||||
import com.bsd.pjcloud.admin.mapper.SysUserFaceMapper;
|
||||
import com.bsd.pjcloud.admin.service.SysDeptService;
|
||||
import com.bsd.pjcloud.admin.service.SysRoleService;
|
||||
import com.bsd.pjcloud.admin.service.SysUserFaceService;
|
||||
import com.bsd.pjcloud.admin.service.SysUserRelationService;
|
||||
import com.bsd.pjcloud.admin.service.SysUserService;
|
||||
import com.bsd.pjcloud.admin.utils.flow.FlowUtil;
|
||||
import com.bsd.pjcloud.admin.utils.flow.dto.UserFaceApplyFlowDto;
|
||||
import com.bsd.pjcloud.common.core.constant.CommonConstants;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.CheckedException;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import com.bsd.pjcloud.common.security.service.PjcloudUser;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
@@ -32,8 +38,6 @@ import com.bsd.pjcloud.flow.task.dto.ProcessNodeRecordAssignUserParamDto;
|
||||
import com.bsd.pjcloud.flow.task.dto.TaskDto;
|
||||
import com.bsd.pjcloud.flow.task.dto.TaskParamDto;
|
||||
import com.bsd.pjcloud.mqtt.api.feign.RemoteMqttEventService;
|
||||
import com.bsd.pjcloud.wallet.api.entity.WalletFreezeEntity;
|
||||
import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeApplyEntity;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -45,8 +49,12 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 人脸样本表
|
||||
@@ -62,9 +70,18 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
|
||||
static private final String TAG = "用户人脸";
|
||||
|
||||
/**
|
||||
* 监护人端允许查看的人脸审核状态。
|
||||
*/
|
||||
private static final List<String> GUARDIAN_WARD_VISIBLE_STATUSES = List.of(
|
||||
TaskCheckStatusEnum.PADDING.getCode(),
|
||||
TaskCheckStatusEnum.RESULT.getCode(),
|
||||
TaskCheckStatusEnum.REJECT.getCode());
|
||||
|
||||
private final SysUserService sysUserService;
|
||||
private final SysDeptService sysDeptService;
|
||||
private final SysRoleService sysRoleService;
|
||||
private final SysUserRelationService sysUserRelationService;
|
||||
|
||||
private final RemoteMqttEventService remoteMqttEventService;
|
||||
private final RemoteFlowEngineService remoteFlowEngineService;
|
||||
@@ -103,6 +120,210 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
return sysUserFace.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 监护人代被监护人提交一至两张人脸图片,所有记录强制进入审核流程。
|
||||
*
|
||||
* @param dto 被监护人及人脸图片
|
||||
* @return 新增的人脸记录ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<Long> createGuardianWardFaces(SysUserFaceGuardianWardCreateDto dto) {
|
||||
PjcloudUser loginUser = SecurityUtils.getUser();
|
||||
if (new HashSet<>(dto.getFaceImgs()).size() != dto.getFaceImgs().size()) {
|
||||
throw new RuntimeException("请勿重复提交同一张人脸图片");
|
||||
}
|
||||
SysUser guardianUser = sysUserService.getById(loginUser.getId());
|
||||
if (guardianUser == null) {
|
||||
throw new RuntimeException("监护人用户不存在");
|
||||
}
|
||||
if (sysUserService.getById(dto.getWardUserId()) == null) {
|
||||
throw new RuntimeException("被监护人用户不存在");
|
||||
}
|
||||
if (!sysUserRelationService.hasActiveGuardianWardRelation(loginUser.getId(), dto.getWardUserId())) {
|
||||
throw new RuntimeException("当前用户不是该用户的有效监护人,无法代为上传人脸");
|
||||
}
|
||||
if (sysDeptService.getById(guardianUser.getDeptId()) == null) {
|
||||
throw new RuntimeException("监护人所属部门不存在,无法发起人脸审核");
|
||||
}
|
||||
validateGuardianWardFaceLimit(dto.getWardUserId(), dto.getFaceImgs().size());
|
||||
|
||||
List<Long> faceIds = new ArrayList<>();
|
||||
for (String faceImg : dto.getFaceImgs()) {
|
||||
SysUserFaceEntity userFace = new SysUserFaceEntity();
|
||||
userFace.setUserId(dto.getWardUserId());
|
||||
userFace.setFaceImg(faceImg);
|
||||
userFace.setProcessStatus(TaskCheckStatusEnum.PADDING.getCode());
|
||||
baseMapper.insert(userFace);
|
||||
updateFaceAutoCode(userFace);
|
||||
getSelf().applyFlow(guardianUser, userFace);
|
||||
faceIds.add(userFace.getId());
|
||||
}
|
||||
return faceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前监护人名下可选择的有效被监护人,并仅返回页面展示所需字段。
|
||||
*
|
||||
* @return 被监护人选择项列表
|
||||
*/
|
||||
@Override
|
||||
public List<SysUserFaceGuardianWardOptionVo> listGuardianWardOptions() {
|
||||
List<Long> wardUserIds = sysUserRelationService.listActiveGuardianWardUserIds(SecurityUtils.getUser().getId());
|
||||
if (wardUserIds.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
Map<Long, SysUser> wardUserMap = sysUserService.listByIds(wardUserIds).stream()
|
||||
.collect(Collectors.toMap(SysUser::getUserId, Function.identity(), (first, second) -> first,
|
||||
LinkedHashMap::new));
|
||||
return wardUserIds.stream()
|
||||
.map(wardUserMap::get)
|
||||
.filter(ObjectUtil::isNotEmpty)
|
||||
.map(this::buildGuardianWardOption)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将被监护人用户转换为移动端选择项。
|
||||
*
|
||||
* @param wardUser 被监护人用户
|
||||
* @return 被监护人选择项
|
||||
*/
|
||||
private SysUserFaceGuardianWardOptionVo buildGuardianWardOption(SysUser wardUser) {
|
||||
SysUserFaceGuardianWardOptionVo option = new SysUserFaceGuardianWardOptionVo();
|
||||
option.setWardUserId(wardUser.getUserId());
|
||||
option.setWardName(StrUtil.blankToDefault(wardUser.getName(), "被监护人"));
|
||||
option.setWardAvatar(wardUser.getAvatar());
|
||||
return option;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询当前监护人名下全部或指定被监护人的人脸审核记录。
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param wardUserId 被监护人用户ID,为空时查询全部被监护人
|
||||
* @param processStatus 审核状态
|
||||
* @return 人脸审核记录分页数据
|
||||
*/
|
||||
@Override
|
||||
public Page<SysUserFaceVo> pageGuardianWardFaces(Page page, Long wardUserId, String processStatus) {
|
||||
Long guardianUserId = SecurityUtils.getUser().getId();
|
||||
List<Long> wardUserIds = sysUserRelationService.listActiveGuardianWardUserIds(guardianUserId);
|
||||
if (wardUserIds.isEmpty()) {
|
||||
return new Page<>(page.getCurrent(), page.getSize());
|
||||
}
|
||||
if (wardUserId != null && !wardUserIds.contains(wardUserId)) {
|
||||
throw new RuntimeException("当前用户不是该用户的有效监护人,无权查看人脸审核记录");
|
||||
}
|
||||
SysUserFaceDto query = new SysUserFaceDto();
|
||||
if (wardUserId == null) {
|
||||
query.setUserIds(wardUserIds);
|
||||
} else {
|
||||
query.setUserId(wardUserId);
|
||||
}
|
||||
if (StrUtil.isNotBlank(processStatus)) {
|
||||
if (!GUARDIAN_WARD_VISIBLE_STATUSES.contains(processStatus)) {
|
||||
throw new RuntimeException("不支持查询该人脸审核状态");
|
||||
}
|
||||
query.setProcessStatus(processStatus);
|
||||
} else {
|
||||
query.setProcessStatuses(GUARDIAN_WARD_VISIBLE_STATUSES);
|
||||
}
|
||||
return baseMapper.pageJoin(page, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前监护人名下被监护人的人脸审核详情。
|
||||
*
|
||||
* @param id 人脸审核记录ID
|
||||
* @return 人脸审核详情
|
||||
*/
|
||||
@Override
|
||||
public SysUserFaceVo getGuardianWardFaceDetail(Long id) {
|
||||
SysUserFaceVo detail = baseMapper.join(id);
|
||||
if (detail == null) {
|
||||
throw new RuntimeException("人脸审核记录不存在");
|
||||
}
|
||||
validateGuardianWardUser(SecurityUtils.getUser().getId(), detail.getUserId());
|
||||
return detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回并删除当前监护人名下被监护人仍在审核中的人脸记录。
|
||||
*
|
||||
* @param id 人脸审核记录ID
|
||||
* @return 重新编辑人脸时需要的被监护人和图片信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SysUserFaceGuardianWardWithdrawVo cancelGuardianWardFace(Long id) {
|
||||
SysUserFaceVo detail = baseMapper.join(id);
|
||||
if (detail == null) {
|
||||
throw new RuntimeException("人脸审核记录不存在");
|
||||
}
|
||||
validateGuardianWardUser(SecurityUtils.getUser().getId(), detail.getUserId());
|
||||
if (!ObjectUtil.equals(detail.getProcessStatus(), TaskCheckStatusEnum.PADDING.getCode())) {
|
||||
throw new RuntimeException("只有审核中的人脸记录可以撤销");
|
||||
}
|
||||
boolean deleted = update(new LambdaUpdateWrapper<SysUserFaceEntity>()
|
||||
.eq(SysUserFaceEntity::getId, detail.getId())
|
||||
.eq(SysUserFaceEntity::getProcessStatus, TaskCheckStatusEnum.PADDING.getCode())
|
||||
.set(SysUserFaceEntity::getDelFlag, CommonConstants.STATUS_DEL)
|
||||
.set(SysUserFaceEntity::getUpdateTime, LocalDateTime.now()));
|
||||
if (!deleted) {
|
||||
throw new RuntimeException("人脸审核状态已发生变化,请刷新后重试");
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(detail.getProcessId())) {
|
||||
TaskParamDto taskParam = new TaskParamDto();
|
||||
taskParam.setProcessInstanceIdList(List.of(detail.getProcessId()));
|
||||
R<String> stopResult = remoteFlowEngineService.stopProcessInstance(taskParam);
|
||||
if (stopResult == null || !stopResult.isOk()) {
|
||||
String errorMessage = stopResult == null ? null : stopResult.getMsg();
|
||||
throw new RuntimeException(StrUtil.blankToDefault(errorMessage, "停止人脸审核流程失败"));
|
||||
}
|
||||
}
|
||||
|
||||
SysUserFaceGuardianWardWithdrawVo result = new SysUserFaceGuardianWardWithdrawVo();
|
||||
result.setWardUserId(detail.getUserId());
|
||||
result.setWardName(detail.getUsername());
|
||||
result.setFaceImg(detail.getFaceImg());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验指定用户是否属于当前监护人的有效被监护人范围。
|
||||
*/
|
||||
private void validateGuardianWardUser(Long guardianUserId, Long wardUserId) {
|
||||
List<Long> wardUserIds = sysUserRelationService.listActiveGuardianWardUserIds(guardianUserId);
|
||||
if (!wardUserIds.contains(wardUserId)) {
|
||||
throw new RuntimeException("当前用户不是该用户的有效监护人,无权查看或操作人脸审核记录");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新人脸记录的自增编码。
|
||||
*/
|
||||
private void updateFaceAutoCode(SysUserFaceEntity userFace) {
|
||||
Long count = baseMapper.selectAllCount();
|
||||
SysUserFaceEntity updateObj = new SysUserFaceEntity();
|
||||
updateObj.setId(userFace.getId());
|
||||
updateObj.setAutoCode(String.valueOf(count));
|
||||
baseMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验被监护人审核中和已通过的人脸总数是否超过三张。
|
||||
*/
|
||||
private void validateGuardianWardFaceLimit(Long wardUserId, int uploadCount) {
|
||||
Long count = baseMapper.selectCount(new LambdaQueryWrapper<SysUserFaceEntity>()
|
||||
.eq(SysUserFaceEntity::getUserId, wardUserId)
|
||||
.in(SysUserFaceEntity::getProcessStatus,
|
||||
TaskCheckStatusEnum.PADDING.getCode(), TaskCheckStatusEnum.RESULT.getCode()));
|
||||
if (count + uploadCount > 3) {
|
||||
throw new RuntimeException("审核中和已通过的人脸合计最多只能保留3张");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void edit(SysUserFaceEntity sysUserFace) {
|
||||
SysUserFaceEntity userFace = baseMapper.selectById(sysUserFace.getId());
|
||||
@@ -258,7 +479,19 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
try {
|
||||
Boolean isConsent = flowUtil.isConsent(dto);
|
||||
String processStatus = isConsent ? TaskCheckStatusEnum.RESULT.getCode() : TaskCheckStatusEnum.REJECT.getCode();
|
||||
baseMapper.updateById(SysUserFaceEntity.builder().id(detail.getId()).processTime(LocalDateTime.now()).processStatus(processStatus).build());
|
||||
boolean updated = update(new LambdaUpdateWrapper<SysUserFaceEntity>()
|
||||
.eq(SysUserFaceEntity::getId, detail.getId())
|
||||
.eq(SysUserFaceEntity::getProcessStatus, TaskCheckStatusEnum.PADDING.getCode())
|
||||
.set(SysUserFaceEntity::getProcessTime, LocalDateTime.now())
|
||||
.set(SysUserFaceEntity::getProcessStatus, processStatus)
|
||||
.set(SysUserFaceEntity::getRejectReason, isConsent ? null : getRejectReason(dto)));
|
||||
if (!updated) {
|
||||
log.warn("|{}|人脸审核状态已变化,忽略本次审批回调,dto:|{}|", TAG, JSON.toJSONString(dto));
|
||||
return;
|
||||
}
|
||||
if (isConsent) {
|
||||
sendFaceMq(List.of(detail.getUserId()), null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("|{}|审批回调意外的错误,dto:|{}|error:|{}|", TAG, JSON.toJSONString(dto), e.getMessage());
|
||||
@@ -266,6 +499,24 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从审批回调中提取拒绝原因,并限制为数据库字段允许的长度。
|
||||
*
|
||||
* @param dto 审批回调参数
|
||||
* @return 审核拒绝原因
|
||||
*/
|
||||
private String getRejectReason(ProcessNodeRecordAssignUserParamDto dto) {
|
||||
String rejectReason = StrUtil.trim(dto.getApproveDesc());
|
||||
if (StrUtil.isBlank(rejectReason) && StrUtil.isNotBlank(dto.getData())) {
|
||||
try {
|
||||
rejectReason = StrUtil.trim(JSON.parseObject(dto.getData()).getString("approveDesc"));
|
||||
} catch (Exception e) {
|
||||
log.warn("|{}|解析人脸审核拒绝原因失败,dto:|{}|", TAG, JSON.toJSONString(dto));
|
||||
}
|
||||
}
|
||||
return StrUtil.sub(StrUtil.blankToDefault(rejectReason, "未填写拒绝原因"), 0, 500);
|
||||
}
|
||||
|
||||
// 上传的人脸是否超过最大限制
|
||||
private Boolean isExceedMax(Long userId) {
|
||||
Long count = baseMapper.selectCount(new LambdaQueryWrapper<SysUserFaceEntity>().eq(SysUserFaceEntity::getUserId, userId).eq(SysUserFaceEntity::getProcessStatus, TaskCheckStatusEnum.RESULT.getCode()));
|
||||
@@ -289,4 +540,4 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
private SysUserFaceServiceImpl getSelf() {
|
||||
return SpringUtil.getBean(getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -7,6 +7,7 @@ import com.bsd.pjcloud.admin.api.dto.UserDTO;
|
||||
import com.bsd.pjcloud.admin.api.dto.user.SysUserRelationCreateUserDto;
|
||||
import com.bsd.pjcloud.admin.api.dto.user.SysUserRelationCreateDto;
|
||||
import com.bsd.pjcloud.admin.api.dto.user.SysUserRelationUpdateDto;
|
||||
import com.bsd.pjcloud.admin.api.constant.user.UserRelationTypeEnum;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.entity.user.SysUserRelationEntity;
|
||||
import com.bsd.pjcloud.admin.api.entity.user.SysUserRelationTypeEntity;
|
||||
@@ -93,6 +94,58 @@ public class SysUserRelationServiceImpl extends ServiceImpl<SysUserRelationMappe
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断指定用户之间是否存在有效的监护人到被监护人关系。
|
||||
*
|
||||
* @param guardianUserId 监护人用户ID
|
||||
* @param wardUserId 被监护人用户ID
|
||||
* @return 是否存在有效监护关系
|
||||
*/
|
||||
@Override
|
||||
public boolean hasActiveGuardianWardRelation(Long guardianUserId, Long wardUserId) {
|
||||
return listActiveGuardianWardUserIds(guardianUserId).contains(wardUserId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定监护人当前所有有效的被监护人用户ID。
|
||||
*
|
||||
* @param guardianUserId 监护人用户ID
|
||||
* @return 被监护人用户ID列表
|
||||
*/
|
||||
@Override
|
||||
public List<Long> listActiveGuardianWardUserIds(Long guardianUserId) {
|
||||
SysUserRelationTypeEntity relationType = getActiveGuardianWardRelationType();
|
||||
if (relationType == null) {
|
||||
return List.of();
|
||||
}
|
||||
return list(Wrappers.<SysUserRelationEntity>lambdaQuery()
|
||||
.eq(SysUserRelationEntity::getSubjectUserId, guardianUserId)
|
||||
.eq(SysUserRelationEntity::getRelationTypeId, relationType.getRelationTypeId())
|
||||
.and(wrapper -> wrapper.isNull(SysUserRelationEntity::getEffectiveTime)
|
||||
.or().le(SysUserRelationEntity::getEffectiveTime, java.time.LocalDateTime.now()))
|
||||
.and(wrapper -> wrapper.isNull(SysUserRelationEntity::getExpireTime)
|
||||
.or().ge(SysUserRelationEntity::getExpireTime, java.time.LocalDateTime.now())))
|
||||
.stream()
|
||||
.map(SysUserRelationEntity::getObjectUserId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前启用的监护关系类型。
|
||||
*
|
||||
* @return 启用的监护关系类型,不存在时返回空
|
||||
*/
|
||||
private SysUserRelationTypeEntity getActiveGuardianWardRelationType() {
|
||||
return sysUserRelationTypeService.getOne(
|
||||
Wrappers.<SysUserRelationTypeEntity>lambdaQuery()
|
||||
.eq(SysUserRelationTypeEntity::getRelationCode,
|
||||
UserRelationTypeEnum.GUARDIAN_WARD.getRelationCode())
|
||||
.eq(SysUserRelationTypeEntity::getStatus, CommonConstants.STATUS_NORMAL)
|
||||
.last("limit 1"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createUserAndRelation(SysUserRelationCreateUserDto dto) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<resultMap id="sysUserFaceMap" type="com.bsd.pjcloud.admin.api.entity.SysUserFaceEntity">
|
||||
<id property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="rejectReason" column="reject_reason"/>
|
||||
<result property="faceImg" column="face_img"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
@@ -20,6 +21,7 @@
|
||||
a.user_id,
|
||||
a.process_id,
|
||||
a.process_status,
|
||||
a.reject_reason,
|
||||
a.face_img,
|
||||
a.create_by,
|
||||
a.create_time,
|
||||
@@ -35,9 +37,21 @@
|
||||
<if test="pa.userId != null">
|
||||
and a.user_id = #{pa.userId}
|
||||
</if>
|
||||
<if test="pa.userIds != null and pa.userIds.size() != 0">
|
||||
and a.user_id in
|
||||
<foreach collection="pa.userIds" item="userId" open="(" separator="," close=")">
|
||||
#{userId}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="pa.processStatus != null">
|
||||
and a.process_status = #{pa.processStatus}
|
||||
</if>
|
||||
<if test="pa.processStatuses != null and pa.processStatuses.size() != 0">
|
||||
and a.process_status in
|
||||
<foreach collection="pa.processStatuses" item="status" open="(" separator="," close=")">
|
||||
#{status}
|
||||
</foreach>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="scopePageList" resultType="com.bsd.pjcloud.admin.api.vo.SysUserFaceVo">
|
||||
@@ -53,10 +67,10 @@
|
||||
left join sys_dept d on d.dept_id = u.dept_id and d.del_flag = '0'
|
||||
<where>
|
||||
<include refid="whereA"/>
|
||||
<if test="pa.username != null">
|
||||
<if test="pa.username != null and pa.username != ''">
|
||||
and u.name LIKE CONCAT('%', #{pa.username}, '%')
|
||||
</if>
|
||||
<if test="pa.phone != null">
|
||||
<if test="pa.phone != null and pa.phone != ''">
|
||||
and u.phone LIKE CONCAT('%', #{pa.phone}, '%')
|
||||
</if>
|
||||
</where>
|
||||
@@ -81,4 +95,4 @@
|
||||
</where>
|
||||
GROUP BY a.user_id
|
||||
</select>
|
||||
</mapper>
|
||||
</mapper>
|
||||
+23
@@ -15,6 +15,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -66,6 +67,28 @@ class SysUserRelationServiceImplTest {
|
||||
assertFalse(graph.getChildren().stream().anyMatch(child -> !child.getChildren().isEmpty()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证监护人查询有效被监护人时,可以返回关系对象用户并自动去重。
|
||||
*/
|
||||
@Test
|
||||
void shouldListDistinctActiveGuardianWardUserIds() {
|
||||
SysUserRelationTypeService relationTypeService = mock(SysUserRelationTypeService.class);
|
||||
SysUserRelationServiceImpl service = spy(
|
||||
new SysUserRelationServiceImpl(mock(SysUserService.class), relationTypeService));
|
||||
when(relationTypeService.getOne(any())).thenReturn(createGuardianRelationType());
|
||||
doReturn(List.of(
|
||||
createRelation(2079104982669385730L, FIRST_WARD_USER_ID),
|
||||
createRelation(2079129636280758273L, SECOND_WARD_USER_ID),
|
||||
createRelation(2079129636280758274L, SECOND_WARD_USER_ID)))
|
||||
.when(service).list(org.mockito.ArgumentMatchers.<Wrapper<SysUserRelationEntity>>any());
|
||||
|
||||
List<Long> wardUserIds = service.listActiveGuardianWardUserIds(GUARDIAN_USER_ID);
|
||||
|
||||
assertEquals(List.of(FIRST_WARD_USER_ID, SECOND_WARD_USER_ID), wardUserIds);
|
||||
assertTrue(service.hasActiveGuardianWardRelation(GUARDIAN_USER_ID, SECOND_WARD_USER_ID));
|
||||
assertFalse(service.hasActiveGuardianWardRelation(GUARDIAN_USER_ID, 999L));
|
||||
}
|
||||
|
||||
private SysUserRelationEntity createRelation(Long relationId, Long wardUserId) {
|
||||
SysUserRelationEntity relation = new SysUserRelationEntity();
|
||||
relation.setRelationId(relationId);
|
||||
|
||||
Reference in new issue
Block a user