Hai Lin пре 2 недеља
родитељ
комит
7fce4c9d08
22 измењених фајлова са 2545 додато и 64 уклоњено
  1. 1 1
      .idea/ApifoxUploaderProjectSetting.xml
  2. 26 0
      .idea/MyBatisCodeHelperDatasource.xml
  3. 130 0
      mirage-service/src/main/java/com/mirage/mirageservice/controller/FamilyController.java
  4. 44 45
      mirage-service/src/main/java/com/mirage/mirageservice/controller/WxController.java
  5. 410 0
      mirage-service/src/main/java/com/mirage/mirageservice/domain/FamilyMemberInfo.java
  6. 142 0
      mirage-service/src/main/java/com/mirage/mirageservice/domain/FamilyRelationInfo.java
  7. 176 0
      mirage-service/src/main/java/com/mirage/mirageservice/domain/FamilyTreeInfo.java
  8. 49 0
      mirage-service/src/main/java/com/mirage/mirageservice/enums/FamilyRelationEnum.java
  9. 3 1
      mirage-service/src/main/java/com/mirage/mirageservice/enums/MinProgramConfigEnum.java
  10. 28 0
      mirage-service/src/main/java/com/mirage/mirageservice/enums/SubRelationTypeEnum.java
  11. 30 0
      mirage-service/src/main/java/com/mirage/mirageservice/mapper/mysql/FamilyMemberInfoMapper.java
  12. 54 0
      mirage-service/src/main/java/com/mirage/mirageservice/mapper/mysql/FamilyRelationInfoMapper.java
  13. 25 0
      mirage-service/src/main/java/com/mirage/mirageservice/meta/FamilyMemberInfoAndRelation.java
  14. 31 0
      mirage-service/src/main/java/com/mirage/mirageservice/meta/FamilyTreeResponse.java
  15. 23 0
      mirage-service/src/main/java/com/mirage/mirageservice/meta/MemberInfoRequest.java
  16. 25 0
      mirage-service/src/main/java/com/mirage/mirageservice/meta/MemberRelationRequest.java
  17. 37 0
      mirage-service/src/main/java/com/mirage/mirageservice/meta/SelfFamilyCardResponse.java
  18. 287 0
      mirage-service/src/main/java/com/mirage/mirageservice/service/FamilyService.java
  19. 443 0
      mirage-service/src/main/resources/com/mirage/mirageservice/mapper/mysql/FamilyMemberInfoMapper.xml
  20. 509 0
      mirage-service/src/main/resources/com/mirage/mirageservice/mapper/mysql/FamilyRelationInfoMapper.xml
  21. 0 17
      sql
  22. 72 0
      sql.sql

Разлика између датотеке није приказан због своје велике величине
+ 1 - 1
.idea/ApifoxUploaderProjectSetting.xml


+ 26 - 0
.idea/MyBatisCodeHelperDatasource.xml

@@ -43,6 +43,32 @@
                 </TableGenerateConfig>
               </value>
             </entry>
+            <entry key="csqz-client:family_member_info">
+              <value>
+                <TableGenerateConfig>
+                  <option name="generatedKey" value="id" />
+                  <option name="javaModelName" value="FamilyMemberInfo" />
+                  <option name="moduleName" value="mirage-service" />
+                  <option name="mybatisplusIdType" value="AUTO" />
+                  <option name="sequenceColumn" value="" />
+                  <option name="sequenceId" value="" />
+                  <option name="useActualColumnName" value="false" />
+                </TableGenerateConfig>
+              </value>
+            </entry>
+            <entry key="csqz-client:family_relation_info">
+              <value>
+                <TableGenerateConfig>
+                  <option name="generatedKey" value="id" />
+                  <option name="javaModelName" value="FamilyRelationInfo" />
+                  <option name="moduleName" value="mirage-service" />
+                  <option name="mybatisplusIdType" value="AUTO" />
+                  <option name="sequenceColumn" value="" />
+                  <option name="sequenceId" value="" />
+                  <option name="useActualColumnName" value="false" />
+                </TableGenerateConfig>
+              </value>
+            </entry>
             <entry key="csqz-client:student_data_report">
               <value>
                 <TableGenerateConfig>

+ 130 - 0
mirage-service/src/main/java/com/mirage/mirageservice/controller/FamilyController.java

@@ -0,0 +1,130 @@
+package com.mirage.mirageservice.controller;
+
+import com.google.common.collect.Maps;
+import com.mirage.core.annotation.Auth;
+import com.mirage.core.exception.AppRuntimeException;
+import com.mirage.core.meta.AppCode;
+import com.mirage.core.meta.AuthType;
+import com.mirage.mirageservice.domain.CsMinWechatUser;
+import com.mirage.mirageservice.domain.FamilyMemberInfo;
+import com.mirage.mirageservice.enums.FamilyRelationEnum;
+import com.mirage.mirageservice.meta.AppContext;
+import com.mirage.mirageservice.meta.MemberInfoRequest;
+import com.mirage.mirageservice.service.FamilyService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by hzlinhai on 2025/10/21.
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/mp/wx/family")
+public class FamilyController {
+
+    @Resource
+    private FamilyService familyService;
+
+    /**
+     * 获取自己的亲属关系卡片信息.
+     *
+     * @return
+     */
+    @Auth(value = AuthType.COOKIES)
+    @RequestMapping(value = "/member/selfCard", method = RequestMethod.GET)
+    public Object getSelfCard(){
+        return familyService.getSelfFamilyMember(AppContext.getUid());
+    }
+
+    /**
+     * 根据成员id获取成员详细信息.
+     * @param id
+     * @return
+     */
+    @Auth(value = AuthType.COOKIES)
+    @RequestMapping(value = "/member/get", method = RequestMethod.GET)
+    public Object getMemberById(@RequestParam Long id){
+        return familyService.getMemberById(id);
+    }
+
+    /**
+     * 1.微信小程序授权登陆后填写自己信息;
+     * 2.填写名称后校验是否已有同名记录,此接口会返回所有同名者信息;
+     * 3.确认选择已有信息作为自己或者修改数据(名字不允许修改);
+     * 4.确认同名者非自己,填写自己信息isConfirm=1代表确认同名者非自己,填写新信息.
+     * @param request
+     * @return
+     */
+    @Auth(value = AuthType.COOKIES)
+    @RequestMapping(value = "/member/addOrUpdate", method = RequestMethod.POST)
+    public Object addOrUpdateMember(@RequestBody MemberInfoRequest request){
+        // 当前登陆用户.
+        CsMinWechatUser csMinWechatUser = AppContext.getUserInfo();
+        if(null == request
+                || null == csMinWechatUser
+                || null == request.getRelationRequest()
+                || null == request.getRelationRequest().getRelationType()
+                || null == request.getMemberInfo()
+                || StringUtils.isBlank(request.getMemberInfo().getName())
+                || null == request.getMemberInfo().getSex()
+                || null == request.getMemberInfo().getBirthday()){
+            throw new AppRuntimeException(AppCode.BAD_REQUEST);
+        }
+        if(null != request.getMemberInfo().getId()){
+            // 冲突检测,已被认领情况下不允许自己填写.
+            FamilyMemberInfo memberInfo = familyService.getMemberById(request.getMemberInfo().getId());
+            if(null == memberInfo){
+                throw new AppRuntimeException(AppCode.BAD_REQUEST);
+            }
+            if(memberInfo.getUid() != -1L){
+                throw new AppRuntimeException("该成员已被其他成员填写并认领,请联系管理员!");
+            }
+        }else if(null == request.getIsConfirm() || request.getIsConfirm() == 0){ // 没有经过二次确认返回同名列表
+            // 同名返回,二次确认认领
+            // 1.选择已有信息其他亲属填写的信息做修改
+            // 2.确认同名,不同人
+            List<FamilyMemberInfo> memberInfoList = familyService.getMemberInfoByName(request.getMemberInfo().getName());
+            if(null != memberInfoList && !memberInfoList.isEmpty()){
+                Map<String, Object> alreadyList = Maps.newHashMap();
+                alreadyList.put("alreadyList", memberInfoList);
+                return alreadyList;
+            }
+        }
+        FamilyRelationEnum relationEnum = FamilyRelationEnum.getByType(request.getRelationRequest().getRelationType());
+        if(null == relationEnum){
+            throw new AppRuntimeException(AppCode.BAD_REQUEST);
+        }
+        // SELF代表填写自己
+        if(relationEnum == FamilyRelationEnum.SELF) {
+            request.getMemberInfo().setUid(csMinWechatUser.getId());
+            request.getMemberInfo().setPhone(csMinWechatUser.getPhone());
+        }else{ // 非SELF代表填写其他亲属
+            FamilyMemberInfo selfMemberInfo = familyService.getMemberByUid(csMinWechatUser.getId());
+            if(null == selfMemberInfo){
+                throw new AppRuntimeException("请先填写自己信息再录入亲属信息");
+            }
+            request.getMemberInfo().setUid(-1L);
+        }
+        try {
+            return familyService.addOrUpdateMember(request, csMinWechatUser);
+        } catch (Exception e) {
+            throw new AppRuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 获取用户家族树.
+     * @param generation (非必填,默认上下5代)
+     * @return
+     */
+    @Auth(value = AuthType.COOKIES)
+    @RequestMapping(value = "/member/familyTree", method = RequestMethod.GET)
+    public Object getUserFamilyTreeMember(@RequestParam(required = false) Integer generation){
+        return familyService.getFamilyTree(AppContext.getUid(), generation);
+    }
+}

+ 44 - 45
mirage-service/src/main/java/com/mirage/mirageservice/controller/WxController.java

@@ -2,15 +2,14 @@ package com.mirage.mirageservice.controller;
 
 import com.mirage.core.annotation.Auth;
 import com.mirage.core.exception.AppRuntimeException;
-import com.mirage.core.meta.AppCode;
 import com.mirage.core.meta.AuthType;
 import com.mirage.mirageservice.enums.MinProgramConfigEnum;
-import com.mirage.mirageservice.meta.AppContext;
-import com.mirage.mirageservice.meta.BindRequest;
 import com.mirage.mirageservice.service.UserService;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 
@@ -75,44 +74,44 @@ public class WxController {
         }
         return userService.getUserWxInfo(code, configEnum);
     }
-
-    @Auth(value = AuthType.COOKIES)
-    @RequestMapping(value = "/user/bind", method = RequestMethod.POST)
-    public Object bind(@RequestBody BindRequest bindRequest){
-        if(null == bindRequest
-                || null == bindRequest.getScanPageId()
-                || StringUtils.isBlank(bindRequest.getStudentName())){
-            throw new AppRuntimeException(AppCode.BAD_REQUEST);
-        }
-        String openId = AppContext.getUserInfo().getOpenId();
-        if(StringUtils.isBlank(openId)){
-            throw new AppRuntimeException(AppCode.UNAUTHORIZED);
-        }
-        bindRequest.setOpenId(openId);
-        return userService.bind(bindRequest);
-    }
-
-    @Auth(value = AuthType.COOKIES)
-    @RequestMapping(value = "/user/unbind")
-    public Object unbind(){
-        String openId = AppContext.getUserInfo().getOpenId();
-        if(StringUtils.isBlank(openId)){
-            throw new AppRuntimeException(AppCode.UNAUTHORIZED);
-        }
-        return userService.unBind(openId);
-    }
-
-    @Auth(value = AuthType.COOKIES)
-    @RequestMapping(value = "/user/reports", method = RequestMethod.GET)
-    public Object reportList(@RequestParam String openId,
-                             @RequestParam(required = false, defaultValue = "1") Integer pageIndex,
-                             @RequestParam(required = false, defaultValue = "10") Integer pageSize){
-        return userService.reportList(openId, pageIndex, pageSize);
-    }
-
-    @Auth(value = AuthType.COOKIES)
-    @RequestMapping(value = "/user/report/{id}", method = RequestMethod.GET)
-    public Object getReportDetail(@PathVariable Integer id){
-        return userService.getReportDetail(id);
-    }
+//
+//    @Auth(value = AuthType.COOKIES)
+//    @RequestMapping(value = "/user/bind", method = RequestMethod.POST)
+//    public Object bind(@RequestBody BindRequest bindRequest){
+//        if(null == bindRequest
+//                || null == bindRequest.getScanPageId()
+//                || StringUtils.isBlank(bindRequest.getStudentName())){
+//            throw new AppRuntimeException(AppCode.BAD_REQUEST);
+//        }
+//        String openId = AppContext.getUserInfo().getOpenId();
+//        if(StringUtils.isBlank(openId)){
+//            throw new AppRuntimeException(AppCode.UNAUTHORIZED);
+//        }
+//        bindRequest.setOpenId(openId);
+//        return userService.bind(bindRequest);
+//    }
+//
+//    @Auth(value = AuthType.COOKIES)
+//    @RequestMapping(value = "/user/unbind")
+//    public Object unbind(){
+//        String openId = AppContext.getUserInfo().getOpenId();
+//        if(StringUtils.isBlank(openId)){
+//            throw new AppRuntimeException(AppCode.UNAUTHORIZED);
+//        }
+//        return userService.unBind(openId);
+//    }
+//
+//    @Auth(value = AuthType.COOKIES)
+//    @RequestMapping(value = "/user/reports", method = RequestMethod.GET)
+//    public Object reportList(@RequestParam String openId,
+//                             @RequestParam(required = false, defaultValue = "1") Integer pageIndex,
+//                             @RequestParam(required = false, defaultValue = "10") Integer pageSize){
+//        return userService.reportList(openId, pageIndex, pageSize);
+//    }
+//
+//    @Auth(value = AuthType.COOKIES)
+//    @RequestMapping(value = "/user/report/{id}", method = RequestMethod.GET)
+//    public Object getReportDetail(@PathVariable Integer id){
+//        return userService.getReportDetail(id);
+//    }
 }

