zjk
13 小时以前 8ea6a7dd1fcdbd4e22c564ed63a5a8023510161a
hugray-server/ruoyi-modules/ruoyi-user/src/main/java/com/ruoyi/user/service/impl/AccountCertificationApplyServiceImpl.java
@@ -10,8 +10,11 @@
import com.ruoyi.user.domain.AccountCertification;
import com.ruoyi.user.domain.AccountCertificationApply;
import com.ruoyi.user.domain.AccountUser;
import com.ruoyi.user.domain.dto.CompanyCertificationApplyDto;
import com.ruoyi.user.domain.vo.AccountCertificationApplyDetailVo;
import com.ruoyi.user.domain.vo.AccountCertificationApplyVo;
import com.ruoyi.user.domain.vo.AccountCertificationStatusVo;
import com.ruoyi.user.domain.vo.CompanyCertificationStatusVo;
import com.ruoyi.user.mapper.AccountCertificationApplyMapper;
import com.ruoyi.user.mapper.AccountCertificationMapper;
import com.ruoyi.user.mapper.AccountUserMapper;
@@ -31,11 +34,32 @@
    /** 审核结果:驳回 */
    private static final String AUDIT_REJECT = "2";
    /** 审核状态:待审核(提交后的初始状态) */
    private static final String AUDIT_PENDING = "0";
    /** account_user.auth_status:审核中 */
    private static final String AUTH_AUDITING = "1";
    /** account_user.auth_status:已认证 */
    private static final String AUTH_VERIFIED = "2";
    /** account_user.auth_status:认证失败 */
    private static final String AUTH_FAILED = "3";
    /** 主体类型:个人(C端实名认证固定为该类型) */
    private static final String SUBJECT_PERSONAL = "1";
    /** 主体类型:个体工商户 */
    private static final String SUBJECT_INDIVIDUAL = "2";
    /** 主体类型:企业 */
    private static final String SUBJECT_COMPANY = "3";
    /** 有效期类型:长期(此时起止日期可空) */
    private static final String VALID_TYPE_LONG_TERM = "1";
    /** 有效期类型:短期(此时起止日期必填) */
    private static final String VALID_TYPE_SHORT_TERM = "2";
    @Autowired
    private AccountCertificationApplyMapper certificationApplyMapper;
