Explorar el Código

测试文件调整

liuchengsen hace 1 mes
padre
commit
c6e03bf3a4

+ 235 - 8
zhijiayun-gateway/src/test/java/com/xuekairui/gateway/AdminLicenseTest.java

@@ -101,10 +101,197 @@ class AdminLicenseTest extends GatewayBaseTest {
                 .andExpect(status().isUnauthorized());
     }
 
-    // ==================== 审核操作 ====================
+    // ==================== 管理员新增 ====================
+
+    @Test
+    @Order(7)
+    @DisplayName("POST /api/admin/license - 管理员新增入驻信息(创建后状态为PENDING)")
+    void createByAdmin_shouldSucceedAndReturnPending() throws Exception {
+        String body = """
+                {
+                    "userId": 3,
+                    "storeName": "管理员新增药房",
+                    "terminalType": "SINGLE",
+                    "province": "广东省",
+                    "city": "深圳市",
+                    "district": "福田区",
+                    "storeAddress": "福华路100号",
+                    "contactPerson": "赵六",
+                    "contactPhone": "13900139003",
+                    "businessLicenseUrl": "https://oss.example.com/license/admin-create.jpg",
+                    "drugLicenseUrl": "https://oss.example.com/drug/admin-create.jpg",
+                    "creditCode": "91110000MA11111111",
+                    "medicalDeviceClass3Url": "https://oss.example.com/device/class3.jpg"
+                }
+                """;
+        mockMvc.perform(post("/api/admin/license")
+                        .header("Authorization", "Bearer " + adminToken())
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(body))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200));
+
+        // 验证创建后状态为 PENDING(待审核确认)
+        mockMvc.perform(get("/api/admin/license/review?reviewStatus=PENDING")
+                        .header("Authorization", "Bearer " + adminToken()))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200))
+                .andExpect(jsonPath("$.data").isArray());
+    }
+
+    @Test
+    @Order(8)
+    @DisplayName("POST /api/admin/license - 缺少必填字段应返回400(缺少店铺名称)")
+    void createByAdmin_missingStoreName_shouldReturn400() throws Exception {
+        String body = """
+                {
+                    "userId": 4,
+                    "terminalType": "SINGLE",
+                    "province": "广东省",
+                    "city": "深圳市",
+                    "district": "福田区",
+                    "storeAddress": "福华路100号",
+                    "contactPerson": "赵六",
+                    "contactPhone": "13900139004",
+                    "businessLicenseUrl": "https://oss.example.com/license/missing.jpg",
+                    "drugLicenseUrl": "https://oss.example.com/drug/missing.jpg"
+                }
+                """;
+        mockMvc.perform(post("/api/admin/license")
+                        .header("Authorization", "Bearer " + adminToken())
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(body))
+                .andExpect(status().isBadRequest());
+    }
+
+    @Test
+    @Order(9)
+    @DisplayName("POST /api/admin/license - 缺少userId应返回400")
+    void createByAdmin_missingUserId_shouldReturn400() throws Exception {
+        String body = """
+                {
+                    "storeName": "无客户药房",
+                    "terminalType": "SINGLE",
+                    "province": "广东省",
+                    "city": "深圳市",
+                    "district": "福田区",
+                    "storeAddress": "福华路100号",
+                    "contactPerson": "赵六",
+                    "contactPhone": "13900139005",
+                    "businessLicenseUrl": "https://oss.example.com/license/no-user.jpg",
+                    "drugLicenseUrl": "https://oss.example.com/drug/no-user.jpg"
+                }
+                """;
+        mockMvc.perform(post("/api/admin/license")
+                        .header("Authorization", "Bearer " + adminToken())
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(body))
+                .andExpect(status().isBadRequest());
+    }
 
     @Test
     @Order(10)
