This commit is contained in:
=
2026-06-17 14:15:32 +08:00
11 changed files with 464 additions and 92 deletions
@@ -15,6 +15,7 @@ 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;
@@ -49,6 +50,7 @@ public class CoffeeTicketActivityController {
if (StrUtil.isNotBlank(title)) {
cnd.and(Cnd.likeEX("title", title));
}
cnd.desc("createdAt");
Pagination pagination = coffeeTicketActivityService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
return Result.success(pagination);
}
@@ -67,4 +69,23 @@ public class CoffeeTicketActivityController {
coffeeTicketActivityService.deleteActivity(id);
return Result.success();
}
/**
* 开启或关闭咖啡抢票活动。
*
* @param id 活动ID,传 coffee_ticket_activity 表主键
* @param enabled true 表示开启报名并推送首页,false 表示关闭报名并移除首页入口
* @return Result,成功后前端刷新列表即可看到最新状态
*/
@At
@SaCheckPermission("coffeeTicket.activity")
@Aop(TransAop.READ_COMMITTED)
public Result updateEnabled(@Param("id") @Valid String id, @Param("enabled") Boolean enabled) {
try {
coffeeTicketActivityService.updateEnabled(id, enabled);
return Result.success(Boolean.TRUE.equals(enabled) ? "开启成功" : "关闭成功");
} catch (IllegalStateException e) {
return Result.error(e.getMessage());
}
}
}
@@ -35,7 +35,7 @@ public class CoffeeTicketNewController {
/**
* 保存咖啡抢票活动。
*
* @param activity 页面提交的活动配置,包含标题、封面、描述、活动开始/结束日期、可预约星期、票数、每日预约时间段、预约方式、活动地点和参与须知
* @param activity 页面提交的活动配置,包含标题、封面、描述、活动开始/结束日期、可预约星期、票数、每日预约时间段、可报名人员范围、预约方式、活动地点和参与须知
* @return Result,成功时 data 为 CoffeeTicketActivity,可通过 data.id 获取活动ID
*/
@At
@@ -46,8 +46,12 @@ public class CoffeeTicketNewController {
if (validateResult != null) {
return validateResult;
}
CoffeeTicketActivity savedActivity = coffeeTicketActivityService.saveActivity(activity);
return Result.success(savedActivity);
try {
CoffeeTicketActivity savedActivity = coffeeTicketActivityService.saveActivity(activity);
return Result.success(savedActivity);
} catch (IllegalStateException e) {
return Result.error(e.getMessage());
}
}
/**
@@ -87,6 +91,9 @@ public class CoffeeTicketNewController {
if (StrUtil.isBlank(activity.getReserveMode())) {
return Result.error("请选择预约方式");
}
if (activity.getActivityGroupId() == null) {
return Result.error("请选择可报名人员范围");
}
return null;
}
}
@@ -45,6 +45,13 @@ public class H5CoffeeTicketDetailController {
if (activity == null) {
return Result.error("活动不存在");
}
if (!Boolean.TRUE.equals(activity.getEnabled())) {
return Result.error("活动未开启");
}
String scopeMsg = coffeeTicketActivityService.checkH5ActivityUserScope(activity, SecurityUtil.getUserId());
if (scopeMsg != null) {
return Result.error(scopeMsg);
}
CoffeeTicketActivityH5DetailVO detailVO = BeanUtil.copyProperties(activity, CoffeeTicketActivityH5DetailVO.class);
CoffeeTicketRecord userRecord = coffeeTicketRecordService.fetchLatestUserRecord(id, SecurityUtil.getUserId());
detailVO.setHasGrabbed(userRecord != null);
@@ -1,12 +1,15 @@
package com.budwk.app.zhgh.dayofficework.coffeeTicket.models;
import com.budwk.app.base.model.BaseModel;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.services.SysHomeConvert;
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.Default;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.entity.annotation.TableMeta;
@@ -21,7 +24,7 @@ import java.util.List;
@Table("coffee_ticket_activity")
@TableMeta("{'mysql-charset':'utf8mb4'}")
@Comment("咖啡抢票活动表")
public class CoffeeTicketActivity extends BaseModel implements Serializable {
public class CoffeeTicketActivity extends BaseModel implements Serializable, SysHomeConvert {
@Name
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@@ -78,6 +81,17 @@ public class CoffeeTicketActivity extends BaseModel implements Serializable {
@ColDefine(type = ColType.VARCHAR, width = 20)
private String reserveMode;
@Column
@Comment("可报名人员范围分组ID,对应 activity_user_scope.groupId")
@ColDefine(type = ColType.INT, width = 32)
private Integer activityGroupId;
@Column
@Comment("是否开启,开启后手机端可报名并推送首页")
@ColDefine(type = ColType.BOOLEAN)
@Default("0")
private Boolean enabled;
@Column
@Comment("活动地点")
@ColDefine(type = ColType.VARCHAR, width = 100)
@@ -87,4 +101,21 @@ public class CoffeeTicketActivity extends BaseModel implements Serializable {
@Comment("参与须知")
@ColDefine(type = ColType.TEXT)
private String notice;
@Override
public Sys_home_activity covertToSysHomeActivity() {
Sys_home_activity sysHomeActivity = new Sys_home_activity();
sysHomeActivity.setId(this.getId());
sysHomeActivity.setName(this.getTitle());
sysHomeActivity.setCover(this.getCover());
sysHomeActivity.setContent(this.getDescription());
sysHomeActivity.setUrl("/platform/coffeeTicket/activity");
sysHomeActivity.setH5Url("/platform/h5/coffeeTicket/detail?id=" + this.getId());
sysHomeActivity.setStartDate(this.getActivityStartDate());
sysHomeActivity.setEndDate(this.getActivityEndDate());
sysHomeActivity.setAllowUserGroupId(this.getActivityGroupId());
sysHomeActivity.setEnable(Boolean.TRUE.equals(this.getEnabled()));
sysHomeActivity.setClassPath(this.getClass().getPackageName() + this.getClass().getName());
return sysHomeActivity;
}
}
@@ -25,6 +25,14 @@ public interface CoffeeTicketActivityService extends BaseService<CoffeeTicketAct
*/
void deleteActivity(String id);
/**
* 开启或关闭咖啡抢票活动,并同步移动端首页入口。
*
* @param id 活动ID
* @param enabled true 表示开启报名并推送首页,false 表示关闭报名并移除首页入口
*/
void updateEnabled(String id, Boolean enabled);
/**
* 手机端分页查询可展示的咖啡抢票活动。
*
@@ -51,6 +59,15 @@ public interface CoffeeTicketActivityService extends BaseService<CoffeeTicketAct
*/
String checkH5GrabTicket(String id, Integer ticketNum);
/**
* 校验当前用户是否在活动可报名人员范围内。
*
* @param activity 活动实体,必须包含 activityGroupId
* @param userId 当前登录用户ID
* @return String,返回 null 表示在范围内;返回非空字符串表示不可参与原因
*/
String checkH5ActivityUserScope(CoffeeTicketActivity activity, String userId);
/**
* 手机端立即抢票并保存抢票记录。
*
@@ -6,7 +6,9 @@ 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.sys.models.Sys_home_activity;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
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;
@@ -30,6 +32,9 @@ public class CoffeeTicketActivityServiceImpl extends BaseServiceImpl<CoffeeTicke
@Inject
private CoffeeTicketRecordService coffeeTicketRecordService;
@Inject
private ActivityBasicScopeService activityBasicScopeService;
public CoffeeTicketActivityServiceImpl(Dao dao) {
super(dao);
}
@@ -37,7 +42,14 @@ public class CoffeeTicketActivityServiceImpl extends BaseServiceImpl<CoffeeTicke
@Override
@Aop(TransAop.READ_COMMITTED)
public CoffeeTicketActivity saveActivity(CoffeeTicketActivity activity) {
if (activity.getActivityGroupId() == null || activityBasicScopeService.getGroupInfo(activity.getActivityGroupId()) == null) {
throw new IllegalStateException("请选择有效的可报名人员范围");
}
if (activity.getEnabled() == null) {
activity.setEnabled(false);
}
dao().insertOrUpdate(activity);
syncHomeActivity(activity);
return activity;
}
@@ -45,11 +57,25 @@ public class CoffeeTicketActivityServiceImpl extends BaseServiceImpl<CoffeeTicke
@Aop(TransAop.READ_COMMITTED)
public void deleteActivity(String id) {
dao().delete(CoffeeTicketActivity.class, id);
dao().delete(Sys_home_activity.class, id);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void updateEnabled(String id, Boolean enabled) {
CoffeeTicketActivity activity = fetch(id);
if (activity == null) {
throw new IllegalStateException("活动不存在");
}
activity.setEnabled(Boolean.TRUE.equals(enabled));
dao().updateIgnoreNull(activity);
syncHomeActivity(activity);
}
@Override
public Pagination h5PageData(PageForm pageForm, String status) {
Cnd cnd = Cnd.NEW();
cnd.and("enabled", "=", true);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
String keyword = "%" + pageForm.getSearchKeyword() + "%";
cnd.and(Cnd.exps("title", "like", keyword).or("address", "like", keyword));
@@ -64,6 +90,12 @@ public class CoffeeTicketActivityServiceImpl extends BaseServiceImpl<CoffeeTicke
} else if ("ended".equals(status)) {
cnd.and("activityEndDate", "<", todayStart);
}
List<Integer> visibleGroupIds = buildCurrentUserVisibleGroupIds(cnd);
if (visibleGroupIds.isEmpty()) {
cnd.and("id", "=", "__none__");
} else {
cnd.and("activityGroupId", "in", visibleGroupIds);
}
cnd.desc("activityStartDate");
Pagination pagination = listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
List<CoffeeTicketActivity> activityList = pagination.getList(CoffeeTicketActivity.class);
@@ -93,6 +125,13 @@ public class CoffeeTicketActivityServiceImpl extends BaseServiceImpl<CoffeeTicke
if (activity == null) {
return "活动不存在";
}
if (!Boolean.TRUE.equals(activity.getEnabled())) {
return "活动未开启";
}
String scopeMsg = checkH5ActivityUserScope(activity, SecurityUtil.getUserId());
if (scopeMsg != null) {
return scopeMsg;
}
Date now = new Date();
if (activity.getActivityStartDate() == null || activity.getActivityEndDate() == null) {
return "活动周期未配置";
@@ -126,6 +165,20 @@ public class CoffeeTicketActivityServiceImpl extends BaseServiceImpl<CoffeeTicke
return null;
}
@Override
public String checkH5ActivityUserScope(CoffeeTicketActivity activity, String userId) {
if (activity == null) {
return "活动不存在";
}
if (activity.getActivityGroupId() == null) {
return "活动未配置可报名人员范围";
}
if (!activityBasicScopeService.isUserInGroup(activity.getActivityGroupId(), userId)) {
return "您不在本活动可报名人员范围内";
}
return null;
}
@Override
@Aop(TransAop.READ_COMMITTED)
public CoffeeTicketRecord grabH5Ticket(String id, Integer ticketNum) {
@@ -169,6 +222,35 @@ public class CoffeeTicketActivityServiceImpl extends BaseServiceImpl<CoffeeTicke
return vo;
}
/**
* 按当前查询条件先收集活动分组,再复用分组服务过滤出当前用户可参与的分组ID。
*
* @param cnd H5列表搜索条件,包含关键字和活动状态筛选
* @return List<Integer>,当前登录用户在人员范围内的活动分组ID列表
*/
private List<Integer> buildCurrentUserVisibleGroupIds(Cnd cnd) {
List<Integer> groupIds = dao().query(CoffeeTicketActivity.class, cnd)
.stream()
.map(CoffeeTicketActivity::getActivityGroupId)
.filter(groupId -> groupId != null)
.distinct()
.toList();
return activityBasicScopeService.filterGroupIdsByUser(groupIds, SecurityUtil.getUserId());
}
/**
* 同步移动端首页入口。活动开启时写入首页,关闭时删除首页入口。
*
* @param activity 咖啡抢票活动,包含首页展示和跳转所需字段
*/
private void syncHomeActivity(CoffeeTicketActivity activity) {
if (Boolean.TRUE.equals(activity.getEnabled())) {
dao().insertOrUpdate(activity.covertToSysHomeActivity());
return;
}
dao().delete(Sys_home_activity.class, activity.getId());
}
/**
* 将 Java 星期值转换为页面保存的 1-7 格式,其中 1 表示周一、7 表示周日。
*