+ 410 - 0
mirage-service/src/main/java/com/mirage/mirageservice/domain/FamilyMemberInfo.java

@@ -0,0 +1,410 @@
+package com.mirage.mirageservice.domain;
+
+import java.util.Date;
+
+/** 
+* Created by hzlinhai on 2025/10/23. 
+*/
+
+/**
+ * 成员表
+ */
+public class FamilyMemberInfo {
+    private Long id;
+
+    private Long uid;
+
+    private String name;
+
+    /**
+     * 曾用名,多个jsonArray格式
+     */
+    private String formerName;
+
+    /**
+     * 乳名,多个jsonArray格式
+     */
+    private String childhoodName;
+
+    /**
+     * 字,多个jsonArray格式
+     */
+    private String nameWord;
+
+    /**
+     * 字辈,多个jsonArray格式
+     */
+    private String nameWordGeneration;
+
+    /**
+     * 号,多个jsonArray格式
+     */
+    private String nameTitle;
+
+    /**
+     * 1:男 2:女
+     */
+    private Integer sex;
+
+    private Long birthday;
+
+    /**
+     * 是否过世 0:否 1:是
+     */
+    private Integer isPassAway;
+
+    /**
+     * 逝世时间
+     */
+    private Date passAwayTime;
+
+    /**
+     * 0:未婚 1:已婚 2:离异 3:丧偶
+     */
+    private Integer maritalStatus;
+
+    /**
+     * 出生地
+     */
+    private String birthPlace;
+
+    /**
+     * 支系堂派
+     */
+    private String branchFamilyHall;
+
+    /**
+     * 聚落
+     */
+    private String clusterPlace;
+
+    /**
+     * 民族
+     */
+    private String nation;
+
+    /**
+     * 居住地址
+     */
+    private String residentialAddress;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+    /**
+     * 邮箱地址
+     */
+    private String mail;
+
+    /**
+     * 微信号
+     */
+    private String wechatAccount;
+
+    /**
+     * 头像照片
+     */
+    private String headImgUrl;
+
+    /**
+     * 身份证号
+     */
+    private String idNumber;
+
+    /**
+     * 职业
+     */
+    private String occupation;
+
+    /**
+     * 教育背景
+     */
+    private String educational;
+
+    /**
+     * 血型
+     */
+    private String bloodType;
+
+    /**
+     * 宗教信仰
+     */
+    private String religion;
+
+    /**
+     * 兴趣爱好
+     */
+    private String hobbies;
+
+    /**
+     * 个人简介、个人成就
+     */
+    private String personalAchievements;
+
+    /**
+     * 代填人uid
+     */
+    private Long createUid;
+
+    private Date createTime;
+
+    private Date modifiedTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getUid() {
+        return uid;
+    }
+
+    public void setUid(Long uid) {
+        this.uid = uid;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getFormerName() {
+        return formerName;
+    }
+
+    public void setFormerName(String formerName) {
+        this.formerName = formerName;
+    }
+
+    public String getChildhoodName() {
+        return childhoodName;
+    }
+
+    public void setChildhoodName(String childhoodName) {
+        this.childhoodName = childhoodName;
+    }
+
+    public String getNameWord() {
+        return nameWord;
+    }
+
+    public void setNameWord(String nameWord) {
+        this.nameWord = nameWord;
+    }
+
+    public String getNameWordGeneration() {
+        return nameWordGeneration;
+    }
+
+    public void setNameWordGeneration(String nameWordGeneration) {
+        this.nameWordGeneration = nameWordGeneration;
+    }
+
+    public String getNameTitle() {
+        return nameTitle;
+    }
+
+    public void setNameTitle(String nameTitle) {
+        this.nameTitle = nameTitle;
+    }
+
+    public Integer getSex() {
+        return sex;
+    }
+
+    public void setSex(Integer sex) {
+        this.sex = sex;
+    }
+
+    public Long getBirthday() {
+        return birthday;
+    }
+
+    public void setBirthday(Long birthday) {
+        this.birthday = birthday;
+    }
+
+    public Integer getIsPassAway() {
+        return isPassAway;
+    }
+
+    public void setIsPassAway(Integer isPassAway) {
+        this.isPassAway = isPassAway;
+    }
+
+    public Date getPassAwayTime() {
+        return passAwayTime;
+    }
+
+    public void setPassAwayTime(Date passAwayTime) {
+        this.passAwayTime = passAwayTime;
+    }
+
+    public Integer getMaritalStatus() {
+        return maritalStatus;
+    }
+
+    public void setMaritalStatus(Integer maritalStatus) {
+        this.maritalStatus = maritalStatus;
+    }
+
+    public String getBirthPlace() {
+        return birthPlace;
+    }
+
+    public void setBirthPlace(String birthPlace) {
+        this.birthPlace = birthPlace;
+    }
+
+    public String getBranchFamilyHall() {
+        return branchFamilyHall;
+    }
+
+    public void setBranchFamilyHall(String branchFamilyHall) {
+        this.branchFamilyHall = branchFamilyHall;
+    }
+
+    public String getClusterPlace() {
+        return clusterPlace;
+    }
+
+    public void setClusterPlace(String clusterPlace) {
+        this.clusterPlace = clusterPlace;
+    }
+
+    public String getNation() {
+        return nation;
+    }
+
+    public void setNation(String nation) {
+        this.nation = nation;
+    }
+
+    public String getResidentialAddress() {
+        return residentialAddress;
+    }
+
+    public void setResidentialAddress(String residentialAddress) {
+        this.residentialAddress = residentialAddress;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public String getMail() {
+        return mail;
+    }
+
+    public void setMail(String mail) {
+        this.mail = mail;
+    }
+
+    public String getWechatAccount() {
+        return wechatAccount;
+    }
+
+    public void setWechatAccount(String wechatAccount) {
+        this.wechatAccount = wechatAccount;
+    }
+
+    public String getHeadImgUrl() {
+        return headImgUrl;
+    }
+
+    public void setHeadImgUrl(String headImgUrl) {
+        this.headImgUrl = headImgUrl;
+    }
+
+    public String getIdNumber() {
+        return idNumber;
+    }
+
+    public void setIdNumber(String idNumber) {
+        this.idNumber = idNumber;
+    }
+
+    public String getOccupation() {
+        return occupation;
+    }
+
+    public void setOccupation(String occupation) {
+        this.occupation = occupation;
+    }
+
+    public String getEducational() {
+        return educational;
+    }
+
+    public void setEducational(String educational) {
+        this.educational = educational;
+    }
+
+    public String getBloodType() {
+        return bloodType;
+    }
+
+    public void setBloodType(String bloodType) {
+        this.bloodType = bloodType;
+    }
+
+    public String getReligion() {
+        return religion;
+    }
+
+    public void setReligion(String religion) {
+        this.religion = religion;
+    }
+
+    public String getHobbies() {
+        return hobbies;
+    }
+
+    public void setHobbies(String hobbies) {
+        this.hobbies = hobbies;
+    }
+
+    public String getPersonalAchievements() {
+        return personalAchievements;
+    }
+
+    public void setPersonalAchievements(String personalAchievements) {
+        this.personalAchievements = personalAchievements;
+    }
+
+    public Long getCreateUid() {
+        return createUid;
+    }
+
+    public void setCreateUid(Long createUid) {
+        this.createUid = createUid;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getModifiedTime() {
+        return modifiedTime;
+    }
+
+    public void setModifiedTime(Date modifiedTime) {
+        this.modifiedTime = modifiedTime;
+    }
+}

+ 142 - 0
mirage-service/src/main/java/com/mirage/mirageservice/domain/FamilyRelationInfo.java

@@ -0,0 +1,142 @@
+package com.mirage.mirageservice.domain;
+
+import java.util.Date;
+
+/**
+ * Created by hzlinhai on 2025/10/22.
+ */
+public class FamilyRelationInfo {
+    private Long id;
+
+    /**
+     * 若为 “父子 / 母子关系”,填父亲 / 母亲的uid;若为 “配偶关系”,填配偶的uid(通过relation_type区分)
+     */
+    private Long parentMid;
+
+    /**
+     * 仅 “亲子关系” 必填,填子女的uid;“配偶关系” 不填(配偶关系无 “子女方”)
+     */
+    private Long childMid;
+
+    /**
+     * 来源mid
+     */
+    private Long sourceMid;
+
+    /**
+     * 关系类型: 1:父子 2:母子 10:夫妻 11:兄弟 12:姐妹
+     */
+    private Integer relationType;
+
+    /**
+     * 关系子类型: 0:亲生/正妻 1:养父 2:过继 10:妾 11:外室
+     */
+    private Integer subRelationType;
+
+    /**
+     * 特殊记录例如:结婚时间,过继时间,领养时间
+     */
+    private String relationValue;
+
+    /**
+     * 代差标记:亲子关系为-1 配偶、兄妹为0,子女为+1
+     */
+    private Integer generationDiff;
+
+    /**
+     * 0:正常 1:离异(夫妻) 2:失联(亲子) 3:已故
+     */
+    private Integer relationStatus;
+
+    private Date createTime;
+
+    private Date modifiedTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getParentMid() {
+        return parentMid;
+    }
+
+    public void setParentMid(Long parentMid) {
+        this.parentMid = parentMid;
+    }
+
+    public Long getChildMid() {
+        return childMid;
+    }
+
+    public void setChildMid(Long childMid) {
+        this.childMid = childMid;
+    }
+
+    public Long getSourceMid() {
+        return sourceMid;
+    }
+
+    public void setSourceMid(Long sourceMid) {
+        this.sourceMid = sourceMid;
+    }
+
+    public Integer getRelationType() {
+        return relationType;
+    }
+
+    public void setRelationType(Integer relationType) {
+        this.relationType = relationType;
+    }
+
+    public Integer getSubRelationType() {
+        return subRelationType;
+    }
+
+    public void setSubRelationType(Integer subRelationType) {
+        this.subRelationType = subRelationType;
+    }
+
+    public String getRelationValue() {
+        return relationValue;
+    }
+
+    public void setRelationValue(String relationValue) {
+        this.relationValue = relationValue;
+    }
+
+    public Integer getGenerationDiff() {
+        return generationDiff;
+    }
+
+    public void setGenerationDiff(Integer generationDiff) {
+        this.generationDiff = generationDiff;
+    }
+
+    public Integer getRelationStatus() {
+        return relationStatus;
+    }
+
+    public void setRelationStatus(Integer relationStatus) {
+        this.relationStatus = relationStatus;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getModifiedTime() {
+        return modifiedTime;
+    }
+
+    public void setModifiedTime(Date modifiedTime) {
+        this.modifiedTime = modifiedTime;
+    }
+}

+ 176 - 0
mirage-service/src/main/java/com/mirage/mirageservice/domain/FamilyTreeInfo.java

@@ -0,0 +1,176 @@
+package com.mirage.mirageservice.domain;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * Created by hzlinhai on 2025/10/21.
+ */
+@Data
+public class FamilyTreeInfo {
+
+    private Integer generation;
+
+    private Long mid;
+
+    private Long uid;
+
+    private String name;
+
+    /**
+     * 曾用名,多个jsonArray格式
+     */
+    private String formerName;
+
+    /**
+     * 乳名,多个jsonArray格式
+     */
+    private String childhoodName;
+
+    /**
+     * 字,多个jsonArray格式
+     */
+    private String nameWord;
+
+    /**
+     * 字辈,多个jsonArray格式
+     */
+    private String nameWordGeneration;
+
+    /**
+     * 号,多个jsonArray格式
+     */
+    private String nameTitle;
+
+    /**
+     * 1:男 2:女
+     */
+    private Integer sex;
+
+    private Long birthday;
+
+    /**
+     * 是否过世 0:否 1:是
+     */
+    private Integer isPassAway;
+
+    /**
+     * 逝世时间
+     */
+    private Date passAwayTime;
+
+    /**
+     * 0:未婚 1:已婚 2:离异 3:丧偶
+     */
+    private Integer maritalStatus;
+
+    /**
+     * 出生地
+     */
+    private String birthPlace;
+
+    /**
+     * 支系堂派
+     */
+    private String branchFamilyHall;
+
+    /**
+     * 聚落
+     */
+    private String clusterPlace;
+
+    /**
+     * 民族
+     */
+    private String nation;
+
+    /**
+     * 居住地址
+     */
+    private String residentialAddress;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+    /**
+     * 邮箱地址
+     */
+    private String mail;
+
+    /**
+     * 微信号
+     */
+    private String wechatAccount;
+
+    /**
+     * 头像照片
+     */
+    private String headImgUrl;
+
+    /**
+     * 身份证号
+     */
+    private String idNumber;
+
+    /**
+     * 职业
+     */
+    private String occupation;
+
+    /**
+     * 教育背景
+     */
+    private String educational;
+
+    /**
+     * 血型
+     */
+    private String bloodType;
+
+    /**
+     * 宗教信仰
+     */
+    private String religion;
+
+    /**
+     * 兴趣爱好
+     */
+    private String hobbies;
+
+    /**
+     * 个人简介、个人成就
+     */
+    private String personalAchievements;
+
+    /**
+     * 代填人uid
+     */
+    private Long createUid;
+
+    private Date createTime;
+
+    private Date modifiedTime;
+
+    /**
+     * 关系类型: 1:父子 2:母子 10:夫妻 11:兄弟 12:姐妹
+     */
+    private Integer relationType;
+
+    /**
+     * 0:正常 1:离异(夫妻) 2:失联(亲子) 3:已故
+     */
+    private String relationStatus;
+
+    /**
+     * 关系子类型: 0:亲生/正妻 1:养父 2:过继 10:妾 11:外室
+     */
+    private Integer subRelationType;
+
+    /**
+     * 特殊记录例如:结婚时间,过继时间,领养时间
+     */
+    private String relationValue;
+}

+ 49 - 0
mirage-service/src/main/java/com/mirage/mirageservice/enums/FamilyRelationEnum.java

@@ -0,0 +1,49 @@
+package com.mirage.mirageservice.enums;
+
+import lombok.Getter;
+
+/**
+ * Created by hzlinhai on 2025/10/21.
+ */
+@Getter
+public enum FamilyRelationEnum {
+
+    SELF(0, "自己"),
+
+    FATHER(1, "父亲"),
+
+    MATHER(2, "母亲"),
+
+    SPOUSE(10, "配偶"),
+
+    SMALL_BROTHER(11,"弟弟"),
+
+    BIG_BROTHER(12,"哥哥"),
+
+    SMALL_SISTER(13, "妹妹"),
+
+    BIG_SISTER(14, "姐姐"),
+
+    SON(100, "儿子"),
+
+    DAUGHTER(101, "女儿");
+
+    private Integer type;
+
+    private String relationName;
+
+    FamilyRelationEnum(Integer type, String relationName){
+        this.type = type;
+        this.relationName = relationName;
+    }
+
+    public static FamilyRelationEnum getByType(Integer type){
+        FamilyRelationEnum[] familyRelationEnums = FamilyRelationEnum.values();
+        for(FamilyRelationEnum familyRelationEnum : familyRelationEnums){
+            if(familyRelationEnum.getType().equals(type)){
+                return familyRelationEnum;
+            }
+        }
+        return null;
+    }
+}

+ 3 - 1
mirage-service/src/main/java/com/mirage/mirageservice/enums/MinProgramConfigEnum.java

@@ -7,7 +7,9 @@ import lombok.Getter;
  */
 @Getter
 public enum MinProgramConfigEnum {
-    CHUNSUN_ENGLISH_MIN_PROGRAM("CS_ENGLISH", "wx7c38acf414870e06", "54d22d78cb553f0001a78753747ba150", "春笋英语学情小程序");
+    CHUNSUN_ENGLISH_MIN_PROGRAM("CS_ENGLISH", "wx7c38acf414870e06", "54d22d78cb553f0001a78753747ba150", "春笋英语学情小程序"),
+
+    FAMILY_MIN_PROGRAM("FAMILY", "", "","家族小程序");
 
     private String name;
 

+ 28 - 0
mirage-service/src/main/java/com/mirage/mirageservice/enums/SubRelationTypeEnum.java

@@ -0,0 +1,28 @@
+package com.mirage.mirageservice.enums;
+
+import lombok.Getter;
+
+/**
+ * Created by hzlinhai on 2025/10/22.
+ */
+@Getter
+public enum SubRelationTypeEnum {
+    NORMAL_OR_WIFE(0, "亲生或正妻"),
+
+    ADOPTED(1, "领养"),
+
+    SAME_CLAN_ADOPTED(2, "过继"),
+
+    CONCUBINE(10, "妾"),
+
+    EXTERNAL_CONCUBINE(11, "外室");
+
+    private Integer type;
+
+    private String message;
+
+    SubRelationTypeEnum(Integer type, String message){
+        this.type = type;
+        this.message = message;
+    }
+}

+ 30 - 0
mirage-service/src/main/java/com/mirage/mirageservice/mapper/mysql/FamilyMemberInfoMapper.java

@@ -0,0 +1,30 @@
+package com.mirage.mirageservice.mapper.mysql;
+
+import com.mirage.mirageservice.domain.FamilyMemberInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Created by hzlinhai on 2025/10/23.
+ */
+public interface FamilyMemberInfoMapper {
+    int deleteByPrimaryKey(Long id);
+
+    int insert(FamilyMemberInfo record);
+
+    int insertSelective(FamilyMemberInfo record);
+
+    FamilyMemberInfo selectByPrimaryKey(Long id);
+
+    int updateByPrimaryKeySelective(FamilyMemberInfo record);
+
+    int updateByPrimaryKey(FamilyMemberInfo record);
+
+    List<FamilyMemberInfo> selectAllByName(@Param("name") String name);
+
+    FamilyMemberInfo selectByUid(@Param("uid") Long uid);
+
+    List<FamilyMemberInfo> selectByIdIn(@Param("idCollection") Collection<Long> idCollection);
+}

+ 54 - 0
mirage-service/src/main/java/com/mirage/mirageservice/mapper/mysql/FamilyRelationInfoMapper.java

@@ -0,0 +1,54 @@
+package com.mirage.mirageservice.mapper.mysql;
+
+import com.mirage.mirageservice.domain.FamilyRelationInfo;
+import com.mirage.mirageservice.domain.FamilyTreeInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Created by hzlinhai on 2025/10/22.
+ */
+public interface FamilyRelationInfoMapper {
+    int deleteByPrimaryKey(Long id);
+
+    int insert(FamilyRelationInfo record);
+
+    int insertSelective(FamilyRelationInfo record);
+
+    FamilyRelationInfo selectByPrimaryKey(Long id);
+
+    int updateByPrimaryKeySelective(FamilyRelationInfo record);
+
+    int updateByPrimaryKey(FamilyRelationInfo record);
+
+    List<FamilyRelationInfo> selectByChildMidAndParentMidAndRelationTypeIn(@Param("childMid") Long childMid, @Param("parentMid") Long parentMid, @Param("relationTypeCollection") Collection<Integer> relationTypeCollection);
+
+    List<FamilyRelationInfo> selectByChildMidAndParentMidAndSourceMidAndRelationTypeIn(@Param("childMid") Long childMid, @Param("parentMid") Long parentMid, @Param("sourceMid") Long sourceMid, @Param("relationTypeCollection") Collection<Integer> relationTypeCollection);
+
+    /**
+     * 上几代查询.
+     *
+     * @param childMid
+     * @param relationTypeCollection
+     * @param generation
+     * @return
+     */
+    List<FamilyTreeInfo> selectElderGeneration(@Param("childMid") Long childMid, @Param("relationTypeCollection") Collection<Integer> relationTypeCollection, @Param("generation") Integer generation);
+
+    /**
+     * 下几代查询.
+     *
+     * @param parentMid
+     * @param relationTypeCollection
+     * @param generation
+     * @return
+     */
+    List<FamilyTreeInfo> selectOffspringGeneration(@Param("parentMid") Long parentMid, @Param("relationTypeCollection") Collection<Integer> relationTypeCollection, @Param("generation") Integer generation);
+
+    /**
+     * 取同代.
+     */
+    List<FamilyTreeInfo> selectPeerGeneration(@Param("mid") Long mid);
+}

+ 25 - 0
mirage-service/src/main/java/com/mirage/mirageservice/meta/FamilyMemberInfoAndRelation.java

@@ -0,0 +1,25 @@
+package com.mirage.mirageservice.meta;
+
+import com.mirage.mirageservice.domain.FamilyMemberInfo;
+import com.mirage.mirageservice.domain.FamilyRelationInfo;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created by hzlinhai on 2025/10/22.
+ */
+@Data
+public class FamilyMemberInfoAndRelation {
+
+    private FamilyMemberInfo memberInfo;
+
+    private FamilyRelationInfo relationInfo;
+
+    public FamilyMemberInfoAndRelation(){}
+
+    public FamilyMemberInfoAndRelation(FamilyMemberInfo memberInfo, FamilyRelationInfo relationInfo){
+        this.memberInfo = memberInfo;
+        this.relationInfo = relationInfo;
+    }
+}

+ 31 - 0
mirage-service/src/main/java/com/mirage/mirageservice/meta/FamilyTreeResponse.java

@@ -0,0 +1,31 @@
+package com.mirage.mirageservice.meta;
+
+import com.mirage.mirageservice.domain.FamilyMemberInfo;
+import com.mirage.mirageservice.domain.FamilyTreeInfo;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created by hzlinhai on 2025/10/23.
+ */
+@Data
+public class FamilyTreeResponse {
+
+    /**
+     * 自己信息
+     */
+    private FamilyMemberInfo self;
+    /**
+     * 长辈信息
+     */
+    private List<FamilyTreeInfo> elderMemberInfo;
+    /**
+     * 下辈信息
+     */
+    private List<FamilyTreeInfo> offspringMemberInfo;
+    /**
+     * 同辈信息
+     */
+    private List<FamilyTreeInfo> peerMemberInfo;
+}

+ 23 - 0
mirage-service/src/main/java/com/mirage/mirageservice/meta/MemberInfoRequest.java

@@ -0,0 +1,23 @@
+package com.mirage.mirageservice.meta;
+
+import com.mirage.mirageservice.domain.FamilyMemberInfo;
+import lombok.Data;
+
+/**
+ * Created by hzlinhai on 2025/10/21.
+ */
+@Data
+public class MemberInfoRequest {
+
+    /**
+     * 二次确认标识,
+     * 同名返回,二次确认认领
+     * 1.选择已有信息其他亲属填写的信息做修改(选择已有id,进行修改)
+     * 2.确认同名,不同人 isConfirm 设置为1
+     */
+    private Integer isConfirm;
+
+    private MemberRelationRequest relationRequest;
+
+    private FamilyMemberInfo memberInfo;
+}

+ 25 - 0
mirage-service/src/main/java/com/mirage/mirageservice/meta/MemberRelationRequest.java

@@ -0,0 +1,25 @@
+package com.mirage.mirageservice.meta;
+
+import lombok.Data;
+
+/**
+ * Created by hzlinhai on 2025/10/22.
+ */
+@Data
+public class MemberRelationRequest {
+
+    private Integer relationType;
+
+    /**
+     * 0:正常 1:离异(夫妻) 2:失联(亲子) 3:已故
+     */
+    private Integer relationStatus;
+
+    private Integer subRelationType;
+
+    /**
+     * 特殊记录例如:结婚时间,过继时间,领养时间
+     */
+    private String relationValue;
+
+}

+ 37 - 0
mirage-service/src/main/java/com/mirage/mirageservice/meta/SelfFamilyCardResponse.java

@@ -0,0 +1,37 @@
+package com.mirage.mirageservice.meta;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created by hzlinhai on 2025/10/21.
+ */
+@Data
+public class SelfFamilyCardResponse {
+
+    /**
+     * 自己信息
+     */
+    private FamilyMemberInfoAndRelation self;
+    /**
+     * 父母信息
+     */
+    private List<FamilyMemberInfoAndRelation> parents;
+    /**
+     * 孩子信息
+     */
+    private List<FamilyMemberInfoAndRelation> children;
+    /**
+     * 兄弟信息
+     */
+    private List<FamilyMemberInfoAndRelation> brothers;
+    /**
+     * 姐妹信息
+     */
+    private List<FamilyMemberInfoAndRelation> sisters;
+    /**
+     * 配偶信息
+     */
+    private List<FamilyMemberInfoAndRelation> spouses;
+}

+ 287 - 0
mirage-service/src/main/java/com/mirage/mirageservice/service/FamilyService.java

@@ -0,0 +1,287 @@
+package com.mirage.mirageservice.service;
+
+import com.google.common.collect.Lists;
+import com.mirage.mirageservice.domain.CsMinWechatUser;
+import com.mirage.mirageservice.domain.FamilyMemberInfo;
+import com.mirage.mirageservice.domain.FamilyRelationInfo;
+import com.mirage.mirageservice.domain.FamilyTreeInfo;
+import com.mirage.mirageservice.enums.FamilyRelationEnum;
+import com.mirage.mirageservice.mapper.mysql.FamilyMemberInfoMapper;
+import com.mirage.mirageservice.mapper.mysql.FamilyRelationInfoMapper;
+import com.mirage.mirageservice.meta.FamilyMemberInfoAndRelation;
+import com.mirage.mirageservice.meta.FamilyTreeResponse;
+import com.mirage.mirageservice.meta.MemberInfoRequest;
+import com.mirage.mirageservice.meta.SelfFamilyCardResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Created by hzlinhai on 2025/10/21.
+ */
+@Service
+@Slf4j
+public class FamilyService {
+
+    @Resource
+    private FamilyMemberInfoMapper familyMemberInfoMapper;
+    @Resource
+    private FamilyRelationInfoMapper familyRelationInfoMapper;
+
+    public SelfFamilyCardResponse getSelfFamilyMember(Long uid){
+        SelfFamilyCardResponse familyCardResponse = new SelfFamilyCardResponse();
+        // 获取自己
+        FamilyMemberInfo self = getMemberByUid(uid);
+        if(null == self){
+            return null;
+        }
+        familyCardResponse.setSelf(new FamilyMemberInfoAndRelation(self, null));
+        // 获取父母
+        List<FamilyRelationInfo> parentsRelation = familyRelationInfoMapper.selectByChildMidAndParentMidAndSourceMidAndRelationTypeIn(self.getId(), null, null, Lists.newArrayList(FamilyRelationEnum.FATHER.getType(), FamilyRelationEnum.MATHER.getType()));
+        if(null != parentsRelation){
+            List<FamilyRelationInfo> fatherList = parentsRelation.stream()
+                    .filter(info -> FamilyRelationEnum.FATHER.getType().equals(info.getRelationType()))
+                    .collect(Collectors.toList());
+            List<Long> fatherIdList = !fatherList.isEmpty() ? fatherList.stream().map(FamilyRelationInfo :: getParentMid).collect(Collectors.toList()) : Lists.newArrayList();
+            List<FamilyRelationInfo> matherList = parentsRelation.stream()
+                    .filter(info -> FamilyRelationEnum.MATHER.getType().equals(info.getRelationType()))
+                    .collect(Collectors.toList());
+            List<Long> matherIdList = !matherList.isEmpty() ? matherList.stream().map(FamilyRelationInfo :: getParentMid).collect(Collectors.toList()) : Lists.newArrayList();
+
+            List<FamilyMemberInfoAndRelation> parents = Lists.newArrayList();
+            if(!fatherIdList.isEmpty()){
+                List<FamilyMemberInfo> fatherMemberInfoList = familyMemberInfoMapper.selectByIdIn(fatherIdList);
+                parents.add(new FamilyMemberInfoAndRelation(fatherMemberInfoList.get(0), fatherList.get(0)));
+            }
+            if(!matherIdList.isEmpty()){
+                List<FamilyMemberInfo> matherMemberInfoList = familyMemberInfoMapper.selectByIdIn(fatherIdList);
+                parents.add(new FamilyMemberInfoAndRelation(matherMemberInfoList.get(0), matherList.get(0)));
+            }
+            familyCardResponse.setParents(parents);
+        }
+        // 获取子女
+        List<FamilyRelationInfo> childRelation = familyRelationInfoMapper.selectByChildMidAndParentMidAndSourceMidAndRelationTypeIn(null, self.getId(), null, Lists.newArrayList(FamilyRelationEnum.FATHER.getType(), FamilyRelationEnum.MATHER.getType()));
+        if(null != childRelation){
+            List<Long> childrenIdList = childRelation.stream().map(FamilyRelationInfo :: getChildMid).collect(Collectors.toList());
+            if(!childrenIdList.isEmpty()){
+                List<FamilyMemberInfoAndRelation> childrenList = Lists.newArrayList();
+                List<FamilyMemberInfo> children = familyMemberInfoMapper.selectByIdIn(childrenIdList);
+                for(FamilyMemberInfo familyMemberInfo : children){
+                    List<FamilyRelationInfo> childRelationInfo = childRelation.stream()
+                            .filter(info -> familyMemberInfo.getId().equals(info.getChildMid()))
+                            .collect(Collectors.toList());
+                    childrenList.add(new FamilyMemberInfoAndRelation(familyMemberInfo, childRelationInfo.get(0)));
+                }
+                familyCardResponse.setChildren(childrenList);
+            }
+        }
+        // 获取配偶
+        List<FamilyRelationInfo> spousesRelation = familyRelationInfoMapper.selectByChildMidAndParentMidAndSourceMidAndRelationTypeIn(null, null, self.getId(), Lists.newArrayList(FamilyRelationEnum.SPOUSE.getType()));
+        if(null != spousesRelation){
+            List<Long> spousesIdList = spousesRelation.stream().map(FamilyRelationInfo :: getParentMid).collect(Collectors.toList());
+            if(!spousesIdList.isEmpty()){
+                List<FamilyMemberInfoAndRelation> spousesList = Lists.newArrayList();
+                List<FamilyMemberInfo> spouses = familyMemberInfoMapper.selectByIdIn(spousesIdList);
+                for(FamilyMemberInfo memberInfo : spouses){
+                    List<FamilyRelationInfo> spousesRelationInfo = spousesRelation.stream()
+                            .filter(info -> memberInfo.getId().equals(info.getParentMid()))
+                            .collect(Collectors.toList());
+                    spousesList.add(new FamilyMemberInfoAndRelation(memberInfo, spousesRelationInfo.get(0)));
+                }
+                familyCardResponse.setSpouses(spousesList);
+            }
+        }
+        // 获取兄弟
+        List<FamilyRelationInfo> brothersRelation = familyRelationInfoMapper.selectByChildMidAndParentMidAndSourceMidAndRelationTypeIn(null, null, self.getId()
+                , Lists.newArrayList(FamilyRelationEnum.BIG_BROTHER.getType(), FamilyRelationEnum.SMALL_BROTHER.getType()));
+        if(null != brothersRelation){
+            List<Long> brothersIdList = brothersRelation.stream().map(FamilyRelationInfo :: getParentMid).collect(Collectors.toList());
+            if(!brothersIdList.isEmpty()){
+                List<FamilyMemberInfoAndRelation> brothersList = Lists.newArrayList();
+                List<FamilyMemberInfo> brothers = familyMemberInfoMapper.selectByIdIn(brothersIdList);
+                for(FamilyMemberInfo familyMemberInfo : brothers){
+                    List<FamilyRelationInfo> brothersRelationInfo = brothersRelation.stream()
+                            .filter(info -> familyMemberInfo.getId().equals(info.getParentMid()))
+                            .collect(Collectors.toList());
+                    brothersList.add(new FamilyMemberInfoAndRelation(familyMemberInfo, brothersRelationInfo.get(0)));
+                }
+                familyCardResponse.setBrothers(brothersList);
+            }
+        }
+        // 获取姐妹
+        List<FamilyRelationInfo> sistersRelation = familyRelationInfoMapper.selectByChildMidAndParentMidAndSourceMidAndRelationTypeIn(null, null, self.getId()
+                , Lists.newArrayList(FamilyRelationEnum.BIG_SISTER.getType(), FamilyRelationEnum.SMALL_SISTER.getType()));
+        if(null != sistersRelation){
+            List<Long> sistersIdList = sistersRelation.stream().map(FamilyRelationInfo :: getParentMid).collect(Collectors.toList());
+            if(!sistersIdList.isEmpty()){
+                List<FamilyMemberInfoAndRelation> sistersList = Lists.newArrayList();
+                List<FamilyMemberInfo> sisters = familyMemberInfoMapper.selectByIdIn(sistersIdList);
+                for(FamilyMemberInfo familyMemberInfo : sisters){
+                    List<FamilyRelationInfo> sistersRelationInfo = sistersRelation.stream()
+                            .filter(info -> familyMemberInfo.getId().equals(info.getParentMid()))
+                            .collect(Collectors.toList());
+                    sistersList.add(new FamilyMemberInfoAndRelation(familyMemberInfo, sistersRelationInfo.get(0)));
+                }
+                familyCardResponse.setSisters(sistersList);
+            }
+        }
+        return familyCardResponse;
+    }
+
+    public FamilyTreeResponse getFamilyTree(Long uid, Integer generation){
+        if(null == uid){
+            return null;
+        }
+        if(null == generation){
+            // 默认取上下5代
+            generation = 5;
+        }
+        FamilyMemberInfo memberInfo = familyMemberInfoMapper.selectByUid(uid);
+        if(null == memberInfo){
+            return null;
+        }
+        // 取上几代
+        List<FamilyTreeInfo> elderMemberInfo = familyRelationInfoMapper.selectElderGeneration(memberInfo.getId(), Lists.newArrayList(FamilyRelationEnum.FATHER.getType(), FamilyRelationEnum.MATHER.getType()), generation);
+        // 取下几代
+        List<FamilyTreeInfo> offspringMemberInfo = familyRelationInfoMapper.selectOffspringGeneration(memberInfo.getId(), Lists.newArrayList(FamilyRelationEnum.SON.getType(), FamilyRelationEnum.DAUGHTER.getType()), generation);
+        // 取同代
+        List<FamilyTreeInfo> peerMemberInfo = familyRelationInfoMapper.selectPeerGeneration(memberInfo.getId());
+        FamilyTreeResponse familyTreeResponse = new FamilyTreeResponse();
+        familyTreeResponse.setSelf(memberInfo);
+        familyTreeResponse.setOffspringMemberInfo(elderMemberInfo);
+        familyTreeResponse.setOffspringMemberInfo(offspringMemberInfo);
+        familyTreeResponse.setPeerMemberInfo(peerMemberInfo);
+        return familyTreeResponse;
+    }
+
+
+    /**
+     * 根据名字获取成员详细信息.
+     *
+     * @param name
+     * @return
+     */
+    public List<FamilyMemberInfo> getMemberInfoByName(String name){
+        if(StringUtils.isBlank(name)){
+            return null;
+        }
+        return familyMemberInfoMapper.selectAllByName(name);
+    }
+
+    /**
+     * 根据成员id获取成员详细信息.
+     * @param id
+     * @return
+     */
+    public FamilyMemberInfo getMemberById(Long id){
+        if(null == id){
+            return null;
+        }
+        return familyMemberInfoMapper.selectByPrimaryKey(id);
+    }
+
+    public FamilyMemberInfo getMemberByUid(Long uid){
+        if(null == uid){
+            return null;
+        }
+        return familyMemberInfoMapper.selectByUid(uid);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public FamilyMemberInfo addOrUpdateMember(MemberInfoRequest request, CsMinWechatUser csMinWechatUser) throws Exception {
+        FamilyMemberInfo memberInfo = request.getMemberInfo();
+        if(null == memberInfo){
+            return null;
+        }
+        FamilyRelationEnum relationEnum = FamilyRelationEnum.getByType(request.getRelationRequest().getRelationType());
+        if(null == relationEnum){
+           return null;
+        }
+        // 代填写标记uid为-1
+        if(relationEnum == FamilyRelationEnum.SELF){
+            memberInfo.setUid(csMinWechatUser.getId());
+            memberInfo.setPhone(csMinWechatUser.getPhone());
+        }else{
+            memberInfo.setUid(-1L);
+        }
+        if(null == memberInfo.getId()){
+            memberInfo.setCreateTime(new Date());
+            memberInfo.setModifiedTime(new Date());
+            memberInfo.setCreateUid(csMinWechatUser.getId());
+            familyMemberInfoMapper.insertSelective(memberInfo);
+            FamilyMemberInfo selfMemberInfo = familyMemberInfoMapper.selectByUid(csMinWechatUser.getId());
+            if(null == selfMemberInfo){
+                throw new Exception("请先填写自己信息再录入亲属信息");
+            }
+            // 保存亲属关系
+            FamilyRelationInfo relationInfo = null;
+            switch (relationEnum) {
+                case FATHER:
+                    relationInfo = new FamilyRelationInfo();
+                    relationInfo.setChildMid(selfMemberInfo.getId());
+                    relationInfo.setParentMid(memberInfo.getId());
+                    relationInfo.setRelationType(FamilyRelationEnum.FATHER.getType());
+                    relationInfo.setSubRelationType(request.getRelationRequest().getSubRelationType());
+                    relationInfo.setRelationValue(request.getRelationRequest().getRelationValue());
+                    relationInfo.setGenerationDiff(-1);
+                    break;
+                case MATHER:
+                    relationInfo = new FamilyRelationInfo();
+                    relationInfo.setChildMid(selfMemberInfo.getId());
+                    relationInfo.setParentMid(memberInfo.getId());
+                    relationInfo.setRelationType(FamilyRelationEnum.MATHER.getType());
+                    relationInfo.setSubRelationType(request.getRelationRequest().getSubRelationType());
+                    relationInfo.setRelationValue(request.getRelationRequest().getRelationValue());
+                    relationInfo.setGenerationDiff(-1);
+                    break;
+                case SPOUSE:
+                    relationInfo = new FamilyRelationInfo();
+                    relationInfo.setParentMid(memberInfo.getId());
+                    relationInfo.setRelationType(FamilyRelationEnum.SPOUSE.getType());
+                    relationInfo.setSubRelationType(request.getRelationRequest().getSubRelationType());
+                    relationInfo.setRelationValue(request.getRelationRequest().getRelationValue());
+                    relationInfo.setGenerationDiff(0);
+                    break;
+                case SON:
+                case DAUGHTER:
+                    relationInfo = new FamilyRelationInfo();
+                    relationInfo.setChildMid(memberInfo.getId());
+                    relationInfo.setParentMid(selfMemberInfo.getId());
+                    relationInfo.setRelationType(FamilyRelationEnum.FATHER.getType());
+                    relationInfo.setSubRelationType(request.getRelationRequest().getSubRelationType());
+                    relationInfo.setRelationValue(request.getRelationRequest().getRelationValue());
+                    relationInfo.setGenerationDiff(1);
+                    break;
+                case SMALL_BROTHER:
+                case BIG_BROTHER:
+                case SMALL_SISTER:
+                case BIG_SISTER:
+                    relationInfo = new FamilyRelationInfo();
+                    relationInfo.setParentMid(memberInfo.getId());
+                    relationInfo.setRelationType(request.getRelationRequest().getRelationType());
+                    relationInfo.setGenerationDiff(0);
+                    break;
+                default:
+                    break;
+            }
+            if(null != relationInfo) {
+                relationInfo.setSourceMid(selfMemberInfo.getId());
+                relationInfo.setRelationStatus(request.getRelationRequest().getRelationStatus());
+                relationInfo.setCreateTime(new Date());
+                relationInfo.setModifiedTime(new Date());
+                familyRelationInfoMapper.insertSelective(relationInfo);
+            }
+        }else{
+            memberInfo.setModifiedTime(new Date());
+            memberInfo.setCreateUid(csMinWechatUser.getId());
+            familyMemberInfoMapper.updateByPrimaryKeySelective(memberInfo);
+        }
+        return memberInfo;
+    }
+}

+ 443 - 0
mirage-service/src/main/resources/com/mirage/mirageservice/mapper/mysql/FamilyMemberInfoMapper.xml

@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.mirage.mirageservice.mapper.mysql.FamilyMemberInfoMapper">
+  <resultMap id="BaseResultMap" type="com.mirage.mirageservice.domain.FamilyMemberInfo">
+    <!--@mbg.generated-->
+    <!--@Table family_member_info-->
+    <id column="id" jdbcType="BIGINT" property="id" />
+    <result column="uid" jdbcType="BIGINT" property="uid" />
+    <result column="name" jdbcType="VARCHAR" property="name" />
+    <result column="former_name" jdbcType="VARCHAR" property="formerName" />
+    <result column="childhood_name" jdbcType="VARCHAR" property="childhoodName" />
+    <result column="name_word" jdbcType="VARCHAR" property="nameWord" />
+    <result column="name_word_generation" jdbcType="VARCHAR" property="nameWordGeneration" />
+    <result column="name_title" jdbcType="VARCHAR" property="nameTitle" />
+    <result column="sex" jdbcType="INTEGER" property="sex" />
+    <result column="birthday" jdbcType="BIGINT" property="birthday" />
+    <result column="is_pass_away" jdbcType="INTEGER" property="isPassAway" />
+    <result column="pass_away_time" jdbcType="TIMESTAMP" property="passAwayTime" />
+    <result column="marital_status" jdbcType="INTEGER" property="maritalStatus" />
+    <result column="birth_place" jdbcType="VARCHAR" property="birthPlace" />
+    <result column="branch_family_hall" jdbcType="VARCHAR" property="branchFamilyHall" />
+    <result column="cluster_place" jdbcType="VARCHAR" property="clusterPlace" />
+    <result column="nation" jdbcType="VARCHAR" property="nation" />
+    <result column="residential_address" jdbcType="VARCHAR" property="residentialAddress" />
+    <result column="phone" jdbcType="VARCHAR" property="phone" />
+    <result column="mail" jdbcType="VARCHAR" property="mail" />
+    <result column="wechat_account" jdbcType="VARCHAR" property="wechatAccount" />
+    <result column="head_img_url" jdbcType="VARCHAR" property="headImgUrl" />
+    <result column="id_number" jdbcType="VARCHAR" property="idNumber" />
+    <result column="occupation" jdbcType="LONGVARCHAR" property="occupation" />
+    <result column="educational" jdbcType="LONGVARCHAR" property="educational" />
+    <result column="blood_type" jdbcType="VARCHAR" property="bloodType" />
+    <result column="religion" jdbcType="VARCHAR" property="religion" />
+    <result column="hobbies" jdbcType="VARCHAR" property="hobbies" />
+    <result column="personal_achievements" jdbcType="LONGVARCHAR" property="personalAchievements" />
+    <result column="create_uid" jdbcType="BIGINT" property="createUid" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="modified_time" jdbcType="TIMESTAMP" property="modifiedTime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--@mbg.generated-->
+    id, `uid`, `name`, former_name, childhood_name, name_word, name_word_generation, 
+    name_title, sex, birthday, is_pass_away, pass_away_time, marital_status, birth_place, 
+    branch_family_hall, cluster_place, nation, residential_address, phone, mail, wechat_account, 
+    head_img_url, id_number, occupation, educational, blood_type, religion, hobbies, 
+    personal_achievements, create_uid, create_time, modified_time
+  </sql>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+    <!--@mbg.generated-->
+    select 
+    <include refid="Base_Column_List" />
+    from family_member_info
+    where id = #{id,jdbcType=BIGINT}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+    <!--@mbg.generated-->
+    delete from family_member_info
+    where id = #{id,jdbcType=BIGINT}
+  </delete>
+  <insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.mirage.mirageservice.domain.FamilyMemberInfo" useGeneratedKeys="true">
+    <!--@mbg.generated-->
+    insert into family_member_info (`uid`, `name`, former_name, 
+      childhood_name, name_word, name_word_generation, 
+      name_title, sex, birthday, 
+      is_pass_away, pass_away_time, marital_status, 
+      birth_place, branch_family_hall, cluster_place, 
+      nation, residential_address, phone, 
+      mail, wechat_account, head_img_url, 
+      id_number, occupation, educational, 
+      blood_type, religion, hobbies, 
+      personal_achievements, create_uid, create_time, 
+      modified_time)
+    values (#{uid,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{formerName,jdbcType=VARCHAR}, 
+      #{childhoodName,jdbcType=VARCHAR}, #{nameWord,jdbcType=VARCHAR}, #{nameWordGeneration,jdbcType=VARCHAR}, 
+      #{nameTitle,jdbcType=VARCHAR}, #{sex,jdbcType=INTEGER}, #{birthday,jdbcType=BIGINT}, 
+      #{isPassAway,jdbcType=INTEGER}, #{passAwayTime,jdbcType=TIMESTAMP}, #{maritalStatus,jdbcType=INTEGER}, 
+      #{birthPlace,jdbcType=VARCHAR}, #{branchFamilyHall,jdbcType=VARCHAR}, #{clusterPlace,jdbcType=VARCHAR}, 
+      #{nation,jdbcType=VARCHAR}, #{residentialAddress,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, 
+      #{mail,jdbcType=VARCHAR}, #{wechatAccount,jdbcType=VARCHAR}, #{headImgUrl,jdbcType=VARCHAR}, 
+      #{idNumber,jdbcType=VARCHAR}, #{occupation,jdbcType=LONGVARCHAR}, #{educational,jdbcType=LONGVARCHAR}, 
+      #{bloodType,jdbcType=VARCHAR}, #{religion,jdbcType=VARCHAR}, #{hobbies,jdbcType=VARCHAR}, 
+      #{personalAchievements,jdbcType=LONGVARCHAR}, #{createUid,jdbcType=BIGINT}, #{createTime,jdbcType=TIMESTAMP}, 
+      #{modifiedTime,jdbcType=TIMESTAMP})
+  </insert>
+  <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.mirage.mirageservice.domain.FamilyMemberInfo" useGeneratedKeys="true">
+    <!--@mbg.generated-->
+    insert into family_member_info
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="uid != null">
+        `uid`,
+      </if>
+      <if test="name != null">
+        `name`,
+      </if>
+      <if test="formerName != null">
+        former_name,
+      </if>
+      <if test="childhoodName != null">
+        childhood_name,
+      </if>
+      <if test="nameWord != null">
+        name_word,
+      </if>
+      <if test="nameWordGeneration != null">
+        name_word_generation,
+      </if>
+      <if test="nameTitle != null">
+        name_title,
+      </if>
+      <if test="sex != null">
+        sex,
+      </if>
+      <if test="birthday != null">
+        birthday,
+      </if>
+      <if test="isPassAway != null">
+        is_pass_away,
+      </if>
+      <if test="passAwayTime != null">
+        pass_away_time,
+      </if>
+      <if test="maritalStatus != null">
+        marital_status,
+      </if>
+      <if test="birthPlace != null">
+        birth_place,
+      </if>
+      <if test="branchFamilyHall != null">
+        branch_family_hall,
+      </if>
+      <if test="clusterPlace != null">
+        cluster_place,
+      </if>
+      <if test="nation != null">
+        nation,
+      </if>
+      <if test="residentialAddress != null">
+        residential_address,
+      </if>
+      <if test="phone != null">
+        phone,
+      </if>
+      <if test="mail != null">
+        mail,
+      </if>
+      <if test="wechatAccount != null">
+        wechat_account,
+      </if>
+      <if test="headImgUrl != null">
+        head_img_url,
+      </if>
+      <if test="idNumber != null">
+        id_number,
+      </if>
+      <if test="occupation != null">
+        occupation,
+      </if>
+      <if test="educational != null">
+        educational,
+      </if>
+      <if test="bloodType != null">
+        blood_type,
+      </if>
+      <if test="religion != null">
+        religion,
+      </if>
+      <if test="hobbies != null">
+        hobbies,
+      </if>
+      <if test="personalAchievements != null">
+        personal_achievements,
+      </if>
+      <if test="createUid != null">
+        create_uid,
+      </if>
+      <if test="createTime != null">
+        create_time,
+      </if>
+      <if test="modifiedTime != null">
+        modified_time,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="uid != null">
+        #{uid,jdbcType=BIGINT},
+      </if>
+      <if test="name != null">
+        #{name,jdbcType=VARCHAR},
+      </if>
+      <if test="formerName != null">
+        #{formerName,jdbcType=VARCHAR},
+      </if>
+      <if test="childhoodName != null">
+        #{childhoodName,jdbcType=VARCHAR},
+      </if>
+      <if test="nameWord != null">
+        #{nameWord,jdbcType=VARCHAR},
+      </if>
+      <if test="nameWordGeneration != null">
+        #{nameWordGeneration,jdbcType=VARCHAR},
+      </if>
+      <if test="nameTitle != null">
+        #{nameTitle,jdbcType=VARCHAR},
+      </if>
+      <if test="sex != null">
+        #{sex,jdbcType=INTEGER},
+      </if>
+      <if test="birthday != null">
+        #{birthday,jdbcType=BIGINT},
+      </if>
+      <if test="isPassAway != null">
+        #{isPassAway,jdbcType=INTEGER},
+      </if>
+      <if test="passAwayTime != null">
+        #{passAwayTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="maritalStatus != null">
+        #{maritalStatus,jdbcType=INTEGER},
+      </if>
+      <if test="birthPlace != null">
+        #{birthPlace,jdbcType=VARCHAR},
+      </if>
+      <if test="branchFamilyHall != null">
+        #{branchFamilyHall,jdbcType=VARCHAR},
+      </if>
+      <if test="clusterPlace != null">
+        #{clusterPlace,jdbcType=VARCHAR},
+      </if>
+      <if test="nation != null">
+        #{nation,jdbcType=VARCHAR},
+      </if>
+      <if test="residentialAddress != null">
+        #{residentialAddress,jdbcType=VARCHAR},
+      </if>
+      <if test="phone != null">
+        #{phone,jdbcType=VARCHAR},
+      </if>
+      <if test="mail != null">
+        #{mail,jdbcType=VARCHAR},
+      </if>
+      <if test="wechatAccount != null">
+        #{wechatAccount,jdbcType=VARCHAR},
+      </if>
+      <if test="headImgUrl != null">
+        #{headImgUrl,jdbcType=VARCHAR},
+      </if>
+      <if test="idNumber != null">
+        #{idNumber,jdbcType=VARCHAR},
+      </if>
+      <if test="occupation != null">
+        #{occupation,jdbcType=LONGVARCHAR},
+      </if>
+      <if test="educational != null">
+        #{educational,jdbcType=LONGVARCHAR},
+      </if>
+      <if test="bloodType != null">
+        #{bloodType,jdbcType=VARCHAR},
+      </if>
+      <if test="religion != null">
+        #{religion,jdbcType=VARCHAR},
+      </if>
+      <if test="hobbies != null">
+        #{hobbies,jdbcType=VARCHAR},
+      </if>
+      <if test="personalAchievements != null">
+        #{personalAchievements,jdbcType=LONGVARCHAR},
+      </if>
+      <if test="createUid != null">
+        #{createUid,jdbcType=BIGINT},
+      </if>
+      <if test="createTime != null">
+        #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="modifiedTime != null">
+        #{modifiedTime,jdbcType=TIMESTAMP},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.mirage.mirageservice.domain.FamilyMemberInfo">
+    <!--@mbg.generated-->
+    update family_member_info
+    <set>
+      <if test="uid != null">
+        `uid` = #{uid,jdbcType=BIGINT},
+      </if>
+      <if test="name != null">
+        `name` = #{name,jdbcType=VARCHAR},
+      </if>
+      <if test="formerName != null">
+        former_name = #{formerName,jdbcType=VARCHAR},
+      </if>
+      <if test="childhoodName != null">
+        childhood_name = #{childhoodName,jdbcType=VARCHAR},
+      </if>
+      <if test="nameWord != null">
+        name_word = #{nameWord,jdbcType=VARCHAR},
+      </if>
+      <if test="nameWordGeneration != null">
+        name_word_generation = #{nameWordGeneration,jdbcType=VARCHAR},
+      </if>
+      <if test="nameTitle != null">
+        name_title = #{nameTitle,jdbcType=VARCHAR},
+      </if>
+      <if test="sex != null">
+        sex = #{sex,jdbcType=INTEGER},
+      </if>
+      <if test="birthday != null">
+        birthday = #{birthday,jdbcType=BIGINT},
+      </if>
+      <if test="isPassAway != null">
+        is_pass_away = #{isPassAway,jdbcType=INTEGER},
+      </if>
+      <if test="passAwayTime != null">
+        pass_away_time = #{passAwayTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="maritalStatus != null">
+        marital_status = #{maritalStatus,jdbcType=INTEGER},
+      </if>
+      <if test="birthPlace != null">
+        birth_place = #{birthPlace,jdbcType=VARCHAR},
+      </if>
+      <if test="branchFamilyHall != null">
+        branch_family_hall = #{branchFamilyHall,jdbcType=VARCHAR},
+      </if>
+      <if test="clusterPlace != null">
+        cluster_place = #{clusterPlace,jdbcType=VARCHAR},
+      </if>
+      <if test="nation != null">
+        nation = #{nation,jdbcType=VARCHAR},
+      </if>
+      <if test="residentialAddress != null">
+        residential_address = #{residentialAddress,jdbcType=VARCHAR},
+      </if>
+      <if test="phone != null">
+        phone = #{phone,jdbcType=VARCHAR},
+      </if>
+      <if test="mail != null">
+        mail = #{mail,jdbcType=VARCHAR},
+      </if>
+      <if test="wechatAccount != null">
+        wechat_account = #{wechatAccount,jdbcType=VARCHAR},
+      </if>
+      <if test="headImgUrl != null">
+        head_img_url = #{headImgUrl,jdbcType=VARCHAR},
+      </if>
+      <if test="idNumber != null">
+        id_number = #{idNumber,jdbcType=VARCHAR},
+      </if>
+      <if test="occupation != null">
+        occupation = #{occupation,jdbcType=LONGVARCHAR},
+      </if>
+      <if test="educational != null">
+        educational = #{educational,jdbcType=LONGVARCHAR},
+      </if>
+      <if test="bloodType != null">
+        blood_type = #{bloodType,jdbcType=VARCHAR},
+      </if>
+      <if test="religion != null">
+        religion = #{religion,jdbcType=VARCHAR},
+      </if>
+      <if test="hobbies != null">
+        hobbies = #{hobbies,jdbcType=VARCHAR},
+      </if>
+      <if test="personalAchievements != null">
+        personal_achievements = #{personalAchievements,jdbcType=LONGVARCHAR},
+      </if>
+      <if test="createUid != null">
+        create_uid = #{createUid,jdbcType=BIGINT},
+      </if>
+      <if test="createTime != null">
+        create_time = #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="modifiedTime != null">
+        modified_time = #{modifiedTime,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.mirage.mirageservice.domain.FamilyMemberInfo">
+    <!--@mbg.generated-->
+    update family_member_info
+    set `uid` = #{uid,jdbcType=BIGINT},
+      `name` = #{name,jdbcType=VARCHAR},
+      former_name = #{formerName,jdbcType=VARCHAR},
+      childhood_name = #{childhoodName,jdbcType=VARCHAR},
+      name_word = #{nameWord,jdbcType=VARCHAR},
+      name_word_generation = #{nameWordGeneration,jdbcType=VARCHAR},
+      name_title = #{nameTitle,jdbcType=VARCHAR},
+      sex = #{sex,jdbcType=INTEGER},
+      birthday = #{birthday,jdbcType=BIGINT},
+      is_pass_away = #{isPassAway,jdbcType=INTEGER},
+      pass_away_time = #{passAwayTime,jdbcType=TIMESTAMP},
+      marital_status = #{maritalStatus,jdbcType=INTEGER},
+      birth_place = #{birthPlace,jdbcType=VARCHAR},
+      branch_family_hall = #{branchFamilyHall,jdbcType=VARCHAR},
+      cluster_place = #{clusterPlace,jdbcType=VARCHAR},
+      nation = #{nation,jdbcType=VARCHAR},
+      residential_address = #{residentialAddress,jdbcType=VARCHAR},
+      phone = #{phone,jdbcType=VARCHAR},
+      mail = #{mail,jdbcType=VARCHAR},
+      wechat_account = #{wechatAccount,jdbcType=VARCHAR},
+      head_img_url = #{headImgUrl,jdbcType=VARCHAR},
+      id_number = #{idNumber,jdbcType=VARCHAR},
+      occupation = #{occupation,jdbcType=LONGVARCHAR},
+      educational = #{educational,jdbcType=LONGVARCHAR},
+      blood_type = #{bloodType,jdbcType=VARCHAR},
+      religion = #{religion,jdbcType=VARCHAR},
+      hobbies = #{hobbies,jdbcType=VARCHAR},
+      personal_achievements = #{personalAchievements,jdbcType=LONGVARCHAR},
+      create_uid = #{createUid,jdbcType=BIGINT},
+      create_time = #{createTime,jdbcType=TIMESTAMP},
+      modified_time = #{modifiedTime,jdbcType=TIMESTAMP}
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+
+<!--auto generated by MybatisCodeHelper on 2025-10-21-->
+  <select id="selectAllByName" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List" />
+        from family_member_info
+        where `name`=#{name,jdbcType=VARCHAR}
+    </select>
+
+<!--auto generated by MybatisCodeHelper on 2025-10-21-->
+  <select id="selectByUid" resultMap="BaseResultMap">
+    select
+    <include refid="Base_Column_List" />
+    from family_member_info
+    where `uid`=#{uid,jdbcType=BIGINT} LIMIT 1
+  </select>
+
+<!--auto generated by MybatisCodeHelper on 2025-10-21-->
+  <select id="selectByIdIn" resultMap="BaseResultMap">
+    select
+    <include refid="Base_Column_List" />
+    from family_member_info
+    where id in
+    <foreach close=")" collection="idCollection" index="index" item="item" open="(" separator=",">
+      #{item,jdbcType=BIGINT}
+    </foreach>
+  </select>
+
+</mapper>

+ 509 - 0
mirage-service/src/main/resources/com/mirage/mirageservice/mapper/mysql/FamilyRelationInfoMapper.xml

@@ -0,0 +1,509 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.mirage.mirageservice.mapper.mysql.FamilyRelationInfoMapper">
+  <resultMap id="BaseResultMap" type="com.mirage.mirageservice.domain.FamilyRelationInfo">
+    <!--@mbg.generated-->
+    <!--@Table family_relation_info-->
+    <id column="id" jdbcType="BIGINT" property="id" />
+    <result column="parent_mid" jdbcType="BIGINT" property="parentMid" />
+    <result column="child_mid" jdbcType="BIGINT" property="childMid" />
+    <result column="source_mid" jdbcType="BIGINT" property="sourceMid" />
+    <result column="relation_type" jdbcType="INTEGER" property="relationType" />
+    <result column="sub_relation_type" jdbcType="INTEGER" property="subRelationType" />
+    <result column="relation_value" jdbcType="VARCHAR" property="relationValue" />
+    <result column="generation_diff" jdbcType="INTEGER" property="generationDiff" />
+    <result column="relation_status" jdbcType="INTEGER" property="relationStatus" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="modified_time" jdbcType="TIMESTAMP" property="modifiedTime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--@mbg.generated-->
+    id, parent_mid, child_mid, source_mid, relation_type, sub_relation_type, relation_value, 
+    generation_diff, relation_status, create_time, modified_time
+  </sql>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+    <!--@mbg.generated-->
+    select 
+    <include refid="Base_Column_List" />
+    from family_relation_info
+    where id = #{id,jdbcType=BIGINT}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+    <!--@mbg.generated-->
+    delete from family_relation_info
+    where id = #{id,jdbcType=BIGINT}
+  </delete>
+  <insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.mirage.mirageservice.domain.FamilyRelationInfo" useGeneratedKeys="true">
+    <!--@mbg.generated-->
+    insert into family_relation_info (parent_mid, child_mid, source_mid, 
+      relation_type, sub_relation_type, relation_value, 
+      generation_diff, relation_status, create_time, 
+      modified_time)
+    values (#{parentMid,jdbcType=BIGINT}, #{childMid,jdbcType=BIGINT}, #{sourceMid,jdbcType=BIGINT}, 
+      #{relationType,jdbcType=INTEGER}, #{subRelationType,jdbcType=INTEGER}, #{relationValue,jdbcType=VARCHAR}, 
+      #{generationDiff,jdbcType=INTEGER}, #{relationStatus,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP}, 
+      #{modifiedTime,jdbcType=TIMESTAMP})
+  </insert>
+  <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.mirage.mirageservice.domain.FamilyRelationInfo" useGeneratedKeys="true">
+    <!--@mbg.generated-->
+    insert into family_relation_info
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="parentMid != null">
+        parent_mid,
+      </if>
+      <if test="childMid != null">
+        child_mid,
+      </if>
+      <if test="sourceMid != null">
+        source_mid,
+      </if>
+      <if test="relationType != null">
+        relation_type,
+      </if>
+      <if test="subRelationType != null">
+        sub_relation_type,
+      </if>
+      <if test="relationValue != null">
+        relation_value,
+      </if>
+      <if test="generationDiff != null">
+        generation_diff,
+      </if>
+      <if test="relationStatus != null">
+        relation_status,
+      </if>
+      <if test="createTime != null">
+        create_time,
+      </if>
+      <if test="modifiedTime != null">
+        modified_time,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="parentMid != null">
+        #{parentMid,jdbcType=BIGINT},
+      </if>
+      <if test="childMid != null">
+        #{childMid,jdbcType=BIGINT},
+      </if>
+      <if test="sourceMid != null">
+        #{sourceMid,jdbcType=BIGINT},
+      </if>
+      <if test="relationType != null">
+        #{relationType,jdbcType=INTEGER},
+      </if>
+      <if test="subRelationType != null">
+        #{subRelationType,jdbcType=INTEGER},
+      </if>
+      <if test="relationValue != null">
+        #{relationValue,jdbcType=VARCHAR},
+      </if>
+      <if test="generationDiff != null">
+        #{generationDiff,jdbcType=INTEGER},
+      </if>
+      <if test="relationStatus != null">
+        #{relationStatus,jdbcType=INTEGER},
+      </if>
+      <if test="createTime != null">
+        #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="modifiedTime != null">
+        #{modifiedTime,jdbcType=TIMESTAMP},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.mirage.mirageservice.domain.FamilyRelationInfo">
+    <!--@mbg.generated-->
+    update family_relation_info
+    <set>
+      <if test="parentMid != null">
+        parent_mid = #{parentMid,jdbcType=BIGINT},
+      </if>
+      <if test="childMid != null">
+        child_mid = #{childMid,jdbcType=BIGINT},
+      </if>
+      <if test="sourceMid != null">
+        source_mid = #{sourceMid,jdbcType=BIGINT},
+      </if>
+      <if test="relationType != null">
+        relation_type = #{relationType,jdbcType=INTEGER},
+      </if>
+      <if test="subRelationType != null">
+        sub_relation_type = #{subRelationType,jdbcType=INTEGER},
+      </if>
+      <if test="relationValue != null">
+        relation_value = #{relationValue,jdbcType=VARCHAR},
+      </if>
+      <if test="generationDiff != null">
+        generation_diff = #{generationDiff,jdbcType=INTEGER},
+      </if>
+      <if test="relationStatus != null">
+        relation_status = #{relationStatus,jdbcType=INTEGER},
+      </if>
+      <if test="createTime != null">
+        create_time = #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="modifiedTime != null">
+        modified_time = #{modifiedTime,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.mirage.mirageservice.domain.FamilyRelationInfo">
+    <!--@mbg.generated-->
+    update family_relation_info
+    set parent_mid = #{parentMid,jdbcType=BIGINT},
+      child_mid = #{childMid,jdbcType=BIGINT},
+      source_mid = #{sourceMid,jdbcType=BIGINT},
+      relation_type = #{relationType,jdbcType=INTEGER},
+      sub_relation_type = #{subRelationType,jdbcType=INTEGER},
+      relation_value = #{relationValue,jdbcType=VARCHAR},
+      generation_diff = #{generationDiff,jdbcType=INTEGER},
+      relation_status = #{relationStatus,jdbcType=INTEGER},
+      create_time = #{createTime,jdbcType=TIMESTAMP},
+      modified_time = #{modifiedTime,jdbcType=TIMESTAMP}
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+
+<!--auto generated by MybatisCodeHelper on 2025-10-21-->
+  <select id="selectByChildMidAndParentMidAndRelationTypeIn" resultMap="BaseResultMap">
+    select
+    <include refid="Base_Column_List" />
+    from family_relation_info
+    <where>
+      <if test="childMid != null">
+        and child_mid=#{childMid,jdbcType=BIGINT}
+      </if>
+      <if test="parentMid != null">
+        and parent_mid=#{parentMid,jdbcType=BIGINT}
+      </if>
+      and relation_type in
+      <foreach close=")" collection="relationTypeCollection" index="index" item="item" open="(" separator=",">
+        #{item,jdbcType=INTEGER}
+      </foreach>
+    </where>
+  </select>
+
+<!--auto generated by MybatisCodeHelper on 2025-10-21-->
+  <select id="selectByChildMidAndParentMidAndSourceMidAndRelationTypeIn" resultMap="BaseResultMap">
+    select
+    <include refid="Base_Column_List" />
+    from family_relation_info
+    <where>
+      <if test="childMid != null">
+        and child_mid=#{childMid,jdbcType=BIGINT}
+      </if>
+      <if test="parentMid != null">
+        and parent_mid=#{parentMid,jdbcType=BIGINT}
+      </if>
+      <if test="sourceMid != null">
+        and source_mid=#{sourceMid,jdbcType=BIGINT}
+      </if>
+      and relation_type in
+      <foreach close=")" collection="relationTypeCollection" index="index" item="item" open="(" separator=",">
+        #{item,jdbcType=INTEGER}
+      </foreach>
+    </where>
+  </select>
+  
+  <select id="selectElderGeneration" resultType="com.mirage.mirageservice.domain.FamilyTreeInfo">
+    WITH RECURSIVE family_ancestors AS (
+    -- 第1层:目标成员的父亲/母亲(上1代)
+    SELECT
+    parent_mid AS mid,
+    1 AS generation, -- 标记“上1代”
+    fm.id,
+    fm.uid,
+    fm.name,
+    fm.former_name,
+    fm.childhood_name,
+    fm.name_word,
+    fm.name_word_generation,
+    fm.name_title,
+    fm.sex,
+    fm.birthday,
+    fm.is_pass_away,
+    fm.pass_away_time,
+    fm.marital_status,
+    fm.birth_place,
+    fm.branch_family_hall,
+    fm.cluster_place,
+    fm.nation,
+    fm.residential_address,
+    fm.phone,
+    fm.mail,
+    fm.wechat_account,
+    fm.head_img_url,
+    fm.Id_number,
+    fm.occupation,
+    fm.educational,
+    fm.blood_type,
+    fm.religion,
+    fm.hobbies,
+    fm.personal_achievements,
+    fm.create_uid,
+    fm.create_time,
+    fm.modified_time,
+    fr.relation_type,
+    fr.sub_relation_type,
+    fr.relation_value,
+    fr.relation_status
+    FROM family_relation_info fr
+    JOIN family_member_info fm ON fr.parent_mid = fm.id
+    WHERE fr.child_mid = #{childMid,jdbcType=BIGINT}
+    AND fr.relation_type IN
+    <foreach close=")" collection="relationTypeCollection" index="index" item="item" open="(" separator=",">
+      #{item,jdbcType=BIGINT}
+    </foreach>
+    AND fr.generation_diff = -1 -- 上1代
+    UNION ALL
+    -- 递归查询2~5代(祖父→天祖)
+    SELECT
+    fr.parent_mid AS mid,
+    fa.generation + 1 AS generation,
+    fm.id,
+    fm.uid,
+    fm.name,
+    fm.former_name,
+    fm.childhood_name,
+    fm.name_word,
+    fm.name_word_generation,
+    fm.name_title,
+    fm.sex,
+    fm.birthday,
+    fm.is_pass_away,
+    fm.pass_away_time,
+    fm.marital_status,
+    fm.birth_place,
+    fm.branch_family_hall,
+    fm.cluster_place,
+    fm.nation,
+    fm.residential_address,
+    fm.phone,
+    fm.mail,
+    fm.wechat_account,
+    fm.head_img_url,
+    fm.id_number,
+    fm.occupation,
+    fm.educational,
+    fm.blood_type,
+    fm.religion,
+    fm.hobbies,
+    fm.personal_achievements,
+    fm.create_uid,
+    fm.create_time,
+    fm.modified_time,
+    fr.relation_type,
+    fr.sub_relation_type,
+    fr.relation_value,
+    fr.relation_status
+    FROM family_relation_info fr
+    JOIN family_member_info fm ON fr.parent_mid = fm.id
+    JOIN family_ancestors fa ON fr.child_mid = fa.mid
+    WHERE fa.generation <![CDATA[<]]> #{generation,jdbcType=INTEGER}
+    AND fr.relation_type IN
+    <foreach close=")" collection="relationTypeCollection" index="index" item="item" open="(" separator=",">
+      #{item,jdbcType=BIGINT}
+    </foreach>
+    AND fr.generation_diff = -1 -- 每代均为“上1代”
+    )
+    -- 最终返回上1~5代成员信息
+    SELECT
+    generation,
+    id AS mid,
+    uid,
+    name,
+    former_name,
+    childhood_name,
+    name_word,
+    name_word_generation,
+    name_title,
+    sex,
+    birthday,
+    is_pass_away,
+    pass_away_time,
+    marital_status,
+    birth_place,
+    branch_family_hall,
+    cluster_place,
+    nation,
+    residential_address,
+    phone,
+    mail,
+    wechat_account,
+    head_img_url,
+    id_number,
+    occupation,
+    educational,
+    blood_type,
+    religion,
+    hobbies,
+    personal_achievements,
+    create_uid,
+    create_time,
+    modified_time,
+    relation_type,
+    sub_relation_type,
+    relation_value,
+    relation_status
+    FROM family_ancestors
+    ORDER BY generation ASC;
+  </select>
+
+  <select id="selectOffspringGeneration" resultType="com.mirage.mirageservice.domain.FamilyTreeInfo">
+    WITH RECURSIVE family_descendants AS (
+    -- 第1层:目标成员的子女(下1代)
+    SELECT
+    child_mid AS mid,
+    1 AS generation, -- 标记“下1代”
+    fm.id,
+    fm.uid,
+    fm.name,
+    fm.former_name,
+    fm.childhood_name,
+    fm.name_word,
+    fm.name_word_generation,
+    fm.name_title,
+    fm.sex,
+    fm.birthday,
+    fm.is_pass_away,
+    fm.pass_away_time,
+    fm.marital_status,
+    fm.birth_place,
+    fm.branch_family_hall,
+    fm.cluster_place,
+    fm.nation,
+    fm.residential_address,
+    fm.phone,
+    fm.mail,
+    fm.wechat_account,
+    fm.head_img_url,
+    fm.Id_number,
+    fm.occupation,
+    fm.educational,
+    fm.blood_type,
+    fm.religion,
+    fm.hobbies,
+    fm.personal_achievements,
+    fm.create_uid,
+    fm.create_time,
+    fm.modified_time,
+    fr.relation_type,
+    fr.sub_relation_type,
+    fr.relation_value,
+    fr.relation_status
+    FROM family_relation_info fr
+    JOIN family_member_info fm ON fr.child_mid = fm.id
+    WHERE fr.parent_mid = #{parentMid,jdbcType=BIGINT}
+    AND fr.relation_type IN
+    <foreach close=")" collection="relationTypeCollection" index="index" item="item" open="(" separator=",">
+      #{item,jdbcType=BIGINT}
+    </foreach>
+    AND fr.generation_diff = +1 -- 下1代
+    UNION ALL
+    -- 递归查询2~5代(孙辈→来孙)
+    SELECT
+    fr.child_mid AS mid,
+    fd.generation + 1 AS generation,
+    fm.id,
+    fm.uid,
+    fm.name,
+    fm.former_name,
+    fm.childhood_name,
+    fm.name_word,
+    fm.name_word_generation,
+    fm.name_title,
+    fm.sex,
+    fm.birthday,
+    fm.is_pass_away,
+    fm.pass_away_time,
+    fm.marital_status,
+    fm.birth_place,
+    fm.branch_family_hall,
+    fm.cluster_place,
+    fm.nation,
+    fm.residential_address,
+    fm.phone,
+    fm.mail,
+    fm.wechat_account,
+    fm.head_img_url,
+    fm.id_number,
+    fm.occupation,
+    fm.educational,
+    fm.blood_type,
+    fm.religion,
+    fm.hobbies,
+    fm.personal_achievements,
+    fm.create_uid,
+    fm.create_time,
+    fm.modified_time,
+    fr.relation_type,
+    fr.sub_relation_type,
+    fr.relation_value,
+    fr.relation_status
+    FROM family_relation_info fr
+    JOIN family_member_info fm ON fr.child_mid = fm.id
+    JOIN family_descendants fd ON fr.parent_mid = fd.mid
+    WHERE fd.generation <![CDATA[<]]>  #{generation,jdbcType=INTEGER}
+    AND fr.relation_type IN
+    <foreach close=")" collection="relationTypeCollection" index="index" item="item" open="(" separator=",">
+      #{item,jdbcType=BIGINT}
+    </foreach>
+    AND fr.generation_diff = +1 -- 每代均为“下1代”
+    )
+    -- 最终返回下1~5代成员信息
+    SELECT
+    generation,
+    mid,
+    uid,
+    name,
+    former_name,
+    childhood_name,
+    name_word,
+    name_word_generation,
+    name_title,
+    sex,
+    birthday,
+    is_pass_away,
+    pass_away_time,
+    marital_status,
+    birth_place,
+    branch_family_hall,
+    cluster_place,
+    nation,
+    residential_address,
+    phone,
+    mail,
+    wechat_account,
+    head_img_url,
+    id_number,
+    occupation,
+    educational,
+    blood_type,
+    religion,
+    hobbies,
+    personal_achievements,
+    create_uid,
+    create_time,
+    modified_time,
+    relation_type,
+    sub_relation_type,
+    relation_value,
+    relation_status
+    FROM family_descendants
+    ORDER BY generation ASC;
+  </select>
+
+  <select id="selectPeerGeneration" resultType="com.mirage.mirageservice.domain.FamilyTreeInfo">
+    select
+    fr.generation_diff as generation,
+    fr.parent_mid as mid,
+    fm.*,
+    fr.relation_type as relationType,
+    fr.relation_status as relationStatus,
+    fr.sub_relation_type as subRelationType,
+    fr.relation_value
+    from family_relation_info fr, family_member_info fm
+    where source_mid = #{mid,jdbcType=BIGINT} and generation_diff = 0 and fr.parent_mid = fm.id
+  </select>
+</mapper>

+ 0 - 17
sql

@@ -1,17 +0,0 @@
-CREATE TABLE `cs_min_wechat_user` (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `open_id` varchar(512) DEFAULT NULL,
-  `union_id` varchar(512) DEFAULT NULL,
-  `phone` varchar(256) DEFAULT NULL COMMENT '用户手机号',
-  `wechat_type` int NOT NULL DEFAULT '0' COMMENT '0:小程序 1:公众号',
-  `wechat_app_id` varchar(512) NOT NULL COMMENT '小程序、公众号appId',
-  `nick_name` varchar(256) DEFAULT NULL COMMENT '微信昵称',
-  `head_img_url` varchar(512) DEFAULT NULL COMMENT '微信头像',
-  `is_deleted` int NOT NULL DEFAULT '0',
-  `create_time` bigint NOT NULL,
-  `modified_time` bigint NOT NULL,
-  PRIMARY KEY (`id`),
-  KEY `idx_app_id` (`wechat_app_id`),
-  KEY `idx_open_id` (`open_id`),
-  KEY `idx_phone` (`phone`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='春笋小程序公众号用户表'

+ 72 - 0
sql.sql

@@ -0,0 +1,72 @@
+CREATE TABLE `cs_min_wechat_user` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `open_id` varchar(512) DEFAULT NULL,
+  `union_id` varchar(512) DEFAULT NULL,
+  `phone` varchar(256) DEFAULT NULL COMMENT '用户手机号',
+  `wechat_type` int NOT NULL DEFAULT '0' COMMENT '0:小程序 1:公众号',
+  `wechat_app_id` varchar(512) NOT NULL COMMENT '小程序、公众号appId',
+  `nick_name` varchar(256) DEFAULT NULL COMMENT '微信昵称',
+  `head_img_url` varchar(512) DEFAULT NULL COMMENT '微信头像',
+  `is_deleted` int NOT NULL DEFAULT '0',
+  `create_time` bigint NOT NULL,
+  `modified_time` bigint NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `idx_app_id` (`wechat_app_id`),
+  KEY `idx_open_id` (`open_id`),
+  KEY `idx_phone` (`phone`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='春笋小程序公众号用户表';
+
+CREATE TABLE `family_member_info` (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `uid` bigint DEFAULT NULL,
+  `name` varchar(512) NOT NULL,
+  `former_name` varchar(512) DEFAULT NULL COMMENT '曾用名,多个jsonArray格式',
+  `childhood_name` varchar(512) DEFAULT NULL COMMENT '乳名,多个jsonArray格式',
+  `name_word` varchar(512) DEFAULT NULL COMMENT '字,多个jsonArray格式',
+  `name_word_generation` varchar(515) DEFAULT NULL COMMENT '字辈,多个jsonArray格式',
+  `name_title` varchar(512) DEFAULT NULL COMMENT '号,多个jsonArray格式',
+  `sex` int NOT NULL COMMENT '1:男 2:女',
+  `birthday` bigint NOT NULL,
+  `is_pass_away` int NOT NULL DEFAULT '0' COMMENT '是否过世 0:否 1:是',
+  `pass_away_time` timestamp NULL DEFAULT NULL COMMENT '逝世时间',
+  `marital_status` int DEFAULT '0' COMMENT '0:未婚 1:已婚 2:离异 3:丧偶',
+  `birth_place` varchar(128) DEFAULT NULL COMMENT '出生地',
+  `branch_family_hall` varchar(256) DEFAULT NULL COMMENT '支系堂派',
+  `cluster_place` varchar(256) DEFAULT NULL COMMENT '聚落',
+  `nation` varchar(128) DEFAULT NULL COMMENT '民族',
+  `residential_address` varchar(1024) DEFAULT NULL COMMENT '居住地址',
+  `phone` varchar(128) NULL COMMENT '手机号',
+  `mail` varchar(128) DEFAULT NULL COMMENT '邮箱地址',
+  `wechat_account` varchar(256) DEFAULT NULL COMMENT '微信号',
+  `head_img_url` varchar(512) DEFAULT NULL COMMENT '头像照片',
+  `Id_number` varchar(128) DEFAULT NULL COMMENT '身份证号',
+  `occupation` text COMMENT '职业',
+  `educational` text COMMENT '教育背景',
+  `blood_type` varchar(32) DEFAULT NULL COMMENT '血型',
+  `religion` varchar(128) DEFAULT NULL COMMENT '宗教信仰',
+  `hobbies` varchar(512) DEFAULT NULL COMMENT '兴趣爱好',
+  `personal_achievements` text COMMENT '个人简介、个人成就',
+  `create_uid` bigint DEFAULT NULL COMMENT '代填人uid',
+  `create_time` timestamp NOT NULL,
+  `modified_time` timestamp NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `idx_name` (`name`),
+  KEY `idx_uid` (`uid`)
+) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='成员表';
+
+CREATE TABLE `family_relation_info` (
+    `id` bigint NOT NULL AUTO_INCREMENT,
+    `parent_mid` bigint DEFAULT NULL COMMENT '若为 “父子 / 母子关系”,填父亲 / 母亲的uid;若为 “配偶关系”,填配偶的uid(通过relation_type区分)',
+    `child_mid` bigint DEFAULT NULL COMMENT '仅 “亲子关系” 必填,填子女的uid;“配偶关系” 不填(配偶关系无 “子女方”)',
+    `source_mid` bigint NOT NULL COMMENT '来源mid',
+    `relation_type` int NOT NULL COMMENT '关系类型: 1:父子 2:母子 10:夫妻 11:兄弟 12:姐妹',
+    `sub_relation_type` int DEFAULT '0' COMMENT '关系子类型: 0:亲生/正妻 1:养父 2:过继 10:妾 11:外室',
+    `relation_value` varchar(1024) DEFAULT NULL COMMENT '特殊记录例如:结婚时间,过继时间,领养时间',
+    `generation_diff` int NOT NULL COMMENT '代差标记:亲子关系为-1 配偶、兄妹为0,子女为+1',
+    `relation_status` int NOT NULL DEFAULT '0' COMMENT '0:正常 1:离异(夫妻) 2:失联(亲子) 3:已故',
+    `create_time` timestamp NOT NULL,
+    `modified_time` timestamp NOT NULL,
+    PRIMARY KEY (`id`),
+    KEY `idx_relation` (`parent_mid`,`child_mid`,`relation_type`),
+    KEY `idx_spouse_relation` (`parent_mid`,`relation_type`,`relation_status`)
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

Неке датотеке нису приказане због велике количине промена