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 createActivity(@Valid @RequestBody WxCpActivitySaveReqVO createReqVO) { return success(activityService.createActivity(createReqVO)); } @PutMapping("/update") @Operation(summary = "修改活动") @PreAuthorize("@ss.hasPermission('wxcp:activity:update')") public CommonResult 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 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 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> getActivityPage(@Valid WxCpActivityPageReqVO pageReqVO) { PageResult pageResult = activityService.getActivityPage(pageReqVO); PageResult result = BeanUtils.toBean(pageResult, WxCpActivityRespVO.class); result.getList().forEach(this::fillActivityExtra); return success(result); } @PutMapping("/publish") @Operation(summary = "发布活动") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('wxcp:activity:update')") public CommonResult 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 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 cancelActivity(@RequestParam("id") Long id) { activityService.cancelActivity(id); return success(true); } // ==================== 推送与二维码 ==================== @PostMapping("/push") @Operation(summary = "推送活动给企业微信成员", description = "支持覆盖推送范围与目标;不传则沿用活动上已配置的值") @PreAuthorize("@ss.hasPermission('wxcp:activity:push')") public CommonResult 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 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 getSignupUrl(@RequestParam("id") Long id) { return success(activityService.buildSignupUrl(id)); } // ==================== 报名记录 ==================== @GetMapping("/signup/page") @Operation(summary = "获得报名记录分页") @PreAuthorize("@ss.hasPermission('wxcp:signup:query')") public CommonResult> getSignupPage(@Valid WxCpSignupPageReqVO pageReqVO) { PageResult pageResult = activityService.getSignupPage(pageReqVO); PageResult 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 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 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 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> 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); fillActivityExtra(vo); return vo; } /** * 补齐状态名、推送范围名与封面附件 * * 封面不落业务表字段,统一从 system_storage_attachment 中间表读, * 前端取 attachmentList[0].previewURL 展示。 */ private void fillActivityExtra(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); if (vo.getId() != null) { vo.setAttachmentList(activityService.getActivityAttachments(vo.getId())); } } }