+    @DisplayName("POST /api/admin/license - 无Token应返回401")
+    void createByAdmin_withoutToken_shouldReturn401() throws Exception {
+        mockMvc.perform(post("/api/admin/license")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content("{\"userId\":5,\"storeName\":\"test\"}"))
+                .andExpect(status().isUnauthorized());
+    }
+
+    // ==================== 管理员编辑 ====================
+
+    @Test
+    @Order(20)
+    @DisplayName("PUT /api/admin/license/{licenseId} - 管理员编辑入驻信息")
+    void editByAdmin_shouldSucceed() throws Exception {
+        String body = """
+                {
+                    "storeName": "编辑后药房名称",
+                    "terminalType": "CHAIN",
+                    "province": "北京市",
+                    "city": "北京市",
+                    "district": "海淀区",
+                    "storeAddress": "中关村大街1号",
+                    "contactPerson": "李四更新",
+                    "contactPhone": "13900139001",
+                    "businessLicenseUrl": "https://oss.example.com/license/edited.jpg",
+                    "drugLicenseUrl": "https://oss.example.com/drug/edited.jpg",
+                    "creditCode": "91110000MA12345678"
+                }
+                """;
+        mockMvc.perform(put("/api/admin/license/1")
+                        .header("Authorization", "Bearer " + adminToken())
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(body))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200));
+    }
+
+    @Test
+    @Order(21)
+    @DisplayName("PUT /api/admin/license/{licenseId} - 缺少必填字段应返回400(缺少营业执照)")
+    void editByAdmin_missingBusinessLicense_shouldReturn400() throws Exception {
+        String body = """
+                {
+                    "storeName": "编辑测试药房",
+                    "terminalType": "SINGLE",
+                    "province": "广东省",
+                    "city": "深圳市",
+                    "district": "南山区",
+                    "storeAddress": "科技园路1号",
+                    "contactPerson": "李四",
+                    "contactPhone": "13900139001",
+                    "drugLicenseUrl": "https://oss.example.com/drug/edited.jpg"
+                }
+                """;
+        mockMvc.perform(put("/api/admin/license/1")
+                        .header("Authorization", "Bearer " + adminToken())
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(body))
+                .andExpect(status().isBadRequest());
+    }
+
+    @Test
+    @Order(22)
+    @DisplayName("PUT /api/admin/license/{licenseId} - 不存在的licenseId应返回404")
+    void editByAdmin_nonExistent_shouldReturn404() throws Exception {
+        String body = """
+                {
+                    "storeName": "不存在的药房",
+                    "terminalType": "SINGLE",
+                    "province": "广东省",
+                    "city": "深圳市",
+                    "district": "南山区",
+                    "storeAddress": "科技园路1号",
+                    "contactPerson": "李四",
+                    "contactPhone": "13900139001",
+                    "businessLicenseUrl": "https://oss.example.com/license/not-found.jpg",
+                    "drugLicenseUrl": "https://oss.example.com/drug/not-found.jpg"
+                }
+                """;
+        mockMvc.perform(put("/api/admin/license/9999")
+                        .header("Authorization", "Bearer " + adminToken())
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(body))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(404));
+    }
+
+    @Test
+    @Order(23)
+    @DisplayName("PUT /api/admin/license/{licenseId} - 无Token应返回401")
+    void editByAdmin_withoutToken_shouldReturn401() throws Exception {
+        mockMvc.perform(put("/api/admin/license/1")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content("{\"storeName\":\"test\"}"))
+                .andExpect(status().isUnauthorized());
+    }
+
+    // ==================== 审核操作 ====================
+
+    @Test
+    @Order(30)
     @DisplayName("POST /api/admin/license/review - 审核通过")
     void reviewLicense_approve_shouldSucceed() throws Exception {
         String body = """
@@ -122,7 +309,7 @@ class AdminLicenseTest extends GatewayBaseTest {
     }
 
     @Test
-    @Order(11)
+    @Order(31)
     @DisplayName("POST /api/admin/license/review - 重复审核应返回错误")
     void reviewLicense_duplicate_shouldReturnError() throws Exception {
         String body = """
@@ -140,7 +327,7 @@ class AdminLicenseTest extends GatewayBaseTest {
     }
 
     @Test
-    @Order(12)
+    @Order(32)
     @DisplayName("POST /api/admin/license/review - 不存在的licenseId应返回404")
     void reviewLicense_nonExistent_shouldReturn404() throws Exception {
         String body = """
@@ -158,7 +345,7 @@ class AdminLicenseTest extends GatewayBaseTest {
     }
 
     @Test
-    @Order(13)
+    @Order(33)
     @DisplayName("POST /api/admin/license/review - 参数缺失应返回400(缺少action)")
     void reviewLicense_missingAction_shouldReturn400() throws Exception {
         String body = """
@@ -174,7 +361,7 @@ class AdminLicenseTest extends GatewayBaseTest {
     }
 
     @Test
-    @Order(14)
+    @Order(34)
     @DisplayName("POST /api/admin/license/review - 参数缺失应返回400(缺少licenseId)")
     void reviewLicense_missingLicenseId_shouldReturn400() throws Exception {
         String body = """
@@ -190,7 +377,7 @@ class AdminLicenseTest extends GatewayBaseTest {
     }
 
     @Test
-    @Order(15)
+    @Order(35)
     @DisplayName("POST /api/admin/license/review - 无效审核动作应返回400")
     void reviewLicense_invalidAction_shouldReturn400() throws Exception {
         String body = """
@@ -208,7 +395,7 @@ class AdminLicenseTest extends GatewayBaseTest {
     }
 
     @Test
-    @Order(16)
+    @Order(36)
     @DisplayName("POST /api/admin/license/review - 拒绝并填写原因")
     void reviewLicense_rejectWithReason_shouldSucceed() throws Exception {
         // 需要一条新的PENDING记录来测试拒绝
@@ -251,7 +438,47 @@ class AdminLicenseTest extends GatewayBaseTest {
     }
 
     @Test
-    @Order(17)
+    @Order(37)
+    @DisplayName("POST /api/admin/license/review - 驳回原因必填,缺失应返回400")
+    void reviewLicense_rejectWithoutReason_shouldReturn400() throws Exception {
+        // 先创建一条新的PENDING记录用于测试驳回原因必填
+        String uploadBody = """
+                {
+                    "storeName": "驳回原因测试药房",
+                    "terminalType": "CLINIC",
+                    "province": "上海市",
+                    "city": "上海市",
+                    "district": "浦东新区",
+                    "storeAddress": "张江路66号",
+                    "contactPerson": "钱七",
+                    "contactPhone": "13900139006",
+                    "businessLicenseUrl": "https://oss.example.com/license/reject-reason.jpg",
+                    "drugLicenseUrl": "https://oss.example.com/drug/reject-reason.jpg"
+                }
+                """;
+        mockMvc.perform(post("/api/business-license/upload")
+                        .header("Authorization", "Bearer " + generateAccessToken(5L, "13900139006"))
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(uploadBody))
+                .andExpect(status().isOk());
+
+        // 驳回但不填原因,应返回400
+        String rejectBody = """
+                {
+                    "licenseId": 3,
+                    "action": "REJECTED"
+                }
+                """;
+        mockMvc.perform(post("/api/admin/license/review")
+                        .header("Authorization", "Bearer " + adminToken())
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(rejectBody))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(400));
+    }
+
+    @Test
+    @Order(38)
     @DisplayName("POST /api/admin/license/review - 无Token应返回401")
     void reviewLicense_withoutToken_shouldReturn401() throws Exception {
         mockMvc.perform(post("/api/admin/license/review")

+ 56 - 4
zhijiayun-gateway/src/test/java/com/xuekairui/gateway/OperationAuditLogTest.java

@@ -1,10 +1,14 @@
 package com.xuekairui.gateway;
 
-import org.junit.jupiter.api.*;
-import org.springframework.http.MediaType;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
 
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 /**
  * 操作审计日志接口测试
@@ -130,6 +134,54 @@ class OperationAuditLogTest extends GatewayBaseTest {
 
     @Test
     @Order(10)
+    @DisplayName("GET /api/admin/audit-log?operationSource=ADMIN_CREATE - 按操作来源筛选(管理员新增)")
+    void queryLogs_filterByOperationSource_adminCreate_shouldFilter() throws Exception {
+        mockMvc.perform(get("/api/admin/audit-log?operationSource=ADMIN_CREATE")
+                        .header("Authorization", "Bearer " + adminToken()))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200))
+                .andExpect(jsonPath("$.data.records").isArray());
+    }
+
+    @Test
+    @Order(11)
+    @DisplayName("GET /api/admin/audit-log?operationSource=USER_SUBMIT - 按操作来源筛选(用户自主提交)")
+    void queryLogs_filterByOperationSource_userSubmit_shouldFilter() throws Exception {
+        mockMvc.perform(get("/api/admin/audit-log?operationSource=USER_SUBMIT")
+                        .header("Authorization", "Bearer " + adminToken()))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200))
+                .andExpect(jsonPath("$.data.records").isArray());
+    }
+
+    @Test
+    @Order(12)
+    @DisplayName("GET /api/admin/audit-log?operationSource=EXTERNAL - 按操作来源筛选(外部系统)")
+    void queryLogs_filterByOperationSource_external_shouldFilter() throws Exception {
+        mockMvc.perform(get("/api/admin/audit-log?operationSource=EXTERNAL")
+                        .header("Authorization", "Bearer " + adminToken()))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200))
+                .andExpect(jsonPath("$.data.records").isArray());
+    }
+
+    @Test
+    @Order(13)
+    @DisplayName("GET /api/admin/audit-log - 操作来源与其他条件组合筛选")
+    void queryLogs_operationSourceCombinedWithModule_shouldWork() throws Exception {
+        mockMvc.perform(get("/api/admin/audit-log")
+                        .param("operationSource", "ADMIN_CREATE")
+                        .param("module", "LICENSE")
+                        .param("page", "1")
+                        .param("size", "10")
+                        .header("Authorization", "Bearer " + adminToken()))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200))
+                .andExpect(jsonPath("$.data.records").isArray());
+    }
+
+    @Test
+    @Order(14)
     @DisplayName("GET /api/admin/audit-log - 无Token应返回401")
     void queryLogs_withoutToken_shouldReturn401() throws Exception {
         mockMvc.perform(get("/api/admin/audit-log"))

+ 39 - 3
zhijiayun-test/src/main/resources/static/activity-test.html

@@ -203,6 +203,7 @@
         <div class="module-tab" data-module="admin-activity-lottery">4.比价抽奖管理</div>
         <div class="module-tab" data-module="admin-license">5.入驻信息审核</div>
         <div class="module-tab" data-module="admin-system-config">6.系统配置管理</div>
+        <div class="module-tab" data-module="admin-audit-log">7.操作审计日志</div>
     </div>
 
     <div id="panels"></div>
@@ -221,7 +222,7 @@ const SMS_CODE = () => document.getElementById('smsCode')?.value || '123456';
 let stats = { pass: 0, fail: 0, pending: 0, total: 0 };
 
 const USER_MODULES = ['checkin', 'activity-invite', 'activity-lottery', 'business-license', 'activity-available', 'activity-rewards-tab', 'search-record', 'external-login'];
-const ADMIN_MODULES = ['admin-checkin', 'admin-activity-invite', 'admin-activity-checkin', 'admin-activity-lottery', 'admin-license', 'admin-system-config'];
+const ADMIN_MODULES = ['admin-checkin', 'admin-activity-invite', 'admin-activity-checkin', 'admin-activity-lottery', 'admin-license', 'admin-system-config', 'admin-audit-log'];
 
 // ===================== 大整数安全JSON解析 =====================
 function safeJsonParse(text) {
@@ -449,6 +450,7 @@ function renderModule(module) {
         case 'admin-activity-lottery': html = renderAdminActivityLotteryModule(); break;
         case 'admin-license': html = renderAdminLicenseModule(); break;
         case 'admin-system-config': html = renderAdminSystemConfigModule(); break;
+        case 'admin-audit-log': html = renderAdminAuditLogModule(); break;
     }
     panels.innerHTML = html;
     panels.querySelectorAll('input[data-raw]').forEach(input => {
@@ -1348,6 +1350,40 @@ function renderAdminLicenseModule() {
     ${testSection('admin-license-list', '待审核列表', 'GET', 'get', '/api/admin/license/review?reviewStatus=PENDING', '需认证', 'auth-required',
         [{label:'审核状态(reviewStatus,可选)', name:'reviewStatus', placeholder:'PENDING/APPROVED/REJECTED', default:'PENDING'}],
         true, null, '查询入驻信息审核列表。status: PENDING-待审核, APPROVED-已通过, REJECTED-已拒绝')}
+    ${testSection('admin-license-create', '管理员新增入驻信息', 'POST', 'post', '/api/admin/license', '需认证', 'auth-required',
+        [
+         {label:'客户用户ID(userId) *', name:'userId', placeholder:'3', default:'3'},
+         {label:'店铺名称(storeName) *', name:'storeName', placeholder:'管理员新增药房', default:'管理员新增药房'},
+         {label:'终端类型(terminalType) *', name:'terminalType', placeholder:'SINGLE/CHAIN/CLINIC/COMMUNITY_HEALTH', default:'SINGLE'},
+         {label:'所在省(province) *', name:'province', placeholder:'广东省', default:'广东省'},
+         {label:'所在市(city) *', name:'city', placeholder:'深圳市', default:'深圳市'},
+         {label:'所在区(district) *', name:'district', placeholder:'福田区', default:'福田区'},
+         {label:'店铺地址(storeAddress) *', name:'storeAddress', placeholder:'福华路100号', default:'福华路100号'},
+         {label:'联系人姓名(contactPerson) *', name:'contactPerson', placeholder:'赵六', default:'赵六'},
+         {label:'联系电话(contactPhone) *', name:'contactPhone', placeholder:'13900139003', default:'13900139003'},
+         {label:'营业执照URL(businessLicenseUrl) *', name:'businessLicenseUrl', placeholder:'https://oss.../license.jpg', default:'https://oss.example.com/license/admin-create.jpg'},
+         {label:'药品经营许可证URL(drugLicenseUrl) *', name:'drugLicenseUrl', placeholder:'https://oss.../drug.jpg', default:'https://oss.example.com/drug/admin-create.jpg'},
+         {label:'统一社会信用代码(creditCode)', name:'creditCode', placeholder:'91110000MA12345678', default:''},
+         {label:'二类医疗器械URL(medicalDeviceClass2Url)', name:'medicalDeviceClass2Url', placeholder:'https://oss.../class2.jpg', default:''},
+         {label:'三类医疗器械URL(medicalDeviceClass3Url)', name:'medicalDeviceClass3Url', placeholder:'https://oss.../class3.jpg', default:''}
+        ], true, null, '管理员代客户填写入驻信息。创建后状态为PENDING(待审核),需再操作一次审核确认才转为APPROVED。必须选择未提交过入驻信息的客户,必填基础信息+营业执照+药品经营许可,二类/三类医疗器械至少上传一个')}
+    ${testSection('admin-license-edit', '管理员编辑入驻信息', 'PUT', 'put', '/api/admin/license/{licenseId}', '需认证', 'auth-required',
+        [
+         {label:'资质ID(licenseId) *', name:'licenseId', placeholder:'1', default:'1'},
+         {label:'店铺名称(storeName) *', name:'storeName', placeholder:'编辑后药房名称', default:'编辑后药房名称'},
+         {label:'终端类型(terminalType) *', name:'terminalType', placeholder:'SINGLE/CHAIN/CLINIC/COMMUNITY_HEALTH', default:'CHAIN'},
+         {label:'所在省(province) *', name:'province', placeholder:'北京市', default:'北京市'},
+         {label:'所在市(city) *', name:'city', placeholder:'北京市', default:'北京市'},
+         {label:'所在区(district) *', name:'district', placeholder:'海淀区', default:'海淀区'},
+         {label:'店铺地址(storeAddress) *', name:'storeAddress', placeholder:'中关村大街1号', default:'中关村大街1号'},
+         {label:'联系人姓名(contactPerson) *', name:'contactPerson', placeholder:'李四更新', default:'李四更新'},
+         {label:'联系电话(contactPhone) *', name:'contactPhone', placeholder:'13900139001', default:'13900139001'},
+         {label:'营业执照URL(businessLicenseUrl) *', name:'businessLicenseUrl', placeholder:'https://oss.../license.jpg', default:'https://oss.example.com/license/edited.jpg'},
+         {label:'药品经营许可证URL(drugLicenseUrl) *', name:'drugLicenseUrl', placeholder:'https://oss.../drug.jpg', default:'https://oss.example.com/drug/edited.jpg'},
+         {label:'统一社会信用代码(creditCode)', name:'creditCode', placeholder:'91110000MA12345678', default:'91110000MA12345678'},
+         {label:'二类医疗器械URL(medicalDeviceClass2Url)', name:'medicalDeviceClass2Url', placeholder:'https://oss.../class2.jpg', default:''},
+         {label:'三类医疗器械URL(medicalDeviceClass3Url)', name:'medicalDeviceClass3Url', placeholder:'https://oss.../class3.jpg', default:''}
+        ], true, null, '管理员编辑入驻信息(可修改客户信息、替换资质图片,保存后即时生效)。可编辑全部入驻数据(含已审核),必填项约束同样生效。编辑不含userId,客户绑定关系不可更改')}
     ${testSection('admin-license-approve', '审核通过', 'POST', 'post', '/api/admin/license/review', '需认证', 'auth-required',
         [
          {label:'资质ID(licenseId) *', name:'licenseId', placeholder:'1', default:'1'},
@@ -1357,8 +1393,8 @@ function renderAdminLicenseModule() {
         [
          {label:'资质ID(licenseId) *', name:'licenseId', placeholder:'1', default:'1'},
          {label:'审核动作(action)', name:'action', placeholder:'REJECTED', default:'REJECTED'},
-         {label:'拒绝原因(rejectReason)', name:'rejectReason', placeholder:'图片不清晰', default:''}
-        ], true, null, '拒绝入驻信息申请,需填写拒绝原因供申请人查看')}`;
+         {label:'拒绝原因(rejectReason) *', name:'rejectReason', placeholder:'图片不清晰,请重新上传', default:'资质图片不清晰,请重新上传'}
+        ], true, null, '拒绝入驻信息申请,驳回原因必填。只能对PENDING(新提交/未审核通过)的记录驳回,APPROVED不允许驳回。驳回后客户端移除展示,用户可重新上传提交')}`;
 };
 
 // ==================== 运营端:系统配置管理模块 ====================