diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/controller/PointsMallUserPointsController.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/controller/PointsMallUserPointsController.java new file mode 100644 index 00000000..6067ec3b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/controller/PointsMallUserPointsController.java @@ -0,0 +1,114 @@ +package com.budwk.app.zhgh.pointsmall.points.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.annotation.SLog; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsBatchParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsChangeParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsLogPageParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsPageParam; +import com.budwk.app.zhgh.pointsmall.points.service.PointsMallUserPointsService; +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 java.util.List; + +@IocBean +@Ok("json:full") +@At("/platform/zhgh/points-mall/points") +public class PointsMallUserPointsController { + + @Inject + private PointsMallUserPointsService pointsMallUserPointsService; + + @At("") + @Ok("beetl:/platform/zhgh/points-mall/points/index.html") + @SaCheckPermission("points.mall.points") + public void index() { + } + + @At + @SaCheckPermission("points.mall.points") + public Result pageData(PointsMallUserPointsPageParam param) { + return Result.success(pointsMallUserPointsService.page(param)); + } + + @At + @SaCheckPermission("points.mall.points") + public Result logPage(PointsMallUserPointsLogPageParam param) { + if (StrUtil.isBlank(param.getUserId())) { + return Result.error("用户ID不能为空"); + } + return Result.success(pointsMallUserPointsService.logPage(param)); + } + + @At + @SaCheckPermission("points.mall.points") + public Result userIds(PointsMallUserPointsPageParam param) { + return Result.success(pointsMallUserPointsService.userIds(param)); + } + + @At + @SLog(tag = "用户积分管理", msg = "增加积分") + @SaCheckPermission("points.mall.points") + public Result doGrant(PointsMallUserPointsChangeParam param) { + try { + pointsMallUserPointsService.grant(param); + return Result.success(); + } catch (IllegalArgumentException e) { + return Result.error(e.getMessage()); + } + } + + @At + @SLog(tag = "用户积分管理", msg = "扣减积分") + @SaCheckPermission("points.mall.points") + public Result doDeduction(PointsMallUserPointsChangeParam param) { + try { + pointsMallUserPointsService.deduction(param); + return Result.success(); + } catch (IllegalArgumentException e) { + return Result.error(e.getMessage()); + } + } + + @At + @SLog(tag = "用户积分管理", msg = "批量增加积分") + @SaCheckPermission("points.mall.points") + public Result batchGrant(PointsMallUserPointsBatchParam param) { + try { + pointsMallUserPointsService.batchGrant(param); + return Result.success(); + } catch (IllegalArgumentException e) { + return Result.error(e.getMessage()); + } + } + + @At + @SLog(tag = "用户积分管理", msg = "批量扣减积分") + @SaCheckPermission("points.mall.points") + public Result batchDeduction(PointsMallUserPointsBatchParam param) { + try { + pointsMallUserPointsService.batchDeduction(param); + return Result.success(); + } catch (IllegalArgumentException e) { + return Result.error(e.getMessage()); + } + } + + @At + @SLog(tag = "用户积分管理", msg = "删除积分记录") + @SaCheckPermission("points.mall.points") + public Result doDelete(@Param("ids") String ids) { + List idList = StrUtil.split(ids, ','); + if (idList.isEmpty()) { + return Result.error("请选择需要删除的数据"); + } + pointsMallUserPointsService.deleteByIds(idList); + return Result.success(); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/models/PointsMallUserPoints.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/models/PointsMallUserPoints.java new file mode 100644 index 00000000..458572bb --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/models/PointsMallUserPoints.java @@ -0,0 +1,59 @@ +package com.budwk.app.zhgh.pointsmall.points.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") +@Comment("积分商城用户积分") +public class PointsMallUserPoints extends BaseModel implements Serializable { + + @Name + @Column + @Comment("ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(uu32 = true) + private String id; + + @Column + @Comment("用户ID") + @ColDefine(type = ColType.VARCHAR, width = 64) + private String userId; + + @Column + @Comment("总积分") + @Default("0") + @ColDefine(customType = "decimal(18,2)") + private BigDecimal totalPoints; + + @Column + @Comment("已用积分") + @Default("0") + @ColDefine(customType = "decimal(18,2)") + private BigDecimal usedPoints; + + @Column + @Comment("可用积分") + @Default("0") + @ColDefine(customType = "decimal(18,2)") + private BigDecimal availablePoints; + + @Column + @Comment("锁定积分") + @Default("0") + @ColDefine(customType = "decimal(18,2)") + private BigDecimal lockPoints; +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/models/PointsMallUserPointsLog.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/models/PointsMallUserPointsLog.java new file mode 100644 index 00000000..c634c30b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/models/PointsMallUserPointsLog.java @@ -0,0 +1,61 @@ +package com.budwk.app.zhgh.pointsmall.points.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_log") +@Comment("积分商城用户积分流水") +public class PointsMallUserPointsLog extends BaseModel implements Serializable { + + @Name + @Column + @Comment("ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(uu32 = true) + private String id; + + @Column + @Comment("用户ID") + @ColDefine(type = ColType.VARCHAR, width = 64) + private String userId; + + @Column + @Comment("变动积分") + @Default("0") + @ColDefine(customType = "decimal(18,2)") + private BigDecimal changeAmount; + + @Column + @Comment("变动类型") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String changeType; + + @Column + @Comment("子订单ID") + @ColDefine(type = ColType.VARCHAR, width = 64) + private String subOrderId; + + @Column + @Comment("消息模板ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String templateId; + + @Column + @Comment("备注") + @ColDefine(type = ColType.VARCHAR, width = 1000) + private String remark; +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsBatchParam.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsBatchParam.java new file mode 100644 index 00000000..8f45872c --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsBatchParam.java @@ -0,0 +1,13 @@ +package com.budwk.app.zhgh.pointsmall.points.param; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class PointsMallUserPointsBatchParam { + + private String userIds; + private BigDecimal points; + private String remark; +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsChangeParam.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsChangeParam.java new file mode 100644 index 00000000..16103f0c --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsChangeParam.java @@ -0,0 +1,13 @@ +package com.budwk.app.zhgh.pointsmall.points.param; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class PointsMallUserPointsChangeParam { + + private String userId; + private BigDecimal points; + private String remark; +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsLogPageParam.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsLogPageParam.java new file mode 100644 index 00000000..3eee042f --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsLogPageParam.java @@ -0,0 +1,13 @@ +package com.budwk.app.zhgh.pointsmall.points.param; + +import com.budwk.app.base.param.PageForm; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class PointsMallUserPointsLogPageParam extends PageForm { + + private String userId; + private String changeType; +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsPageParam.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsPageParam.java new file mode 100644 index 00000000..5f973c27 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/param/PointsMallUserPointsPageParam.java @@ -0,0 +1,16 @@ +package com.budwk.app.zhgh.pointsmall.points.param; + +import com.budwk.app.base.param.PageForm; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class PointsMallUserPointsPageParam extends PageForm { + + private String account; + private String realName; + private String mobile; + private String unitId; + private Boolean member; +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/service/PointsMallUserPointsService.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/service/PointsMallUserPointsService.java new file mode 100644 index 00000000..684ae490 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/service/PointsMallUserPointsService.java @@ -0,0 +1,31 @@ +package com.budwk.app.zhgh.pointsmall.points.service; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.pointsmall.points.models.PointsMallUserPoints; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsBatchParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsChangeParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsLogPageParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsPageParam; +import org.nutz.dao.entity.Record; + +import java.util.List; + +public interface PointsMallUserPointsService extends BaseService { + + Pagination page(PointsMallUserPointsPageParam param); + + Pagination logPage(PointsMallUserPointsLogPageParam param); + + List userIds(PointsMallUserPointsPageParam param); + + void grant(PointsMallUserPointsChangeParam param); + + void deduction(PointsMallUserPointsChangeParam param); + + void batchGrant(PointsMallUserPointsBatchParam param); + + void batchDeduction(PointsMallUserPointsBatchParam param); + + void deleteByIds(List ids); +} diff --git a/src/main/java/com/budwk/app/zhgh/pointsmall/points/service/impl/PointsMallUserPointsServiceImpl.java b/src/main/java/com/budwk/app/zhgh/pointsmall/points/service/impl/PointsMallUserPointsServiceImpl.java new file mode 100644 index 00000000..024ca23d --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/pointsmall/points/service/impl/PointsMallUserPointsServiceImpl.java @@ -0,0 +1,201 @@ +package com.budwk.app.zhgh.pointsmall.points.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.service.impl.BaseServiceImpl; +import com.budwk.app.zhgh.pointsmall.points.models.PointsMallUserPoints; +import com.budwk.app.zhgh.pointsmall.points.models.PointsMallUserPointsLog; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsBatchParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsChangeParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsLogPageParam; +import com.budwk.app.zhgh.pointsmall.points.param.PointsMallUserPointsPageParam; +import com.budwk.app.zhgh.pointsmall.points.service.PointsMallUserPointsService; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.entity.Record; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.trans.Atom; +import org.nutz.trans.Trans; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; + +@IocBean(args = {"refer:dao"}) +public class PointsMallUserPointsServiceImpl extends BaseServiceImpl implements PointsMallUserPointsService { + + public PointsMallUserPointsServiceImpl(Dao dao) { + super(dao); + } + + @Override + public Pagination page(PointsMallUserPointsPageParam param) { + Sql sql = Sqls.create(""" + select + p.id, + u.id as userId, + u.loginname as account, + u.username as realName, + u.sex as gender, + u.mobile, + u.member, + u.unitid as unitId, + n.name as unitName, + ifnull(p.totalPoints, 0) as totalPoints, + ifnull(p.usedPoints, 0) as usedPoints, + ifnull(p.availablePoints, 0) as availablePoints, + ifnull(p.lockPoints, 0) as lockPoints + from sys_user u + left join points_mall_user_points p on p.userId = u.id and p.delFlag = false + left join sys_unit n on n.id = u.unitid + $condition + """); + sql.setCondition(userCondition(param).asc("u.loginname")); + return listPageMap(param.getPageNumber(), param.getPageSize(), sql); + } + + @Override + public Pagination logPage(PointsMallUserPointsLogPageParam param) { + Cnd cnd = Cnd.where("l.delFlag", "=", false); + cnd.and("l.userId", "=", param.getUserId()); + if (StrUtil.isNotBlank(param.getChangeType())) { + cnd.and("l.changeType", "=", param.getChangeType()); + } + cnd.desc("l.createdAt"); + Sql sql = Sqls.create(""" + select + l.*, + u.loginname as account, + u.username as realName + from points_mall_user_points_log l + left join sys_user u on u.id = l.userId + $condition + """); + sql.setCondition(cnd); + return listPageMap(param.getPageNumber(), param.getPageSize(), sql); + } + + @Override + public List userIds(PointsMallUserPointsPageParam param) { + Sql sql = Sqls.create("select u.id from sys_user u $condition"); + sql.setCallback(Sqls.callback.strList()); + sql.setCondition(userCondition(param).asc("u.loginname")); + dao().execute(sql); + return sql.getList(String.class); + } + + @Override + public void grant(PointsMallUserPointsChangeParam param) { + BigDecimal points = checkedPoints(param.getPoints()); + Trans.exec((Atom) () -> change(param.getUserId(), points, "GRANT", param.getRemark())); + } + + @Override + public void deduction(PointsMallUserPointsChangeParam param) { + BigDecimal points = checkedPoints(param.getPoints()).negate(); + Trans.exec((Atom) () -> change(param.getUserId(), points, "DEDUCTION", param.getRemark())); + } + + @Override + public void batchGrant(PointsMallUserPointsBatchParam param) { + List userIds = splitUserIds(param.getUserIds()); + BigDecimal points = checkedPoints(param.getPoints()); + Trans.exec((Atom) () -> userIds.forEach(userId -> change(userId, points, "GRANT", param.getRemark()))); + } + + @Override + public void batchDeduction(PointsMallUserPointsBatchParam param) { + List userIds = splitUserIds(param.getUserIds()); + BigDecimal points = checkedPoints(param.getPoints()).negate(); + Trans.exec((Atom) () -> userIds.forEach(userId -> change(userId, points, "DEDUCTION", param.getRemark()))); + } + + @Override + public void deleteByIds(List ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + dao().update(PointsMallUserPoints.class, Chain.make("delFlag", true), Cnd.where("id", "in", ids)); + } + + private Cnd userCondition(PointsMallUserPointsPageParam param) { + Cnd cnd = Cnd.where("u.delFlag", "=", false).and("u.disabled", "=", false); + if (StrUtil.isNotBlank(param.getAccount())) { + cnd.and("u.loginname", "like", "%" + param.getAccount() + "%"); + } + if (StrUtil.isNotBlank(param.getRealName())) { + cnd.and("u.username", "like", "%" + param.getRealName() + "%"); + } + if (StrUtil.isNotBlank(param.getMobile())) { + cnd.and("u.mobile", "=", param.getMobile()); + } + if (StrUtil.isNotBlank(param.getUnitId())) { + cnd.and("u.unitid", "=", param.getUnitId()); + } + if (param.getMember() != null) { + cnd.and("u.member", "=", param.getMember()); + } + return cnd; + } + + private void change(String userId, BigDecimal amount, String changeType, String remark) { + if (StrUtil.isBlank(userId)) { + throw new IllegalArgumentException("用户ID不能为空"); + } + PointsMallUserPoints points = fetch(Cnd.where("userId", "=", userId).and("delFlag", "=", false)); + if (points == null && amount.signum() < 0) { + throw new IllegalArgumentException("积分记录不存在"); + } + if (points == null) { + points = new PointsMallUserPoints(); + points.setUserId(userId); + points.setTotalPoints(amount); + points.setUsedPoints(BigDecimal.ZERO); + points.setAvailablePoints(amount); + points.setLockPoints(BigDecimal.ZERO); + insert(points); + } else { + BigDecimal total = nvl(points.getTotalPoints()).add(amount); + BigDecimal available = nvl(points.getAvailablePoints()).add(amount); + if (amount.signum() < 0 && available.signum() < 0) { + throw new IllegalArgumentException("积分不足,无法扣减"); + } + Chain chain = Chain.make("totalPoints", total).add("availablePoints", available); + update(chain, Cnd.where("id", "=", points.getId())); + } + + PointsMallUserPointsLog log = new PointsMallUserPointsLog(); + log.setUserId(userId); + log.setChangeAmount(amount.abs()); + log.setChangeType(changeType); + log.setRemark(remark); + dao().insert(log); + } + + private BigDecimal checkedPoints(BigDecimal points) { + if (points == null || points.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("请输入有效的积分数量"); + } + return points; + } + + private BigDecimal nvl(BigDecimal value) { + return value == null ? BigDecimal.ZERO : value; + } + + private List splitUserIds(String userIds) { + List list = Arrays.stream(StrUtil.blankToDefault(userIds, "").split(",")) + .map(String::trim) + .filter(StrUtil::isNotBlank) + .distinct() + .toList(); + if (list.isEmpty()) { + throw new IllegalArgumentException("请选择用户"); + } + return list; + } +} diff --git a/src/main/resources/views/platform/zhgh/points-mall/points/index.html b/src/main/resources/views/platform/zhgh/points-mall/points/index.html new file mode 100644 index 00000000..86ee6f26 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/points-mall/points/index.html @@ -0,0 +1,279 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + 批量增加积分 + 批量扣减积分 + 删除积分记录 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 取消 + 保存 + + + + + + + + + + + + + + + 取消 + 确认 + + + + + + + + + + + + + + + + + +
+ + +