Просмотр исходного кода

feat(realname): T39 统一真实姓名回填昵称规则 - 扩展 RealNameBackfillService 同时补 realName+nickname 并接入全部姓名写入入口

- RealNameBackfillService 新增 backfillRealNameAndNickname(userId,name):realName 为空时同时补 realName+nickname(nickname 仅空时补,不覆盖已有昵称);原 backfill 委托新方法保持兼容
- UserService.updateUserInfo / backfillProfile / registerWithIdCard 接入回填(同步内存 nickname 防外层 updateById 覆盖;registerWithIdCard 在 createUserAndFamily 后调用以获取 userId)
- GuideManagementController.registerGuide / AdminController.createUser / SupplyManageController create+update 接入回填
- ButlerController.apply / NutritionistController.apply 新增接收 realName 参数并接入回填
- cfc-frontend pages/butler/apply.vue 提交时补传 realName(原仅传 tier/description)
- 约束:触发条件=realName 为空;幂等;失败静默不阻塞主流程;不新增 DB 迁移
Agnes Agent 1 неделя назад
Родитель
Сommit
2e9eb54391

+ 10 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/NutritionistController.java

@@ -4,6 +4,7 @@ import com.etotem.cfc.common.Result;
 import com.etotem.cfc.entity.User;
 import com.etotem.cfc.mapper.UserMapper;
 import com.etotem.cfc.service.UserService;
