Bläddra i källkod

chore: auto bump version and changelog [skip ci]

iwt 2 dagar sedan
förälder
incheckning
729ebab885

+ 32 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/guide/GuideFamilyTaskController.java

@@ -8,11 +8,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.etotem.cfc.common.Result;
 import com.etotem.cfc.dto.TaskReviewDTO;
 import com.etotem.cfc.entity.FamilyMember;
+import com.etotem.cfc.entity.GuideFamily;
 import com.etotem.cfc.entity.Task;
 import com.etotem.cfc.entity.User;
 import com.etotem.cfc.mapper.FamilyMemberMapper;
 import com.etotem.cfc.mapper.TaskMapper;
 import com.etotem.cfc.mapper.UserMapper;
+import com.etotem.cfc.service.GuideFamilyService;
 import com.etotem.cfc.service.MembershipService;
 import com.etotem.cfc.service.TaskService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -23,6 +25,7 @@ import java.time.LocalDate;
 import java.time.ZoneId;
 import java.util.*;
 import java.util.stream.Collectors;
+import com.etotem.cfc.util.ParamUtils;
 
 @Tag(name = "指导师-家庭任务管理", description = "指导师查看家庭任务、审核任务等接口")
 @RestController
@@ -44,6 +47,35 @@ public class GuideFamilyTaskController {
     @Resource
     private MembershipService membershipService;
 
+    @Resource
+    private GuideFamilyService guideFamilyService;
+
+    /**
+     * 规划师解除家庭绑定(仅限解除属于自己的绑定)
+     */
+    @Operation(summary = "规划师解除家庭绑定")
+    @PostMapping("/unbind")
+    public Result<Map<String, Object>> unbindFamily(@RequestAttribute("userId") Long guideId,
+                                                   @RequestAttribute("role") String role,
+                                                   @RequestBody Map<String, Object> params) {
+        if (!"teacher".equals(role)) {
+            return Result.error("Access denied");
+        }
+        Long id = ParamUtils.getLong(params.get("id"));
+        if (id == null) {
+            return Result.error("缺少绑定记录ID");
+        }
+        try {
+            GuideFamily gf = guideFamilyService.unbindByGuide(id, guideId);
+            Map<String, Object> result = new HashMap<>();
+            result.put("familyId", gf.getFamilyId());
+            result.put("serviceType", gf.getServiceType());
+            return Result.success(result);
+        } catch (RuntimeException e) {
+            return Result.error(400, e.getMessage());
+        }
+    }
+
     /**
      * 会员任务校验:task.memberOnly==1 且家庭非会员 → 拒绝(提示开通会员)
      */

+ 19 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/GuideFamilyService.java

@@ -116,6 +116,25 @@ public class GuideFamilyService {
         return gf;
     }
 
+    /**
+     * 规划师解除绑定(仅允许解除属于自己的绑定)
+     */
+    public GuideFamily unbindByGuide(Long id, Long guideId) {
+        GuideFamily gf = guideFamilyMapper.selectOne(
+            new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<GuideFamily>()
+                .eq("id", id)
+                .eq("guide_id", guideId)
+                .eq("status", "binding")
+        );
+        if (gf == null) {
+            throw new RuntimeException("绑定关系不存在或已解除");
+        }
+        gf.setStatus("cancelled");
+        gf.setUpdatedAt(new Date());
+        guideFamilyMapper.updateById(gf);
+        return gf;
+    }
+
     /**
      * 解除绑定
      */

+ 2 - 2
cfc-frontend/utils/api.js

@@ -896,9 +896,9 @@ export const confirmBind = (data) => {
   return request('/api/guide/bind/confirm', 'POST', data)
 }
 
-// 解除绑定
+// 规划师解除家庭绑定
 export const unbindFamily = (id) => {
-  return request(`/api/guide/bind/${id}`, 'POST', { _method: 'DELETE' })
+  return request('/api/guide/families/unbind', 'POST', { id })
 }
 
 // 创建任务模板

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-0320615b6f69b54f96dcb8bec40f5a9b0b713a12
+6d4ce7236f8ddf913a93b8ced9acd339a2073a71

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
   "name": "cfc-web",
-  "version": "1.0.1489",
+  "version": "1.0.1490",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

+ 6 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,12 @@
 
 ---
 
+## v1.0.1490 (2026-10-04)
+
+### 重构
+- move share QR to floating button on profile page - remove invite share menu item from ProfileMenu - remove share.vue page and its registration - add floating QR code button in profile-main/profile.vue - add share poster modal with QR code, copy and share actions - add support for ref code on homepage onLoad
+
+
 ## v1.0.1489 (2026-10-04)
 
 ### 新功能

+ 7 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.1489
+> 当前版本: v1.0.1490
 
 ## 历史版本
 
@@ -8,6 +8,12 @@
 
 ---
 
+## v1.0.1490 (2026-10-04)
+
+### 重构
+- move share QR to floating button on profile page - remove invite share menu item from ProfileMenu - remove share.vue page and its registration - add floating QR code button in profile-main/profile.vue - add share poster modal with QR code, copy and share actions - add support for ref code on homepage onLoad
+
+
 ## v1.0.1489 (2026-10-04)
 
 ### 新功能

+ 1 - 1
docs/superpowers/PROJECT-OVERVIEW.md

@@ -374,7 +374,7 @@
 | `2026-08-31-self-check-ai-integration-design.md` | 🟡 设计稿(P0-1 纯AI替换静态建议 + P0-2 用户点击生成健康计划 + P1-1 历史趋势AI解读 + P1-2 Chat上下文注入,P2延后) | 五维家庭自检 AI 结合设计 |
 | `2026-09-09-team-hierarchy-design.md` | 🟡 设计稿(团队层级树从下往上生长 + 团队消费额分级统计 + 直推成员消费/CF明细 + 我的推荐人展示 + 去掉富页面推荐码) | 团队层级与推荐关系可视化 |
 | `2026-09-10-report-quick-analyze-design.md` | 🟡 设计稿(报告详情页快速分析:免费版每日 1 次 Redis 计数 + 付费版多轮;复用 chat_graph + AiGateway,LangGraph 零改动) | 报告快速分析设计 |
-| `api/API_REFERENCE.md` | 🟢 已建立(2026-08-18;200+ 接口清单;废弃接口标注;新增接口检查流程;2026-09-06 补充家庭成员切换/回收箱接口:`/leave`、`/kick` 回收箱分流、`/recycle`;2026-09-10 补充关系三图接口:`/api/octopus`、`/api/pearl`、`/api/ability`;2026-09-12 补充供应商审核接口:`/api/product/order/review/update`) | 后台接口参考文档 |
+| `api/API_REFERENCE.md` | 🟢 已建立(2026-08-18;200+ 接口清单;废弃接口标注;新增接口检查流程;2026-09-06 补充家庭成员切换/回收箱接口:`/leave`、`/kick` 回收箱分流、`/recycle`;2026-09-10 补充关系三图接口:`/api/octopus`、`/api/pearl`、`/api/ability`;2026-09-12 补充供应商审核接口:`/api/product/order/review/update`;2026-10-04 补充统一服务角色申请 6 接口 `/api/service-role/*`(4.44,含 status 语义与角色落地规则)及规划师解绑家庭 `/api/guide/families/unbind`(4.45)) | 后台接口参考文档 |
 | `2026-09-10-key-person-expansion-octopus-design.md` | 🟡 设计规格已确认(成效对象=会员客户 + 类型bitmask + 关键人画像 + 四步法 + 高频词≤8方向;3表/10接口/三层画布;替换旧章鱼图) | 关键人拓展章鱼图替换设计(关系三图重构) |
 | `2026-09-19-article-reading-quiz-design.md` | 🟢 已实施(补全现有阅读答题:article_quiz_records 表 + LangGraph article_quiz_graph 出题 + AiGateway 接入 + 提交答题落库 + CF值/五维能量双奖励 + profile_snapshot.quiz_summary 认知雷达) | 文章阅读后答题奖励 + 认知雷达记录设计 |
 | `2026-09-22-guide-popup-config-design.md` | ✅ 已实施(4表/guide_popup+step+trigger+log,9接口,ConfigurableGuide.vue组件+管理端2页;旧 sys_config 方案保留并行) | 弹窗引导页配置化管理设计 |

+ 67 - 1
docs/superpowers/api/API_REFERENCE.md

@@ -77,6 +77,9 @@ find cfc-backend/src/main/java -name "*XxxService.java" -o -name "*XxxController
 | `OctopusController` | `/api/octopus` | 章鱼图(帮助记录/触手聚合) | — |
 | `PearlController` | `/api/pearl` | 珍珠图(25 类社会连接聚合 + 互动/提醒/优先级) | — |
 | `AbilityController` | `/api/ability` | 能力图(SKILL 帮助记录聚合为能力节点) | — |
+| `ServiceRoleApplicationController` | `/api/service-role` | 统一服务角色申请(多角色合一 + 管理端审批) | — |
+| `GuideTeamController` | `/api/guide/team` | 规划师团队/邀请码/上下级 | — |
+| `GuideFamilyTaskController` | `/api/guide/families` | 规划师侧家庭任务管理 + 家庭解绑 | — |
 
 ---
 
@@ -1397,4 +1400,67 @@ interactionType 取值:`PHONE` / `WECHAT` / `MEETING` / `OTHER`。
 
 ---
 
-*文档最后更新:2026-09-29*
+### 4.44 统一服务角色申请(`/api/service-role/*`)
+
+多角色(规划师/营养师/管家/供应商/内容管理员/活动策划)统一申请入口,一次提交可含多个角色,管理端审批通过后回写 `users.roles` 并按角色初始化附属记录。
+
+| 路径 | 说明 |
+|------|------|
+| `POST /api/service-role/apply` | 提交服务角色申请(`roles` 必填) |
+| `POST /api/service-role/my-apply` | 查询我的最新申请记录 |
+| `POST /api/service-role/upload-image` | 上传身份证/资质证书图片(multipart,字段名 `file`) |
+| `POST /api/service-role/admin/list` | 管理端:申请列表(`status` 查询参数,默认 `0`) |
+| `POST /api/service-role/admin/approve` | 管理端:批准(`{ id }`) |
+| `POST /api/service-role/admin/reject` | 管理端:驳回(`{ id, reason }`) |
+
+**状态语义**(`service_role_applications.status`)
+
+| 值 | 含义 |
+|----|------|
+| `0` | 待审核(同一 userId 仅允许一条待审,重复提交返回「您已提交过申请,请等待审核」) |
+| `1` | 已通过 |
+| `2` | 已驳回(原因存 `reject_reason`) |
+
+**POST `/api/service-role/apply`** 请求体(`ServiceRoleApplyDTO`)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `roles` | List\<String\> | 申请角色,`@NotEmpty` 至少一个 |
+| `idCard` | String | 身份证号 |
+| `idCardImages` | List\<String\> | 身份证图片 URL 数组(落库转 JSON 字符串) |
+| `certificateImages` | List\<String\> | 资质证书图片 URL 数组 |
+| `province` / `city` / `district` / `street` | String | 四级地址 |
+| `addressDetail` | String | 详细地址 |
+
+**审批通过后的角色落地规则**(`ServiceRoleApplicationServiceImpl.approve`)
+
+| 申请角色 | 副作用 |
+|----------|--------|
+| `planner` | `guides` 新增一行(`status=active`)+ `users.roles` 追加 `teacher` |
+| `nutritionist` | `users.nutritionist_status=approved` + `roles` 追加 `nutritionist` |
+| `butler` | `users.butler_status=approved` + `butler_profiles` 新增一行 + `roles` 追加 `butler` |
+| `vendor` | `users.vendor_status=approved` + `roles` 追加 `supplier` |
+| `article_admin` | `users.article_admin_status=approved` + `roles` 追加 `knowledge_admin` |
+| `activity_provider` | `users.activity_provider_status=approved` + `roles` 追加 `activity_manager` |
+
+> **注意**:approve/reject 仅对 `status=0` 的记录生效,已处理返回「该申请已处理」。
+> `upload-image` 对图片类型文件先走 `wechatService.checkImage()` 内容安全检测,未通过直接拒绝。
+
+---
+
+### 4.45 规划师解除家庭绑定(`POST /api/guide/families/unbind`)
+
+| 路径 | 说明 |
+|------|------|
+| `POST /api/guide/families/unbind` | 规划师解除自己名下的家庭绑定(请求体 `{ id }`,即 `guide_families.id`) |
+
+- 角色校验:仅 `role=teacher` 可调用,否则返回 `Access denied`。
+- 归属校验:`GuideFamilyService.unbindByGuide()` 按 `id + guide_id + status='binding'` 定位,只能解除属于自己的绑定。
+- 副作用:将 `guide_families.status` 置为 `cancelled`。
+- 家长侧解绑为独立接口 `POST /api/bind/unbind`(按 familyId 定位,并通知规划师)。
+
+> **注意**:前端 `unbindFamily(id)` 需传 `guide_families.id`(绑定记录 ID),不是 `familyId`。
+
+---
+
+*文档最后更新:2026-10-04*