feat: 用户积分管理
This commit is contained in:
+114
@@ -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<String> idList = StrUtil.split(ids, ',');
|
||||
if (idList.isEmpty()) {
|
||||
return Result.error("请选择需要删除的数据");
|
||||
}
|
||||
pointsMallUserPointsService.deleteByIds(idList);
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+61
@@ -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;
|
||||
}
|
||||
+13
@@ -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;
|
||||
}
|
||||
+13
@@ -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;
|
||||
}
|
||||
+13
@@ -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;
|
||||
}
|
||||
+16
@@ -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;
|
||||
}
|
||||
+31
@@ -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<PointsMallUserPoints> {
|
||||
|
||||
Pagination<Record> page(PointsMallUserPointsPageParam param);
|
||||
|
||||
Pagination<Record> logPage(PointsMallUserPointsLogPageParam param);
|
||||
|
||||
List<String> userIds(PointsMallUserPointsPageParam param);
|
||||
|
||||
void grant(PointsMallUserPointsChangeParam param);
|
||||
|
||||
void deduction(PointsMallUserPointsChangeParam param);
|
||||
|
||||
void batchGrant(PointsMallUserPointsBatchParam param);
|
||||
|
||||
void batchDeduction(PointsMallUserPointsBatchParam param);
|
||||
|
||||
void deleteByIds(List<String> ids);
|
||||
}
|
||||
+201
@@ -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<PointsMallUserPoints> implements PointsMallUserPointsService {
|
||||
|
||||
public PointsMallUserPointsServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<Record> 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<Record> 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<String> 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<String> 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<String> 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<String> 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<String> splitUserIds(String userIds) {
|
||||
List<String> list = Arrays.stream(StrUtil.blankToDefault(userIds, "").split(","))
|
||||
.map(String::trim)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (list.isEmpty()) {
|
||||
throw new IllegalArgumentException("请选择用户");
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user