✨ 新增认证记录不可变快照数据模型与迁移脚本
按 ADR-0001/0002 建立司机与车辆共用的认证记录表 blade_transport_cert_record (biz_type 区分、载荷存 JSON、检索字段提升为真实列),并为司机/车辆表补生效快照指针。 不变式结构性保证: - I1 同对象至多一条待审:生成列 pending_biz_id + 唯一索引,数据库层拦截; 生成列同时排除 is_deleted,避免逻辑删除的待审记录永久占用唯一键。 - I3 快照不可变:snapshot_json 等 5 列标 FieldStrategy.NEVER,永不进入 UPDATE。 - status 承载审核状态(0审核中/1已通过/2已驳回/3已作废),新增时必须显式设置: 框架 resolveEntity 会把 null 的 status 静默填成 1(即「已通过」), 且继承来的 changeStatus 可直接写 status,两条通道均已封堵。 其他:司机表补身份证有效期三列并订正排序规则为 utf8mb4_general_ci (原先为 0900_ai_ci,与车辆表 JOIN 已发生过 Illegal mix of collations); 生效快照指针加 @JsonProperty(READ_ONLY),防止以 /submit 请求体自行「认证」自己; 同步基线建表脚本与认证审核菜单/权限码。本票不含任何业务接口。
This commit is contained in:
+44
@@ -28,6 +28,9 @@ package org.springblade.transport.pojo.entity;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -111,6 +114,21 @@ public class Driver extends TenantEntity {
|
||||
*/
|
||||
@Schema(description = "身份证反面照")
|
||||
private String idCardBack;
|
||||
/**
|
||||
* 身份证有效期起
|
||||
*/
|
||||
@Schema(description = "身份证有效期起")
|
||||
private LocalDate idCardValidStart;
|
||||
/**
|
||||
* 身份证有效期止
|
||||
*/
|
||||
@Schema(description = "身份证有效期止")
|
||||
private LocalDate idCardValidEnd;
|
||||
/**
|
||||
* 身份证长期有效
|
||||
*/
|
||||
@Schema(description = "身份证长期有效")
|
||||
private Integer idCardLongTerm;
|
||||
/**
|
||||
* 大头照
|
||||
*/
|
||||
@@ -221,5 +239,31 @@ public class Driver extends TenantEntity {
|
||||
*/
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
/**
|
||||
* 最新提交状态展示缓存:0审核中 1已通过 2已驳回 3已作废,null 表示从未提交
|
||||
* <p>
|
||||
* 仅为列表展示而冗余,<b>不是</b>可用性判据;「是否已认证」一律读生效快照指针。
|
||||
*/
|
||||
@Schema(description = "最新提交状态展示缓存:0审核中 1已通过 2已驳回 3已作废,null为从未提交")
|
||||
private Integer certificationStatus;
|
||||
/**
|
||||
* 最新一次驳回原因展示缓存
|
||||
*/
|
||||
@Schema(description = "最新一次驳回原因展示缓存")
|
||||
private String certificationRejectReason;
|
||||
/**
|
||||
* 生效快照指针:指向 blade_transport_cert_record.id
|
||||
* <p>
|
||||
* 「该司机是否已认证」的<b>唯一</b>判据。为 null 表示从未认证通过;
|
||||
* 一经设置<b>永不回退</b>——提交、驳回、作废都不得修改它(见 ADR-0002)。
|
||||
* <p>
|
||||
* ⚠️ {@code READ_ONLY}:本字段<b>只能由审核链路</b>(03)写入。
|
||||
* 司机档案的 {@code /submit} 直接以本实体接收请求体,若允许反序列化,
|
||||
* 调用方就能自行填一个记录 ID 把自己「认证」掉,绕过审核与 D10 的可用性门槛。
|
||||
*/
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "生效快照指针")
|
||||
private Long effectiveCertRecordId;
|
||||
|
||||
}
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springblade.core.tenant.mp.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 认证记录实体类
|
||||
* <p>
|
||||
* 认证对象(司机 / 车辆)<b>每一次提交</b>所产生的、<b>不可变</b>的快照。
|
||||
* 记录一经创建,其 {@code snapshotJson} 与提交元信息永不修改;被同对象的后续提交取代时
|
||||
* 标记为「已作废」,而<b>不是</b>删除。判定某个对象「是否已认证」只看它持有的生效快照指针,
|
||||
* 与记录表里的任何一条记录的状态都无关。
|
||||
* <p>
|
||||
* 设计依据:{@code docs/adr/0001-certification-record-immutable-snapshot.md},
|
||||
* 术语见根工作区 {@code GLOSSARY.md}。
|
||||
* <p>
|
||||
* ⚠️ <b>{@code status} 承载的是「审核状态」,不是 BladeX 的「启用 / 停用」。</b>
|
||||
* 该字段继承自 {@link TenantEntity},带来两条必须堵住的框架通道:
|
||||
* 一是 {@code BaseServiceImpl#resolveEntity} 在插入时会把 {@code null} 的 {@code status}
|
||||
* <b>静默填成 {@code 1}</b>(恰好是 {@link #STATUS_APPROVED});
|
||||
* 二是继承来的 {@code changeStatus(ids, 1)} 会直接写 {@code status},等于批量通过审核。
|
||||
* 二者都已在 {@code TransportCertRecordServiceImpl} 中封堵(前者校验抛错、后者覆写抛错),
|
||||
* 审核一律走 03 的审核接口。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("blade_transport_cert_record")
|
||||
@Schema(description = "认证记录")
|
||||
public class TransportCertRecord extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 认证对象类型:司机
|
||||
*/
|
||||
public static final String BIZ_TYPE_DRIVER = "driver";
|
||||
/**
|
||||
* 认证对象类型:车辆
|
||||
*/
|
||||
public static final String BIZ_TYPE_VEHICLE = "vehicle";
|
||||
|
||||
/**
|
||||
* 审核状态:审核中(即该对象的「待审快照」)
|
||||
*/
|
||||
public static final Integer STATUS_PENDING = 0;
|
||||
/**
|
||||
* 审核状态:已通过(该对象最新一条已通过者即其「生效快照」)
|
||||
*/
|
||||
public static final Integer STATUS_APPROVED = 1;
|
||||
/**
|
||||
* 审核状态:已驳回(审核的否定结论,需带驳回原因)
|
||||
*/
|
||||
public static final Integer STATUS_REJECTED = 2;
|
||||
/**
|
||||
* 审核状态:已作废(被同对象的再次提交取代,非驳回)
|
||||
*/
|
||||
public static final Integer STATUS_SUPERSEDED = 3;
|
||||
|
||||
/**
|
||||
* 认证对象类型:driver-司机,vehicle-车辆
|
||||
* <p>
|
||||
* {@code NEVER}:记录一经创建,认证对象的身份不可改(详见类注释的不变式 I3)。
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@Schema(description = "认证对象类型:driver-司机,vehicle-车辆")
|
||||
private String bizType;
|
||||
/**
|
||||
* 认证对象主键:司机ID 或 车辆ID(车辆按具体车辆,不是司机)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "认证对象主键")
|
||||
private Long bizId;
|
||||
/**
|
||||
* 展示键:司机姓名 / 车牌号,供审核列表直接展示
|
||||
*/
|
||||
@Schema(description = "展示键:司机姓名 / 车牌号")
|
||||
private String bizKey;
|
||||
/**
|
||||
* 该次提交的全量认证内容(JSON),一经创建不可修改
|
||||
* <p>
|
||||
* {@code NEVER}:这是不变式 <b>I3</b> 的结构性保证——本字段<b>永不进入 UPDATE 语句</b>,
|
||||
* 因此不存在「某条链路忘了保护快照」的可能。改内容只能靠<b>新提交一条记录</b>。
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@Schema(description = "该次提交的全量认证内容JSON")
|
||||
private String snapshotJson;
|
||||
/**
|
||||
* 驳回原因,仅当审核状态为已驳回时有值
|
||||
*/
|
||||
@Schema(description = "驳回原因")
|
||||
private String rejectReason;
|
||||
/**
|
||||
* 提交时间
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@Schema(description = "提交时间")
|
||||
private LocalDateTime submitTime;
|
||||
/**
|
||||
* 提交人
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "提交人")
|
||||
private Long submitUser;
|
||||
/**
|
||||
* 审核时间
|
||||
*/
|
||||
@Schema(description = "审核时间")
|
||||
private LocalDateTime auditTime;
|
||||
/**
|
||||
* 审核人
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "审核人")
|
||||
private Long auditUser;
|
||||
|
||||
}
|
||||
+19
@@ -26,6 +26,9 @@
|
||||
package org.springblade.transport.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -224,5 +227,21 @@ public class TransportVehicle extends TenantEntity {
|
||||
/** 认证驳回原因 */
|
||||
@Schema(description = "认证驳回原因")
|
||||
private String certificationRejectReason;
|
||||
/**
|
||||
* 生效快照指针:指向 blade_transport_cert_record.id
|
||||
* <p>
|
||||
* 「该车辆是否已认证」的<b>唯一</b>判据。为 null 表示从未认证通过;
|
||||
* 一经设置<b>永不回退</b>——重新提交、待审、被驳回都不得修改它(见 ADR-0002)。
|
||||
* 改造后 {@link #certificationStatus} 降级为「最新提交状态」的展示缓存。
|
||||
* <p>
|
||||
* ⚠️ {@code READ_ONLY}:本字段<b>只能由审核链路</b>(03)写入。
|
||||
* {@code POST /transport-vehicle/submit} 直接以本实体接收请求体,
|
||||
* 若允许反序列化,调用方就能自行填一个记录 ID 把自己「认证」掉,
|
||||
* 从而完全绕过审核与 D10 的可用性门槛。
|
||||
*/
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@Schema(description = "生效快照指针")
|
||||
private Long effectiveCertRecordId;
|
||||
|
||||
}
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.pojo.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springblade.transport.pojo.entity.TransportCertRecord;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 认证记录视图实体类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "认证记录")
|
||||
public class TransportCertRecordVO extends TransportCertRecord {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 创建人姓名
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "创建人姓名")
|
||||
private String createUserName;
|
||||
/**
|
||||
* 更新人姓名
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "更新人姓名")
|
||||
private String updateUserName;
|
||||
/**
|
||||
* 提交人姓名
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "提交人姓名")
|
||||
private String submitUserName;
|
||||
/**
|
||||
* 审核人姓名
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "审核人姓名")
|
||||
private String auditUserName;
|
||||
|
||||
}
|
||||
+13
-1
@@ -46,6 +46,12 @@
|
||||
<result column="emergency_contact_name" property="emergencyContactName"/>
|
||||
<result column="emergency_contact_mobile" property="emergencyContactMobile"/>
|
||||
<result column="remark" property="remark"/>
|
||||
<result column="id_card_valid_start" property="idCardValidStart"/>
|
||||
<result column="id_card_valid_end" property="idCardValidEnd"/>
|
||||
<result column="id_card_long_term" property="idCardLongTerm"/>
|
||||
<result column="certification_status" property="certificationStatus"/>
|
||||
<result column="certification_reject_reason" property="certificationRejectReason"/>
|
||||
<result column="effective_cert_record_id" property="effectiveCertRecordId"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="BaseColumn">
|
||||
@@ -70,6 +76,9 @@
|
||||
posts,
|
||||
id_card_front,
|
||||
id_card_back,
|
||||
id_card_valid_start,
|
||||
id_card_valid_end,
|
||||
id_card_long_term,
|
||||
head_photo,
|
||||
driving_type,
|
||||
driving_license_no,
|
||||
@@ -91,7 +100,10 @@
|
||||
organization_name,
|
||||
emergency_contact_name,
|
||||
emergency_contact_mobile,
|
||||
remark
|
||||
remark,
|
||||
certification_status,
|
||||
certification_reject_reason,
|
||||
effective_cert_record_id
|
||||
</sql>
|
||||
|
||||
<select id="selectByIdCardNoIncludingDeleted" resultType="org.springblade.transport.pojo.entity.Driver">
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.springblade.transport.pojo.entity.TransportCertRecord;
|
||||
|
||||
/**
|
||||
* 认证记录 Mapper 接口
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface TransportCertRecordMapper extends BaseMapper<TransportCertRecord> {
|
||||
|
||||
}
|
||||
+2
@@ -48,6 +48,7 @@
|
||||
<result column="remark" property="remark"/>
|
||||
<result column="certification_status" property="certificationStatus"/>
|
||||
<result column="certification_reject_reason" property="certificationRejectReason"/>
|
||||
<result column="effective_cert_record_id" property="effectiveCertRecordId"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="BaseColumn">
|
||||
@@ -96,6 +97,7 @@
|
||||
remark
|
||||
, certification_status
|
||||
, certification_reject_reason
|
||||
, effective_cert_record_id
|
||||
</sql>
|
||||
|
||||
<sql id="ExpiryWithin30Condition">
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.service;
|
||||
|
||||
import org.springblade.core.mp.base.BaseService;
|
||||
import org.springblade.transport.pojo.entity.TransportCertRecord;
|
||||
import org.springblade.transport.pojo.vo.TransportCertRecordVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 认证记录 服务类
|
||||
* <p>
|
||||
* 只承载认证记录本身的读写与<b>数据模型不变式</b>的守护;
|
||||
* 提交(02/05)、审核(03)、可用性门槛(04)等业务链路在各自的票中实现。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface ITransportCertRecordService extends BaseService<TransportCertRecord> {
|
||||
|
||||
/**
|
||||
* 某认证对象的认证记录列表,按提交时间倒序
|
||||
*
|
||||
* @param bizType 认证对象类型:driver-司机,vehicle-车辆
|
||||
* @param bizId 认证对象主键
|
||||
* @return 认证记录列表
|
||||
*/
|
||||
List<TransportCertRecordVO> selectRecordList(String bizType, Long bizId);
|
||||
|
||||
/**
|
||||
* 取某认证对象当前的待审快照(至多一条)
|
||||
*
|
||||
* @param bizType 认证对象类型:driver-司机,vehicle-车辆
|
||||
* @param bizId 认证对象主键
|
||||
* @return 待审快照,无则返回 null
|
||||
*/
|
||||
TransportCertRecord selectPendingRecord(String bizType, Long bizId);
|
||||
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.transport.mapper.TransportCertRecordMapper;
|
||||
import org.springblade.transport.pojo.entity.TransportCertRecord;
|
||||
import org.springblade.transport.pojo.vo.TransportCertRecordVO;
|
||||
import org.springblade.transport.service.ITransportCertRecordService;
|
||||
import org.springblade.transport.wrapper.TransportCertRecordWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 认证记录 服务实现类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Service
|
||||
public class TransportCertRecordServiceImpl extends BaseServiceImpl<TransportCertRecordMapper, TransportCertRecord> implements ITransportCertRecordService {
|
||||
|
||||
/**
|
||||
* 合法的审核状态取值
|
||||
*/
|
||||
private static final Set<Integer> VALID_STATUS = Set.of(
|
||||
TransportCertRecord.STATUS_PENDING,
|
||||
TransportCertRecord.STATUS_APPROVED,
|
||||
TransportCertRecord.STATUS_REJECTED,
|
||||
TransportCertRecord.STATUS_SUPERSEDED
|
||||
);
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean save(TransportCertRecord transportCertRecord) {
|
||||
validateRecord(transportCertRecord);
|
||||
return super.save(transportCertRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean saveBatch(Collection<TransportCertRecord> entityList, int batchSize) {
|
||||
entityList.forEach(this::validateRecord);
|
||||
return super.saveBatch(entityList, batchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean saveOrUpdateBatch(Collection<TransportCertRecord> entityList, int batchSize) {
|
||||
entityList.forEach(this::validateRecord);
|
||||
return super.saveOrUpdateBatch(entityList, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用继承自 {@code BaseService} 的「修改状态」
|
||||
* <p>
|
||||
* ⚠️ 本表的 {@code status} 是<b>审核状态</b>,不是「启用 / 停用」。
|
||||
* 而 {@code BaseServiceImpl#changeStatus} 会绕过 {@link #validateRecord} 直接写 status,
|
||||
* 调用 {@code changeStatus(ids, 1)} 即等于<b>批量通过审核</b>——
|
||||
* 审核人、审核时间、驳回原因全部缺失,既破坏 I3 的留痕,也会凭空造出生效快照。
|
||||
* 审核必须走 03 的审核接口(作用于单条记录、带留痕)。
|
||||
*
|
||||
* @param ids 主键集合
|
||||
* @param status 状态
|
||||
* @return 永不返回,直接抛出
|
||||
*/
|
||||
@Override
|
||||
public boolean changeStatus(List<Long> ids, Integer status) {
|
||||
throw new ServiceException("认证记录不支持直接修改状态,请使用审核接口");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TransportCertRecordVO> selectRecordList(String bizType, Long bizId) {
|
||||
return list(recordQuery(bizType, bizId)).stream()
|
||||
.map(TransportCertRecordWrapper.build()::entityVO)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportCertRecord selectPendingRecord(String bizType, Long bizId) {
|
||||
validateBizTarget(bizType, bizId);
|
||||
return getOne(Wrappers.<TransportCertRecord>lambdaQuery()
|
||||
.eq(TransportCertRecord::getBizType, bizType)
|
||||
.eq(TransportCertRecord::getBizId, bizId)
|
||||
.eq(TransportCertRecord::getStatus, TransportCertRecord.STATUS_PENDING)
|
||||
.last("LIMIT 1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证对象检索条件:按提交时间倒序
|
||||
* <p>
|
||||
* 排序用 {@code submit_time} 而非框架默认的 {@code create_time},是刻意为之:
|
||||
* 「认证记录」的业务时间轴是<b>提交</b>,ticket 02 明确要求
|
||||
* 「查询某辆车的认证记录列表:按提交时间倒序」。
|
||||
*
|
||||
* @param bizType 认证对象类型
|
||||
* @param bizId 认证对象主键
|
||||
* @return 检索条件
|
||||
*/
|
||||
private LambdaQueryWrapper<TransportCertRecord> recordQuery(String bizType, Long bizId) {
|
||||
validateBizTarget(bizType, bizId);
|
||||
return Wrappers.<TransportCertRecord>lambdaQuery()
|
||||
.eq(TransportCertRecord::getBizType, bizType)
|
||||
.eq(TransportCertRecord::getBizId, bizId)
|
||||
.orderByDesc(TransportCertRecord::getSubmitTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证对象标识校验
|
||||
*
|
||||
* @param bizType 认证对象类型
|
||||
* @param bizId 认证对象主键
|
||||
*/
|
||||
private void validateBizTarget(String bizType, Long bizId) {
|
||||
if (Func.isEmpty(bizType) || Func.isEmpty(bizId)) {
|
||||
throw new ServiceException("认证对象类型与主键不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录落库前的强制校验
|
||||
* <p>
|
||||
* ⚠️ 这里防的是框架的一个<b>静默</b>行为:{@code BaseServiceImpl#resolveEntity} 在插入时
|
||||
* 若 {@code status} 为 {@code null},会填充 {@code BladeConstant.DB_STATUS_NORMAL}(值 1),
|
||||
* 而 1 在本表恰好是 {@link TransportCertRecord#STATUS_APPROVED}。
|
||||
* 那会让一条「忘了设状态」的提交凭空变成「已通过」,进而可能被当成生效快照。
|
||||
* 故此处对空状态与非法取值直接拒绝,不依赖调用方自觉。
|
||||
*
|
||||
* @param transportCertRecord 待落库的认证记录
|
||||
*/
|
||||
private void validateRecord(TransportCertRecord transportCertRecord) {
|
||||
if (Func.isEmpty(transportCertRecord)) {
|
||||
throw new ServiceException("认证记录不能为空");
|
||||
}
|
||||
if (Func.isEmpty(transportCertRecord.getBizType())) {
|
||||
throw new ServiceException("认证对象类型不能为空");
|
||||
}
|
||||
if (Func.isEmpty(transportCertRecord.getBizId())) {
|
||||
throw new ServiceException("认证对象主键不能为空");
|
||||
}
|
||||
if (Func.isEmpty(transportCertRecord.getSnapshotJson())) {
|
||||
throw new ServiceException("认证内容快照不能为空");
|
||||
}
|
||||
Integer status = transportCertRecord.getStatus();
|
||||
if (Func.isEmpty(status)) {
|
||||
throw new ServiceException("认证记录状态不能为空,不允许依赖框架默认值(默认值 1 会被误判为已通过)");
|
||||
}
|
||||
if (!VALID_STATUS.contains(status)) {
|
||||
throw new ServiceException("认证记录状态取值不正确");
|
||||
}
|
||||
if (TransportCertRecord.STATUS_REJECTED.equals(status) && Func.isEmpty(transportCertRecord.getRejectReason())) {
|
||||
throw new ServiceException("请输入认证驳回原因");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.wrapper;
|
||||
|
||||
import org.springblade.core.mp.support.BaseEntityWrapper;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.transport.pojo.entity.TransportCertRecord;
|
||||
import org.springblade.transport.pojo.vo.TransportCertRecordVO;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 认证记录包装类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class TransportCertRecordWrapper extends BaseEntityWrapper<TransportCertRecord, TransportCertRecordVO> {
|
||||
|
||||
public static TransportCertRecordWrapper build() {
|
||||
return new TransportCertRecordWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportCertRecordVO entityVO(TransportCertRecord transportCertRecord) {
|
||||
TransportCertRecordVO transportCertRecordVO = Objects.requireNonNull(BeanUtil.copyProperties(transportCertRecord, TransportCertRecordVO.class));
|
||||
transportCertRecordVO.setCreateUserName(UserCache.getUserRealName(transportCertRecord.getCreateUser()));
|
||||
transportCertRecordVO.setUpdateUserName(UserCache.getUserRealName(transportCertRecord.getUpdateUser()));
|
||||
transportCertRecordVO.setSubmitUserName(UserCache.getUserRealName(transportCertRecord.getSubmitUser()));
|
||||
transportCertRecordVO.setAuditUserName(UserCache.getUserRealName(transportCertRecord.getAuditUser()));
|
||||
return transportCertRecordVO;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
-- 认证记录数据模型(司机 / 车辆共用一张不可变快照表)
|
||||
--
|
||||
-- 背景与设计依据:
|
||||
-- docs/adr/0001-certification-record-immutable-snapshot.md(不可变快照 + 生效指针)
|
||||
-- docs/adr/0002-certification-does-not-block-usage.md(提交不影响可用性)
|
||||
-- 术语定义见根工作区 GLOSSARY.md
|
||||
--
|
||||
-- 本脚本只做 schema 变更,不含任何业务数据订正:
|
||||
-- 1. 新建 blade_transport_cert_record(认证记录,司机与车辆共用,biz_type 区分)
|
||||
-- 2. blade_transport_driver 补认证字段、生效快照指针、身份证有效期
|
||||
-- 3. blade_transport_vehicle 补生效快照指针
|
||||
-- 4. blade_transport_driver 排序规则订正为 utf8mb4_general_ci
|
||||
-- 5. 新增「认证审核-司机 / 车辆」菜单与权限码
|
||||
--
|
||||
-- 幂等:全部语句可重复执行(建表用 IF NOT EXISTS,加列先查 information_schema)。
|
||||
-- MySQL 5.7+ 兼容。
|
||||
--
|
||||
-- ⚠️ 生效快照指针(effective_cert_record_id)的语义:
|
||||
-- "该认证对象是否已认证"的**唯一**判据。为 NULL 表示从未通过审核。
|
||||
-- 一旦被指向,**永不回退为 NULL**——提交、驳回、作废都不得修改它。
|
||||
--
|
||||
-- ⚠️ 留给后续票的两条约束(本脚本无法用 DDL 表达):
|
||||
-- 1) 指针所指记录的 status 必须恒为「已通过」(1),且不得再被改动。
|
||||
-- 这正是不变式 I2 的后半句;由 03 的「已终态记录不可再次审核」保证。
|
||||
-- 2) 指针所指记录的 biz_type / biz_id 必须与持有它的对象一致。
|
||||
-- 由 03 写指针时保证(通过时用的是待审记录自身的 biz_id)。
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. 认证记录表
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS `blade_transport_cert_record` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键',
|
||||
`tenant_id` varchar(12) NOT NULL DEFAULT '000000' COMMENT '租户ID',
|
||||
`biz_type` varchar(20) NOT NULL COMMENT '认证对象类型:driver-司机,vehicle-车辆',
|
||||
`biz_id` bigint(20) NOT NULL COMMENT '认证对象主键:司机ID或车辆ID(车辆按具体车辆,不是司机)',
|
||||
`biz_key` varchar(100) DEFAULT NULL COMMENT '展示键:司机姓名/车牌号',
|
||||
`status` int(11) NOT NULL COMMENT '审核状态:0审核中 1已通过 2已驳回 3已作废',
|
||||
`snapshot_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '该次提交的全量认证内容JSON,一经创建不可修改',
|
||||
`reject_reason` varchar(200) DEFAULT NULL COMMENT '驳回原因,仅状态为已驳回时有值',
|
||||
`submit_time` datetime DEFAULT NULL COMMENT '提交时间',
|
||||
`submit_user` bigint(20) DEFAULT NULL COMMENT '提交人',
|
||||
`audit_time` datetime DEFAULT NULL COMMENT '审核时间',
|
||||
`audit_user` bigint(20) DEFAULT NULL COMMENT '审核人',
|
||||
`create_user` bigint(20) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_user` bigint(20) DEFAULT NULL COMMENT '修改人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||
`is_deleted` int(11) DEFAULT '0' COMMENT '是否已删除',
|
||||
`pending_biz_id` bigint(20) GENERATED ALWAYS AS (if((`status` = 0) and (`is_deleted` = 0),`biz_id`,NULL)) STORED COMMENT '待审唯一键:仅未删除的审核中记录非空,用于保证同对象至多一条待审快照',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_cert_record_pending` (`tenant_id`,`biz_type`,`pending_biz_id`) USING BTREE,
|
||||
KEY `idx_cert_record_biz` (`biz_type`,`biz_id`,`submit_time`) USING BTREE,
|
||||
KEY `idx_cert_record_status` (`biz_type`,`status`,`submit_time`) USING BTREE,
|
||||
KEY `idx_cert_record_submit_time` (`submit_time`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='认证记录';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2~4. 加列与排序规则订正
|
||||
-- ---------------------------------------------------------------------------
|
||||
DELIMITER $$
|
||||
|
||||
DROP PROCEDURE IF EXISTS `upgrade_transport_cert_record_20261002`$$
|
||||
CREATE PROCEDURE `upgrade_transport_cert_record_20261002`()
|
||||
BEGIN
|
||||
DECLARE db_name varchar(128);
|
||||
SET db_name = DATABASE();
|
||||
|
||||
-- ---- 2. 司机表:认证字段 + 生效快照指针 ----
|
||||
-- certification_status 是「最新提交状态」的展示缓存,不是可用性判据;
|
||||
-- 初始为 NULL 表示「从未提交」,与「审核中(0)」语义不同。
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = db_name AND table_name = 'blade_transport_driver' AND column_name = 'certification_status') THEN
|
||||
ALTER TABLE `blade_transport_driver` ADD COLUMN `certification_status` int(11) DEFAULT NULL COMMENT '最新提交状态展示缓存:0审核中 1已通过 2已驳回 3已作废,NULL为从未提交' AFTER `remark`;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = db_name AND table_name = 'blade_transport_driver' AND column_name = 'certification_reject_reason') THEN
|
||||
ALTER TABLE `blade_transport_driver` ADD COLUMN `certification_reject_reason` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最新一次驳回原因展示缓存' AFTER `certification_status`;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = db_name AND table_name = 'blade_transport_driver' AND column_name = 'effective_cert_record_id') THEN
|
||||
ALTER TABLE `blade_transport_driver` ADD COLUMN `effective_cert_record_id` bigint(20) DEFAULT NULL COMMENT '生效快照指针:指向 blade_transport_cert_record.id,NULL 表示从未认证通过;一经设置永不回退' AFTER `certification_reject_reason`;
|
||||
END IF;
|
||||
|
||||
-- ---- 2.1 司机表:身份证有效期(小程序 person.vue 标为必填,原表缺列)----
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = db_name AND table_name = 'blade_transport_driver' AND column_name = 'id_card_valid_start') THEN
|
||||
ALTER TABLE `blade_transport_driver` ADD COLUMN `id_card_valid_start` date DEFAULT NULL COMMENT '身份证有效期起' AFTER `id_card_back`;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = db_name AND table_name = 'blade_transport_driver' AND column_name = 'id_card_valid_end') THEN
|
||||
ALTER TABLE `blade_transport_driver` ADD COLUMN `id_card_valid_end` date DEFAULT NULL COMMENT '身份证有效期止' AFTER `id_card_valid_start`;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = db_name AND table_name = 'blade_transport_driver' AND column_name = 'id_card_long_term') THEN
|
||||
ALTER TABLE `blade_transport_driver` ADD COLUMN `id_card_long_term` int(11) DEFAULT '0' COMMENT '身份证长期有效:0否 1是' AFTER `id_card_valid_end`;
|
||||
END IF;
|
||||
|
||||
-- ---- 3. 车辆表:生效快照指针 ----
|
||||
-- 现有 certification_status / certification_reject_reason 保留,降级为「最新提交状态」展示缓存;
|
||||
-- 可用性判定一律改读本指针(改造见 ticket 04)。
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = db_name AND table_name = 'blade_transport_vehicle' AND column_name = 'effective_cert_record_id') THEN
|
||||
ALTER TABLE `blade_transport_vehicle` ADD COLUMN `effective_cert_record_id` bigint(20) DEFAULT NULL COMMENT '生效快照指针:指向 blade_transport_cert_record.id,NULL 表示从未认证通过;一经设置永不回退' AFTER `certification_reject_reason`;
|
||||
END IF;
|
||||
|
||||
-- ---- 4. 司机表排序规则订正 ----
|
||||
-- blade_transport_driver 建表未显式指定 COLLATE,MySQL 8+ 默认 utf8mb4_0900_ai_ci,
|
||||
-- 与项目规范(utf8mb4_general_ci)不一致;blade_transport_vehicle 曾因此报
|
||||
-- Illegal mix of collations,故一并订正,避免司机认证 JOIN 重演同一故障。
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = db_name AND table_name = 'blade_transport_driver' AND table_collation <> 'utf8mb4_general_ci') THEN
|
||||
ALTER TABLE `blade_transport_driver` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
END IF;
|
||||
|
||||
-- ---- 4.1 待审唯一键自修复 ----
|
||||
-- 生成列必须同时排除「已逻辑删除」的行:MyBatis-Plus 的 removeById 只把 is_deleted 置 1,
|
||||
-- 不会改 status。若生成列只看 status = 0,一条被逻辑删除的待审记录会继续占用唯一键,
|
||||
-- 导致该认证对象**永远无法再提交**(ticket 02 明确要求车辆认证按逻辑删除处理)。
|
||||
-- 建表语句已是正确版本;这里负责把按早期版本建过表的环境就地修正过来。
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = db_name AND table_name = 'blade_transport_cert_record'
|
||||
AND column_name = 'pending_biz_id' AND generation_expression NOT LIKE '%is_deleted%'
|
||||
) THEN
|
||||
ALTER TABLE `blade_transport_cert_record`
|
||||
MODIFY COLUMN `pending_biz_id` bigint(20) GENERATED ALWAYS AS (if((`status` = 0) and (`is_deleted` = 0),`biz_id`,NULL)) STORED COMMENT '待审唯一键:仅未删除的审核中记录非空,用于保证同对象至多一条待审快照';
|
||||
END IF;
|
||||
|
||||
-- ---- 4.2 tenant_id 收紧为 NOT NULL ----
|
||||
-- tenant_id 是待审唯一键 uk_cert_record_pending 的第一列,而 MySQL 的唯一索引**不对 NULL 去重**:
|
||||
-- 若 tenant_id 允许为 NULL,两条 tenant_id IS NULL 的待审记录可以并存,I1 会被整个绕过。
|
||||
-- 本库三张表(driver / vehicle / waybill)实测均无 tenant_id 为 NULL 的行,
|
||||
-- 且「NOT NULL DEFAULT '000000'」是项目既有写法(doc/sql/transport 下 23 个脚本如此)。
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = db_name AND table_name = 'blade_transport_cert_record'
|
||||
AND column_name = 'tenant_id' AND is_nullable = 'YES'
|
||||
) THEN
|
||||
UPDATE `blade_transport_cert_record` SET `tenant_id` = '000000' WHERE `tenant_id` IS NULL;
|
||||
ALTER TABLE `blade_transport_cert_record`
|
||||
MODIFY COLUMN `tenant_id` varchar(12) NOT NULL DEFAULT '000000' COMMENT '租户ID';
|
||||
END IF;
|
||||
|
||||
-- ---- 4.3 车辆认证状态缓存词表对齐 ----
|
||||
-- 改造前车辆侧是「0认证中 1认证通过 2认证驳回」,不含「已作废」;
|
||||
-- 而 02/03 会把「被同对象再次提交取代」写成 3,届时该列无对应语义。
|
||||
-- 取值 0/1/2 在两套词表下含义一致(进行中 / 通过 / 驳回),故这里只补 3 并统一措辞,
|
||||
-- 不改变任何既有数据的含义。仅改列注释(元数据),不动数据。
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = db_name AND table_name = 'blade_transport_vehicle'
|
||||
AND column_name = 'certification_status' AND column_comment NOT LIKE '%已作废%'
|
||||
) THEN
|
||||
ALTER TABLE `blade_transport_vehicle`
|
||||
MODIFY COLUMN `certification_status` int(11) DEFAULT '0' COMMENT '最新提交状态展示缓存:0审核中 1已通过 2已驳回 3已作废;可用性判定只看 effective_cert_record_id';
|
||||
END IF;
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = db_name AND table_name = 'blade_transport_vehicle'
|
||||
AND column_name = 'certification_reject_reason' AND column_comment NOT LIKE '%展示缓存%'
|
||||
) THEN
|
||||
ALTER TABLE `blade_transport_vehicle`
|
||||
MODIFY COLUMN `certification_reject_reason` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最新一次驳回原因展示缓存';
|
||||
END IF;
|
||||
END$$
|
||||
|
||||
CALL `upgrade_transport_cert_record_20261002`()$$
|
||||
DROP PROCEDURE `upgrade_transport_cert_record_20261002`$$
|
||||
|
||||
DELIMITER ;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 5. 菜单与权限码
|
||||
-- 挂在「运力管理」(2079000000000000001) 下,与司机管理 / 车辆管理同级。
|
||||
-- 权限码按 spec 约定:列表用 cert_certification_audit_{driver|vehicle},
|
||||
-- 审核动作用对应 _audit 后缀。
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO `blade_menu` (`id`, `parent_id`, `code`, `name`, `alias`, `path`, `source`, `sort`, `category`, `action`, `is_open`, `component`, `remark`, `is_deleted`) VALUES
|
||||
(2079000000000000300, 2079000000000000001, 'cert_certification_audit_driver', '认证审核-司机', 'cert_certification_audit_driver', '/transportCapacity/cert-audit-driver', 'iconfont iconicon_doc', 4, 1, 0, 1, '', '司机认证待审列表', 0),
|
||||
(2079000000000000301, 2079000000000000300, 'cert_certification_audit_driver_audit', '审核', 'cert_certification_audit_driver_audit', '', '', 1, 2, 0, 1, NULL, '通过/驳回司机认证', 0),
|
||||
(2079000000000000310, 2079000000000000001, 'cert_certification_audit_vehicle', '认证审核-车辆', 'cert_certification_audit_vehicle', '/transportCapacity/cert-audit-vehicle', 'iconfont iconicon_doc', 5, 1, 0, 1, '', '车辆认证待审列表', 0),
|
||||
(2079000000000000311, 2079000000000000310, 'cert_certification_audit_vehicle_audit', '审核', 'cert_certification_audit_vehicle_audit', '', '', 1, 2, 0, 1, NULL, '通过/驳回车辆认证', 0)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`parent_id` = VALUES(`parent_id`),
|
||||
`code` = VALUES(`code`),
|
||||
`name` = VALUES(`name`),
|
||||
`alias` = VALUES(`alias`),
|
||||
`path` = VALUES(`path`),
|
||||
`source` = VALUES(`source`),
|
||||
`sort` = VALUES(`sort`),
|
||||
`category` = VALUES(`category`),
|
||||
`action` = VALUES(`action`),
|
||||
`is_open` = VALUES(`is_open`),
|
||||
`component` = VALUES(`component`),
|
||||
`remark` = VALUES(`remark`),
|
||||
`is_deleted` = VALUES(`is_deleted`);
|
||||
@@ -17,6 +17,9 @@ CREATE TABLE `blade_transport_driver` (
|
||||
`posts` varchar(100) DEFAULT NULL COMMENT '岗位,多个使用逗号分隔',
|
||||
`id_card_front` varchar(1000) DEFAULT NULL COMMENT '身份证正面照',
|
||||
`id_card_back` varchar(1000) DEFAULT NULL COMMENT '身份证反面照',
|
||||
`id_card_valid_start` date DEFAULT NULL COMMENT '身份证有效期起',
|
||||
`id_card_valid_end` date DEFAULT NULL COMMENT '身份证有效期止',
|
||||
`id_card_long_term` int(11) DEFAULT '0' COMMENT '身份证长期有效:0否 1是',
|
||||
`head_photo` varchar(1000) DEFAULT NULL COMMENT '大头照',
|
||||
`driving_type` varchar(20) NOT NULL COMMENT '准驾车型',
|
||||
`driving_license_no` varchar(50) DEFAULT NULL COMMENT '驾驶证档案编号',
|
||||
@@ -39,6 +42,9 @@ CREATE TABLE `blade_transport_driver` (
|
||||
`emergency_contact_name` varchar(20) NOT NULL COMMENT '紧急联系人姓名',
|
||||
`emergency_contact_mobile` varchar(20) NOT NULL COMMENT '紧急联系人手机号',
|
||||
`remark` varchar(200) DEFAULT NULL COMMENT '备注',
|
||||
`certification_status` int(11) DEFAULT NULL COMMENT '最新提交状态展示缓存:0审核中 1已通过 2已驳回 3已作废,NULL为从未提交',
|
||||
`certification_reject_reason` varchar(200) DEFAULT NULL COMMENT '最新一次驳回原因展示缓存',
|
||||
`effective_cert_record_id` bigint(20) DEFAULT NULL COMMENT '生效快照指针:指向 blade_transport_cert_record.id,NULL 表示从未认证通过;一经设置永不回退',
|
||||
`create_user` bigint(20) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
@@ -54,7 +60,7 @@ CREATE TABLE `blade_transport_driver` (
|
||||
KEY `idx_transport_driver_license_end` (`driving_license_end_date`) USING BTREE,
|
||||
KEY `idx_transport_driver_qualification_end` (`qualification_end_date`) USING BTREE,
|
||||
KEY `idx_transport_driver_status` (`status`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='司机管理';
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='司机管理';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of blade_menu for transport capacity driver
|
||||
|
||||
@@ -39,8 +39,9 @@ CREATE TABLE `blade_transport_vehicle` (
|
||||
`registration_date` date DEFAULT NULL COMMENT '机动车登记日期',
|
||||
`registration_image` varchar(1000) DEFAULT NULL COMMENT '机动车登记本图片',
|
||||
`remark` varchar(200) DEFAULT NULL COMMENT '备注',
|
||||
`certification_status` int(11) DEFAULT '0' COMMENT '认证状态:0认证中 1认证通过 2认证驳回',
|
||||
`certification_reject_reason` varchar(200) DEFAULT NULL COMMENT '认证驳回原因',
|
||||
`certification_status` int(11) DEFAULT '0' COMMENT '最新提交状态展示缓存:0审核中 1已通过 2已驳回 3已作废;可用性判定只看 effective_cert_record_id',
|
||||
`certification_reject_reason` varchar(200) DEFAULT NULL COMMENT '最新一次驳回原因展示缓存',
|
||||
`effective_cert_record_id` bigint(20) DEFAULT NULL COMMENT '生效快照指针:指向 blade_transport_cert_record.id,NULL 表示从未认证通过;一经设置永不回退',
|
||||
`create_user` bigint(20) DEFAULT NULL COMMENT '创建人',
|
||||
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
|
||||
Reference in New Issue
Block a user