|
@@ -336,6 +336,133 @@ private FamilyInvitationService familyInvitationService;
|
|
|
return userMapper.selectById(userId);
|
|
return userMapper.selectById(userId);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /** 回写字段白名单(user 目标) */
|
|
|
|
|
+ private static final String[] USER_BACKFILL_WHITELIST = {"phone", "gender", "birthday", "birthHour", "dietPreferences", "address"};
|
|
|
|
|
+
|
|
|
|
|
+ /** 回写字段白名单(member 目标,family_members 表无 dietPreferences/address 列) */
|
|
|
|
|
+ private static final String[] MEMBER_BACKFILL_WHITELIST = {"phone", "gender", "birthday", "birthHour"};
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 就地补充信息回写(字段白名单校验 + 目标归属校验)
|
|
|
|
|
+ * @return Map: { updatedFields: List<String>, profile: Object(最新完整信息) }
|
|
|
|
|
+ */
|
|
|
|
|
+ public Map<String, Object> backfillProfile(Long userId, ProfileBackfillDTO dto) {
|
|
|
|
|
+ if (dto == null || dto.getFields() == null || dto.getFields().isEmpty()) {
|
|
|
|
|
+ throw new RuntimeException("回写字段不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ User me = userMapper.selectById(userId);
|
|
|
|
|
+ if (me == null) {
|
|
|
|
|
+ throw new RuntimeException("用户不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ List<String> updatedFields = new ArrayList<>();
|
|
|
|
|
+ Object profile;
|
|
|
|
|
+
|
|
|
|
|
+ if ("user".equals(dto.getTargetType())) {
|
|
|
|
|
+ // 仅允许回写自己
|
|
|
|
|
+ if (dto.getTargetId() != null && !dto.getTargetId().equals(userId)) {
|
|
|
|
|
+ throw new RuntimeException("仅能回写本人的个人信息");
|
|
|
|
|
+ }
|
|
|
|
|
+ for (String field : USER_BACKFILL_WHITELIST) {
|
|
|
|
|
+ String value = dto.getFields().get(field);
|
|
|
|
|
+ if (value == null || value.isEmpty()) continue;
|
|
|
|
|
+ applyUserBackfillField(me, field, value.trim());
|
|
|
|
|
+ updatedFields.add(field);
|
|
|
|
|
+ }
|
|
|
|
|
+ me.setUpdatedAt(new Date());
|
|
|
|
|
+ userMapper.updateById(me);
|
|
|
|
|
+ profile = me;
|
|
|
|
|
+ } else if ("member".equals(dto.getTargetType())) {
|
|
|
|
|
+ Long memberId = dto.getTargetId();
|
|
|
|
|
+ if (memberId == null) {
|
|
|
|
|
+ throw new RuntimeException("回写家庭成员时 targetId 不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ FamilyMember member = familyMemberMapper.selectById(memberId);
|
|
|
|
|
+ if (member == null) {
|
|
|
|
|
+ throw new RuntimeException("家庭成员不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ // 归属校验:成员必须属于当前用户家庭
|
|
|
|
|
+ Long myFamilyId = me.getFamilyId();
|
|
|
|
|
+ if (myFamilyId == null || !myFamilyId.equals(member.getFamilyId())) {
|
|
|
|
|
+ throw new RuntimeException("该成员不属于您的家庭");
|
|
|
|
|
+ }
|
|
|
|
|
+ for (String field : MEMBER_BACKFILL_WHITELIST) {
|
|
|
|
|
+ String value = dto.getFields().get(field);
|
|
|
|
|
+ if (value == null || value.isEmpty()) continue;
|
|
|
|
|
+ applyMemberBackfillField(member, field, value.trim());
|
|
|
|
|
+ updatedFields.add(field);
|
|
|
|
|
+ }
|
|
|
|
|
+ familyMemberMapper.updateById(member);
|
|
|
|
|
+ profile = member;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new RuntimeException("targetType 仅支持 user/member");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("updatedFields", updatedFields);
|
|
|
|
|
+ result.put("profile", profile);
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void applyUserBackfillField(User user, String field, String value) {
|
|
|
|
|
+ switch (field) {
|
|
|
|
|
+ case "phone":
|
|
|
|
|
+ if (!value.matches("^1[3-9]\\d{9}$")) throw new RuntimeException("手机号格式不正确");
|
|
|
|
|
+ user.setPhone(value);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "gender":
|
|
|
|
|
+ if (!"male".equals(value) && !"female".equals(value)) throw new RuntimeException("性别取值非法");
|
|
|
|
|
+ user.setGender(value);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "birthday":
|
|
|
|
|
+ try {
|
|
|
|
|
+ java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
|
|
|
|
|
+ user.setBirthday(sdf.parse(value));
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ throw new RuntimeException("生日格式不正确,应为 yyyy-MM-dd");
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "birthHour":
|
|
|
|
|
+ if (!"子丑寅卯辰巳午未申酉戌亥".contains(value)) throw new RuntimeException("出生时辰取值非法");
|
|
|
|
|
+ user.setBirthHour(value);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "dietPreferences":
|
|
|
|
|
+ user.setDietPreferences(value);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "address":
|
|
|
|
|
+ user.setAddress(value);
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void applyMemberBackfillField(FamilyMember member, String field, String value) {
|
|
|
|
|
+ switch (field) {
|
|
|
|
|
+ case "phone":
|
|
|
|
|
+ if (!value.matches("^1[3-9]\\d{9}$")) throw new RuntimeException("手机号格式不正确");
|
|
|
|
|
+ member.setPhone(value);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "gender":
|
|
|
|
|
+ if (!"male".equals(value) && !"female".equals(value)) throw new RuntimeException("性别取值非法");
|
|
|
|
|
+ member.setGender(value);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "birthday":
|
|
|
|
|
+ try {
|
|
|
|
|
+ java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
|
|
|
|
|
+ member.setBirthday(sdf.parse(value));
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ throw new RuntimeException("生日格式不正确,应为 yyyy-MM-dd");
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "birthHour":
|
|
|
|
|
+ if (!"子丑寅卯辰巳午未申酉戌亥".contains(value)) throw new RuntimeException("出生时辰取值非法");
|
|
|
|
|
+ member.setBirthHour(value);
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 检查手机号是否已注册
|
|
* 检查手机号是否已注册
|
|
|
* @param phone 手机号
|
|
* @param phone 手机号
|