wenminjie
2026-08-04 93414e8ee25852aca467213402585d0e65c08a4a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.talentcard.server.business.admin;
 
import java.util.Map;
 
import com.talentcard.server.business.PageResult;
import com.talentcard.server.common.ApiResponse;
import com.talentcard.server.request.TicketPackageCodeImportRequest;
import com.talentcard.server.request.TicketPackageCodeStatusRequest;
import com.talentcard.server.request.TicketPackageSaveRequest;
import com.talentcard.server.request.TicketPackageStatusRequest;
import com.talentcard.server.service.TicketPackageAdminService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
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 org.springframework.web.multipart.MultipartFile;
 
@Tag(name = "后台-票包码池", description = "后台维护票包、兑换码码池、库存、发放记录和兑换码状态")
@RestController
@RequestMapping("/api/admin/ticket-packages")
public class TicketPackageAdminController {
    private final TicketPackageAdminService service;
 
    public TicketPackageAdminController(TicketPackageAdminService service) {
        this.service = service;
    }
 
    @Operation(summary = "查询票包列表", description = "分页查询票包配置和兑换码库存汇总")
    @GetMapping
    public ApiResponse<PageResult<Map<String, Object>>> packages(
            @Parameter(description = "指定兑换商家ID") @RequestParam(required = false) Long merchantId,
            @Parameter(description = "状态:1启用,0停用") @RequestParam(required = false) Integer status,
            @Parameter(description = "票包名称或编号关键词") @RequestParam(required = false) String keyword,
            @Parameter(description = "页码") @RequestParam(defaultValue = "1") int page,
            @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") int size
    ) {
        return ApiResponse.success(service.packages(merchantId, status, keyword, page, size));
    }
 
    @Operation(summary = "查询票包详情", description = "查看票包基础配置和码池库存汇总")
    @GetMapping("/{packageId}")
    public ApiResponse<Map<String, Object>> packageDetail(@PathVariable Long packageId) {
        return ApiResponse.success(service.packageDetail(packageId));
    }
 
    @Operation(summary = "查询票包库存", description = "查看指定票包兑换码总量、可发放、锁定、已发放、已使用和作废数量")
    @GetMapping("/{packageId}/stock")
    public ApiResponse<Map<String, Object>> stock(@Parameter(description = "票包ID") @PathVariable Long packageId) {
        return ApiResponse.success(service.stock(packageId));
    }
 
    @Operation(summary = "新增票包", description = "后台录入票包,不涉及具体电影票场次")
    @PostMapping
    public ApiResponse<Map<String, Object>> createPackage(@Valid @RequestBody TicketPackageSaveRequest request) {
        return ApiResponse.success(service.createPackage(request));
    }
 
    @Operation(summary = "修改票包", description = "修改票包名称、适用卡等级、有效期、商家APP信息等")
    @PutMapping("/{packageId}")
    public ApiResponse<Map<String, Object>> updatePackage(
            @PathVariable Long packageId,
            @Valid @RequestBody TicketPackageSaveRequest request
    ) {
        return ApiResponse.success(service.updatePackage(packageId, request));
    }
 
    @Operation(summary = "修改票包状态", description = "启用或停用票包")
    @PatchMapping("/{packageId}/status")
    public ApiResponse<Map<String, Object>> updatePackageStatus(
            @PathVariable Long packageId,
            @Valid @RequestBody TicketPackageStatusRequest request
    ) {
        return ApiResponse.success(service.updatePackageStatus(packageId, request.status()));
    }
 
    @Operation(summary = "导入票包兑换码", description = "批量导入兑换码到指定票包码池,重复兑换码自动跳过")
    @PostMapping("/{packageId}/codes/import")
    public ApiResponse<Map<String, Object>> importCodes(
            @PathVariable Long packageId,
            @Valid @RequestBody TicketPackageCodeImportRequest request
    ) {
        return ApiResponse.success(service.importCodes(packageId, request));
    }
 
    @Operation(summary = "导入票包兑换码Excel", description = "上传Excel文件导入兑换码,读取第一个Sheet第一列,首行可为兑换码标题,重复兑换码自动跳过")
    @PostMapping(value = "/{packageId}/codes/import-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ApiResponse<Map<String, Object>> importCodeFile(
            @Parameter(description = "票包ID") @PathVariable Long packageId,
            @Parameter(description = "兑换码Excel文件") @RequestParam("file") MultipartFile file,
            @Parameter(description = "导入批次号;不传后端自动生成") @RequestParam(required = false) String batchNo,
            @Parameter(description = "备注") @RequestParam(required = false) String remark
    ) {
        return ApiResponse.success(service.importCodeFile(packageId, file, batchNo, remark));
    }
 
    @Operation(summary = "查询票包兑换码列表", description = "分页查询码池兑换码,支持状态、批次号和关键词筛选")
    @GetMapping("/codes")
    public ApiResponse<PageResult<Map<String, Object>>> codes(
            @Parameter(description = "票包ID") @RequestParam(required = false) Long packageId,
            @Parameter(description = "兑换码状态") @RequestParam(required = false) String status,
            @Parameter(description = "导入批次号") @RequestParam(required = false) String batchNo,
            @Parameter(description = "兑换码或票包名称关键词") @RequestParam(required = false) String keyword,
            @Parameter(description = "页码") @RequestParam(defaultValue = "1") int page,
            @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") int size
    ) {
        return ApiResponse.success(service.codes(packageId, status, batchNo, keyword, page, size));
    }
 
    @Operation(summary = "修改兑换码状态", description = "后台作废兑换码,或将已发放兑换码标记为已使用")
    @PatchMapping("/codes/{codeId}/status")
    public ApiResponse<Map<String, Object>> updateCodeStatus(
            @PathVariable Long codeId,
            @Valid @RequestBody TicketPackageCodeStatusRequest request
    ) {
        return ApiResponse.success(service.updateCodeStatus(codeId, request));
    }
 
    @Operation(summary = "查询票包发放记录", description = "分页查询用户领取兑换码记录")
    @GetMapping("/claims")
    public ApiResponse<PageResult<Map<String, Object>>> claims(
            @Parameter(description = "票包ID") @RequestParam(required = false) Long packageId,
            @Parameter(description = "持卡人ID") @RequestParam(required = false) Long talentId,
            @Parameter(description = "发放状态") @RequestParam(required = false) String status,
            @Parameter(description = "领取编号、兑换码、姓名或手机号关键词") @RequestParam(required = false) String keyword,
            @Parameter(description = "页码") @RequestParam(defaultValue = "1") int page,
            @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") int size
    ) {
        return ApiResponse.success(service.claims(packageId, talentId, status, keyword, page, size));
    }
}