Parcourir la source

抽奖活动,邀请有礼活动,签到活动这几种更新

liuchengsen il y a 1 mois
Parent
commit
12d5aaecd1

+ 16 - 1
zhijiayun-activity/src/main/java/com/xuekairui/activity/controller/ActivityController.java

@@ -4,6 +4,7 @@ import com.xuekairui.activity.dto.ActivityCheckinCycleStatusResponse;
 import com.xuekairui.activity.dto.ActivityInviteStatusResponse;
 import com.xuekairui.activity.dto.ActivityLotteryResultResponse;
 import com.xuekairui.activity.dto.ActivityLotteryStatusResponse;
+import com.xuekairui.activity.entity.ActivityCheckinCycleRecord;
 import com.xuekairui.activity.entity.ActivityLotteryPrize;
 import com.xuekairui.activity.entity.ActivityLotteryRecord;
 import com.xuekairui.activity.service.ActivityCheckinCycleService;
@@ -12,7 +13,11 @@ import com.xuekairui.activity.service.ActivityLotteryService;
 import com.xuekairui.common.Result;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
 
@@ -54,6 +59,16 @@ public class ActivityController {
         return Result.success(activityCheckinCycleService.getStatus(userId));
     }
 
+    /**
+     * 我的签到周期奖励记录
+     * GET /api/activity/checkin-cycle/rewards
+     */
+    @GetMapping("/checkin-cycle/rewards")
+    public Result<List<ActivityCheckinCycleRecord>> checkinCycleRewards(HttpServletRequest request) {
+        Long userId = (Long) request.getAttribute("userId");
+        return Result.success(activityCheckinCycleService.listMyCycleRewards(userId));
+    }
+
     // ========== 比价抽奖 ==========
 
     /**

+ 16 - 0
zhijiayun-activity/src/main/java/com/xuekairui/activity/controller/AdminActivityController.java

@@ -8,6 +8,7 @@ import com.xuekairui.activity.entity.ActivityCheckinCycleConfig;
 import com.xuekairui.activity.entity.ActivityInviteConfig;
 import com.xuekairui.activity.entity.ActivityLotteryConfig;
 import com.xuekairui.activity.entity.ActivityLotteryPrize;
+import com.xuekairui.activity.entity.ActivityLotteryRecord;
 import com.xuekairui.activity.service.ActivityCheckinCycleService;
 import com.xuekairui.activity.service.ActivityInviteService;
 import com.xuekairui.activity.service.ActivityLotteryService;
@@ -25,6 +26,7 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
@@ -105,6 +107,20 @@ public class AdminActivityController {
         return Result.success(null);
     }
 
+    // ========== 抽奖中奖记录(运营端) ==========
+
+    /**
+     * 分页查询所有用户抽奖记录
+     * GET /api/admin/activity/lottery/records?page=1&size=20&userId=1
+     */
+    @GetMapping("/lottery/records")
+    public Result<com.baomidou.mybatisplus.extension.plugins.pagination.Page<ActivityLotteryRecord>> listLotteryRecords(
+            @RequestParam(defaultValue = "1") int page,
+            @RequestParam(defaultValue = "20") int size,
+            @RequestParam(required = false) Long userId) {
+        return Result.success(activityLotteryService.listAllRecords(userId, page, size));
+    }
+
     // ========== 反作弊:撤销邀请奖励 ==========
 
     @PostMapping("/invite/revoke")

+ 13 - 0
zhijiayun-activity/src/main/java/com/xuekairui/activity/service/ActivityCheckinCycleService.java

@@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * 签到送高级会员活动服务(周期制)。
@@ -207,6 +208,18 @@ public class ActivityCheckinCycleService {
                 .build();
     }
 
