liujie
2026-09-17 825a575deb96cce822468bb9d9ac3e4eea0f91d1
update
5个文件已修改
64 ■■■■■ 已修改文件
backend/src/main/java/com/tourguide/modules/user/mapper/GuideUserMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
backend/src/main/java/com/tourguide/modules/user/service/GuideApplicationService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
backend/src/main/java/com/tourguide/modules/user/service/GuideUserService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
backend/src/test/java/com/tourguide/modules/user/service/GuideUserServiceProfileTest.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
frontend/src/views/DashboardView.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
backend/src/main/java/com/tourguide/modules/user/mapper/GuideUserMapper.java
@@ -21,10 +21,20 @@
    int anonymizeCancelledGuide(@Param("guideId") Long guideId, @Param("username") String username);
    @Update("UPDATE guide_user SET id_card_no = NULL, id_card_front_url = NULL, " +
            "id_card_back_url = NULL, updated_at = NOW() " +
            "id_card_back_url = NULL, certificate_no = NULL, updated_at = NOW() " +
            "WHERE id_card_no = #{idCardNo} AND status = 3 AND deleted = 0")
    int clearCancelledIdentityByIdCard(@Param("idCardNo") String idCardNo);
    @Update("UPDATE guide_user SET id_card_no = NULL, id_card_front_url = NULL, " +
            "id_card_back_url = NULL, certificate_no = NULL, updated_at = NOW() " +
            "WHERE id = #{guideId} AND status = 2 AND deleted = 0")
    int releasePendingIdentity(@Param("guideId") Long guideId);
    @Update("UPDATE guide_user SET id_card_no = NULL, id_card_front_url = NULL, " +
            "id_card_back_url = NULL, certificate_no = NULL, updated_at = NOW() " +
            "WHERE id_card_no = #{idCardNo} AND status = 2 AND deleted = 0")
    int clearPendingIdentityByIdCard(@Param("idCardNo") String idCardNo);
    @Select("SELECT * FROM guide_user WHERE id = #{guideId} AND deleted = 0 FOR UPDATE")
    GuideUser selectForUpdate(@Param("guideId") Long guideId);
backend/src/main/java/com/tourguide/modules/user/service/GuideApplicationService.java
@@ -86,7 +86,11 @@
        if (application.getAuditStatus() == null || application.getAuditStatus() != PENDING) {
            throw new BusinessException(409, "该申请已审核,请勿重复操作");
        }
        if (auditStatus == APPROVED) guideUserService.createFromApprovedApplication(application);
        if (auditStatus == APPROVED) {
            guideUserService.createFromApprovedApplication(application);
        } else if (auditStatus == REJECTED) {
            guideUserService.releaseIdentityForRejectedApplication(application.getMobile());
        }
        LambdaUpdateWrapper<GuideApplication> update = new LambdaUpdateWrapper<GuideApplication>()
                .eq(GuideApplication::getId, id)
                .eq(GuideApplication::getAuditStatus, PENDING)
backend/src/main/java/com/tourguide/modules/user/service/GuideUserService.java
@@ -338,8 +338,11 @@
    private void ensureUniqueGuideIdentity(GuideApplication application, GuideUser existingUser) {
        if (StringUtils.hasText(application.getIdCardNo())) {
            String idCardNo = application.getIdCardNo().trim().toUpperCase();
            // 兼容旧注销数据:释放已注销账号占用的身份证唯一索引。
            userMapper.clearCancelledIdentityByIdCard(application.getIdCardNo().trim().toUpperCase());
            userMapper.clearCancelledIdentityByIdCard(idCardNo);
            // 兼容旧驳回数据:释放待审核账号占用的身份证唯一索引,避免其阻塞重新注册。
            userMapper.clearPendingIdentityByIdCard(idCardNo);
        }
        if (StringUtils.hasText(application.getCertificateNo())
                && userMapper.selectCount(new LambdaQueryWrapper<GuideUser>()
@@ -359,6 +362,15 @@
        }
    }
    /** 申请被驳回后释放待审核账号占用的身份证/导游证唯一索引,避免其阻塞重新注册。 */
    public void releaseIdentityForRejectedApplication(String mobile) {
        if (!StringUtils.hasText(mobile)) return;
        GuideUser user = findByPhone(mobile);
        if (user != null && Integer.valueOf(STATUS_PENDING).equals(user.getStatus())) {
            userMapper.releasePendingIdentity(user.getId());
        }
    }
    private void copyApplicationProfile(GuideUser user, GuideApplication application) {
        user.setRealName(application.getRealName());
        user.setMobile(application.getMobile());
backend/src/test/java/com/tourguide/modules/user/service/GuideUserServiceProfileTest.java
@@ -144,6 +144,34 @@
    }
    @Test
    void shouldReleaseIdentityFromStalePendingGuideBeforeNewRegistration() {
        GuideApplication application = new GuideApplication();
        application.setMobile("13900139000");
        application.setRealName("新导游");
        application.setIdCardNo("11010519491231002X");
        when(userMapper.selectOne(any())).thenReturn(null);
        service.createPendingFromApplication(application);
        verify(userMapper).clearCancelledIdentityByIdCard("11010519491231002X");
        verify(userMapper).clearPendingIdentityByIdCard("11010519491231002X");
        verify(userMapper).insert(any(GuideUser.class));
    }
    @Test
    void shouldReleasePendingIdentityWhenRejectingApplication() {
        GuideUser pendingGuide = new GuideUser();
        pendingGuide.setId(12L);
        pendingGuide.setStatus(GuideUserService.STATUS_PENDING);
        pendingGuide.setMobile("13800138000");
        when(userMapper.selectOne(any())).thenReturn(pendingGuide);
        service.releaseIdentityForRejectedApplication("13800138000");
        verify(userMapper).releasePendingIdentity(12L);
    }
    @Test
    void shouldTreatOneYearOrLessAsZeroWorkYears() {
        GuideApplication application = new GuideApplication();
        application.setMobile("13800138000");
frontend/src/views/DashboardView.vue
@@ -115,7 +115,7 @@
          <el-button link type="primary" @click="router.push('/finance/details')">查看更多</el-button>
        </div>
        <div class="line-chart">
          <svg viewBox="0 0 680 225" preserveAspectRatio="none" role="img" aria-label="近7日平台收益趋势">
          <svg viewBox="0 0 680 225" preserveAspectRatio="xMidYMid meet" role="img" aria-label="近7日平台收益趋势">
            <defs>
              <linearGradient id="revenueArea" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stop-color="#5eb8ff" stop-opacity=".38" />
@@ -222,7 +222,7 @@
.chart-heading div { display: flex; align-items: center; gap: 8px; }
.chart-heading strong, .section-heading h2, .quick-panel h2 { margin: 0; color: #232932; font-size: 14px; }
.chart-heading span { color: #8491a3; font-size: 11px; }
.line-chart { height: 190px; }
.line-chart { aspect-ratio: 680 / 225; }
.line-chart svg { display: block; width: 100%; height: 100%; overflow: visible; }
.grid-line { stroke: #e8eef5; stroke-width: 1; stroke-dasharray: 3 3; }
.axis-label { fill: #8491a3; font-size: 10px; }