+import com.etotem.cfc.service.RealNameBackfillService;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
@@ -20,6 +21,9 @@ public class NutritionistController {
     @Resource
     private UserService userService;
 
+    @Resource
+    private RealNameBackfillService realNameBackfillService;
+
     @PostMapping("/apply")
     public Result<String> apply(@RequestBody Map<String, Object> params,
                                  @RequestAttribute("userId") Long userId) {
@@ -37,6 +41,12 @@ public class NutritionistController {
 
         userService.addRole(user.getId(), "nutritionist");
 
+        // 营养师申请:接收 realName,若 realName 尚未填写则同时回填 realName + nickname(nickname 仅空时补)
+        String realName = (String) params.get("realName");
+        if (realName != null && !realName.trim().isEmpty()) {
+            realNameBackfillService.backfillRealNameAndNickname(user.getId(), realName.trim());
+        }
+
         return Result.success("营养师申请已提交,请等待审核");
     }
 

+ 8 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminController.java

@@ -14,6 +14,7 @@ import com.etotem.cfc.dto.TaskReviewDTO;
 import com.etotem.cfc.service.TaskService;
 import com.etotem.cfc.service.UserService;
 import com.etotem.cfc.service.MembershipService;
+import com.etotem.cfc.service.RealNameBackfillService;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.TypeReference;
 import javax.annotation.Resource;
@@ -106,6 +107,9 @@ public class AdminController {
     @Resource
     private MembershipService membershipService;
 
+    @Resource
+    private RealNameBackfillService realNameBackfillService;
+
     // 终身会员达标阈值(分)
     private static final long LIFETIME_CONSUME_THRESHOLD = 100_000_000L;  // 消费 ≥ 100万元
     private static final long LIFETIME_SALES_THRESHOLD = 200_000_000L;    // 销售 ≥ 200万元
@@ -232,6 +236,10 @@ public class AdminController {
         } catch (Exception e) {
             return Result.error("创建用户失败: " + e.getMessage());
         }
+        // 后台创建用户:若提供了 realName 且 realName 尚未填写,同时回填 realName + nickname(nickname 仅空时补)
+        if (realName != null && !realName.trim().isEmpty()) {
+            realNameBackfillService.backfillRealNameAndNickname(user.getId(), realName.trim());
+        }
         return Result.success(user);
     }
 

+ 18 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/SupplyManageController.java

@@ -6,6 +6,7 @@ import com.etotem.cfc.common.Result;
 import com.etotem.cfc.entity.User;
 import com.etotem.cfc.mapper.UserMapper;
 import com.etotem.cfc.service.UserService;
+import com.etotem.cfc.service.RealNameBackfillService;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
@@ -28,6 +29,9 @@ public class SupplyManageController {
     @Resource
     private UserService userService;
 
+    @Resource
+    private RealNameBackfillService realNameBackfillService;
+
     /**
      * 供应商列表(分页+搜索)
      * 查询拥有 supplier_admin 角色的用户
@@ -127,6 +131,10 @@ public class SupplyManageController {
         user.setUpdatedAt(new Date());
 
         userMapper.insert(user);
+        // 供应商创建:若提供了 realName 且 realName 尚未填写,同时回填 realName + nickname(nickname 仅空时补)
+        if (realName != null && !realName.trim().isEmpty()) {
+            realNameBackfillService.backfillRealNameAndNickname(user.getId(), realName.trim());
+        }
         user.setPassword(null);
         return Result.success(user);
     }
@@ -150,7 +158,16 @@ public class SupplyManageController {
             user.setNickname((String) params.get("nickname"));
         }
         if (params.containsKey("realName")) {
-            user.setRealName((String) params.get("realName"));
+            String realName = (String) params.get("realName");
+            if (realName != null && !realName.trim().isEmpty()) {
+                // 供应商更新:若 realName 尚未填写,同时回填 realName + nickname(nickname 仅空时补)
+                realNameBackfillService.backfillRealNameAndNickname(id, realName.trim());
+                // 同步内存:helper 可能补写了 nickname,保证外层 updateById 不覆盖
+                if (user.getNickname() == null || user.getNickname().trim().isEmpty()) {
+                    user.setNickname(realName.trim());
+                }
+            }
+            user.setRealName(realName);
         }
         if (params.containsKey("vendorType")) {
             user.setVendorType((String) params.get("vendorType"));

+ 11 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/butler/ButlerController.java

@@ -6,6 +6,7 @@ import com.etotem.cfc.common.Result;
 import com.etotem.cfc.entity.User;
 import com.etotem.cfc.mapper.UserMapper;
 import com.etotem.cfc.service.ButlerService;
+import com.etotem.cfc.service.RealNameBackfillService;
 import io.swagger.v3.oas.annotations.Operation;
 import org.springframework.web.bind.annotation.*;
 
@@ -26,6 +27,9 @@ public class ButlerController {
     @Resource
     private UserMapper userMapper;
 
+    @Resource
+    private RealNameBackfillService realNameBackfillService;
+
     /**
      * 申请成为管家
      * POST /api/butler/apply
@@ -35,7 +39,13 @@ public class ButlerController {
                                  @RequestAttribute("userId") Long userId) {
         String tier = (String) params.get("tier");
         String description = (String) params.get("description");
-        return butlerService.apply(userId, tier, description);
+        // 管家申请:接收 realName,若 realName 尚未填写则同时回填 realName + nickname(nickname 仅空时补)
+        String realName = (String) params.get("realName");
+        Result<String> result = butlerService.apply(userId, tier, description);
+        if (result.getCode() == 200 && realName != null && !realName.trim().isEmpty()) {
+            realNameBackfillService.backfillRealNameAndNickname(userId, realName.trim());
+        }
+        return result;
     }
 
     /**

+ 9 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/guide/GuideManagementController.java

@@ -20,6 +20,7 @@ import com.etotem.cfc.service.GuidePackageTemplateService;
 import com.etotem.cfc.service.PlannerCertificationGuard;
 import com.etotem.cfc.service.PlannerCertificationService;
 import com.etotem.cfc.service.UserService;
+import com.etotem.cfc.service.RealNameBackfillService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.web.bind.annotation.*;
@@ -63,6 +64,9 @@ public class GuideManagementController {
     @Resource
     private PlannerCertificationGuard plannerCertificationGuard;
 
+    @Resource
+    private RealNameBackfillService realNameBackfillService;
+
     /**
      * 成长规划师注册(保存草稿)
      */
@@ -79,11 +83,15 @@ public class GuideManagementController {
         user.setTeacherNo(dto.getTeacherNo());
         user.setTeacherPhoto(dto.getTeacherPhoto());
         user.setCertificateImage(dto.getCertificateImage());
-        user.setRealName(dto.getRealName());
         user.setPhone(dto.getPhone());
         user.setIdCard(dto.getIdCard());
         user.setAddress(dto.getAddress());
         user.setTeacherStatus("pending");
+        // 规划师注册:若 realName 尚未填写,同时回填 realName + nickname(nickname 仅空时补)
+        if (dto.getRealName() != null && !dto.getRealName().trim().isEmpty()) {
+            realNameBackfillService.backfillRealNameAndNickname(dto.getUserId(), dto.getRealName().trim());
+        }
+        user.setRealName(dto.getRealName());
         user.setUpdatedAt(new java.util.Date());
         userMapper.updateById(user);
 

+ 15 - 1
cfc-backend/src/main/java/com/etotem/cfc/service/RealNameBackfillService.java

@@ -27,6 +27,15 @@ public class RealNameBackfillService {
      * contactName 空白、userId 为空、用户不存在时直接跳过。
      */
     public void backfill(Long userId, String contactName) {
+        backfillRealNameAndNickname(userId, contactName);
+    }
+
+    /**
+     * 若 userId 对应用户的 realName 为空白,则同时回填 realName 和 nickname(nickname 仅在也为空白时补)。
+     * contactName 空白、userId 为空、用户不存在时直接跳过;失败静默不阻塞主流程。
+     * 幂等:realName 非空后再次调用直接跳过。
+     */
+    public void backfillRealNameAndNickname(Long userId, String contactName) {
         try {
             if (userId == null) return;
             if (contactName == null || contactName.trim().isEmpty()) return;
@@ -34,7 +43,12 @@ public class RealNameBackfillService {
             if (user == null) return;
             String realName = user.getRealName();
             if (realName != null && !realName.trim().isEmpty()) return;
-            user.setRealName(contactName.trim());
+            String name = contactName.trim();
+            user.setRealName(name);
+            String nickname = user.getNickname();
+            if (nickname == null || nickname.trim().isEmpty()) {
+                user.setNickname(name);
+            }
             userMapper.updateById(user);
         } catch (Exception e) {
             log.warn("[RealNameBackfill] 回填失败 userId={} : {}", userId, e.getMessage());

+ 17 - 1
cfc-backend/src/main/java/com/etotem/cfc/service/UserService.java

@@ -88,6 +88,9 @@ private FamilyInvitationService familyInvitationService;
     @Resource
     private ConsigneeMapper consigneeMapper;
 
+    @Resource
+    private RealNameBackfillService realNameBackfillService;
+
     public LoginResultDTO wechatLogin(WechatLoginDTO dto) {
         // 1. 通过code获取openid
         Map<String, String> sessionData = wechatService.code2Session(dto.getCode());
@@ -499,6 +502,11 @@ private FamilyInvitationService familyInvitationService;
             case "realName":
                 if (value.length() > 20) throw new RuntimeException("真实姓名不能超过20字");
                 user.setRealName(value);
+                realNameBackfillService.backfillRealNameAndNickname(user.getId(), value);
+                // 同步内存:helper 可能补写了 nickname,保证外层 updateById 不覆盖
+                if (user.getNickname() == null || user.getNickname().trim().isEmpty()) {
+                    user.setNickname(value.trim());
+                }
                 break;
             default:
                 break;
@@ -1014,11 +1022,14 @@ private FamilyInvitationService familyInvitationService;
             user.setNickname(dto.getNickname());
             user.setAvatar(dto.getAvatar());
             user.setIdCard(dto.getIdCard());
-            user.setRealName(dto.getRealName());
             user.setPassword(""); // 初始密码为空,需要后续设置
             user.setCreatedAt(new Date());
             user.setUpdatedAt(new Date());
             createUserAndFamily(user);
+            // 新用户创建后:若 dto 提供了真实姓名且用户表 realName 尚未填写,同时回填 realName + nickname(nickname 仅空时补)
+            if (dto.getRealName() != null && !dto.getRealName().trim().isEmpty()) {
+                realNameBackfillService.backfillRealNameAndNickname(user.getId(), dto.getRealName().trim());
+            }
         }
 
         ensureUserHasFamily(user);
@@ -1199,6 +1210,11 @@ FamilyMember child = familyMemberMapper.selectById(memberId);
         }
         if (dto.getRealName() != null) {
             user.setRealName(dto.getRealName());
+            realNameBackfillService.backfillRealNameAndNickname(userId, dto.getRealName());
+            // 同步内存:helper 可能补写了 nickname,保证外层 updateById 不覆盖(nickname 仅空时补)
+            if (user.getNickname() == null || user.getNickname().trim().isEmpty()) {
+                user.setNickname(dto.getRealName().trim());
+            }
         }
         // 更新角色
         if (dto.getRole() != null) {

+ 1 - 0
cfc-frontend/pages/butler/apply.vue

@@ -86,6 +86,7 @@ export default {
       this.submitting = true
       try {
         const res = await butlerApply({
+          realName: this.formData.realName,
           tier: this.formData.tier,
           description: this.formData.description
         })