+    /**
+     * 用户端:查询我的签到周期奖励记录
+     * 返回已发放的周期奖励列表,按发放时间倒序
+     */
+    public List<ActivityCheckinCycleRecord> listMyCycleRewards(Long userId) {
+        return cycleRecordMapper.selectList(
+                new LambdaQueryWrapper<ActivityCheckinCycleRecord>()
+                        .eq(ActivityCheckinCycleRecord::getUserId, userId)
+                        .eq(ActivityCheckinCycleRecord::getRewardGranted, 1)
+                        .orderByDesc(ActivityCheckinCycleRecord::getGrantTime));
+    }
+
     // ==========================================
     // 私有辅助
     // ==========================================

+ 15 - 0
zhijiayun-activity/src/main/java/com/xuekairui/activity/service/ActivityLotteryService.java

@@ -253,6 +253,21 @@ public class ActivityLotteryService {
         return recordMapper.selectList(wrapper);
     }
 
+    /**
+     * 运营端:分页查询所有用户抽奖记录(支持按用户ID筛选)
+     */
+    public com.baomidou.mybatisplus.extension.plugins.pagination.Page<ActivityLotteryRecord> listAllRecords(
+            Long userId, int pageNum, int pageSize) {
+        com.baomidou.mybatisplus.extension.plugins.pagination.Page<ActivityLotteryRecord> page =
+                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<ActivityLotteryRecord> wrapper = new LambdaQueryWrapper<ActivityLotteryRecord>();
+        if (userId != null) {
+            wrapper.eq(ActivityLotteryRecord::getUserId, userId);
+        }
+        wrapper.orderByDesc(ActivityLotteryRecord::getCreateTime);
+        return recordMapper.selectPage(page, wrapper);
+    }
+
     // ==========================================
     // 奖品管理(运营端)
     // ==========================================

+ 85 - 4
zhijiayun-test/src/main/resources/static/activity-test.html

@@ -559,6 +559,18 @@ const FIELD_DESC = {
         ['data.maxInviterReward', 'Integer', '邀请人最多奖励次数'],
         ['data.remainingCount', 'Long', '剩余可获奖励次数']
     ],
