commit
This commit is contained in:
+70
@@ -0,0 +1,70 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketActivityService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/coffeeTicket/activity")
|
||||
@Ok("json:full")
|
||||
@ApiOperation("咖啡抢票活动管理")
|
||||
public class CoffeeTicketActivityController {
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketActivityService coffeeTicketActivityService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/coffeeTicket/activity/index.html")
|
||||
@SaCheckPermission("coffeeTicket.activity")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询咖啡抢票活动。
|
||||
*
|
||||
* @param pageForm 分页参数,包含 pageNumber、pageSize、排序字段等公共分页信息
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空时不按年度筛选
|
||||
* @param title 活动标题关键字;为空时不按标题筛选
|
||||
* @return Result,data 为 Pagination,list 为活动列表,totalCount 为总数
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("coffeeTicket.activity")
|
||||
public Result pageData(@Valid PageForm pageForm, Integer year, String title) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("YEAR(activityStartDate)", "=", year);
|
||||
if (StrUtil.isNotBlank(title)) {
|
||||
cnd.and(Cnd.likeEX("title", title));
|
||||
}
|
||||
Pagination pagination = coffeeTicketActivityService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"coffeeTicket.activity", "coffeeTicket.new"}, mode = cn.dev33.satoken.annotation.SaMode.OR)
|
||||
public Result findOne(@Valid String id) {
|
||||
CoffeeTicketActivity activity = coffeeTicketActivityService.fetch(id);
|
||||
return Result.success(activity);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("coffeeTicket.activity")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result delete(@Valid String id) {
|
||||
coffeeTicketActivityService.deleteActivity(id);
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketActivityService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/coffeeTicket/new")
|
||||
@Ok("json:full")
|
||||
@ApiOperation("咖啡抢票平台活动创建")
|
||||
public class CoffeeTicketNewController {
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketActivityService coffeeTicketActivityService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/coffeeTicket/new/index.html")
|
||||
@SaCheckPermission("coffeeTicket.new")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存咖啡抢票活动。
|
||||
*
|
||||
* @param activity 页面提交的活动配置,包含标题、封面、描述、活动开始/结束日期、可预约星期、票数、每日预约时间段、预约方式、活动地点和参与须知
|
||||
* @return Result,成功时 data 为 CoffeeTicketActivity,可通过 data.id 获取活动ID
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("coffeeTicket.new")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result save(@Param("data") @Valid CoffeeTicketActivity activity) {
|
||||
Result validateResult = validateActivity(activity);
|
||||
if (validateResult != null) {
|
||||
return validateResult;
|
||||
}
|
||||
CoffeeTicketActivity savedActivity = coffeeTicketActivityService.saveActivity(activity);
|
||||
return Result.success(savedActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 只做入参完整性和范围校验,业务保存交给 service 层处理。
|
||||
*/
|
||||
private Result validateActivity(CoffeeTicketActivity activity) {
|
||||
if (activity == null) {
|
||||
return Result.error("活动信息不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(activity.getTitle())) {
|
||||
return Result.error("请输入活动标题");
|
||||
}
|
||||
if (StrUtil.isBlank(activity.getCover())) {
|
||||
return Result.error("请上传活动封面");
|
||||
}
|
||||
if (StrUtil.isBlank(activity.getDescription())) {
|
||||
return Result.error("请输入活动描述");
|
||||
}
|
||||
if (activity.getActivityStartDate() == null || activity.getActivityEndDate() == null) {
|
||||
return Result.error("请选择活动周期");
|
||||
}
|
||||
if (activity.getActivityStartDate().after(activity.getActivityEndDate())) {
|
||||
return Result.error("活动结束日期必须晚于开始日期");
|
||||
}
|
||||
if (CollUtil.isEmpty(activity.getWeekDays())) {
|
||||
return Result.error("请选择可预约星期");
|
||||
}
|
||||
if (activity.getTicketCount() == null || activity.getTicketCount() <= 0) {
|
||||
return Result.error("每次可预约票数必须大于0");
|
||||
}
|
||||
if (StrUtil.isBlank(activity.getReserveStartTime()) || StrUtil.isBlank(activity.getReserveEndTime())) {
|
||||
return Result.error("请选择每日可预约时间段");
|
||||
}
|
||||
if (activity.getReserveStartTime().compareTo(activity.getReserveEndTime()) >= 0) {
|
||||
return Result.error("每日可预约结束时间必须晚于开始时间");
|
||||
}
|
||||
if (StrUtil.isBlank(activity.getReserveMode())) {
|
||||
return Result.error("请选择预约方式");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.controller;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketActivityService;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketRecordService;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.vo.CoffeeTicketGrabStatisticsVO;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/coffeeTicket/statistics")
|
||||
@Ok("json:full")
|
||||
@ApiOperation("咖啡抢票统计")
|
||||
public class CoffeeTicketStatisticsController {
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketActivityService coffeeTicketActivityService;
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketRecordService coffeeTicketRecordService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/coffeeTicket/statistics/index.html")
|
||||
@SaCheckPermission("coffeeTicket.statistics")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询统计页活动下拉列表。
|
||||
*
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空时返回全部活动
|
||||
* @return Result,data 为 List<CoffeeTicketActivity>,前端使用 id 作为活动值、title 作为活动名称
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("coffeeTicket.statistics")
|
||||
public Result activityList(@Param("year") Integer year) {
|
||||
return Result.success(coffeeTicketActivityService.statisticsActivityList(year));
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询咖啡抢票统计明细。
|
||||
*
|
||||
* @param pageForm 分页参数,包含 pageNumber、pageSize、排序字段等公共分页信息
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空且 activityId 为空时查询全部记录
|
||||
* @param activityId 活动ID,传 coffee_ticket_activity 表主键;为空时按年度查询多个活动
|
||||
* @param unionId 抢票用户所属工会ID,传 vw_user.unionId;为空时不按工会筛选
|
||||
* @param unitId 抢票用户所属单位ID,传 vw_user.unitId;为空时不按单位筛选
|
||||
* @param grabDate 抢票日期,传 yyyy-MM-dd;为空时不按实际抢票日期筛选
|
||||
* @return Result,data 为 Pagination,list 为 CoffeeTicketGrabStatisticsVO 抢票明细列表
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("coffeeTicket.statistics")
|
||||
public Result pageData(@Valid PageForm pageForm, @Param("year") Integer year, @Param("activityId") String activityId,
|
||||
@Param("unionId") String unionId, @Param("unitId") String unitId, @Param("grabDate") String grabDate) {
|
||||
Pagination pagination = coffeeTicketRecordService.statisticsPageData(pageForm, year, activityId, unionId, unitId, grabDate);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前统计条件下有抢票记录的日期。
|
||||
*
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空时不按年度筛选
|
||||
* @param activityId 活动ID,传 coffee_ticket_activity 表主键;为空时按年度查询多个活动
|
||||
* @param unionId 抢票用户所属工会ID,传 vw_user.unionId;为空时不按工会筛选
|
||||
* @param unitId 抢票用户所属单位ID,传 vw_user.unitId;为空时不按单位筛选
|
||||
* @return Result,data 为 yyyy-MM-dd 字符串列表,用于限制抢票日期选择器可选日期
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("coffeeTicket.statistics")
|
||||
public Result grabDateList(@Param("year") Integer year, @Param("activityId") String activityId,
|
||||
@Param("unionId") String unionId, @Param("unitId") String unitId) {
|
||||
return Result.success(coffeeTicketRecordService.statisticsGrabDateList(year, activityId, unionId, unitId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出当前筛选条件下的咖啡抢票统计明细。
|
||||
*
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空时不按年度筛选
|
||||
* @param activityId 活动ID,传 coffee_ticket_activity 表主键;为空时按年度查询多个活动
|
||||
* @param unionId 抢票用户所属工会ID,传 vw_user.unionId;为空时不按工会筛选
|
||||
* @param unitId 抢票用户所属单位ID,传 vw_user.unitId;为空时不按单位筛选
|
||||
* @param grabDate 抢票日期,传 yyyy-MM-dd;为空时不按实际抢票日期筛选
|
||||
* @param response HttpServletResponse,用于输出 xlsx 文件流
|
||||
* @return void,浏览器直接下载 Excel 文件
|
||||
*/
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("coffeeTicket.statistics")
|
||||
public void export(@Param("year") Integer year, @Param("activityId") String activityId,
|
||||
@Param("unionId") String unionId, @Param("unitId") String unitId,
|
||||
@Param("grabDate") String grabDate, HttpServletResponse response) {
|
||||
List<CoffeeTicketGrabStatisticsVO> list = coffeeTicketRecordService.statisticsExportList(year, activityId, unionId, unitId, grabDate);
|
||||
List<NutMap> exportList = list.stream().map(this::buildExportRow).collect(Collectors.toList());
|
||||
List<ExcelExportEntity> entities = new ArrayList<>();
|
||||
entities.add(new ExcelExportEntity("姓名", "userName", 20));
|
||||
entities.add(new ExcelExportEntity("工号", "loginName", 20));
|
||||
entities.add(new ExcelExportEntity("单位", "unitName", 25));
|
||||
entities.add(new ExcelExportEntity("分工会", "unionName", 25));
|
||||
entities.add(new ExcelExportEntity("活动名称", "activityTitle", 30));
|
||||
entities.add(new ExcelExportEntity("抢票张数", "ticketNum", 15));
|
||||
entities.add(new ExcelExportEntity("实际抢票时间", "grabTime", 25));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, exportList);
|
||||
CommonDownloadUtil.download("咖啡抢票统计.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除统计页面中的一条抢票记录。
|
||||
*
|
||||
* @param recordId 抢票记录ID,传 coffee_ticket_record 表主键;删除后该用户可重新参与该活动抢票
|
||||
* @return Result,code 为 0 表示删除成功;非 0 时 msg 为失败原因
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("coffeeTicket.statistics.delete")
|
||||
public Result delete(@Param("recordId") @Valid String recordId) {
|
||||
try {
|
||||
coffeeTicketRecordService.deleteStatisticsRecord(recordId);
|
||||
return Result.success();
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装导出行数据,字段与页面当前统计列表保持一致,不包含操作列。
|
||||
*
|
||||
* @param item 一条抢票统计明细
|
||||
* @return NutMap,key 与 ExcelExportEntity 中的字段名对应
|
||||
*/
|
||||
private NutMap buildExportRow(CoffeeTicketGrabStatisticsVO item) {
|
||||
return NutMap.NEW()
|
||||
.setv("userName", item.getUserName())
|
||||
.setv("loginName", item.getLoginName())
|
||||
.setv("unitName", item.getUnitName())
|
||||
.setv("unionName", item.getUnionName())
|
||||
.setv("activityTitle", item.getActivityTitle())
|
||||
.setv("ticketNum", item.getTicketNum())
|
||||
.setv("grabTime", item.getGrabTime() == null ? "" : DateUtil.format(item.getGrabTime(), "yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.h5controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketActivityService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/h5/coffeeTicket/list")
|
||||
@Ok("json:full")
|
||||
@ApiOperation("手机端咖啡抢票活动列表")
|
||||
public class H5CoffeeTicketActivityController {
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketActivityService coffeeTicketActivityService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/coffeeTicket/list/index.html")
|
||||
@SaCheckPermission("h5.coffeeTicket.list")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机端抢票活动列表。
|
||||
*
|
||||
* @param pageForm 分页参数,searchKeyword 可传活动标题或活动地点关键字
|
||||
* @param status 状态筛选,all全部、active报名中、upcoming即将开始、ended已结束
|
||||
* @return Result,data 为 Pagination,list 为 CoffeeTicketActivity 活动列表
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("h5.coffeeTicket.list")
|
||||
public Result pageData(@Valid PageForm pageForm, String status) {
|
||||
return Result.success(coffeeTicketActivityService.h5PageData(pageForm, status));
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.h5controller;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketRecord;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketActivityService;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketRecordService;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.vo.CoffeeTicketActivityH5DetailVO;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/h5/coffeeTicket/detail")
|
||||
@Ok("json:full")
|
||||
@ApiOperation("手机端咖啡抢票活动详情")
|
||||
public class H5CoffeeTicketDetailController {
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketActivityService coffeeTicketActivityService;
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketRecordService coffeeTicketRecordService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/coffeeTicket/detail/index.html")
|
||||
@SaCheckPermission("h5.coffeeTicket.list")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("h5.coffeeTicket.list")
|
||||
public Result findOne(@Valid String id) {
|
||||
CoffeeTicketActivity activity = coffeeTicketActivityService.fetch(id);
|
||||
if (activity == null) {
|
||||
return Result.error("活动不存在");
|
||||
}
|
||||
CoffeeTicketActivityH5DetailVO detailVO = BeanUtil.copyProperties(activity, CoffeeTicketActivityH5DetailVO.class);
|
||||
CoffeeTicketRecord userRecord = coffeeTicketRecordService.fetchLatestUserRecord(id, SecurityUtil.getUserId());
|
||||
detailVO.setHasGrabbed(userRecord != null);
|
||||
detailVO.setMyTicketNum(userRecord == null ? 0 : coffeeTicketRecordService.countUserTicketNum(id, SecurityUtil.getUserId()));
|
||||
detailVO.setMyGrabTime(userRecord == null ? null : userRecord.getGrabTime());
|
||||
return Result.success(detailVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机端立即抢票并保存记录。
|
||||
*
|
||||
* @param id 活动ID,前端从详情页地址参数或活动详情数据中传入
|
||||
* @param ticketNum 本次抢票张数,当前页面默认传 1,用于判断余票是否足够并写入记录
|
||||
* @return Result,code 为 0 表示抢票记录保存成功,data 为 CoffeeTicketRecord;非 0 时 msg 为不可抢票原因
|
||||
*/
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("h5.coffeeTicket.list")
|
||||
public Result grab(@Param("id") @Valid String id, @Param("ticketNum") Integer ticketNum) {
|
||||
try {
|
||||
CoffeeTicketRecord record = coffeeTicketActivityService.grabH5Ticket(id, ticketNum);
|
||||
return Result.success("抢票成功", record);
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.h5controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketRecordService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/h5/coffeeTicket/mine")
|
||||
@Ok("json:full")
|
||||
@ApiOperation("手机端我的咖啡抢票")
|
||||
public class H5CoffeeTicketMineController {
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketRecordService coffeeTicketRecordService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/coffeeTicket/mine/index.html")
|
||||
@SaCheckPermission("h5.coffeeTicket.list")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机端我的抢票列表。
|
||||
*
|
||||
* @param pageForm 分页参数,searchKeyword 可传活动标题关键字
|
||||
* @return Result,data 为 Pagination,list 为 CoffeeTicketMineListVO,按抢票时间倒序排列
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("h5.coffeeTicket.list")
|
||||
public Result pageData(@Valid PageForm pageForm) {
|
||||
return Result.success(coffeeTicketRecordService.h5MinePageData(pageForm));
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机端取消抢票。
|
||||
*
|
||||
* @param recordId 抢票记录ID
|
||||
* @return Result,code 为 0 表示取消成功
|
||||
*/
|
||||
@At("/cancel")
|
||||
@SaCheckPermission("h5.coffeeTicket.list")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result cancel(@Param("recordId") @Valid String recordId) {
|
||||
try {
|
||||
coffeeTicketRecordService.cancelH5Ticket(recordId);
|
||||
return Result.success("取消成功", null);
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Table("coffee_ticket_activity")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("咖啡抢票活动表")
|
||||
public class CoffeeTicketActivity extends BaseModel implements Serializable {
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("活动标题")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String title;
|
||||
|
||||
@Column
|
||||
@Comment("活动封面")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
private String cover;
|
||||
|
||||
@Column
|
||||
@Comment("活动描述")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String description;
|
||||
|
||||
@Column
|
||||
@Comment("活动开始日期")
|
||||
@ColDefine(type = ColType.DATE)
|
||||
private Date activityStartDate;
|
||||
|
||||
@Column
|
||||
@Comment("活动结束日期")
|
||||
@ColDefine(type = ColType.DATE)
|
||||
private Date activityEndDate;
|
||||
|
||||
@Column
|
||||
@Comment("可预约星期,保存周一至周日对应的1-7")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private List<String> weekDays;
|
||||
|
||||
@Column
|
||||
@Comment("每次可预约票数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer ticketCount;
|
||||
|
||||
@Column
|
||||
@Comment("每日可预约开始时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 5)
|
||||
private String reserveStartTime;
|
||||
|
||||
@Column
|
||||
@Comment("每日可预约结束时间")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 5)
|
||||
private String reserveEndTime;
|
||||
|
||||
@Column
|
||||
@Comment("预约方式:WEEKLY每周固定,SPECIAL特殊日期")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String reserveMode;
|
||||
|
||||
@Column
|
||||
@Comment("活动地点")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String address;
|
||||
|
||||
@Column
|
||||
@Comment("参与须知")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String notice;
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Index;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableIndexes;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Table("coffee_ticket_record")
|
||||
@TableIndexes({
|
||||
@Index(name = "UK_COFFEE_TICKET_RECORD_ACTIVITY_USER", fields = {"activityId", "userId"}, unique = true)
|
||||
})
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("咖啡抢票记录表")
|
||||
public class CoffeeTicketRecord extends BaseModel implements Serializable {
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("活动ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String activityId;
|
||||
|
||||
@Column
|
||||
@Comment("活动标题")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String activityTitle;
|
||||
|
||||
@Column
|
||||
@Comment("抢票张数")
|
||||
@ColDefine(type = ColType.INT)
|
||||
private Integer ticketNum;
|
||||
|
||||
@Column
|
||||
@Comment("抢票时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date grabTime;
|
||||
|
||||
@Column
|
||||
@Comment("用户ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String userId;
|
||||
|
||||
@Column
|
||||
@Comment("姓名")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String userName;
|
||||
|
||||
@Column
|
||||
@Comment("工号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 120)
|
||||
private String loginName;
|
||||
|
||||
@Column
|
||||
@Comment("状态:SUCCESS已抢票")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String status;
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketRecord;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CoffeeTicketActivityService extends BaseService<CoffeeTicketActivity> {
|
||||
|
||||
/**
|
||||
* 保存咖啡抢票活动基础配置。
|
||||
*
|
||||
* @param activity 页面提交的活动配置,包含标题、封面、活动日期、预约星期、票数、每日预约时间段、地点和须知等内容
|
||||
* @return CoffeeTicketActivity 保存后的活动实体,新增时会带有生成后的活动ID
|
||||
*/
|
||||
CoffeeTicketActivity saveActivity(CoffeeTicketActivity activity);
|
||||
|
||||
/**
|
||||
* 删除咖啡抢票活动及其基础配置。
|
||||
*
|
||||
* @param id 活动ID
|
||||
*/
|
||||
void deleteActivity(String id);
|
||||
|
||||
/**
|
||||
* 手机端分页查询可展示的咖啡抢票活动。
|
||||
*
|
||||
* @param pageForm 分页参数,searchKeyword 可传活动标题或活动地点关键字
|
||||
* @param status 活动状态,all全部、active报名中、upcoming即将开始、ended已结束
|
||||
* @return Pagination,list 为 CoffeeTicketActivity 活动实体列表
|
||||
*/
|
||||
Pagination h5PageData(PageForm pageForm, String status);
|
||||
|
||||
/**
|
||||
* 查询统计页面年度活动下拉列表。
|
||||
*
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空时返回全部咖啡抢票活动
|
||||
* @return List<CoffeeTicketActivity>,按活动开始日期倒序排列
|
||||
*/
|
||||
List<CoffeeTicketActivity> statisticsActivityList(Integer year);
|
||||
|
||||
/**
|
||||
* 校验手机端抢票请求是否符合活动开放规则。
|
||||
*
|
||||
* @param id 活动ID,必须传 coffee_ticket_activity 表中的活动主键
|
||||
* @param ticketNum 本次抢票张数,当前详情页默认传 1,用于判断是否超过活动配置的每次可预约票数
|
||||
* @return String,返回 null 表示校验通过;返回非空字符串表示不可抢票的具体原因
|
||||
*/
|
||||
String checkH5GrabTicket(String id, Integer ticketNum);
|
||||
|
||||
/**
|
||||
* 手机端立即抢票并保存抢票记录。
|
||||
*
|
||||
* @param id 活动ID,必须传 coffee_ticket_activity 表中的活动主键
|
||||
* @param ticketNum 本次抢票张数,当前详情页默认传 1
|
||||
* @return CoffeeTicketRecord,返回保存后的抢票记录;校验失败时抛出 IllegalStateException,异常消息为前端提示文案
|
||||
*/
|
||||
CoffeeTicketRecord grabH5Ticket(String id, Integer ticketNum);
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketRecord;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CoffeeTicketRecordService extends BaseService<CoffeeTicketRecord> {
|
||||
|
||||
/**
|
||||
* 统计指定活动已经占用的票数。
|
||||
*
|
||||
* @param activityId 活动ID,必须传 coffee_ticket_activity 表中的活动主键
|
||||
* @return int,返回 coffee_ticket_record 中该活动 ticketNum 的合计值,无记录时返回 0
|
||||
*/
|
||||
int countGrabbedTicketNum(String activityId);
|
||||
|
||||
/**
|
||||
* 判断用户是否已经抢过指定活动的票。
|
||||
*
|
||||
* @param activityId 活动ID
|
||||
* @param userId 当前登录用户ID
|
||||
* @return boolean,true 表示该用户已有该活动抢票记录
|
||||
*/
|
||||
boolean hasUserGrabbed(String activityId, String userId);
|
||||
|
||||
/**
|
||||
* 查询用户在指定活动下最近一次抢票记录。
|
||||
*
|
||||
* @param activityId 活动ID
|
||||
* @param userId 当前登录用户ID
|
||||
* @return CoffeeTicketRecord,返回最近一次抢票记录;没有记录时返回 null
|
||||
*/
|
||||
CoffeeTicketRecord fetchLatestUserRecord(String activityId, String userId);
|
||||
|
||||
/**
|
||||
* 统计用户在指定活动下已抢票数。
|
||||
*
|
||||
* @param activityId 活动ID
|
||||
* @param userId 当前登录用户ID
|
||||
* @return int,返回该用户在当前活动下 ticketNum 的合计值,无记录时返回 0
|
||||
*/
|
||||
int countUserTicketNum(String activityId, String userId);
|
||||
|
||||
/**
|
||||
* 保存手机端抢票记录。
|
||||
*
|
||||
* @param activity 已通过规则校验的活动实体,用于回填活动ID和标题
|
||||
* @param ticketNum 本次抢票张数,当前 H5 详情页默认传 1
|
||||
* @return CoffeeTicketRecord,返回已经写入数据库的抢票记录实体
|
||||
*/
|
||||
CoffeeTicketRecord saveGrabRecord(CoffeeTicketActivity activity, Integer ticketNum);
|
||||
|
||||
/**
|
||||
* 手机端分页查询当前用户的抢票记录。
|
||||
*
|
||||
* @param pageForm 分页参数,searchKeyword 可传活动标题关键字
|
||||
* @return Pagination,list 为 CoffeeTicketMineListVO,按抢票时间倒序排列
|
||||
*/
|
||||
Pagination h5MinePageData(PageForm pageForm);
|
||||
|
||||
/**
|
||||
* PC端分页查询咖啡抢票统计明细。
|
||||
*
|
||||
* @param pageForm 分页参数,包含 pageNumber、pageSize、排序字段等公共分页信息
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空且 activityId 为空时查询全部记录
|
||||
* @param activityId 活动ID,传 coffee_ticket_activity 表主键;为空时按年度查询多个活动
|
||||
* @param unionId 抢票用户所属工会ID,传 vw_user.unionId;为空时不按工会筛选
|
||||
* @param unitId 抢票用户所属单位ID,传 vw_user.unitId;为空时不按单位筛选
|
||||
* @param grabDate 抢票日期,传 yyyy-MM-dd;为空时不按实际抢票日期筛选
|
||||
* @return Pagination,list 为 CoffeeTicketGrabStatisticsVO,展示用户、活动、票数和抢票时间
|
||||
*/
|
||||
Pagination statisticsPageData(PageForm pageForm, Integer year, String activityId, String unionId, String unitId, String grabDate);
|
||||
|
||||
/**
|
||||
* 查询当前统计条件下的全部抢票明细,用于按页面筛选条件导出。
|
||||
*
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空时不按年度筛选
|
||||
* @param activityId 活动ID,传 coffee_ticket_activity 表主键;为空时按年度查询多个活动
|
||||
* @param unionId 抢票用户所属工会ID,传 vw_user.unionId;为空时不按工会筛选
|
||||
* @param unitId 抢票用户所属单位ID,传 vw_user.unitId;为空时不按单位筛选
|
||||
* @param grabDate 抢票日期,传 yyyy-MM-dd;为空时不按实际抢票日期筛选
|
||||
* @return List<CoffeeTicketGrabStatisticsVO>,返回与统计列表字段一致的全部匹配数据
|
||||
*/
|
||||
List<com.budwk.app.zhgh.dayofficework.coffeeTicket.vo.CoffeeTicketGrabStatisticsVO> statisticsExportList(Integer year, String activityId, String unionId, String unitId, String grabDate);
|
||||
|
||||
/**
|
||||
* 查询当前统计条件下存在抢票记录的日期。
|
||||
*
|
||||
* @param year 活动开始日期所属年度,传 yyyy 年份;为空时不按年度筛选
|
||||
* @param activityId 活动ID,传 coffee_ticket_activity 表主键;为空时按年度查询多个活动
|
||||
* @param unionId 抢票用户所属工会ID,传 vw_user.unionId;为空时不按工会筛选
|
||||
* @param unitId 抢票用户所属单位ID,传 vw_user.unitId;为空时不按单位筛选
|
||||
* @return List<String>,返回 yyyy-MM-dd 格式的实际抢票日期列表,前端据此控制日期选择器可选范围
|
||||
*/
|
||||
List<String> statisticsGrabDateList(Integer year, String activityId, String unionId, String unitId);
|
||||
|
||||
/**
|
||||
* PC端统计页面删除一条抢票记录。
|
||||
*
|
||||
* @param recordId 抢票记录ID,必须传 coffee_ticket_record 表中的记录主键
|
||||
* @return void,成功则删除该条抢票记录
|
||||
*/
|
||||
void deleteStatisticsRecord(String recordId);
|
||||
|
||||
/**
|
||||
* 手机端取消一条抢票记录。
|
||||
*
|
||||
* @param recordId 要取消的抢票记录ID
|
||||
* @return void,成功则直接删除该条抢票记录
|
||||
*/
|
||||
void cancelH5Ticket(String recordId);
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketRecord;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketActivityService;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketRecordService;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.vo.CoffeeTicketActivityH5ListVO;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.DaoException;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class CoffeeTicketActivityServiceImpl extends BaseServiceImpl<CoffeeTicketActivity> implements CoffeeTicketActivityService {
|
||||
|
||||
@Inject
|
||||
private CoffeeTicketRecordService coffeeTicketRecordService;
|
||||
|
||||
public CoffeeTicketActivityServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public CoffeeTicketActivity saveActivity(CoffeeTicketActivity activity) {
|
||||
dao().insertOrUpdate(activity);
|
||||
return activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void deleteActivity(String id) {
|
||||
dao().delete(CoffeeTicketActivity.class, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination h5PageData(PageForm pageForm, String status) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
String keyword = "%" + pageForm.getSearchKeyword() + "%";
|
||||
cnd.and(Cnd.exps("title", "like", keyword).or("address", "like", keyword));
|
||||
}
|
||||
Date todayStart = DateUtil.beginOfDay(new Date());
|
||||
Date todayEnd = DateUtil.endOfDay(new Date());
|
||||
if ("active".equals(status)) {
|
||||
cnd.and("activityStartDate", "<=", todayEnd);
|
||||
cnd.and("activityEndDate", ">=", todayStart);
|
||||
} else if ("upcoming".equals(status)) {
|
||||
cnd.and("activityStartDate", ">", todayEnd);
|
||||
} else if ("ended".equals(status)) {
|
||||
cnd.and("activityEndDate", "<", todayStart);
|
||||
}
|
||||
cnd.desc("activityStartDate");
|
||||
Pagination pagination = listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
List<CoffeeTicketActivity> activityList = pagination.getList(CoffeeTicketActivity.class);
|
||||
List<CoffeeTicketActivityH5ListVO> voList = activityList.stream().map(this::buildH5ListVO).toList();
|
||||
pagination.setList(voList);
|
||||
return pagination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CoffeeTicketActivity> statisticsActivityList(Integer year) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("YEAR(activityStartDate)", "=", year);
|
||||
cnd.desc("activityStartDate");
|
||||
return dao().query(CoffeeTicketActivity.class, cnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String checkH5GrabTicket(String id, Integer ticketNum) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return "活动ID不能为空";
|
||||
}
|
||||
int currentTicketNum = ticketNum == null ? 1 : ticketNum;
|
||||
if (currentTicketNum <= 0) {
|
||||
return "抢票张数必须大于0";
|
||||
}
|
||||
CoffeeTicketActivity activity = fetch(id);
|
||||
if (activity == null) {
|
||||
return "活动不存在";
|
||||
}
|
||||
Date now = new Date();
|
||||
if (activity.getActivityStartDate() == null || activity.getActivityEndDate() == null) {
|
||||
return "活动周期未配置";
|
||||
}
|
||||
if (now.before(DateUtil.beginOfDay(activity.getActivityStartDate()))) {
|
||||
return "活动尚未开始";
|
||||
}
|
||||
if (now.after(DateUtil.endOfDay(activity.getActivityEndDate()))) {
|
||||
return "活动已结束";
|
||||
}
|
||||
List<String> weekDays = activity.getWeekDays();
|
||||
if (weekDays == null || weekDays.isEmpty()) {
|
||||
return "活动未配置可预约星期";
|
||||
}
|
||||
if (!weekDays.contains(getTodayWeekValue(now))) {
|
||||
return "今天不在可预约星期范围内";
|
||||
}
|
||||
if (StrUtil.isBlank(activity.getReserveStartTime()) || StrUtil.isBlank(activity.getReserveEndTime())) {
|
||||
return "活动未配置每日可预约时间段";
|
||||
}
|
||||
String currentTime = DateUtil.format(now, "HH:mm");
|
||||
if (currentTime.compareTo(activity.getReserveStartTime()) < 0 || currentTime.compareTo(activity.getReserveEndTime()) > 0) {
|
||||
return "当前不在每日可预约时间段内";
|
||||
}
|
||||
if (activity.getTicketCount() == null || activity.getTicketCount() <= 0) {
|
||||
return "活动票数不足";
|
||||
}
|
||||
if (currentTicketNum > activity.getTicketCount()) {
|
||||
return "本次抢票张数超过每次可预约票数";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public CoffeeTicketRecord grabH5Ticket(String id, Integer ticketNum) {
|
||||
int currentTicketNum = ticketNum == null ? 1 : ticketNum;
|
||||
String errorMsg = checkH5GrabTicket(id, currentTicketNum);
|
||||
if (errorMsg != null) {
|
||||
throw new IllegalStateException(errorMsg);
|
||||
}
|
||||
CoffeeTicketActivity activity = fetch(id);
|
||||
if (coffeeTicketRecordService.hasUserGrabbed(activity.getId(), SecurityUtil.getUserId())) {
|
||||
throw new IllegalStateException("您已抢过该活动票");
|
||||
}
|
||||
int grabbedTicketNum = coffeeTicketRecordService.countGrabbedTicketNum(activity.getId());
|
||||
int remainingTicketNum = activity.getTicketCount() - grabbedTicketNum;
|
||||
if (remainingTicketNum < currentTicketNum) {
|
||||
throw new IllegalStateException("票数不足");
|
||||
}
|
||||
try {
|
||||
return coffeeTicketRecordService.saveGrabRecord(activity, currentTicketNum);
|
||||
} catch (DaoException e) {
|
||||
if (isDuplicateGrabException(e)) {
|
||||
throw new IllegalStateException("您已抢过该活动票");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装手机端列表展示对象,补齐活动总票数、已抢票数和剩余票数字段。
|
||||
*
|
||||
* @param activity 当前页活动实体
|
||||
* @return CoffeeTicketActivityH5ListVO,包含活动基础字段和票数统计字段
|
||||
*/
|
||||
private CoffeeTicketActivityH5ListVO buildH5ListVO(CoffeeTicketActivity activity) {
|
||||
CoffeeTicketActivityH5ListVO vo = BeanUtil.copyProperties(activity, CoffeeTicketActivityH5ListVO.class);
|
||||
int totalTicketNum = activity.getTicketCount() == null ? 0 : activity.getTicketCount();
|
||||
int grabbedTicketNum = coffeeTicketRecordService.countGrabbedTicketNum(activity.getId());
|
||||
vo.setTotalTicketNum(totalTicketNum);
|
||||
vo.setGrabbedTicketNum(grabbedTicketNum);
|
||||
vo.setRemainingTicketNum(Math.max(totalTicketNum - grabbedTicketNum, 0));
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Java 星期值转换为页面保存的 1-7 格式,其中 1 表示周一、7 表示周日。
|
||||
*
|
||||
* @param date 需要判断星期的日期
|
||||
* @return String,返回当前日期对应的星期配置值
|
||||
*/
|
||||
private String getTodayWeekValue(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
if (dayOfWeek == Calendar.SUNDAY) {
|
||||
return "7";
|
||||
}
|
||||
return String.valueOf(dayOfWeek - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库唯一索引用于兜底防止同一用户并发重复抢同一活动。
|
||||
*
|
||||
* @param e 抢票记录插入时抛出的数据库异常
|
||||
* @return boolean,true 表示命中 activityId + userId 唯一约束
|
||||
*/
|
||||
private boolean isDuplicateGrabException(DaoException e) {
|
||||
String message = e.getMessage();
|
||||
return StrUtil.containsIgnoreCase(message, "Duplicate")
|
||||
|| StrUtil.containsIgnoreCase(message, "UK_COFFEE_TICKET_RECORD_ACTIVITY_USER");
|
||||
}
|
||||
}
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketRecord;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.service.CoffeeTicketRecordService;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.vo.CoffeeTicketGrabStatisticsVO;
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.vo.CoffeeTicketMineListVO;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class CoffeeTicketRecordServiceImpl extends BaseServiceImpl<CoffeeTicketRecord> implements CoffeeTicketRecordService {
|
||||
|
||||
public CoffeeTicketRecordServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countGrabbedTicketNum(String activityId) {
|
||||
return dao().func(CoffeeTicketRecord.class, "sum", "ticketNum", Cnd.where("activityId", "=", activityId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUserGrabbed(String activityId, String userId) {
|
||||
return dao().count(CoffeeTicketRecord.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId)) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CoffeeTicketRecord fetchLatestUserRecord(String activityId, String userId) {
|
||||
Cnd cnd = Cnd.where("activityId", "=", activityId).and("userId", "=", userId);
|
||||
cnd.desc("grabTime");
|
||||
return dao().fetch(CoffeeTicketRecord.class, cnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countUserTicketNum(String activityId, String userId) {
|
||||
return dao().func(CoffeeTicketRecord.class, "sum", "ticketNum", Cnd.where("activityId", "=", activityId).and("userId", "=", userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public CoffeeTicketRecord saveGrabRecord(CoffeeTicketActivity activity, Integer ticketNum) {
|
||||
CoffeeTicketRecord record = new CoffeeTicketRecord();
|
||||
record.setActivityId(activity.getId());
|
||||
record.setActivityTitle(activity.getTitle());
|
||||
record.setTicketNum(ticketNum);
|
||||
record.setGrabTime(new Date());
|
||||
record.setUserId(SecurityUtil.getUserId());
|
||||
record.setUserName(SecurityUtil.getUserUsername());
|
||||
record.setLoginName(SecurityUtil.getUserLoginname());
|
||||
record.setStatus("SUCCESS");
|
||||
return dao().insert(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination h5MinePageData(PageForm pageForm) {
|
||||
Cnd cnd = Cnd.where("userId", "=", SecurityUtil.getUserId());
|
||||
cnd.desc("grabTime");
|
||||
List<CoffeeTicketRecord> recordList = dao().query(CoffeeTicketRecord.class, cnd);
|
||||
List<CoffeeTicketMineListVO> voList = recordList.stream()
|
||||
.map(this::buildMineListVO)
|
||||
.filter(item -> matchKeyword(item, pageForm.getSearchKeyword()))
|
||||
.toList();
|
||||
int totalCount = voList.size();
|
||||
int fromIndex = Math.min((pageForm.getPageNumber() - 1) * pageForm.getPageSize(), totalCount);
|
||||
int toIndex = Math.min(fromIndex + pageForm.getPageSize(), totalCount);
|
||||
return new Pagination<>(pageForm.getPageNumber(), pageForm.getPageSize(), totalCount, new ArrayList<>(voList.subList(fromIndex, toIndex)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination statisticsPageData(PageForm pageForm, Integer year, String activityId, String unionId, String unitId, String grabDate) {
|
||||
Sql sql = buildStatisticsSql(year, activityId, unionId, unitId, grabDate);
|
||||
Pagination pagination = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
List<NutMap> recordList = pagination.getList();
|
||||
List<CoffeeTicketGrabStatisticsVO> voList = recordList.stream().map(this::buildGrabStatisticsVO).collect(Collectors.toList());
|
||||
pagination.setList(voList);
|
||||
return pagination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CoffeeTicketGrabStatisticsVO> statisticsExportList(Integer year, String activityId, String unionId, String unitId, String grabDate) {
|
||||
Sql sql = buildStatisticsSql(year, activityId, unionId, unitId, grabDate);
|
||||
return listMap(sql).stream().map(this::buildGrabStatisticsVO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> statisticsGrabDateList(Integer year, String activityId, String unionId, String unitId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
DATE_FORMAT(r.grabTime, '%Y-%m-%d') AS grabDate
|
||||
FROM
|
||||
coffee_ticket_record r
|
||||
LEFT JOIN vw_user u ON u.id = r.userId
|
||||
LEFT JOIN coffee_ticket_activity a ON a.id = r.activityId
|
||||
$condition
|
||||
GROUP BY DATE_FORMAT(r.grabTime, '%Y-%m-%d')
|
||||
ORDER BY grabDate DESC
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("r.activityId", "=", activityId);
|
||||
cnd.andEX("YEAR(a.activityStartDate)", "=", year);
|
||||
cnd.andEX("u.unionId", "=", unionId);
|
||||
cnd.andEX("u.unitId", "=", unitId);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> list = listMap(sql);
|
||||
return list.stream().map(item -> item.getString("grabDate")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void deleteStatisticsRecord(String recordId) {
|
||||
if (StrUtil.isBlank(recordId)) {
|
||||
throw new IllegalStateException("抢票记录ID不能为空");
|
||||
}
|
||||
CoffeeTicketRecord record = fetch(recordId);
|
||||
if (record == null) {
|
||||
throw new IllegalStateException("抢票记录不存在");
|
||||
}
|
||||
dao().delete(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void cancelH5Ticket(String recordId) {
|
||||
if (StrUtil.isBlank(recordId)) {
|
||||
throw new IllegalStateException("抢票记录ID不能为空");
|
||||
}
|
||||
CoffeeTicketRecord record = fetch(recordId);
|
||||
if (record == null) {
|
||||
throw new IllegalStateException("抢票记录不存在");
|
||||
}
|
||||
if (!SecurityUtil.getUserId().equals(record.getUserId())) {
|
||||
throw new IllegalStateException("无权取消该抢票记录");
|
||||
}
|
||||
CoffeeTicketActivity activity = dao().fetch(CoffeeTicketActivity.class, record.getActivityId());
|
||||
if (activity == null) {
|
||||
throw new IllegalStateException("活动不存在");
|
||||
}
|
||||
if (!isWithinGrabWindow(activity)) {
|
||||
throw new IllegalStateException("当前不在可取消时间内");
|
||||
}
|
||||
dao().delete(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将抢票记录和活动信息组合成手机端“我的抢票”卡片数据。
|
||||
*
|
||||
* @param record 当前用户的一条抢票记录
|
||||
* @return CoffeeTicketMineListVO,包含记录字段和活动字段
|
||||
*/
|
||||
private CoffeeTicketMineListVO buildMineListVO(CoffeeTicketRecord record) {
|
||||
CoffeeTicketActivity activity = dao().fetch(CoffeeTicketActivity.class, record.getActivityId());
|
||||
CoffeeTicketMineListVO vo = new CoffeeTicketMineListVO();
|
||||
vo.setRecordId(record.getId());
|
||||
vo.setActivityId(record.getActivityId());
|
||||
vo.setTitle(activity == null ? record.getActivityTitle() : activity.getTitle());
|
||||
vo.setCover(activity == null ? null : activity.getCover());
|
||||
vo.setDescription(activity == null ? null : activity.getDescription());
|
||||
vo.setActivityStartDate(activity == null ? null : activity.getActivityStartDate());
|
||||
vo.setActivityEndDate(activity == null ? null : activity.getActivityEndDate());
|
||||
vo.setReserveStartTime(activity == null ? null : activity.getReserveStartTime());
|
||||
vo.setReserveEndTime(activity == null ? null : activity.getReserveEndTime());
|
||||
vo.setAddress(activity == null ? null : activity.getAddress());
|
||||
vo.setTicketNum(record.getTicketNum());
|
||||
vo.setGrabTime(record.getGrabTime());
|
||||
vo.setCanCancel(activity != null && isWithinGrabWindow(activity));
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装PC端抢票统计明细,保留记录表中的用户、活动、票数和实际抢票时间。
|
||||
*
|
||||
* @param record 当前页的一条抢票记录
|
||||
* @return CoffeeTicketGrabStatisticsVO,返回给统计页面展示的明细数据
|
||||
*/
|
||||
private CoffeeTicketGrabStatisticsVO buildGrabStatisticsVO(NutMap record) {
|
||||
CoffeeTicketGrabStatisticsVO vo = new CoffeeTicketGrabStatisticsVO();
|
||||
vo.setRecordId(record.getString("recordId"));
|
||||
vo.setActivityId(record.getString("activityId"));
|
||||
vo.setActivityTitle(record.getString("activityTitle"));
|
||||
vo.setUserId(record.getString("userId"));
|
||||
vo.setUserName(record.getString("userName"));
|
||||
vo.setLoginName(record.getString("loginName"));
|
||||
vo.setUnitId(record.getString("unitId"));
|
||||
vo.setUnitName(record.getString("unitName"));
|
||||
vo.setUnionId(record.getString("unionId"));
|
||||
vo.setUnionName(record.getString("unionName"));
|
||||
vo.setTicketNum(record.getInt("ticketNum"));
|
||||
vo.setGrabTime(record.getAs("grabTime", Date.class));
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建PC端抢票统计查询SQL,分页列表和导出共用同一套筛选条件,避免页面展示与导出结果不一致。
|
||||
*
|
||||
* @param year 活动开始日期所属年度
|
||||
* @param activityId 活动ID
|
||||
* @param unionId 抢票用户所属工会ID
|
||||
* @param unitId 抢票用户所属单位ID
|
||||
* @param grabDate 实际抢票日期,格式 yyyy-MM-dd
|
||||
* @return Sql,已带查询条件和按抢票时间倒序排序
|
||||
*/
|
||||
private Sql buildStatisticsSql(Integer year, String activityId, String unionId, String unitId, String grabDate) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
r.id AS recordId,
|
||||
r.activityId,
|
||||
r.activityTitle,
|
||||
r.userId,
|
||||
r.userName,
|
||||
r.loginName,
|
||||
u.unitId,
|
||||
u.unitName,
|
||||
u.unionId,
|
||||
u.unionName,
|
||||
r.ticketNum,
|
||||
r.grabTime
|
||||
FROM
|
||||
coffee_ticket_record r
|
||||
LEFT JOIN vw_user u ON u.id = r.userId
|
||||
LEFT JOIN coffee_ticket_activity a ON a.id = r.activityId
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("r.activityId", "=", activityId);
|
||||
cnd.andEX("YEAR(a.activityStartDate)", "=", year);
|
||||
cnd.andEX("u.unionId", "=", unionId);
|
||||
cnd.andEX("u.unitId", "=", unitId);
|
||||
if (StrUtil.isNotBlank(grabDate)) {
|
||||
Date date = DateUtil.parse(grabDate, DatePattern.NORM_DATE_PATTERN);
|
||||
cnd.and("r.grabTime", ">=", DateUtil.beginOfDay(date));
|
||||
cnd.and("r.grabTime", "<=", DateUtil.endOfDay(date));
|
||||
}
|
||||
cnd.desc("r.grabTime");
|
||||
sql.setCondition(cnd);
|
||||
return sql;
|
||||
}
|
||||
|
||||
private boolean isWithinGrabWindow(CoffeeTicketActivity activity) {
|
||||
Date now = new Date();
|
||||
if (activity.getActivityStartDate() == null || activity.getActivityEndDate() == null) {
|
||||
return false;
|
||||
}
|
||||
if (now.before(DateUtil.beginOfDay(activity.getActivityStartDate()))) {
|
||||
return false;
|
||||
}
|
||||
if (now.after(DateUtil.endOfDay(activity.getActivityEndDate()))) {
|
||||
return false;
|
||||
}
|
||||
List<String> weekDays = activity.getWeekDays();
|
||||
if (weekDays == null || weekDays.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!weekDays.contains(getTodayWeekValue(now))) {
|
||||
return false;
|
||||
}
|
||||
if (StrUtil.isBlank(activity.getReserveStartTime()) || StrUtil.isBlank(activity.getReserveEndTime())) {
|
||||
return false;
|
||||
}
|
||||
String currentTime = DateUtil.format(now, "HH:mm");
|
||||
if (currentTime.compareTo(activity.getReserveStartTime()) < 0 || currentTime.compareTo(activity.getReserveEndTime()) > 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getTodayWeekValue(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
if (dayOfWeek == Calendar.SUNDAY) {
|
||||
return "7";
|
||||
}
|
||||
return String.valueOf(dayOfWeek - 1);
|
||||
}
|
||||
|
||||
private boolean matchKeyword(CoffeeTicketMineListVO item, String keyword) {
|
||||
return StrUtil.isBlank(keyword) || StrUtil.containsIgnoreCase(item.getTitle(), keyword);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.vo;
|
||||
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class CoffeeTicketActivityH5DetailVO extends CoffeeTicketActivity implements Serializable {
|
||||
|
||||
/**
|
||||
* 当前登录用户是否已经抢过该活动票。
|
||||
*/
|
||||
private Boolean hasGrabbed;
|
||||
|
||||
/**
|
||||
* 当前登录用户在该活动下已抢票张数合计。
|
||||
*/
|
||||
private Integer myTicketNum;
|
||||
|
||||
/**
|
||||
* 当前登录用户最近一次抢票时间。
|
||||
*/
|
||||
private Date myGrabTime;
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.vo;
|
||||
|
||||
import com.budwk.app.zhgh.dayofficework.coffeeTicket.models.CoffeeTicketActivity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class CoffeeTicketActivityH5ListVO extends CoffeeTicketActivity implements Serializable {
|
||||
|
||||
/**
|
||||
* 活动总票数,当前业务按活动表 ticketCount 字段计算。
|
||||
*/
|
||||
private Integer totalTicketNum;
|
||||
|
||||
/**
|
||||
* 已抢票数,统计抢票记录表中当前活动 ticketNum 合计。
|
||||
*/
|
||||
private Integer grabbedTicketNum;
|
||||
|
||||
/**
|
||||
* 剩余票数,按 totalTicketNum - grabbedTicketNum 计算,小于 0 时按 0 返回。
|
||||
*/
|
||||
private Integer remainingTicketNum;
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class CoffeeTicketGrabStatisticsVO implements Serializable {
|
||||
|
||||
/**
|
||||
* 抢票记录ID,用于定位一条用户抢票明细。
|
||||
*/
|
||||
private String recordId;
|
||||
|
||||
/**
|
||||
* 活动ID,对应 coffee_ticket_activity 表主键。
|
||||
*/
|
||||
private String activityId;
|
||||
|
||||
/**
|
||||
* 活动标题,优先使用当前活动表标题,活动被删除时使用记录表冗余标题。
|
||||
*/
|
||||
private String activityTitle;
|
||||
|
||||
/**
|
||||
* 抢票用户ID,对应当前登录用户体系中的用户主键。
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 抢票用户姓名,来源于抢票时保存的用户信息。
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 抢票用户工号,来源于抢票时保存的登录名。
|
||||
*/
|
||||
private String loginName;
|
||||
|
||||
/**
|
||||
* 抢票用户所属单位ID,来源于 vw_user 当前用户视图。
|
||||
*/
|
||||
private String unitId;
|
||||
|
||||
/**
|
||||
* 抢票用户所属单位名称,来源于 vw_user 当前用户视图。
|
||||
*/
|
||||
private String unitName;
|
||||
|
||||
/**
|
||||
* 抢票用户所属工会ID,来源于 vw_user 当前用户视图。
|
||||
*/
|
||||
private String unionId;
|
||||
|
||||
/**
|
||||
* 抢票用户所属工会名称,来源于 vw_user 当前用户视图。
|
||||
*/
|
||||
private String unionName;
|
||||
|
||||
/**
|
||||
* 本次抢票张数。
|
||||
*/
|
||||
private Integer ticketNum;
|
||||
|
||||
/**
|
||||
* 用户实际点击抢票并生成记录的时间。
|
||||
*/
|
||||
private Date grabTime;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.budwk.app.zhgh.dayofficework.coffeeTicket.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class CoffeeTicketMineListVO implements Serializable {
|
||||
|
||||
private String recordId;
|
||||
private String activityId;
|
||||
private String title;
|
||||
private String cover;
|
||||
private String description;
|
||||
private Date activityStartDate;
|
||||
private Date activityEndDate;
|
||||
private String reserveStartTime;
|
||||
private String reserveEndTime;
|
||||
private String address;
|
||||
private Integer ticketNum;
|
||||
private Date grabTime;
|
||||
private Boolean canCancel;
|
||||
}
|
||||
@@ -9,8 +9,10 @@ import com.budwk.app.zhgh.dayofficework.qsv.models.QsvBank;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvSubject;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvBankService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
@@ -51,6 +53,7 @@ public class QsvBankController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("qsv.bank")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("保存题库")
|
||||
public Result save(@Param("qsvBank") QsvBank qsvBank) {
|
||||
dao.insert(qsvBank);
|
||||
@@ -59,6 +62,7 @@ public class QsvBankController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("qsv.bank")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("修改题库")
|
||||
public Result update(@Param("qsvBank") QsvBank qsvBank) {
|
||||
dao.updateIgnoreNull(qsvBank);
|
||||
@@ -75,6 +79,7 @@ public class QsvBankController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("qsv.bank")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("删除题库")
|
||||
public Result delete(@Valid String id) {
|
||||
dao.delete(QsvBank.class, id);
|
||||
@@ -83,6 +88,7 @@ public class QsvBankController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("qsv.bank")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("保存题库题目")
|
||||
public Result saveSubjects(@Valid String id, @Param("subjects") QsvSubject[] subjects) {
|
||||
QsvBank qsvBank = dao.fetch(QsvBank.class, id);
|
||||
|
||||
@@ -13,8 +13,8 @@ import org.nutz.mvc.annotation.Ok;
|
||||
public class QsvNewController {
|
||||
|
||||
@At("/new")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/qsv/activity/new.html")
|
||||
@SaCheckPermission("qsv.activity")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/qsv/activity/index.html")
|
||||
@SaCheckPermission("qsv.new")
|
||||
public void newPage() {
|
||||
|
||||
}
|
||||
|
||||
+2
-9
@@ -10,12 +10,12 @@ import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.dto.QsvCheckAnswerResult;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvOption;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvSubject;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvUserAnswerRecord;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.param.QsvAnswerParam;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.dto.QsvCheckAnswerResult;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvQuizService;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvUserAnswerRecordService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@@ -31,14 +31,7 @@ import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
+15
@@ -4,11 +4,14 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvUserAnswerRecord;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.param.QsvQuizRankPageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvQuizRankService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
@@ -64,5 +67,17 @@ public class QsvQuizRankController {
|
||||
qsvQuizRankService.exportXlsx(pageForm, response);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("qsv.quiz.rank.delete")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("删除答题记录")
|
||||
public Result deleteAnswerRecord(@Valid String id) {
|
||||
QsvUserAnswerRecord record = dao.fetch(QsvUserAnswerRecord.class, id);
|
||||
if (record == null) {
|
||||
return Result.error("答题记录不存在");
|
||||
}
|
||||
dao.delete(QsvUserAnswerRecord.class, id);
|
||||
return Result.success("删除成功");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,8 +22,10 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
@@ -377,6 +379,7 @@ public class QsvSurveyController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("qsv.survey")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("删除用户答题记录")
|
||||
@SLog(type = "qsv.survey", tag = "删除用户答题记录", msg = "删除用户答题记录")
|
||||
public Result deleteUserAnswer(@Valid String id) {
|
||||
|
||||
+1
-1
@@ -3,7 +3,6 @@ package com.budwk.app.zhgh.dayofficework.qsv.h5controller;
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.result.Result;
|
||||
@@ -335,6 +334,7 @@ public class H5QsvQuizController {
|
||||
@At
|
||||
@ApiOperation("提交答题")
|
||||
@SLog(type = "qsv.quiz", tag = "提交答题", msg = "问卷调查提交答题")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result submitAnswer(@Valid @Param("answer") QsvAnswerParam qsvAnswerParam) {
|
||||
QsvUserAnswerRecord answerRecord = dao.fetch(QsvUserAnswerRecord.class, qsvAnswerParam.getAnswerRecordId());
|
||||
JSONObject extJson = answerRecord.getExtJson();
|
||||
|
||||
+2
-6
@@ -10,9 +10,9 @@ import com.budwk.app.zhgh.dayofficework.qsv.models.QsvSubject;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvUserAnswerRecord;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.param.QsvAnswerParam;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvUserAnswerRecordService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
@@ -22,11 +22,7 @@ import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
+1
-6
@@ -23,12 +23,7 @@ import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ public class QsvActivity extends BaseModel implements Serializable, SysHomeConve
|
||||
sysHomeActivity.setName(this.getTitle());
|
||||
sysHomeActivity.setCover(this.getCover());
|
||||
sysHomeActivity.setContent(this.getDescription());
|
||||
sysHomeActivity.setUrl("/platform/qsv/activity");
|
||||
sysHomeActivity.setUrl("/platform/qsv/online");
|
||||
sysHomeActivity.setH5Url(getH5Url());
|
||||
sysHomeActivity.setStartDate(this.getStartTime());
|
||||
sysHomeActivity.setEndDate(this.getEndTime());
|
||||
|
||||
+1
@@ -90,6 +90,7 @@ public class QsvQuizRankServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord>
|
||||
private Sql buildQuerySql(String activityId, String mode, String scoreStatisticsMode, QsvQuizRankPageForm pageForm) {
|
||||
StringBuilder sqlBuilder = new StringBuilder("""
|
||||
SELECT
|
||||
t1.id,
|
||||
t1.userId,
|
||||
t1.userName,
|
||||
t1.loginName,
|
||||
|
||||
Reference in New Issue
Block a user