diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/controller/PointsMallUserPointsGrantPlanController.java b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/controller/PointsMallUserPointsGrantPlanController.java new file mode 100644 index 00000000..a991179f --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/controller/PointsMallUserPointsGrantPlanController.java @@ -0,0 +1,68 @@ +package com.budwk.app.zhgh.pointsmall.pointsgrant.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.budwk.app.base.annotation.SLog; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.pointsmall.pointsgrant.models.PointsMallUserPointsGrantPlan; +import com.budwk.app.zhgh.pointsmall.pointsgrant.param.PointsMallUserPointsGrantPlanPageParam; +import com.budwk.app.zhgh.pointsmall.pointsgrant.service.PointsMallUserPointsGrantPlanService; +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; + +@IocBean +@Ok("json:full") +@At("/platform/zhgh/points-mall/pointsgrant") +public class PointsMallUserPointsGrantPlanController { + + @Inject + private PointsMallUserPointsGrantPlanService grantPlanService; + + @At("") + @Ok("beetl:/platform/zhgh/points-mall/pointsgrant/index.html") + @SaCheckPermission("points.mall.pointsgrant") + public void index() { + } + + @At + @SaCheckPermission("points.mall.pointsgrant") + public Result pageData(PointsMallUserPointsGrantPlanPageParam param) { + return Result.success(grantPlanService.page(param)); + } + + @At + @SLog(tag = "积分发放", msg = "创建发放计划") + @SaCheckPermission("points.mall.pointsgrant") + public Result doAdd(PointsMallUserPointsGrantPlan plan) { + try { + grantPlanService.createPlan(plan); + return Result.success(); + } catch (IllegalArgumentException e) { + return Result.error(e.getMessage()); + } + } + + @At + @SLog(tag = "积分发放", msg = "执行发放计划") + @SaCheckPermission("points.mall.pointsgrant") + public Result startPlan(@Param("id") String id) { + try { + return Result.success(grantPlanService.startPlan(id)); + } catch (IllegalArgumentException e) { + return Result.error(e.getMessage()); + } + } + + @At + @SLog(tag = "积分发放", msg = "取消发放计划") + @SaCheckPermission("points.mall.pointsgrant") + public Result cancelPlan(@Param("id") String id) { + try { + return Result.success(grantPlanService.cancelPlan(id)); + } catch (IllegalArgumentException e) { + return Result.error(e.getMessage()); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/models/PointsMallUserPointsGrantPlan.java b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/models/PointsMallUserPointsGrantPlan.java new file mode 100644 index 00000000..28888051 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/models/PointsMallUserPointsGrantPlan.java @@ -0,0 +1,71 @@ +package com.budwk.app.zhgh.pointsmall.pointsgrant.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.Default; +import org.nutz.dao.entity.annotation.Name; +import org.nutz.dao.entity.annotation.Table; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.io.Serializable; +import java.math.BigDecimal; + +@Data +@EqualsAndHashCode(callSuper = true) +@Table("points_mall_user_points_grant_plan") +@Comment("积分商城积分发放计划") +public class PointsMallUserPointsGrantPlan extends BaseModel implements Serializable { + + @Name + @Column + @Comment("ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(uu32 = true) + private String id; + + @Column + @Comment("计划名称") + @ColDefine(type = ColType.VARCHAR, width = 100) + private String planName; + + @Column + @Comment("计划描述") + @ColDefine(type = ColType.VARCHAR, width = 1000) + private String planDescription; + + @Column + @Comment("发放模式:1手动发放,2定时发放") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String grantMode; + + @Column + @Comment("发放时间") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String grantTime; + + @Column + @Comment("Cron表达式") + @ColDefine(type = ColType.VARCHAR, width = 100) + private String cronExp; + + @Column + @Comment("计划状态") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String status; + + @Column + @Comment("发放用户ID列表") + @ColDefine(type = ColType.VARCHAR, customType = "mediumtext") + private String userIdList; + + @Column + @Comment("发放积分") + @Default("0") + @ColDefine(customType = "decimal(18,2)") + private BigDecimal grantPoints; +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/param/PointsMallUserPointsGrantPlanPageParam.java b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/param/PointsMallUserPointsGrantPlanPageParam.java new file mode 100644 index 00000000..5449e685 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/param/PointsMallUserPointsGrantPlanPageParam.java @@ -0,0 +1,13 @@ +package com.budwk.app.zhgh.pointsmall.pointsgrant.param; + +import com.budwk.app.base.param.PageForm; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class PointsMallUserPointsGrantPlanPageParam extends PageForm { + + private String planName; + private String status; +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/service/PointsMallUserPointsGrantPlanService.java b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/service/PointsMallUserPointsGrantPlanService.java new file mode 100644 index 00000000..010200ab --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/service/PointsMallUserPointsGrantPlanService.java @@ -0,0 +1,25 @@ +package com.budwk.app.zhgh.pointsmall.pointsgrant.service; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.pointsmall.pointsgrant.models.PointsMallUserPointsGrantPlan; +import com.budwk.app.zhgh.pointsmall.pointsgrant.param.PointsMallUserPointsGrantPlanPageParam; + +public interface PointsMallUserPointsGrantPlanService extends BaseService { + + String STATUS_PENDING = "待执行"; + String STATUS_IN_PROGRESS = "执行中"; + String STATUS_COMPLETED = "已完成"; + String STATUS_CANCELLED = "已取消"; + String STATUS_FAILED = "已失败"; + + Pagination page(PointsMallUserPointsGrantPlanPageParam param); + + void createPlan(PointsMallUserPointsGrantPlan plan); + + boolean startPlan(String id); + + boolean cancelPlan(String id); + + int scheduledGrantPlan(); +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/service/impl/PointsMallUserPointsGrantPlanServiceImpl.java b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/service/impl/PointsMallUserPointsGrantPlanServiceImpl.java new file mode 100644 index 00000000..6cf94fce --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/pointsgrant/service/impl/PointsMallUserPointsGrantPlanServiceImpl.java @@ -0,0 +1,128 @@ +package com.budwk.app.zhgh.pointsmall.pointsgrant.service.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.date.DateUtil; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.service.impl.BaseServiceImpl; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsBatchParam; +import com.budwk.app.zhgh.pointsmall.points.service.PointsMallUserPointsService; +import com.budwk.app.zhgh.pointsmall.pointsgrant.models.PointsMallUserPointsGrantPlan; +import com.budwk.app.zhgh.pointsmall.pointsgrant.param.PointsMallUserPointsGrantPlanPageParam; +import com.budwk.app.zhgh.pointsmall.pointsgrant.service.PointsMallUserPointsGrantPlanService; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.math.BigDecimal; +import java.util.List; + +@IocBean(args = {"refer:dao"}) +public class PointsMallUserPointsGrantPlanServiceImpl extends BaseServiceImpl implements PointsMallUserPointsGrantPlanService { + + @Inject + private PointsMallUserPointsService pointsMallUserPointsService; + + public PointsMallUserPointsGrantPlanServiceImpl(Dao dao) { + super(dao); + } + + @Override + public Pagination page(PointsMallUserPointsGrantPlanPageParam param) { + Cnd cnd = Cnd.where("delFlag", "=", false); + if (StrUtil.isNotBlank(param.getPlanName())) { + cnd.and("planName", "like", "%" + param.getPlanName() + "%"); + } + if (StrUtil.isNotBlank(param.getStatus())) { + cnd.and("status", "=", param.getStatus()); + } + cnd.desc("createdAt"); + return listPage(param.getPageNumber(), param.getPageSize(), PointsMallUserPointsGrantPlan.class, cnd); + } + + @Override + public void createPlan(PointsMallUserPointsGrantPlan plan) { + checkPlan(plan); + plan.setStatus(STATUS_PENDING); + insert(plan); + } + + @Override + public boolean startPlan(String id) { + if (StrUtil.isBlank(id)) { + throw new IllegalArgumentException("计划ID不能为空"); + } + PointsMallUserPointsGrantPlan plan = fetch(id); + if (plan == null || Boolean.TRUE.equals(plan.getDelFlag())) { + throw new IllegalArgumentException("计划不存在"); + } + if (!STATUS_PENDING.equals(plan.getStatus())) { + throw new IllegalArgumentException("计划未处于待执行状态,无法启动"); + } + update(Chain.make("status", STATUS_IN_PROGRESS), Cnd.where("id", "=", id)); + PointsMallUserPointsBatchParam batchParam = new PointsMallUserPointsBatchParam(); + batchParam.setUserIds(plan.getUserIdList()); + batchParam.setPoints(plan.getGrantPoints()); + batchParam.setRemark("积分发放计划:" + plan.getPlanName()); + try { + pointsMallUserPointsService.batchGrant(batchParam); + update(Chain.make("status", STATUS_COMPLETED), Cnd.where("id", "=", id)); + } catch (RuntimeException e) { + update(Chain.make("status", STATUS_FAILED), Cnd.where("id", "=", id)); + throw e; + } + return true; + } + + @Override + public boolean cancelPlan(String id) { + if (StrUtil.isBlank(id)) { + throw new IllegalArgumentException("计划ID不能为空"); + } + PointsMallUserPointsGrantPlan plan = fetch(id); + if (plan == null || Boolean.TRUE.equals(plan.getDelFlag())) { + throw new IllegalArgumentException("计划不存在"); + } + if (!STATUS_PENDING.equals(plan.getStatus())) { + throw new IllegalArgumentException("计划未处于待执行状态,无法取消"); + } + update(Chain.make("status", STATUS_CANCELLED), Cnd.where("id", "=", id)); + return true; + } + + @Override + public int scheduledGrantPlan() { + List plans = query(Cnd.where("delFlag", "=", false) + .and("status", "=", STATUS_PENDING) + .and("grantMode", "=", "2") + .and("grantTime", "<=", DateUtil.now())); + plans.forEach(plan -> startPlan(plan.getId())); + return plans.size(); + } + + private void checkPlan(PointsMallUserPointsGrantPlan plan) { + if (plan == null) { + throw new IllegalArgumentException("计划信息不能为空"); + } + if (StrUtil.isBlank(plan.getPlanName())) { + throw new IllegalArgumentException("计划名称不能为空"); + } + if (StrUtil.isBlank(plan.getGrantMode())) { + throw new IllegalArgumentException("发放模式不能为空"); + } + if (!"1".equals(plan.getGrantMode()) && !"2".equals(plan.getGrantMode())) { + throw new IllegalArgumentException("发放模式不正确"); + } + if ("2".equals(plan.getGrantMode()) && StrUtil.isBlank(plan.getGrantTime())) { + throw new IllegalArgumentException("定时发放时间不能为空"); + } + if (StrUtil.isBlank(plan.getUserIdList())) { + throw new IllegalArgumentException("发放用户不能为空"); + } + BigDecimal grantPoints = plan.getGrantPoints(); + if (grantPoints == null || grantPoints.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("发放积分必须大于0"); + } + } +} diff --git a/src/main/resources/views/platform/zhgh/points-mall/pointsgrant/index.html b/src/main/resources/views/platform/zhgh/points-mall/pointsgrant/index.html new file mode 100644 index 00000000..e590fd0c --- /dev/null +++ b/src/main/resources/views/platform/zhgh/points-mall/pointsgrant/index.html @@ -0,0 +1,199 @@ + +
+ + + + + + + + + + + + + + + + + + + + 新建 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 手动发放 + 定时发放 + + + + + + + + + + + + + + 取消 + 保存 + + +
+ + +