+    'activityInviteRewards': [
+        ['data[].inviterId', 'Long', '邀请人ID'],
+        ['data[].inviterNickname', 'String', '邀请人昵称'],
+        ['data[].inviteeId', 'Long', '被邀请人ID'],
+        ['data[].inviteeNickname', 'String', '被邀请人昵称'],
+        ['data[].inviteePhone', 'String', '被邀请人手机号(脱敏)'],
+        ['data[].inviteeMembershipLevel', 'String', '被邀请人会员等级'],
+        ['data[].registered', 'Integer', '是否已注册(0仅点击/1已注册)'],
+        ['data[].registeredText', 'String', '注册状态文本'],
+        ['data[].rewardCount', 'Integer', '奖励会员月数'],
+        ['data[].inviteTime', 'String', '邀请时间']
+    ],
     'activityCheckinStatus': [
         ['data.enabled', 'Boolean', '活动是否启用'],
         ['data.inWindow', 'Boolean', '是否在活动时间窗内'],
@@ -572,6 +584,15 @@ const FIELD_DESC = {
         ['data.maxRewardCount', 'Integer', '最多可领取奖励次数'],
         ['data.remainingCount', 'Long', '剩余可领取奖励次数']
     ],
+    'activityCheckinCycleRewards': [
+        ['data[].id', 'Long', '记录ID'],
+        ['data[].cycleStart', 'Date', '周期起始日'],
+        ['data[].cycleEnd', 'Date', '周期截止日'],
+        ['data[].checkinCount', 'Integer', '周期内签到天数'],
+        ['data[].rewardGranted', 'Integer', '是否已发放(1=已发)'],
+        ['data[].grantTime', 'DateTime', '奖励发放时间'],
+        ['data[].createTime', 'DateTime', '创建时间']
+    ],
     'activityLotteryStatus': [
         ['data.enabled', 'Boolean', '活动是否启用'],
         ['data.inWindow', 'Boolean', '是否在活动时间窗内'],
@@ -600,6 +621,16 @@ const FIELD_DESC = {
         ['data.win', 'Boolean', '是否中奖(EMPTY=未中奖)'],
         ['data.createTime', 'DateTime', '抽奖时间']
     ],
+    'activityLotteryRecords': [
+        ['data[].id', 'Long', '抽奖记录ID'],
+        ['data[].prizeName', 'String', '奖品名称'],
+        ['data[].rewardType', 'String', '奖励类型(MEMBERSHIP/CRAWLER/EMPTY)'],
+        ['data[].rewardAmount', 'Integer', '奖励数量'],
+        ['data[].rewardDays', 'Integer', '会员奖励天数'],
+        ['data[].rewardLevel', 'String', '会员奖励等级'],
+        ['data[].chanceId', 'Long', '抽奖机会ID'],
+        ['data[].createTime', 'DateTime', '抽奖时间']
+    ],
     'adminActivityInviteConfig': [
         ['data.id', 'Long', '配置ID(固定1)'],
         ['data.enabled', 'Integer', '是否启用:0-停用 1-启用'],
@@ -651,6 +682,33 @@ const FIELD_DESC = {
         ['data.probabilityWeight', 'Integer', '中奖概率权重(越大越容易中)'],
         ['data.enabled', 'Integer', '是否启用:0-停用 1-启用'],
         ['data.sort', 'Integer', '排序(数字越小越靠前)']
+    ],
+    'adminLotteryRecord': [
+        ['data.records[].id', 'Long', '抽奖记录ID'],
+        ['data.records[].userId', 'Long', '用户ID'],
+        ['data.records[].prizeName', 'String', '奖品名称'],
+        ['data.records[].rewardType', 'String', '奖励类型'],
+        ['data.records[].rewardAmount', 'Integer', '奖励数量'],
+        ['data.records[].rewardDays', 'Integer', '会员奖励天数'],
+        ['data.records[].rewardLevel', 'String', '会员奖励等级'],
+        ['data.records[].win', 'Boolean', '是否中奖(EMPTY=未中奖)'],
+        ['data.records[].createTime', 'DateTime', '抽奖时间'],
+        ['data.total', 'Long', '总记录数'],
+        ['data.current', 'Long', '当前页'],
+        ['data.size', 'Long', '每页条数'],
+        ['data.pages', 'Long', '总页数']
+    ],
+    'businessLicenseInfo': [
+        ['data.id', 'Long', '执照ID(null=未上传)'],
+        ['data.userId', 'Long', '用户ID'],
+        ['data.licenseImageUrl', 'String', '执照图片URL'],
+        ['data.creditCode', 'String', '统一社会信用代码'],
+        ['data.pharmacyName', 'String', '药店名称'],
+        ['data.legalPerson', 'String', '法定代表人'],
+        ['data.reviewStatus', 'String', '审核状态:PENDING/APPROVED/REJECTED'],
+        ['data.showVerifiedBadge', 'Boolean', '是否显示认证标识'],
+        ['data.reviewRemark', 'String', '审核备注'],
+        ['data.createTime', 'DateTime', '创建时间']
     ]
 };
 
@@ -792,7 +850,8 @@ function renderActivityInviteModule() {
     <div class="batch-buttons">
         <button class="btn btn-warning btn-sm" onclick="runActivityInviteTests()">运行全部邀请有礼测试</button>
     </div>
-    ${testSection('activity-invite-status', '邀请有礼活动状态', 'GET', 'get', '/api/activity/invite/status', '需认证', 'auth-required', null, true, 'activityInviteStatus', '查询当前邀请有礼活动状态:是否开启、奖励模式、已获/剩余次数')}`;
+    ${testSection('activity-invite-status', '邀请有礼活动状态', 'GET', 'get', '/api/activity/invite/status', '需认证', 'auth-required', null, true, 'activityInviteStatus', '查询当前邀请有礼活动状态:是否开启、奖励模式、已获/剩余次数')}
+    ${testSection('activity-invite-rewards', '我的邀请奖励记录', 'GET', 'get', '/api/invite/rewards', '需认证', 'auth-required', null, true, 'activityInviteRewards', '获取邀请奖励记录列表,包含被邀请人信息、注册状态、奖励月数')}`;
 }
 
 // ==================== 用户端:签到送会员模块(旧版独立接口,周期信息已整合到签到状态接口) ====================
@@ -801,7 +860,8 @@ function renderActivityCheckinModule() {
     <div class="batch-buttons">
         <button class="btn btn-warning btn-sm" onclick="runActivityCheckinTests()">运行全部签到送会员测试</button>
     </div>
-    ${testSection('activity-checkin-status', '签到送会员周期状态(旧版)', 'GET', 'get', '/api/activity/checkin-cycle/status', '需认证', 'auth-required', null, true, 'activityCheckinStatus', '【旧版】查询当前周期签到进度。新版签到状态已整合周期信息到 /api/checkin/status')}`;
+    ${testSection('activity-checkin-status', '签到送会员周期状态(旧版)', 'GET', 'get', '/api/activity/checkin-cycle/status', '需认证', 'auth-required', null, true, 'activityCheckinStatus', '【旧版】查询当前周期签到进度。新版签到状态已整合周期信息到 /api/checkin/status')}
+    ${testSection('activity-checkin-rewards', '我的签到周期奖励记录', 'GET', 'get', '/api/activity/checkin-cycle/rewards', '需认证', 'auth-required', null, true, 'activityCheckinCycleRewards', '获取签到周期达标奖励记录:每个周期的签到天数、是否已发放、发放时间')}`;
 }
 
 // ==================== 用户端:比价抽奖模块 ====================
@@ -814,7 +874,15 @@ function renderActivityLotteryModule() {
     ${testSection('activity-lottery-status', '比价抽奖活动状态', 'GET', 'get', '/api/activity/lottery/status', '需认证', 'auth-required', null, true, 'activityLotteryStatus', '查询抽奖活动状态:是否开启、是否满足资格、今日可用机会')}
     ${testSection('activity-lottery-draw', '执行抽奖', 'POST', 'post', '/api/activity/lottery/draw', '需认证', 'auth-required', null, true, 'activityLotteryDraw', '消耗一次抽奖机会,随机抽取奖品(会员/爬虫次数/谢谢参与)')}
     ${testSection('activity-lottery-records', '我的抽奖记录', 'GET', 'get', '/api/activity/lottery/records?limit=20', '需认证', 'auth-required',
-        [{label:'条数(limit,可选)', name:'limit', placeholder:'20', default:'20'}], true, null, '获取当前用户的抽奖历史记录')}`;
+        [{label:'条数(limit,可选)', name:'limit', placeholder:'20', default:'20'}], true, 'activityLotteryRecords', '获取当前用户的抽奖历史记录,包含奖品名称、奖励类型、会员天数、是否中奖等完整中奖信息')}
+    ${testSection('business-license-info', '我的营业执照信息', 'GET', 'get', '/api/business-license/info', '需认证', 'auth-required', null, true, 'businessLicenseInfo', '查询当前用户的营业执照提交状态和审核结果。审核通过后可在比价抽奖中获得额外抽奖机会')}
+    ${testSection('business-license-upload', '提交营业执照(JSON)', 'POST', 'post', '/api/business-license/upload', '需认证', 'auth-required',
+        [
+         {label:'执照图片URL(licenseImageUrl)', name:'licenseImageUrl', placeholder:'https://example.com/license.jpg', default:''},
+         {label:'统一社会信用代码(creditCode)', name:'creditCode', placeholder:'91110000XXXXXXXXXX', default:''},
+         {label:'药店名称(pharmacyName)', name:'pharmacyName', placeholder:'XX大药房', default:''},
+         {label:'法定代表人(legalPerson,可选)', name:'legalPerson', placeholder:'张三', default:''}
+        ], true, 'businessLicenseInfo', '上传营业执照参与资质审核。审核通过后可获认证标识、解锁邀请有礼奖励、获取比价抽奖资格')}`;
 }
 
 // ==================== 运营端:签到管理模块 ====================
@@ -964,7 +1032,13 @@ function renderAdminActivityLotteryModule() {
          {label:'排序(sort)', name:'sort', placeholder:'0', default:'3'}
         ], true, 'adminActivityLotteryPrize', '更新奖品池中的奖品配置')}
     ${testSection('admin-activity-lottery-prize-delete', '删除奖品', 'DELETE', 'delete', '/api/admin/activity/lottery/prizes/{id}', '需认证', 'auth-required',
-        [{label:'奖品ID(id)', name:'id', placeholder:'需删除的奖品ID', default:''}], true, null, '从奖品池中删除指定奖品')}`;
+        [{label:'奖品ID(id)', name:'id', placeholder:'需删除的奖品ID', default:''}], true, null, '从奖品池中删除指定奖品')}
+    ${testSection('admin-activity-lottery-records', '中奖记录(所有用户)', 'GET', 'get', '/api/admin/activity/lottery/records?page=1&size=20&userId=1', '需认证', 'auth-required',
+        [
+         {label:'页码(page)', name:'page', placeholder:'1', default:'1'},
+         {label:'每页(size)', name:'size', placeholder:'20', default:'20'},
+         {label:'用户ID(userId,可选)', name:'userId', placeholder:'1', default:''}
+        ], true, 'adminLotteryRecord', '分页查询所有用户的抽奖中奖记录,支持按用户ID筛选,按时间倒序')}`;
 }
 
 // ===================== 批量测试 ====================
