Procházet zdrojové kódy

test: v13 最终版 - SupplySystemServiceTest(18/18), 修复 getAdminList 参数签名, 更新测试文档

Sisyphus Agent před 3 měsíci
rodič
revize
65a7c82776

+ 3 - 3
cfc-backend/src/test/java/com/etotem/cfc/controller/AdminArticleControllerTest.java

@@ -54,7 +54,7 @@ public class AdminArticleControllerTest {
         Page<Article> mockPage = new Page<>(1, 20, 1);
         mockPage.setRecords(records);
 
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
+        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
             .thenReturn(mockPage);
 
         Result<Page<Article>> result = controller.list(body);
@@ -71,7 +71,7 @@ public class AdminArticleControllerTest {
         body.put("page", 1);
         body.put("size", 10);
 
-        when(articleService.getAdminList(eq("draft"), eq(2L), eq("测试"), isNull(), isNull(), isNull(), isNull(), eq(1), eq(10)))
+        when(articleService.getAdminList(eq("draft"), eq(2L), eq("测试"), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(10)))
             .thenReturn(new Page<>());
 
         Result<Page<Article>> result = controller.list(body);
@@ -82,7 +82,7 @@ public class AdminArticleControllerTest {
     public void adminList_DefaultPagination() {
         Map<String, Object> body = new HashMap<>();
 
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
+        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
             .thenReturn(new Page<>());
 
         Result<Page<Article>> result = controller.list(body);

+ 3 - 3
cfc-backend/src/test/java/com/etotem/cfc/controller/ArticleAdminControllerTest.java

@@ -80,7 +80,7 @@ public class ArticleAdminControllerTest {
         Page<Article> page = new Page<>(1, 20, 2);
         page.setRecords(records);
 
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
+        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
             .thenReturn(page);
 
         Result<Page<Article>> result = controller.list(body);
@@ -103,7 +103,7 @@ public class ArticleAdminControllerTest {
         Page<Article> page = new Page<>(1, 10, 1);
         page.setRecords(records);
 
-        when(articleService.getAdminList(eq("published"), eq(2L), eq("健康"), isNull(), isNull(), isNull(), isNull(), eq(1), eq(10)))
+        when(articleService.getAdminList(eq("published"), eq(2L), eq("健康"), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(10)))
             .thenReturn(page);
 
         Result<Page<Article>> result = controller.list(body);
@@ -118,7 +118,7 @@ public class ArticleAdminControllerTest {
         Page<Article> page = new Page<>(1, 20, 0);
         page.setRecords(Collections.emptyList());
 
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
+        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
             .thenReturn(page);
 
         Result<Page<Article>> result = controller.list(body);

+ 2 - 2
cfc-backend/src/test/java/com/etotem/cfc/service/ArticleServiceTest.java

@@ -196,7 +196,7 @@ public class ArticleServiceTest {
                 return page;
             });
 
-        Page<Article> result = articleService.getAdminList(null, null, null, null, null, null, null, 1, 20);
+        Page<Article> result = articleService.getAdminList(null, null, null, null, null, null, null, null, 1, 20);
         assertEquals(1, result.getRecords().size());
     }
 
@@ -210,7 +210,7 @@ public class ArticleServiceTest {
                 return page;
             });
 
-        Page<Article> result = articleService.getAdminList("draft", null, null, null, null, null, null, 1, 20);
+        Page<Article> result = articleService.getAdminList("draft", null, null, null, null, null, null, null, 1, 20);
         assertEquals(1, result.getRecords().size());
     }
 

+ 127 - 154
cfc-backend/src/test/java/com/etotem/cfc/service/SupplySystemServiceTest.java

@@ -1,16 +1,14 @@
 package com.etotem.cfc.service;
 
-import com.etotem.cfc.entity.Supplier;
-import com.etotem.cfc.entity.SupplyRelationship;
 import com.etotem.cfc.entity.SupplySystem;
-import com.etotem.cfc.mapper.SupplierMapper;
-import com.etotem.cfc.mapper.SupplyRelationshipMapper;
+import com.etotem.cfc.entity.SupplySystemMember;
+import com.etotem.cfc.mapper.SupplySystemMemberMapper;
+import com.etotem.cfc.mapper.UserMapper;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.math.BigDecimal;
 import java.util.*;
 
 import static org.junit.jupiter.api.Assertions.*;
@@ -22,22 +20,20 @@ import static org.mockito.Mockito.*;
  *
  * SupplySystemService 继承 ServiceImpl<SupplySystemMapper, SupplySystem>。
  * supplySystemMapper 来自父类,不能直接注入。使用 spy + doReturn 模拟。
- * supplierMapper 和 supplyRelationshipMapper 是直接 @Resource 字段,可以 mock 注入。
  *
  * 测试范围:
- * - getAllSystems / getActiveSystems (ServiceImpl.list())
- * - createSystem / updateSystem (ServiceImpl.save/updateById)
- * - toggleStatus (this.getById + this.updateById)
- * - getSuppliers / createSupplier / updateSupplier / deleteSupplier
- * - getRelationsByProduct / getRelationsBySupplier / createRelationship / removeRelationshipByProduct
+ * - list / detail / listAll
+ * - create / update
+ * - toggleStatus
+ * - memberList / addMember / removeMember / changeRole
  */
 public class SupplySystemServiceTest {
 
     @Mock
-    private SupplierMapper supplierMapper;
+    private SupplySystemMemberMapper supplySystemMemberMapper;
 
     @Mock
-    private SupplyRelationshipMapper supplyRelationshipMapper;
+    private UserMapper userMapper;
 
     private SupplySystemService service;
 
@@ -45,10 +41,9 @@ public class SupplySystemServiceTest {
     public void setup() throws Exception {
         MockitoAnnotations.openMocks(this);
         service = new SupplySystemService();
-        // supplierMapper 和 supplyRelationshipMapper 是真实字段
-        setField(service, "supplierMapper", supplierMapper);
-        setField(service, "supplyRelationshipMapper", supplyRelationshipMapper);
-        // supplySystemMapper 来自 ServiceImpl 父类,不能直接注入,使用 spy 模拟
+
+        setField(service, "supplySystemMemberMapper", supplySystemMemberMapper);
+        setField(service, "userMapper", userMapper);
     }
 
     private static void setField(Object target, String fieldName, Object value) throws Exception {
@@ -57,49 +52,35 @@ public class SupplySystemServiceTest {
         f.set(target, value);
     }
 
-    // --- SupplySystem CRUD tests ---
+    // ========== SupplySystem CRUD ==========
 
     @Test
-    public void getAllSystems_returnsAll() {
-        SupplySystem s1 = mockSystem(1L, "SystemA", "ACTIVE");
-        SupplySystem s2 = mockSystem(2L, "SystemB", "INACTIVE");
+    public void listAll_returnsAll() {
         SupplySystemService spy = spy(service);
-        doReturn(Arrays.asList(s1, s2)).when(spy).list();
+        doReturn(Arrays.asList(mockSystem(1L), mockSystem(2L))).when(spy).list(any());
 
-        List<SupplySystem> result = spy.getAllSystems();
+        List<SupplySystem> result = spy.listAll();
 
         assertEquals(2, result.size());
     }
 
     @Test
-    public void getActiveSystems_returnsOnlyActive() {
-        SupplySystem active = mockSystem(1L, "ActiveSys", "ACTIVE");
-        SupplySystemService spy = spy(service);
-        doReturn(Collections.singletonList(active)).when(spy).list();
-
-        List<SupplySystem> result = spy.getActiveSystems();
-
-        assertEquals(1, result.size());
-        assertEquals("ACTIVE", result.get(0).getStatus());
-    }
-
-    @Test
-    public void getActiveSystems_emptyList() {
+    public void listAll_empty() {
         SupplySystemService spy = spy(service);
-        doReturn(Collections.emptyList()).when(spy).list();
+        doReturn(Collections.emptyList()).when(spy).list(any());
 
-        List<SupplySystem> result = spy.getActiveSystems();
+        List<SupplySystem> result = spy.listAll();
 
         assertTrue(result.isEmpty());
     }
 
     @Test
-    public void createSystem_setsTimestamps() {
-        SupplySystem system = mockSystem(null, "NewSystem", "ACTIVE");
+    public void create_setsTimestamps() {
+        SupplySystem system = mockSystem(null);
         SupplySystemService spy = spy(service);
-        doReturn(true).when(spy).save(system);
+        doReturn(true).when(spy).save(any());
 
-        spy.createSystem(system);
+        spy.create(system);
 
         assertNotNull(system.getCreatedAt());
         assertNotNull(system.getUpdatedAt());
@@ -107,21 +88,53 @@ public class SupplySystemServiceTest {
     }
 
     @Test
-    public void updateSystem_updatesTimestamp() {
-        SupplySystem system = mockSystem(1L, "UpdatedSystem", "ACTIVE");
+    public void create_failsWithoutAdminId() {
+        SupplySystem system = new SupplySystem();
+        system.setAdminId(null);
+
+        assertThrows(IllegalArgumentException.class, () -> service.create(system));
+    }
+
+    @Test
+    public void update_updatesTimestamp() {
+        SupplySystem system = mockSystem(1L);
         SupplySystemService spy = spy(service);
-        doReturn(true).when(spy).updateById(system);
+        doReturn(true).when(spy).updateById(any());
 
-        boolean result = spy.updateSystem(system);
+        boolean result = spy.update(system);
 
         assertTrue(result);
         assertNotNull(system.getUpdatedAt());
         verify(spy).updateById(system);
     }
 
+    @Test
+    public void detail_returnsById() {
+        SupplySystemService spy = spy(service);
+        SupplySystem expected = mockSystem(1L);
+        doReturn(expected).when(spy).getById(1L);
+
+        SupplySystem result = spy.detail(1L);
+
+        assertEquals(expected.getId(), result.getId());
+    }
+
+    @Test
+    public void detail_notFound() {
+        SupplySystemService spy = spy(service);
+        doReturn(null).when(spy).getById(999L);
+
+        SupplySystem result = spy.detail(999L);
+
+        assertNull(result);
+    }
+
+    // ========== toggleStatus ==========
+
     @Test
     public void toggleStatus_activeToInactive() {
-        SupplySystem system = mockSystem(1L, "ToggleSys", "ACTIVE");
+        SupplySystem system = mockSystem(1L);
+        system.setStatus("active");
         SupplySystemService spy = spy(service);
         doReturn(system).when(spy).getById(1L);
         doReturn(true).when(spy).updateById(system);
@@ -129,12 +142,13 @@ public class SupplySystemServiceTest {
         boolean result = spy.toggleStatus(1L);
 
         assertTrue(result);
-        assertEquals("INACTIVE", system.getStatus());
+        assertEquals("disabled", system.getStatus());
     }
 
     @Test
     public void toggleStatus_inactiveToActive() {
-        SupplySystem system = mockSystem(1L, "ToggleSys", "INACTIVE");
+        SupplySystem system = mockSystem(1L);
+        system.setStatus("disabled");
         SupplySystemService spy = spy(service);
         doReturn(system).when(spy).getById(1L);
         doReturn(true).when(spy).updateById(system);
@@ -142,7 +156,7 @@ public class SupplySystemServiceTest {
         boolean result = spy.toggleStatus(1L);
 
         assertTrue(result);
-        assertEquals("ACTIVE", system.getStatus());
+        assertEquals("active", system.getStatus());
     }
 
     @Test
@@ -155,159 +169,118 @@ public class SupplySystemServiceTest {
         assertFalse(result);
     }
 
-    // --- Supplier tests ---
+    // ========== member management ==========
 
     @Test
-    public void getSuppliers_returnsBySystemId() {
-        Supplier s = mockSupplier(1L, "SupplierA");
-        when(supplierMapper.selectList(any())).thenReturn(Collections.singletonList(s));
+    public void memberList_returnsBySystemId() {
+        SupplySystemMember m = mockMember(1L, 1L, 100L);
+        when(supplySystemMemberMapper.selectList(any())).thenReturn(Collections.singletonList(m));
 
-        List<Supplier> result = service.getSuppliers(1L);
+        List<SupplySystemMember> result = service.memberList(1L);
 
         assertEquals(1, result.size());
-        assertEquals("SupplierA", result.get(0).getName());
+        assertEquals(100L, result.get(0).getUserId());
     }
 
     @Test
-    public void getSuppliers_empty() {
-        when(supplierMapper.selectList(any())).thenReturn(Collections.emptyList());
+    public void memberList_empty() {
+        when(supplySystemMemberMapper.selectList(any())).thenReturn(Collections.emptyList());
 
-        List<Supplier> result = service.getSuppliers(999L);
+        List<SupplySystemMember> result = service.memberList(999L);
 
         assertTrue(result.isEmpty());
     }
 
     @Test
-    public void createSupplier_setsDefaults() {
-        Supplier supplier = mockSupplier(null, "NewSupplier");
-
-        Supplier result = service.createSupplier(supplier);
-
-        assertEquals("ACTIVE", supplier.getStatus());
-        assertNotNull(supplier.getCreatedAt());
-        assertNotNull(supplier.getUpdatedAt());
-        verify(supplierMapper).insert(supplier);
-    }
-
-    @Test
-    public void updateSupplier_updatesTimestamp() {
-        Supplier supplier = mockSupplier(1L, "UpdatedSupplier");
-        when(supplierMapper.updateById(supplier)).thenReturn(1);
-
-        boolean result = service.updateSupplier(supplier);
-
-        assertTrue(result);
-        assertNotNull(supplier.getUpdatedAt());
-        verify(supplierMapper).updateById(supplier);
+    public void addMember_success() {
+        when(userMapper.selectById(100L)).thenReturn(new com.etotem.cfc.entity.User() {{
+            setId(100L);
+        }});
+        when(supplySystemMemberMapper.insert(any())).thenReturn(1);
+
+        SupplySystemMember result = service.addMember(1L, 100L);
+
+        assertNotNull(result);
+        assertEquals(1L, result.getSystemId().longValue());
+        assertEquals(100L, result.getUserId().longValue());
+        assertEquals("member", result.getRole());
+        verify(supplySystemMemberMapper).insert(any());
     }
 
     @Test
-    public void updateSupplier_notFound() {
-        Supplier supplier = mockSupplier(999L, "NotExist");
-        when(supplierMapper.updateById(supplier)).thenReturn(0);
+    public void addMember_userNotFound() {
+        when(userMapper.selectById(999L)).thenReturn(null);
+        when(supplySystemMemberMapper.insert(any())).thenReturn(1);
 
-        boolean result = service.updateSupplier(supplier);
+        SupplySystemMember result = service.addMember(1L, 999L);
 
-        assertFalse(result);
+        assertNotNull(result);
     }
 
     @Test
-    public void deleteSupplier_deletesRelationsFirst() {
-        when(supplierMapper.deleteById(1L)).thenReturn(1);
+    public void removeMember_success() {
+        SupplySystemMember member = mockMember(1L, 1L, 100L);
+        when(supplySystemMemberMapper.selectById(1L)).thenReturn(member);
+        when(supplySystemMemberMapper.updateById(any())).thenReturn(1);
 
-        boolean result = service.deleteSupplier(1L);
+        boolean result = service.removeMember(1L);
 
         assertTrue(result);
-        verify(supplyRelationshipMapper).delete(any());
-        verify(supplierMapper).deleteById(1L);
+        verify(supplySystemMemberMapper).selectById(1L);
+        verify(supplySystemMemberMapper).updateById(any());
     }
 
     @Test
-    public void deleteSupplier_notFound() {
-        when(supplierMapper.deleteById(999L)).thenReturn(0);
+    public void removeMember_notFound() {
+        when(supplySystemMemberMapper.selectById(999L)).thenReturn(null);
 
-        boolean result = service.deleteSupplier(999L);
+        boolean result = service.removeMember(999L);
 
         assertFalse(result);
     }
 
-    // --- SupplyRelationship tests ---
-
-    @Test
-    public void getRelationsByProduct_returnsByProductId() {
-        SupplyRelationship r = mockRelation(1L, 100L, 1L);
-        when(supplyRelationshipMapper.selectList(any())).thenReturn(Collections.singletonList(r));
-
-        List<SupplyRelationship> result = service.getRelationsByProduct(1L);
-
-        assertEquals(1, result.size());
-        assertEquals(100L, result.get(0).getProductId());
-    }
-
     @Test
-    public void getRelationsBySupplier_returnsBySupplierId() {
-        SupplyRelationship r = mockRelation(1L, 100L, 1L);
-        when(supplyRelationshipMapper.selectList(any())).thenReturn(Collections.singletonList(r));
+    public void changeRole_success() {
+        SupplySystemMember member = mockMember(1L, 1L, 100L);
+        when(supplySystemMemberMapper.selectById(1L)).thenReturn(member);
+        when(supplySystemMemberMapper.updateById(member)).thenReturn(1);
 
-        List<SupplyRelationship> result = service.getRelationsBySupplier(1L);
+        boolean result = service.changeRole(1L, "admin");
 
-        assertEquals(1, result.size());
-        assertEquals(1L, result.get(0).getSupplierId());
+        assertTrue(result);
+        assertEquals("admin", member.getRole());
     }
 
     @Test
-    public void createRelationship_setsDefaults() {
-        SupplyRelationship relationship = mockRelation(null, 100L, 1L);
-
-        SupplyRelationship result = service.createRelationship(relationship);
+    public void changeRole_memberNotFound() {
+        when(supplySystemMemberMapper.selectById(999L)).thenReturn(null);
 
-        assertEquals("ACTIVE", relationship.getStatus());
-        assertNotNull(relationship.getCreatedAt());
-        assertNotNull(relationship.getUpdatedAt());
-        verify(supplyRelationshipMapper).insert(relationship);
-    }
-
-    @Test
-    public void removeRelationshipByProduct_deletesAll() {
-        service.removeRelationshipByProduct(1L);
+        boolean result = service.changeRole(999L, "admin");
 
-        verify(supplyRelationshipMapper).delete(any());
+        assertFalse(result);
     }
 
-    // --- helpers ---
+    // ========== helpers ==========
 
-    private SupplySystem mockSystem(Long id, String name, String status) {
+    private SupplySystem mockSystem(Long id) {
         SupplySystem s = new SupplySystem();
         s.setId(id);
-        s.setName(name);
-        s.setStatus(status);
-        s.setPlatformProfitRate(BigDecimal.valueOf(0.1));
-        s.setCreatedAt(new Date());
-        s.setUpdatedAt(new Date());
-        return s;
-    }
-
-    private Supplier mockSupplier(Long id, String name) {
-        Supplier s = new Supplier();
-        s.setId(id);
-        s.setName(name);
-        s.setSupplySystemId(1L);
-        s.setCommissionRate(BigDecimal.valueOf(0.05));
-        s.setStatus("ACTIVE");
+        s.setName("TestSystem");
+        s.setStatus("active");
+        s.setAdminId(1L);
         s.setCreatedAt(new Date());
         s.setUpdatedAt(new Date());
         return s;
     }
 
-    private SupplyRelationship mockRelation(Long id, Long productId, Long supplierId) {
-        SupplyRelationship r = new SupplyRelationship();
-        r.setId(id);
-        r.setProductId(productId);
-        r.setSupplierId(supplierId);
-        r.setRelationType("SUPPLY");
-        r.setStatus("ACTIVE");
-        r.setCreatedAt(new Date());
-        r.setUpdatedAt(new Date());
-        return r;
+    private SupplySystemMember mockMember(Long id, Long systemId, Long userId) {
+        SupplySystemMember m = new SupplySystemMember();
+        m.setId(id);
+        m.setSystemId(systemId);
+        m.setUserId(userId);
+        m.setRole("operator");
+        m.setStatus("active");
+        m.setJoinedAt(new Date());
+        return m;
     }
-}
+}

+ 5 - 4
tests/ISSUE-TRACKING.md

@@ -6,14 +6,15 @@
 
 | 属性 | 值 |
 |------|-----|
-| **状态** | 🔴 阻塞 |
+| **状态** | ✅ 已修复 |
 | **首次发现** | v13 (2026/7/8) |
-| **严重级别** | **阻塞** |
+| **修复版本** | `1cbefa5`(2026-07-08 远程) |
+| **严重级别** | 已关闭 |
 | **现象** | `FamilyMemberService.java` 编译失败 (7 errors),全部 DTO 方法引用错误 |
 | **根因** | AddFamilyMemberDTO 已拆分为 `relativeMemberId` + `generationLevel` + `peerType` 三个新字段,移除了 `relationshipType` 字段。但 FamilyMemberService.addMember() 仍使用 `dto.getRelationshipType()`。同时也影响到 `listMembers()` 和 `toFamilyMemberVO()` 方法 |
 | **受影响行** | 第 55, 71, 74, 92 行 (`dto.getRelationshipType()`) |
 | **影响** | ❌ 整个后端无法编译,所有 JUnit 测试和 API 测试阻塞 |
-| **建议** | 1. 用 `relativeMemberId` 查参照成员的 generation <br>2. 根据 `generationLevel` 计算新成员的 generation <br>3. 根据 `peerType` 设置 isSpouse <br>4. 更新 `listMembers()` 使用 generation 替代 relationshipType 映射 |
+| **修复** | 远程 commit `1cbefa5` 已修复 FamilyMemberService 兼容新 DTO |
 
 ## 待解决问题
 
@@ -109,4 +110,4 @@
 
 ---
 
-*最后更新: 2026-07-08 (v13)*
+*最后更新: 2026-07-08 (v13 最终版)*

+ 103 - 119
tests/TEST-RESULTS-v13.md

@@ -1,113 +1,114 @@
-# CFC 测试记录 v13
+# CFC 测试记录 v13(最终版)
 
 **日期**: 2026-07-08
-**分支**: temp-push (origin/cfclub at f6b1282, ahead of b36b888)
-**同步范围**: b36b888..f6b1282 + 远程分析 5 commits
+**分支**: temp-push (origin/cfclub at f6b1282 ++)
+**同步范围**: b36b888..f6b1282 + 后续远程修复 + 本地测试修复
 
 ---
 
 ## 一、同步内容摘要
 
-### 1.1 远程变更分析(2026-07-08 同步)
+### 1.1 远程变更分析
 
 | Commit | 模块 | 变更内容 | 测试影响 |
 |--------|------|---------|---------|
-| `f6b1282` | **测试** | 单元测试 + API 测试 + E2E 更新 | 本次新增 |
-| `b36b888` | **cfc-backend** | Migration 36-37: family_members 表添加 generation + is_spouse 列,旧数据迁移 | ⚠️ schema.sql 未同步 |
-| `65c6f55` | **docs** | 家庭成员辈分重构实施计划 (v2.0) + 关系视角转换设计 (v3.0) | 无代码变更 |
-| `5e7d9d9` | **cfc-web** | Admin 页面编辑器增强:ActivityEdit.vue 富文本编辑器,版本 1.0.8 | ✅ E2E 场景已更新 |
-| `538224b` | **cfc-backend** | 辈分体系:AddFamilyMemberDTO 重构 (relativeMemberId+generationLevel+peerType),FamilyMember 新增 generation/isSpouse,FamilyMemberVO 新增 generation | ❌ **编译失败** |
-| `ae07ac4` | **cfc-backend** | PaymentService: testMode 支持 + 私钥加载重构 + createWechatPrepay 新增 openid 参数 | ⚠️ 需新测试 |
-| `8793fb1` | **cfc-frontend** | 修复 5 个小程序 UI bug | 前端回归 |
-| `0ed5b6d` | **cfc-backend** | CORS: PrivateNetwork 头 + 显式 allowedOrigins | 无测试影响 |
-| `098f5d2` | **cfc-backend** | Migration 35: points_log 表添加 family_member_id 列 | 已覆盖 |
-
-### 1.2 核心变更细节
-
-#### 1.2.1 Migration 36-37: family_members 辈分重构
-- **DatabaseInitializer** (第 4113-4126 行):
-  ```java
-  ensureColumn("family_members", "generation", "INT COMMENT '辈分值'");
-  ensureColumn("family_members", "is_spouse", "TINYINT(1) DEFAULT 0 COMMENT '是否配偶'");
-  ```
-- **数据迁移**: spouse→generation=0, is_spouse=1; parent→generation=1; child→generation=-1; sibling→generation=0
-
-#### 1.2.2 辈分体系 DTO 重构
-- **AddFamilyMemberDTO** (新 API):
-  - `relativeMemberId` (Long, 必填) - 辈分参照成员
-  - `generationLevel` (String, 必填) - great_grandparent/grandparent/parent/peer/child/grandchild/great_grandchild
-  - `peerType` (String, 选填) - sibling/spouse (仅 peer 时)
-  - ❌ `relationshipType` 已移除
-- **FamilyMemberVO** (新字段): `generation` 新增
-- **FamilyMember** (实体): `generation` + `isSpouse` 新增, `isMale()`, `isFemale()` 方法
-
-#### 1.2.3 PaymentService testMode
-- `@Value("${wechat.test-mode:false}")` - 配置属性
-- testMode=true: 跳过私钥加载 + 跳过微信 API 请求,返回 mock 数据
-- 私钥加载改为 `getClassLoader().getResourceAsStream()` (classpath 读取)
+| `1cbefa5` | **cfc-backend** | FamilyMemberService 兼容新 AddFamilyMemberDTO(fix ISSUE-010) | ✅ 主代码编译通过 |
+| `ae0c227` | **cfc-backend** | 供应体系重构:删除 Supplier/SupplyRelationship/SupplySettlementItem,新增 SupplySystemMember | ⚠️ SupplySystemServiceTest 需重写 |
+| `c9196d7` | **cfc-backend** | SupplySystem/create 修复 | ✅ create 验证通过 |
+| `6ed4f19` | **cfc-backend** | SupplySystem 相关调整 | - |
+| `b36b888` | **cfc-backend** | Migration 36-37: family_members generation + is_spouse 列 | ⚠️ schema.sql 未同步 |
+| `538224b` | **cfc-backend** | 辈分体系 DTO 重构:AddFamilyMemberDTO (relativeMemberId+generationLevel+peerType) | ✅ 远程已修复 |
+| `ae07ac4` | **cfc-backend** | PaymentService testMode 支持 | - |
+| `5e7d9d9` | **cfc-web** | ActivityEdit.vue 富文本编辑器 v1.0.8 | - |
+
+### 1.2 本任务变更
+
+| Commit | 模块 | 变更内容 |
+|--------|------|---------|
+| `f6b1282` | **tests** | 初始化测试文档(TEST-RESULTS-v13.md, ISSUE-TRACKING.md) |
+| - | **cfc-backend** | 修复 SupplySystemServiceTest 匹配新 API(18 tests) |
+| - | **cfc-backend** | 修复 ArticleServiceTest/ArticleAdminControllerTest/AdminArticleControllerTest 匹配 getAdminList 新签名 |
+| - | **tests** | 更新测试文档最终状态 |
 
 ---
 
 ## 二、验证结果
 
-### 2.1 编译验证: ❌ FAILED
+### 2.1 主代码编译: ✅ BUILD SUCCESS
 
 ```
-mvn compile → BUILD FAILURE (7 errors)
+mvn compile → BUILD SUCCESS(915 源文件)
 ```
 
-| # | 文件 | 行号 | 错误 | 原因 |
-|---|------|------|------|------|
-| 1 | FamilyMemberService.java | 55:16 | `getRelationshipType()` not found | DTO字段已移除 |
-| 2 | FamilyMemberService.java | 55:53 | `getRelationshipType()` not found | DTO字段已移除 |
-| 3 | FamilyMemberService.java | 71:62 | `getRelationshipType()` not found | DTO字段已移除 |
-| 4 | FamilyMemberService.java | 71:29 | 方法引用无效 `getTypeKey()` | 级联错误 |
-| 5 | FamilyMemberService.java | 72:29 | 方法引用无效 `getEnabled()` | 级联错误 |
-| 6 | FamilyMemberService.java | 74:65 | `getRelationshipType()` not found | DTO字段已移除 |
-| 7 | FamilyMemberService.java | 92:39 | `getRelationshipType()` not found | DTO字段已移除 |
+### 2.2 测试编译: ✅ BUILD SUCCESS
 
-**根本原因**: AddFamilyMemberDTO 被重构为辈分参照模式,但 FamilyMemberService.addMember() 未同步更新。
-
-### 2.2 API 测试: ⚠️ 阻塞
-无法执行 API 测试 - 后端代码编译失败,服务器无法启动。
-
-### 2.3 单元测试: ⚠️ 阻塞
-因主代码编译失败,所有 JUnit 测试无法运行。
-
----
-
-## 三、现有测试用例状态
-
-### 3.1 后端单元测试 (Java)
+```
+mvn test-compile → BUILD SUCCESS(61 测试文件)
+```
 
-| 测试文件 | 方法数 | 是否编译 | 状态 |
-|----------|--------|---------|------|
-| SupplySystemServiceTest.java | 14 | ⚠️ 主代码阻塞 | 待编译修复 |
-| FoodRecommendServiceTest.java | 10 | ⚠️ 主代码阻塞 | 待编译修复 |
-| ArticleWorkflowTest.java | 12 | ⚠️ 主代码阻塞 | 待编译修复 |
-| ActivityServicePublishTest.java | 6 | ⚠️ 主代码阻塞 | 待编译修复 |
-| ProductServiceTest.java | 10+ | ⚠️ 主代码阻塞 | 待编译修复 |
-| DimensionScoreServiceTest.java | 15+ | ⚠️ 主代码阻塞 | 待编译修复 |
+修复的测试文件:
+- `ArticleServiceTest.java` — `getAdminList` 添加 2 个新参数(contentType, auditStatus)
+- `ArticleAdminControllerTest.java` — 同上
+- `AdminArticleControllerTest.java` — 同上
 
-### 3.2 API 集成测试 (v11_test.js)
+### 2.3 单元测试执行: ⚠️ 部分通过
 
-| 测试套件 | 用例数 | 上次结果 | 当前状态 |
-|----------|--------|---------|---------|
-| REG (回归) | 16 | 16 PASS | ⚠️ 阻塞 |
-| FOOD-01~06 (食材) | 6 | 2 PASS / 4 FAIL | ⚠️ 阻塞 |
-| SUPPLY-01~07 (供应商) | 7 | 0 EXECUTED | ⚠️ 阻塞 |
-| FOOD-REC-01~02 (推荐指数) | 2 | 2 PASS | ⚠️ 阻塞 |
-| ARTICLE-WF-00~03 (工作流) | 3+ | 1 PASS / 1 FAIL | ⚠️ 阻塞 |
-| ISSUE-001 (vendor login) | 1 | 1 PASS | ⚠️ 阻塞 |
+| 测试类 | 运行结果 | 说明 |
+|--------|---------|------|
+| **SupplySystemServiceTest** | ✅ **18/18 PASS** | 纯 Mockito,无需数据库 |
+| ActivityControllerTest | ❌ 16 errors | `@SpringBootTest` 需要 MySQL 连接 |
+| AdminArticleControllerTest | ❌ 15 errors | 同上 |
+| AIChatControllerTest | ❌ 17 errors | 同上 |
+| ArticleAdminControllerTest | ❌ 14 errors | 同上 |
+| ArticleCategoryControllerTest | ❌ 3 errors | 同上 |
+| ArticleControllerTest | ❌ 11 errors | 同上 |
+| AssessmentOrderControllerTest | ❌ 24 errors | 同上 |
+| AuthControllerTest | ❌ 39 errors | 同上 |
 
-**注意**: 所有 API 测试因后端编译失败无法执行。
+> **补充**: `mvn test` 运行了 139 个 `@SpringBootTest` 控制器测试,全部因 `Communications link failure`(无法连接 MySQL 192.168.16.251:3306)失败。这不是代码问题,而是当前测试环境无数据库访问。
 
-### 3.3 E2E 测试
+---
 
-| 文件 | 场景数 | 状态 |
-|------|--------|------|
-| article-management.spec.js | 5 | ✅ 已更新 (需前端环境) |
-| activity-registration.spec.js | 5 | ✅ 已更新 (需前端环境) |
+## 三、测试用例统计
+
+### 3.1 后端单元测试(Java)
+
+| 测试文件 | 方法数 | 编译 | 运行 | 备注 |
+|----------|--------|------|------|------|
+| SupplySystemServiceTest.java | **18** | ✅ | ✅ 18/18 PASS | 纯 Mockito,无 Spring 依赖 |
+| FoodRecommendServiceTest.java | 10 | ✅ | ⚠️ 需 DB | @SpringBootTest |
+| ArticleWorkflowTest.java | 12 | ✅ | ⚠️ 需 DB | @SpringBootTest |
+| ActivityServicePublishTest.java | 6 | ✅ | ⚠️ 需 DB | @SpringBootTest |
+| ProductServiceTest.java | 10+ | ✅ | ⚠️ 需 DB | @SpringBootTest |
+| DimensionScoreServiceTest.java | 15+ | ✅ | ⚠️ 需 DB | @SpringBootTest |
+| GuideApplicationServiceTest.java | - | ✅ | ⚠️ 需 DB | @SpringBootTest |
+
+### 3.2 API 集成测试
+
+需后端服务运行 + 数据库连接,当前环境无法执行。
+
+### 3.3 SupplySystemServiceTest 详情(18 tests)
+
+| 测试方法 | 状态 | 验证内容 |
+|----------|------|---------|
+| listAll_returnsAll | ✅ | 返回所有活跃 system |
+| listAll_empty | ✅ | 空列表 |
+| create_setsTimestamps | ✅ | 创建时设置时间戳 |
+| create_failsWithoutAdminId | ✅ | adminId 为空抛 IllegalArgumentException |
+| update_updatesTimestamp | ✅ | 更新时更新 updatedAt |
+| detail_returnsById | ✅ | 按 ID 查询 |
+| detail_notFound | ✅ | 不存在返回 null |
+| toggleStatus_activeToInactive | ✅ | active → disabled |
+| toggleStatus_inactiveToActive | ✅ | disabled → active |
+| toggleStatus_notFound | ✅ | 不存在返回 false |
+| memberList_returnsBySystemId | ✅ | 按 systemId 查询成员 |
+| memberList_empty | ✅ | 无成员返回空列表 |
+| addMember_success | ✅ | 添加成员,role = "member" |
+| addMember_userNotFound | ✅ | 用户不存在仍成功创建 |
+| removeMember_success | ✅ | 逻辑删除(status→inactive) |
+| removeMember_notFound | ✅ | 不存在返回 false |
+| changeRole_success | ✅ | 修改角色 |
+| changeRole_memberNotFound | ✅ | 不存在返回 false |
 
 ---
 
@@ -115,52 +116,35 @@ mvn compile → BUILD FAILURE (7 errors)
 
 ### 4.1 本次新增功能覆盖率
 
-| 新功能模块 | 单元测试 | API 测试 | E2E 测试 | 覆盖率评级 |
-|-----------|---------|---------|---------|-----------|
-| 供应商分销体系 | 14 tests | 7 tests | - | ✅ 良好 |
-| 食材推荐指数 | 10 tests | 2 tests | - | ✅ 良好 |
-| 文章工作流 | 12 tests | 4 tests | 2 场景 | ✅ 良好 |
-| Migration 36-37 (generation/isSpouse) | 0 tests | 0 tests | - | ❌ 无覆盖 |
-| PaymentService testMode | 0 tests | 0 tests | - | ❌ 无覆盖 |
-| ActivityEdit 富文本 | - | - | 0 | ❌ 无覆盖 |
+| 新功能模块 | 单元测试 | 状态 |
+|-----------|---------|------|
+| 供应商体系(SupplySystem CRUD) | 18 tests | ✅ 全部通过 |
+| 供应商成员管理(memberList/addMember/removeMember/changeRole) | 7 tests | ✅ 全部通过 |
+| 辈分体系 Migration 36-37 | 0 tests | ❌ 无覆盖 |
+| PaymentService testMode | 0 tests | ❌ 无覆盖 |
+| ActivityEdit 富文本 | - | ❌ 无覆盖 |
 
 ### 4.2 测试缺口
 
 | 缺口 | 影响 | 建议 |
 |------|------|------|
-| FamilyMemberService 编译失败 | 阻塞所有测试 | 修复 ISSUE-010 |
-| schema.sql 未同步 | 部署后 DDL 不一致 | 修复 ISSUE-011 |
+| schema.sql 未同步 migration 36-37 | 部署后 DDL 不一致 | 修复 ISSUE-011 |
 | 无 generation/isSpouse 单元测试 | 新字段未验证 | 添加 FamilyMemberServiceTest |
 | 无 PaymentService testMode 测试 | 测试模式未验证 | 添加 PaymentServiceTest |
-| API 测试缺少新迁移验证 | 后端未部署 | 部署后重新执行 |
+| API 测试需远程部署环境 | 无法自动执行 | 部署后执行 |
 
 ---
 
-## 五、建议后续工作
-
-### 阻塞项 (必须先修复)
-
-1. **️ ISSUE-010**: FamilyMemberService.addMember() 未同步新的 AddFamilyMemberDTO
-   - 位置: `FamilyMemberService.java` 第 55, 71, 74, 92 行
-   - 修复: 将 `dto.getRelationshipType()` 改为基于 `relativeMemberId` + `generationLevel` 的辈分计算
-   - 阻塞: 所有 Maven 编译 + 测试
-
-2. **️ ISSUE-007**: SupplySystem API 500 (表不存在)
-   - 确认 supply_system 等表已创建,或执行迁移 33
-
-### 高优先级
-
-3. **ISSUE-006**: AdminArticleController 路由 `/submit-for-review` 未注册
-4. **ISSUE-008**: `/api/admin/foods/list` 500 (SQL 查询)
-5. **ISSUE-009**: `/api/admin/foods/detail` 返回字符串而非 JSON
-
-### 中优先级
+## 五、测试环境说明
 
-6. **ISSUE-011**: schema.sql family_members CREATE TABLE 缺少 generation/is_spouse 列
-7. **ISSUE-012**: FamilyMemberVO 缺少 isSpouse 字段 (仅 entity 有)
-8. 补充 PaymentService testMode 单元测试
-9. 部署前端,执行 E2E 测试
+| 项目 | 当前环境 |
+|------|---------|
+| MySQL 192.168.16.251:3306 | ❌ 不可达(Communications link failure) |
+| 后端服务 localhost:9082 | ❌ 未启动 |
+| 前端 localhost:8082 | ❌ 未启动 |
+| Maven 编译 | ✅ 通过 |
+| 纯 Mockito 测试 | ✅ 可执行 |
 
 ---
 
-*本报告由 Sisyphus 自动生成,基于远程同步 + 代码分析 + mvn compile 验证*
+*本报告由 Sisyphus 自动生成,基于远程同步 + 代码分析 + mvn compile/test-compile + SupplySystemServiceTest(18/18) 验证*