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

fix(review): 活动报名审核Tab接入全局报名列表接口并回显驳回原因

Xiaogang Liao 5 дней назад
Родитель
Сommit
b25c661720

+ 1 - 2
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminActivityRegistrationController.java

@@ -19,8 +19,7 @@ public class AdminActivityRegistrationController {
         }
         Long activityId = ParamUtils.getLong(params.get("activityId"));
         String status = (String) params.get("status");
-        if (activityId == null) return Result.error("活动ID不能为空");
-        return registrationService.getRegistrationsByActivity(activityId, status);
+        return registrationService.listRegistrationsForAdmin(activityId, status);
     }
 
     @PostMapping("/registration/approve")

+ 44 - 2
cfc-backend/src/main/java/com/etotem/cfc/service/ActivityRegistrationService.java

@@ -17,8 +17,10 @@ import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 import com.etotem.cfc.util.SortUtil;
 
@@ -189,8 +191,48 @@ public class ActivityRegistrationService {
         return Result.success(result);
     }
 
-    public Map<Long, String> getRegistrationStatusMap(List<Long> activityIds, Long userId) {
-        Map<Long, String> map = new HashMap<>();
+    /**
+     * 管理端报名列表:activityId 为空时返回全部(可按状态过滤),补充活动标题与驳回原因。
+     */
+    public Result<List<Map<String, Object>>> listRegistrationsForAdmin(Long activityId, String status) {
+        LambdaQueryWrapper<ActivityRegistration> wrapper = new LambdaQueryWrapper<ActivityRegistration>()
+            .eq(activityId != null, ActivityRegistration::getActivityId, activityId)
+            .orderByDesc(ActivityRegistration::getRegisteredAt);
+        if (status != null && !status.isEmpty()) wrapper.eq(ActivityRegistration::getStatus, status);
+        SortUtil.applySort(wrapper);
+        List<ActivityRegistration> list = registrationMapper.selectList(wrapper);
+
+        Set<Long> activityIds = new HashSet<>();
+        for (ActivityRegistration reg : list) {
+            if (reg.getActivityId() != null) activityIds.add(reg.getActivityId());
+        }
+        Map<Long, String> titleMap = new HashMap<>();
+        if (!activityIds.isEmpty()) {
+            List<Activity> activities = activityMapper.selectBatchIds(activityIds);
+            if (activities != null) {
+                for (Activity a : activities) titleMap.put(a.getId(), a.getTitle());
+            }
+        }
+
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (ActivityRegistration reg : list) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("id", reg.getId());
+            item.put("activityId", reg.getActivityId());
+            item.put("activityTitle", reg.getActivityId() != null ? titleMap.get(reg.getActivityId()) : null);
+            item.put("memberId", reg.getChildId());
+            item.put("userId", reg.getUserId());
+            item.put("status", reg.getStatus());
+            item.put("registrantName", reg.getRegistrantName());
+            item.put("registrantPhone", reg.getRegistrantPhone());
+            item.put("rejectReason", reg.getRejectReason());
+            item.put("registeredAt", reg.getRegisteredAt());
+            result.add(item);
+        }
+        return Result.success(result);
+    }
+
+    public Map<Long, String> getRegistrationStatusMap(List<Long> activityIds, Long userId) {        Map<Long, String> map = new HashMap<>();
         if (activityIds == null || activityIds.isEmpty() || userId == null) return map;
         List<ActivityRegistration> regs = registrationMapper.selectList(new LambdaQueryWrapper<ActivityRegistration>()
             .in(ActivityRegistration::getActivityId, activityIds)

+ 100 - 0
cfc-backend/src/test/java/com/etotem/cfc/unit/ActivityRegistrationListTest.java

@@ -0,0 +1,100 @@
+package com.etotem.cfc.unit;
+
+import com.etotem.cfc.common.Result;
+import com.etotem.cfc.entity.Activity;
+import com.etotem.cfc.entity.ActivityRegistration;
+import com.etotem.cfc.mapper.ActivityMapper;
+import com.etotem.cfc.mapper.ActivityRegistrationMapper;
+import com.etotem.cfc.service.ActivityRegistrationService;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+class ActivityRegistrationListTest {
+
+    private ActivityRegistrationService serviceWith(ActivityRegistrationMapper regMapper,
+                                                    ActivityMapper actMapper) throws Exception {
+        ActivityRegistrationService svc = new ActivityRegistrationService();
+        setField(svc, "registrationMapper", regMapper);
+        setField(svc, "activityMapper", actMapper);
+        return svc;
+    }
+
+    private void setField(Object target, String name, Object value) throws Exception {
+        Field f = ActivityRegistrationService.class.getDeclaredField(name);
+        f.setAccessible(true);
+        f.set(target, value);
+    }
+
+    @Test
+    void 全局列表补充活动标题与驳回原因() throws Exception {
+        ActivityRegistrationMapper regMapper = mock(ActivityRegistrationMapper.class);
+        ActivityMapper actMapper = mock(ActivityMapper.class);
+        ActivityRegistrationService svc = serviceWith(regMapper, actMapper);
+
+        ActivityRegistration reg = new ActivityRegistration();
+        reg.setId(1L);
+        reg.setActivityId(5L);
+        reg.setStatus("rejected");
+        reg.setRegistrantName("张三");
+        reg.setRejectReason("名额已满");
+
+        Activity act = new Activity();
+        act.setId(5L);
+        act.setTitle("亲子营");
+
+        when(regMapper.selectList(any())).thenReturn(Arrays.asList(reg));
+        when(actMapper.selectBatchIds(any())).thenReturn(Arrays.asList(act));
+
+        Result<List<Map<String, Object>>> result = svc.listRegistrationsForAdmin(null, "rejected");
+
+        assertEquals(200, result.getCode());
+        assertEquals(1, result.getData().size());
+        Map<String, Object> row = result.getData().get(0);
+        assertEquals(1L, row.get("id"));
+        assertEquals(5L, row.get("activityId"));
+        assertEquals("亲子营", row.get("activityTitle"));
+        assertEquals("名额已满", row.get("rejectReason"));
+        assertEquals("张三", row.get("registrantName"));
+    }
+
+    @Test
+    void 无活动数据时标题降级为空且不报错() throws Exception {
+        ActivityRegistrationMapper regMapper = mock(ActivityRegistrationMapper.class);
+        ActivityMapper actMapper = mock(ActivityMapper.class);
+        ActivityRegistrationService svc = serviceWith(regMapper, actMapper);
+
+        ActivityRegistration reg = new ActivityRegistration();
+        reg.setId(2L);
+        reg.setStatus("pending");
+
+        when(regMapper.selectList(any())).thenReturn(Arrays.asList(reg));
+
+        Result<List<Map<String, Object>>> result = svc.listRegistrationsForAdmin(null, "pending");
+
+        assertEquals(200, result.getCode());
+        assertNull(result.getData().get(0).get("activityTitle"));
+        verify(actMapper, never()).selectBatchIds(any());
+    }
+
+    @Test
+    void 空列表返回空集合() throws Exception {
+        ActivityRegistrationMapper regMapper = mock(ActivityRegistrationMapper.class);
+        ActivityMapper actMapper = mock(ActivityMapper.class);
+        ActivityRegistrationService svc = serviceWith(regMapper, actMapper);
+
+        when(regMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
+
+        Result<List<Map<String, Object>>> result = svc.listRegistrationsForAdmin(5L, null);
+
+        assertEquals(200, result.getCode());
+        assertTrue(result.getData().isEmpty());
+    }
+}

+ 4 - 17
cfc-web/src/views/admin/review/ActivityRegistrationAudit.vue

@@ -61,8 +61,7 @@
 
 <script>
 import SortMixin from '@/mixins/SortMixin'
-import { getActivityList } from '@/api/activity'
-import { approveRegistration, rejectRegistration } from '@/api/activity'
+import { approveRegistration, rejectRegistration, getRegistrationList } from '@/api/activity'
 import AuditDetailDrawer from './components/AuditDetailDrawer.vue'
 
 export default {
@@ -89,22 +88,10 @@ export default {
     async loadData() {
       this.loading = true
       try {
-        const params = { withRegistrations: true, page: 1, size: 50 }
+        const params = { status: this.statusFilter || undefined, page: 1, size: 500 }
         if (this.sortState.length > 0) params.sort = this.sortState
-        const res = await getActivityList(params)
-        var regs = []
-        var activities = res.data && res.data.records || res.data && res.data.list || res.data || []
-        for (var i = 0; i < activities.length; i++) {
-          var a = activities[i]
-          if (a.registrations) {
-            for (var j = 0; j < a.registrations.length; j++) {
-              var r = a.registrations[j]
-              r.activityTitle = a.title
-              regs.push(r)
-            }
-          }
-        }
-        this.list = this.statusFilter ? regs.filter(function(r) { return r.status === this.statusFilter }.bind(this)) : regs
+        const res = await getRegistrationList(params)
+        this.list = (res && res.data) || []
       } catch (e) { this.$message.error('加载失败')
       } finally { this.loading = false }
     },