@@ -1090,9 +1164,12 @@ function validate_adminCheckinRecords(result) { return result.data?.code === 200
 function validate_adminCheckinUserRecords(result) { return result.data?.code === 200 && Array.isArray(result.data?.data); }
 
 function validate_activityInviteStatus(result) { return result.data?.code === 200 && result.data?.data?.enabled !== undefined; }
+function validate_activityInviteRewards(result) { return result.data?.code === 200 && Array.isArray(result.data?.data); }
 function validate_activityCheckinStatus(result) { return result.data?.code === 200 && result.data?.data?.enabled !== undefined; }
+function validate_activityCheckinRewards(result) { return result.data?.code === 200 && Array.isArray(result.data?.data); }
 function validate_activityLotteryStatus(result) { return result.data?.code === 200 && result.data?.data?.enabled !== undefined; }
 function validate_activityLotteryPrizes(result) { return result.data?.code === 200 && Array.isArray(result.data?.data); }
+function validate_activityLotteryRecords(result) { return result.data?.code === 200 && Array.isArray(result.data?.data); }
 function validate_activityLotteryDraw(result) { return result.data?.code === 200 && result.data?.data?.prizeName !== undefined; }
 function validate_adminActivityInviteConfig(result) { return result.data?.code === 200 && result.data?.data?.id; }
 function validate_adminActivityInviteRevoke(result) { return result.data?.code === 200 && result.data?.data !== undefined; }
@@ -1103,6 +1180,10 @@ function validate_adminActivityLotteryPrizeCreate(result) { return result.data?.
 function validate_adminActivityLotteryPrizeUpdate(result) { return result.data?.code === 200 && result.data?.data?.id; }
 function validate_adminActivityLotteryPrizeDelete(result) { return result.data?.code === 200; }
 
+function validate_adminActivityLotteryRecords(result) { return result.data?.code === 200 && result.data?.data?.records !== undefined; }
+function validate_businessLicenseInfo(result) { return result.data?.code === 200 && result.data?.data !== undefined; }
+function validate_businessLicenseUpload(result) { return result.data?.code === 200; }
+
 // ===================== 初始化 =====================
 window.addEventListener('DOMContentLoaded', () => {
     const params = new URLSearchParams(window.location.search);