feat:车牌申请

This commit is contained in:
dzc committed 2025-08-26 19:39:38 +08:00
1 parent 9eaa9998c3
commit 5c6549713d
9 files changed
+279 -21

No files matched your search

+16 -11
View File
@@ -65,17 +65,22 @@ CREATE INDEX idx_dept_id ON sys_user_face (user_id);
DROP TABLE IF EXISTS sys_user_car;
CREATE TABLE `sys_user_car`
(
id bigint NOT NULL COMMENT '编号',
user_id bigint NOT NULL COMMENT '用户ID',
car_number char(64) COMMENT '车牌号',
car_type char(32) COMMENT '车辆类型(字典)',
enable_status char(32) COMMENT '启用状态(字典)',
create_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
create_time datetime DEFAULT NULL COMMENT '创建时间',
update_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
update_time datetime DEFAULT NULL COMMENT '修改时间',
del_flag char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
tenant_id bigint DEFAULT NULL COMMENT '租户ID',
id bigint NOT NULL COMMENT '编号',
user_id bigint NOT NULL COMMENT '用户ID',
car_number char(64) COMMENT '车牌号',
car_type char(32) COMMENT '车辆类型(字典)',
enable_status char(32) COMMENT '启用状态(字典)',
process_id varchar(256) COMMENT '流程id',
process_status varchar(10) NOT NULL COMMENT '审核状体',
process_time datetime COMMENT '审核时间',
create_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
create_time datetime DEFAULT NULL COMMENT '创建时间',
update_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
update_time datetime DEFAULT NULL COMMENT '修改时间',
del_flag char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
tenant_id bigint DEFAULT NULL COMMENT '租户ID',
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
@@ -0,0 +1,33 @@
package com.bsd.pjcloud.admin.api.constant.car;
import cn.hutool.core.util.ObjectUtil;
import com.bsd.pjcloud.admin.api.constant.UserTransactionEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 车辆类型
*/
@AllArgsConstructor
@Getter
public enum CarTypeEnum {
SELF("1", "私家车"),
PUBLIC("2", "公车"),
ARMY("3", "军车"),
POLICE("4", "警车"),
;
private final String type;
private final String description;
public static CarTypeEnum valueOfByType(String type) {
if (ObjectUtil.isEmpty(type)) return null;
return Arrays.stream(values()).filter(v -> ObjectUtil.equals(type, v.getType())).findFirst().get();
}
}
@@ -1,21 +1,23 @@
package com.bsd.pjcloud.admin.api.dto.car;
import com.bsd.pjcloud.admin.api.entity.car.SysUserCarEntity;
import com.bsd.pjcloud.admin.api.vo.base.BaseUserInterface;
import com.bsd.pjcloud.admin.api.vo.base.BaseUserDeptInterface;
import lombok.Data;
@Data
public class SysUserCarDto extends SysUserCarEntity implements BaseUserInterface {
public class SysUserCarDto extends SysUserCarEntity implements BaseUserDeptInterface {
/**
* 用户相关
*/
private Long userId;
private String username;
private String userMobile;
private String userAvatar;
private Long userDeptId;
private String userDeptName;
}
@@ -3,8 +3,9 @@ package com.bsd.pjcloud.admin.api.entity.car;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import com.bsd.pjcloud.common.core.util.TenantTable;
import java.time.LocalDateTime;
@@ -17,6 +18,9 @@ import java.time.LocalDateTime;
@TableName("sys_user_car")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "车辆管理")
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SysUserCarEntity extends Model<SysUserCarEntity> {
@@ -31,18 +35,21 @@ public class SysUserCarEntity extends Model<SysUserCarEntity> {
* 用户ID
*/
@Schema(description = "用户ID")
@NotNull(message = "用户ID不能为空")
private Long userId;
/**
* 车牌号
*/
@Schema(description = "车牌号")
@NotEmpty(message = "车牌号不能为空")
private String carNumber;
/**
* 车辆类型(字典)
*/
@Schema(description = "车辆类型(字典)")
@NotEmpty(message = "车辆类型不能为空")
private String carType;
/**
@@ -51,6 +58,24 @@ public class SysUserCarEntity extends Model<SysUserCarEntity> {
@Schema(description = "启用状态(字典)")
private String enableStatus;
/**
* 流程id
*/
@Schema(description = "流程id")
private String processId;
/**
* 审核状体
*/
@Schema(description = "审核状体")
private String processStatus;
/**
* 审核时间
*/
@Schema(description = "审核时间")
private LocalDateTime processTime;
/**
* 创建人
*/
@@ -1,8 +1,23 @@
package com.bsd.pjcloud.admin.api.vo.car;
import com.bsd.pjcloud.admin.api.entity.car.SysUserCarEntity;
import com.bsd.pjcloud.admin.api.vo.base.BaseUserDeptInterface;
import lombok.Data;
@Data
public class SysUserCarVo extends SysUserCarEntity {
public class SysUserCarVo extends SysUserCarEntity implements BaseUserDeptInterface {
/**
* 用户相关
*/
private String username;
private String userMobile;
private String userAvatar;
private Long userDeptId;
private String userDeptName;
}
@@ -2,8 +2,6 @@ package com.bsd.pjcloud.admin.controller.car;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
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.car.SysUserCarDto;
@@ -13,6 +11,10 @@ import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.admin.service.SysUserCarService;
import com.bsd.pjcloud.common.security.annotation.Inner;
import com.bsd.pjcloud.common.security.service.PjcloudUser;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.flow.task.dto.ProcessNodeRecordAssignUserParamDto;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -21,6 +23,7 @@ import org.springframework.http.HttpHeaders;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@@ -38,6 +41,26 @@ public class SysUserCarController {
private final SysUserCarService sysUserCarService;
/* ************************************* start callback start ************************************* */
@Inner(value = false)
@PostMapping("/apply-callback")
public void applyCallback(@RequestBody ProcessNodeRecordAssignUserParamDto dto, @RequestParam(required = false) Long tenantId) {
sysUserCarService.applyCallback(dto, tenantId);
}
/* ************************************* end callback end ************************************* */
/* ************************************* start app start ************************************* */
@PostMapping("/app/create")
public void appCreateCar(@Validated @RequestBody SysUserCarDto dto) {
PjcloudUser user = SecurityUtils.getUser();
dto.setUserId(user.getId());
sysUserCarService.appCreateCar(dto);
}
/* ************************************* end app end ************************************* */
/**
* 分页查询
*/
@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.admin.api.dto.car.SysUserCarDto;
import com.bsd.pjcloud.admin.api.entity.car.SysUserCarEntity;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.flow.task.dto.ProcessNodeRecordAssignUserParamDto;
public interface SysUserCarService extends IService<SysUserCarEntity> {
@@ -14,4 +15,14 @@ public interface SysUserCarService extends IService<SysUserCarEntity> {
Long create(SysUserCarDto sysUserCar);
void edit(SysUserCarDto sysUserCar);
/**
* app创建车辆
*/
void appCreateCar(SysUserCarDto dto);
/**
* 审批回调
*/
void applyCallback(ProcessNodeRecordAssignUserParamDto dto, Long tenantId);
}
@@ -1,29 +1,67 @@
package com.bsd.pjcloud.admin.service.impl.car;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.admin.api.constant.car.CarTypeEnum;
import com.bsd.pjcloud.admin.api.dto.car.SysUserCarDto;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.entity.SysUser;
import com.bsd.pjcloud.admin.api.entity.car.SysUserCarEntity;
import com.bsd.pjcloud.admin.api.utils.DataUtil;
import com.bsd.pjcloud.admin.api.vo.UserVO;
import com.bsd.pjcloud.admin.api.vo.car.SysUserCarVo;
import com.bsd.pjcloud.admin.mapper.car.SysUserCarMapper;
import com.bsd.pjcloud.admin.service.SysDeptService;
import com.bsd.pjcloud.admin.service.SysUserCarService;
import com.bsd.pjcloud.admin.service.SysUserService;
import com.bsd.pjcloud.admin.utils.flow.FlowUtil;
import com.bsd.pjcloud.admin.utils.flow.dto.UserCarFlowDto;
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
import com.bsd.pjcloud.common.core.util.CollectionUtils;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.data.tenant.TenantContextHolder;
import com.bsd.pjcloud.flow.task.constant.TaskCheckStatusEnum;
import com.bsd.pjcloud.flow.task.dto.ProcessNodeRecordAssignUserParamDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* 车辆管理
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserCarServiceImpl extends ServiceImpl<SysUserCarMapper, SysUserCarEntity> implements SysUserCarService {
static private final String TAG = "车辆管理";
private final SysUserService userService;
private final SysDeptService deptService;
private final FlowUtil flowUtil;
@Override
public Page<SysUserCarVo> scopePageJoin(Page page, SysUserCarDto dto, DataScope dataScope) {
return baseMapper.scopePageJoin(page, dto, dataScope);
Page<SysUserCarVo> pageList = baseMapper.scopePageJoin(page, dto, dataScope);
disposeList(pageList.getRecords());
return pageList;
}
@Override
public Long create(SysUserCarDto sysUserCar) {
if (existName(sysUserCar)) {
@@ -32,6 +70,10 @@ public class SysUserCarServiceImpl extends ServiceImpl<SysUserCarMapper, SysUser
if (ObjectUtil.isEmpty(sysUserCar.getEnableStatus())) {
sysUserCar.setEnableStatus(YesNoEnum.YES.getCode());
}
// 后台新增,默认审核通过
sysUserCar.setProcessStatus(TaskCheckStatusEnum.RESULT.getCode());
baseMapper.insert(sysUserCar);
return sysUserCar.getId();
}
@@ -44,6 +86,78 @@ public class SysUserCarServiceImpl extends ServiceImpl<SysUserCarMapper, SysUser
baseMapper.updateById(sysUserCar);
}
/**
* app创建车辆
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void appCreateCar(SysUserCarDto dto) {
if (existName(dto)) {
throw new RuntimeException("车牌号不能重复");
}
if (ObjectUtil.isEmpty(dto.getEnableStatus())) {
dto.setEnableStatus(YesNoEnum.YES.getCode());
}
// 查询申请用户
SysUser user = userService.getById(dto.getUserId());
// 查询申请部门
SysDept dept = deptService.getById(user.getDeptId());
baseMapper.insert(dto);
// 创建审批
UserCarFlowDto flowDto = new UserCarFlowDto();
flowDto.setApplyUsername(user.getUsername());
flowDto.setApplyUserId(user.getUserId());
flowDto.setApplyDeptName(dept.getName());
flowDto.setApplyDeptId(dept.getDeptId());
flowDto.setApplyCreateTime(LocalDateTimeUtil.format(dto.getCreateTime(), DatePattern.NORM_DATETIME_PATTERN));
flowDto.setCarNumber(dto.getCarNumber());
flowDto.setCarType(CarTypeEnum.valueOfByType(dto.getCarType()).getDescription());
String processId = flowUtil.startFlow("TASK_APPLY_USER_CAR", user, dto.getId(), flowDto);
// 更新
SysUserCarEntity updateObj = new SysUserCarEntity();
updateObj.setId(dto.getId());
updateObj.setProcessId(processId);
updateObj.setProcessStatus(TaskCheckStatusEnum.PADDING.getCode());
updateObj.setProcessTime(LocalDateTime.now());
baseMapper.updateById(updateObj);
}
/**
* 审批回调
*/
@Override
public void applyCallback(ProcessNodeRecordAssignUserParamDto dto, Long tenantId) {
if (!flowUtil.checkCallback(dto)) {
return;
}
if (ObjectUtil.isNotEmpty(tenantId) && ObjectUtil.notEqual(tenantId, 1L)) {
TenantContextHolder.setTenantId(tenantId);
}
String processId = dto.getProcessInstanceId();
SysUserCarEntity detail = baseMapper.selectOne(new LambdaQueryWrapper<SysUserCarEntity>().eq(SysUserCarEntity::getProcessId, processId));
if (ObjectUtil.isEmpty(detail)) {
return;
}
if (!ObjectUtil.equals(detail.getProcessStatus(), TaskCheckStatusEnum.PADDING.getCode())) {
log.error("|{}|重复的回调,dto:|{}|", TAG, JSON.toJSONString(dto));
return;
}
try {
Boolean isConsent = flowUtil.isConsent(dto);
String processStatus = isConsent ? TaskCheckStatusEnum.RESULT.getCode() : TaskCheckStatusEnum.REJECT.getCode();
baseMapper.updateById(SysUserCarEntity.builder().id(detail.getId()).processTime(LocalDateTime.now()).processStatus(processStatus).build());
} catch (Exception e) {
e.printStackTrace();
log.error("|{}|审批回调意外的错误,dto:|{}|error:|{}|", TAG, JSON.toJSONString(dto), e.getMessage());
throw new RuntimeException(e);
}
}
// 判断车牌号是否重复
private boolean existName(SysUserCarEntity dto) {
Long count = baseMapper.selectCount(new LambdaQueryWrapper<SysUserCarEntity>()
@@ -55,4 +169,21 @@ public class SysUserCarServiceImpl extends ServiceImpl<SysUserCarMapper, SysUser
}
return count > 0;
}
private void disposeList(List<SysUserCarVo> list) {
if (ObjectUtil.isEmpty(list)) return;
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 用户部门
CompletableFuture<Void> deptUserFuture = CompletableFuture.runAsync(() -> {
RequestContextHolder.setRequestAttributes(requestAttributes);
List<Long> userIds = list.stream().map(SysUserCarVo::getUserId).filter(ObjectUtil::isNotEmpty).distinct().toList();
if (ObjectUtil.isNotEmpty(userIds)) {
List<UserVO> userList = userService.getUserDeptByIds(new ArrayList<>(userIds));
if (ObjectUtil.isNotEmpty(userList)) {
DataUtil.convertUserDeptList(list, CollectionUtils.convertMap(userList, UserVO::getUserId));
}
}
});
CompletableFuture.allOf(deptUserFuture).join();
}
}
@@ -0,0 +1,13 @@
package com.bsd.pjcloud.admin.utils.flow.dto;
import com.bsd.pjcloud.flow.task.dto.base.FlowBaseDto;
import lombok.Data;
@Data
public class UserCarFlowDto extends FlowBaseDto {
private String carNumber;
private String carType;
}