@@ -102,18 +126,221 @@
            throw new ServiceException("该申请已审核,不能重复处理");
        }
        // 同步到 account_user.auth_status:会员列表的「认证状态」列取的就是它
        // 同步认证状态到 account_user:个人写 auth_status,企业/个体写 company_auth_status,两列互不覆盖。
        AccountUser user = new AccountUser();
        user.setUserId(apply.getUserId());
        user.setAuthStatus(pass ? AUTH_VERIFIED : AUTH_FAILED);
        user.setUpdateBy(operator);
        if (isCompanySubject(apply.getSubjectType()))
        {
            user.setCompanyAuthStatus(pass ? AUTH_VERIFIED : AUTH_FAILED);
            // 审核通过时才把主体类型落为 2/3;驳回不动,避免未通过审核就被标成企业主体
            if (pass)
            {
                user.setSubjectType(apply.getSubjectType());
            }
            accountUserMapper.updateUserCompanyAuthStatus(user);
        }
        else
        {
            user.setAuthStatus(pass ? AUTH_VERIFIED : AUTH_FAILED);
        accountUserMapper.updateUserAuthStatus(user);
        }
        if (pass)
        {
            saveCertificationSnapshot(apply, operator);
        }
        return 1;
    }
    @Override
    @Transactional
    public void submitPersonalCertification(Long userId, String realName, String idCard)
    {
        // STEP 1: 校验会员ID(登录态缺失时直接失败,避免无归属写入)
        if (StringUtils.isNull(userId))
        {
            throw new ServiceException("提交实名认证失败");
        }
        // STEP 2: 姓名/身份证号二次校验:Controller 已用 @Validated 拦过一遍,
        //         这里是服务层兜底,防止绕过 Controller 直接调用服务时落脏数据
        if (StringUtils.isEmpty(realName) || StringUtils.isEmpty(idCard))
        {
            throw new ServiceException("姓名与身份证号不能为空");
        }
        // STEP 3: 防重闸门——该会员已有待审核申请时拒绝,避免后台审核列表堆积重复单
        if (certificationApplyMapper.countPendingPersonalApplyByUserId(userId) > 0)
        {
            throw new ServiceException("已有实名认证申请正在审核中,请勿重复提交");
        }
        // STEP 4: 组装申请快照并落库(主体类型固定「个人」;审核状态置「待审核」;
        //         身份证号统一转大写,兼容末位小写 x)
        String operator = SecurityUtils.getUsername();
        AccountCertificationApply apply = new AccountCertificationApply();
        apply.setUserId(userId);
        apply.setSubjectType(SUBJECT_PERSONAL);
        apply.setRealName(realName.trim());
        apply.setIdCard(idCard.trim().toUpperCase());
        apply.setAuditStatus(AUDIT_PENDING);
        apply.setCreateBy(operator);
        if (certificationApplyMapper.insertCertificationApply(apply) <= 0)
        {
            throw new ServiceException("提交实名认证失败,请稍后重试");
        }
        // STEP 5: 联动 account_user.auth_status 为「审核中」,个人中心与会员列表据此显示
        AccountUser user = new AccountUser();
        user.setUserId(userId);
        user.setAuthStatus(AUTH_AUDITING);
        user.setUpdateBy(operator);
        accountUserMapper.updateUserAuthStatus(user);
    }
    @Override
    public AccountCertificationStatusVo getCertificationStatus(Long userId)
    {
        AccountCertificationStatusVo vo = new AccountCertificationStatusVo();
        // 登录态缺失视为从未提交:返回空对象,前端按「未认证」渲染空表单(不返回 null)
        if (StringUtils.isNull(userId))
        {
            return vo;
        }
        AccountCertificationApply apply = certificationApplyMapper.selectLatestPersonalApplyByUserId(userId);
        if (StringUtils.isNull(apply))
        {
            return vo;
        }
        // 回填最近一次申请的资料与状态:认证失败时前端据 auditRemark 展示驳回原因
        vo.setRealName(apply.getRealName());
        vo.setIdCard(apply.getIdCard());
        vo.setAuditStatus(apply.getAuditStatus());
        vo.setAuditRemark(apply.getAuditRemark());
        return vo;
    }
    @Override
    @Transactional
    public void submitCompanyCertification(Long userId, CompanyCertificationApplyDto dto)
    {
        // STEP 1: 校验会员ID(登录态缺失时直接失败,避免无归属写入)
        if (StringUtils.isNull(userId))
        {
            throw new ServiceException("提交企业认证失败");
        }
        // STEP 2: 入参兜底:Controller 已用 @Validated 拦过,这里防止绕过 Controller 直接落脏数据
        if (StringUtils.isNull(dto))
        {
            throw new ServiceException("认证资料不能为空");
        }
        // STEP 3: 有效期必填兜底——「短期」必须填起止日期,「长期」允许为空(前端此时隐藏该输入)
        checkValidPeriod(dto.getLicenseValidType(), dto.getLicenseValidPeriod(), "营业执照");
        checkValidPeriod(dto.getLegalIdValidType(), dto.getLegalIdValidPeriod(), "法人身份证");
        // STEP 4: 防重闸门——该会员已有待审核的企业申请时拒绝,避免后台审核列表堆积重复单
        if (certificationApplyMapper.countPendingCompanyApplyByUserId(userId) > 0)
        {
            throw new ServiceException("已有企业认证申请正在审核中,请勿重复提交");
        }
        // STEP 5: 组装申请快照(主体类型取入参 2/3;审核状态置「待审核」)
        String operator = SecurityUtils.getUsername();
        AccountCertificationApply apply = new AccountCertificationApply();
        apply.setUserId(userId);
        apply.setSubjectType(dto.getSubjectType());
        apply.setCompanyName(dto.getCompanyName().trim());
        apply.setLicenseImage(dto.getLicenseImage());
        apply.setCreditCode(dto.getCreditCode().trim());
        apply.setLicenseValidType(dto.getLicenseValidType());
        apply.setLicenseValidPeriod(dto.getLicenseValidPeriod());
        apply.setRegisteredRegion(dto.getRegisteredRegion());
        apply.setCompanyAddress(dto.getCompanyAddress());
        apply.setLegalPerson(dto.getLegalPerson().trim());
        apply.setLegalIdCardFront(dto.getLegalIdCardFront());
        apply.setLegalIdCardBack(dto.getLegalIdCardBack());
        apply.setLegalIdValidType(dto.getLegalIdValidType());
        apply.setLegalIdValidPeriod(dto.getLegalIdValidPeriod());
        apply.setLegalIdAddress(dto.getLegalIdAddress());
        apply.setContactName(dto.getContactName().trim());
        apply.setContactPhone(dto.getContactPhone().trim());
        apply.setContactEmail(dto.getContactEmail().trim());
        apply.setPayeeType(dto.getPayeeType());
        apply.setBankCardImage(dto.getBankCardImage());
        apply.setBankCardNo(dto.getBankCardNo().trim());
        apply.setBankCity(dto.getBankCity());
        apply.setAuditStatus(AUDIT_PENDING);
        apply.setCreateBy(operator);
        // STEP 6: 落库
        if (certificationApplyMapper.insertCertificationApply(apply) <= 0)
        {
            throw new ServiceException("提交企业认证失败,请稍后重试");
        }
        // STEP 7: 联动 account_user.company_auth_status 为「审核中」(与个人 auth_status 相互独立)
        AccountUser user = new AccountUser();
        user.setUserId(userId);
        user.setCompanyAuthStatus(AUTH_AUDITING);
        user.setUpdateBy(operator);
        accountUserMapper.updateUserCompanyAuthStatus(user);
    }
    @Override
    public CompanyCertificationStatusVo getCompanyCertificationStatus(Long userId)
    {
        CompanyCertificationStatusVo vo = new CompanyCertificationStatusVo();
        // 登录态缺失视为从未提交:返回空对象,前端按「未认证」渲染空表单(不返回 null)
        if (StringUtils.isNull(userId))
        {
            return vo;
        }
        AccountCertificationApply apply = certificationApplyMapper.selectLatestCompanyApplyByUserId(userId);
        if (StringUtils.isNull(apply))
        {
            return vo;
        }
        // 一次性回填整份资料与审核状态:审核中进占位页、已驳回展示原因并允许修改重提
        vo.setSubjectType(apply.getSubjectType());
        vo.setCompanyName(apply.getCompanyName());
        vo.setLicenseImage(apply.getLicenseImage());
        vo.setCreditCode(apply.getCreditCode());
        vo.setLicenseValidType(apply.getLicenseValidType());
        vo.setLicenseValidPeriod(apply.getLicenseValidPeriod());
        vo.setRegisteredRegion(apply.getRegisteredRegion());
        vo.setCompanyAddress(apply.getCompanyAddress());
        vo.setLegalPerson(apply.getLegalPerson());
        vo.setLegalIdCardFront(apply.getLegalIdCardFront());
        vo.setLegalIdCardBack(apply.getLegalIdCardBack());
        vo.setLegalIdValidType(apply.getLegalIdValidType());
        vo.setLegalIdValidPeriod(apply.getLegalIdValidPeriod());
        vo.setLegalIdAddress(apply.getLegalIdAddress());
        vo.setContactName(apply.getContactName());
        vo.setContactPhone(apply.getContactPhone());
        vo.setContactEmail(apply.getContactEmail());
        vo.setPayeeType(apply.getPayeeType());
        vo.setBankCardImage(apply.getBankCardImage());
        vo.setBankCardNo(apply.getBankCardNo());
        vo.setBankCity(apply.getBankCity());
        vo.setAuditStatus(apply.getAuditStatus());
        vo.setAuditRemark(apply.getAuditRemark());
        return vo;
    }
    /**
     * 判定主体类型是否为企业/个体工商户(subject_type ∈ {2,3})。
     */
    private boolean isCompanySubject(String subjectType)
    {
        return SUBJECT_INDIVIDUAL.equals(subjectType) || SUBJECT_COMPANY.equals(subjectType);
    }
    /**
     * 有效期必填兜底:类型为「短期」时,起止日期不得为空。
     *
     * @param validType   有效期类型(1长期 2短期)
     * @param validPeriod 有效期起止(文本)
     * @param label       字段中文名,用于拼接错误提示
     */
    private void checkValidPeriod(String validType, String validPeriod, String label)
    {
        if (VALID_TYPE_SHORT_TERM.equals(validType) && StringUtils.isEmpty(validPeriod))
        {
            throw new ServiceException("请选择" + label + "有效期起止日期");
        }
    }
    /**
@@ -144,6 +371,19 @@
        certification.setRegisterDate(apply.getRegisterDate());
        certification.setLicenseValidPeriod(apply.getLicenseValidPeriod());
        certification.setLicenseImage(apply.getLicenseImage());
        certification.setLicenseValidType(apply.getLicenseValidType());
        certification.setLegalIdCardFront(apply.getLegalIdCardFront());
        certification.setLegalIdCardBack(apply.getLegalIdCardBack());
        certification.setLegalIdValidType(apply.getLegalIdValidType());
        certification.setLegalIdValidPeriod(apply.getLegalIdValidPeriod());
        certification.setLegalIdAddress(apply.getLegalIdAddress());
        certification.setContactName(apply.getContactName());
        certification.setContactPhone(apply.getContactPhone());
        certification.setContactEmail(apply.getContactEmail());
        certification.setPayeeType(apply.getPayeeType());
        certification.setBankCardImage(apply.getBankCardImage());
        certification.setBankCardNo(apply.getBankCardNo());
        certification.setBankCity(apply.getBankCity());
        certification.setCreateBy(operator);
        certification.setRemark("由认证申请(申请号 " + apply.getId() + ")审核通过生成");
        certificationMapper.insertCertification(certification);