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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
package cn.iocoder.yudao.module.wxcp.controller.admin.activity;
 
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.storage.vo.SystemStorageBlobRespVO;
import cn.iocoder.yudao.module.wxcp.controller.admin.activity.vo.*;
import cn.iocoder.yudao.module.wxcp.controller.admin.vo.WxCpPushReqVO;
import cn.iocoder.yudao.module.wxcp.controller.admin.vo.WxCpPushResultVO;
import cn.iocoder.yudao.module.wxcp.dal.dataobject.activity.WxCpActivityDO;
import cn.iocoder.yudao.module.wxcp.dal.dataobject.activity.WxCpActivitySignupDO;
import cn.iocoder.yudao.module.wxcp.enums.activity.WxCpActivityStatusEnum;
import cn.iocoder.yudao.module.wxcp.enums.activity.WxCpPushScopeEnum;
import cn.iocoder.yudao.module.wxcp.enums.activity.WxCpSignupStatusEnum;
import cn.iocoder.yudao.module.wxcp.service.activity.WxCpActivityService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
 
import java.util.List;
 
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
/**
 * 管理后台 - 企业微信活动
 *
 * @author 超级管理员
 */
@Tag(name = "管理后台 - 企业微信活动")
@RestController
@RequestMapping("/wxcp/activity")
@Validated
public class WxCpActivityController {
 
    @Resource
    private WxCpActivityService activityService;
 
    // ==================== 活动管理 ====================
 
    @PostMapping("/create")
    @Operation(summary = "创建活动")
    @PreAuthorize("@ss.hasPermission('wxcp:activity:create')")
    public CommonResult<Long> createActivity(@Valid @RequestBody WxCpActivitySaveReqVO createReqVO) {
        return success(activityService.createActivity(createReqVO));
    }
 
    @PutMapping("/update")
    @Operation(summary = "修改活动")
    @PreAuthorize("@ss.hasPermission('wxcp:activity:update')")
    public CommonResult<Boolean> updateActivity(@Valid @RequestBody WxCpActivitySaveReqVO updateReqVO) {
        activityService.updateActivity(updateReqVO);
        return success(true);
    }
 
    @DeleteMapping("/delete")
    @Operation(summary = "删除活动")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:activity:delete')")
    public CommonResult<Boolean> deleteActivity(@RequestParam("id") Long id) {
        activityService.deleteActivity(id);
        return success(true);
    }
 
    @GetMapping("/get")
    @Operation(summary = "获得活动")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:activity:query')")
    public CommonResult<WxCpActivityRespVO> getActivity(@RequestParam("id") Long id) {
        WxCpActivityDO activity = activityService.getActivity(id);
        return success(buildActivityRespVO(activity));
    }
 
    @GetMapping("/page")
    @Operation(summary = "获得活动分页")
    @PreAuthorize("@ss.hasPermission('wxcp:activity:query')")
    public CommonResult<PageResult<WxCpActivityRespVO>> getActivityPage(@Valid WxCpActivityPageReqVO pageReqVO) {
        PageResult<WxCpActivityDO> pageResult = activityService.getActivityPage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, WxCpActivityRespVO.class, this::fillActivityNames));
    }
 
    @PutMapping("/publish")
    @Operation(summary = "发布活动")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:activity:update')")
    public CommonResult<Boolean> publishActivity(@RequestParam("id") Long id) {
        activityService.publishActivity(id);
        return success(true);
    }
 
    @PutMapping("/finish")
    @Operation(summary = "结束活动")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:activity:update')")
    public CommonResult<Boolean> finishActivity(@RequestParam("id") Long id) {
        activityService.finishActivity(id);
        return success(true);
    }
 
    @PutMapping("/cancel")
    @Operation(summary = "取消活动")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:activity:update')")
    public CommonResult<Boolean> cancelActivity(@RequestParam("id") Long id) {
        activityService.cancelActivity(id);
        return success(true);
    }
 
    // ==================== 推送与二维码 ====================
 
    @PostMapping("/push")
    @Operation(summary = "推送活动给企业微信成员", description = "支持覆盖推送范围与目标;不传则沿用活动上已配置的值")
    @PreAuthorize("@ss.hasPermission('wxcp:activity:push')")
    public CommonResult<WxCpPushResultVO> pushActivity(@Valid @RequestBody WxCpPushReqVO pushReqVO) {
        return success(activityService.pushActivity(pushReqVO));
    }
 
    @GetMapping("/qrcode")
    @Operation(summary = "获得活动报名二维码", description = "返回 PNG 图片,可直接用于展示或下载打印")
    @Parameter(name = "id", description = "活动编号", required = true)
    @Parameter(name = "size", description = "边长像素,不传使用默认值")
    @PreAuthorize("@ss.hasPermission('wxcp:activity:query')")
    public ResponseEntity<byte[]> getSignupQrCode(@RequestParam("id") Long id,
                                                  @RequestParam(value = "size", required = false) Integer size) {
        byte[] png = activityService.generateSignupQrCode(id, size != null ? size : 0);
        return ResponseEntity.ok()
                .contentType(MediaType.IMAGE_PNG)
                .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"activity-signup-" + id + ".png\"")
                .body(png);
    }
 
    @GetMapping("/signup-url")
    @Operation(summary = "获得活动报名页地址", description = "便于前端自行生成二维码或复制链接")
    @Parameter(name = "id", description = "活动编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:activity:query')")
    public CommonResult<String> getSignupUrl(@RequestParam("id") Long id) {
        return success(activityService.buildSignupUrl(id));
    }
 
    // ==================== 报名记录 ====================
 
    @GetMapping("/signup/page")
    @Operation(summary = "获得报名记录分页")
    @PreAuthorize("@ss.hasPermission('wxcp:signup:query')")
    public CommonResult<PageResult<WxCpSignupRespVO>> getSignupPage(@Valid WxCpSignupPageReqVO pageReqVO) {
        PageResult<WxCpActivitySignupDO> pageResult = activityService.getSignupPage(pageReqVO);
        PageResult<WxCpSignupRespVO> result = BeanUtils.toBean(pageResult, WxCpSignupRespVO.class);
        // 补上活动标题与状态名,避免前端为一行记录再查一次活动
        result.getList().forEach(vo -> {
            WxCpActivityDO activity = vo.getActivityId() != null
                    ? activityService.getActivity(vo.getActivityId()) : null;
            if (activity != null) {
                vo.setActivityTitle(activity.getTitle());
            }
            WxCpSignupStatusEnum status = WxCpSignupStatusEnum.valueOf(vo.getStatus());
            vo.setStatusName(status != null ? status.getName() : null);
        });
        return success(result);
    }
 
    @PutMapping("/signup/cancel")
    @Operation(summary = "取消报名")
    @Parameter(name = "id", description = "报名记录编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:signup:update')")
    public CommonResult<Boolean> cancelSignup(@RequestParam("id") Long id) {
        activityService.cancelSignup(id);
        return success(true);
    }
 
    @PutMapping("/signup/check-in")
    @Operation(summary = "报名签到")
    @Parameter(name = "id", description = "报名记录编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:signup:update')")
    public CommonResult<Boolean> checkInSignup(@RequestParam("id") Long id) {
        activityService.checkInSignup(id);
        return success(true);
    }
 
    @GetMapping("/stats")
    @Operation(summary = "获得活动报名统计", description = "含总数、状态分布、按部门分布、按日期趋势、签到率")
    @Parameter(name = "id", description = "活动编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:activity:query')")
    public CommonResult<WxCpActivityStatsRespVO> getActivityStats(@RequestParam("id") Long id) {
        return success(activityService.getActivityStats(id));
    }
 
    @GetMapping("/signup/attachments")
    @Operation(summary = "获得某条报名记录上传的图片/附件")
    @Parameter(name = "signupId", description = "报名记录编号", required = true)
    @PreAuthorize("@ss.hasPermission('wxcp:signup:query')")
    public CommonResult<List<SystemStorageBlobRespVO>> getSignupAttachments(@RequestParam("signupId") Long signupId) {
        return success(activityService.getSignupAttachments(signupId));
    }
 
    // ==================== 转换辅助 ====================
 
    private WxCpActivityRespVO buildActivityRespVO(WxCpActivityDO activity) {
        if (activity == null) {
            return null;
        }
        WxCpActivityRespVO vo = BeanUtils.toBean(activity, WxCpActivityRespVO.class);
        fillActivityNames(vo);
        return vo;
    }
 
    private void fillActivityNames(WxCpActivityRespVO vo) {
        WxCpActivityStatusEnum status = WxCpActivityStatusEnum.valueOf(vo.getStatus());
        vo.setStatusName(status != null ? status.getName() : null);
        WxCpPushScopeEnum scope = WxCpPushScopeEnum.valueOf(vo.getPushScope());
        vo.setPushScopeName(scope != null ? scope.getName() : null);
    }
 
}