Skip to content

Commit

Permalink
perf: 团购代码优化
Browse files Browse the repository at this point in the history
  • Loading branch information
linlinjava committed Dec 8, 2019
1 parent eff4862 commit d6f243d
Show file tree
Hide file tree
Showing 36 changed files with 1,163 additions and 931 deletions.
2 changes: 1 addition & 1 deletion doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2787,7 +2787,7 @@ API应该存在版本控制,以保证兼容性。
请求参数

cartId: 购物车ID,如果0则是购物车商品,如果非0则是立即单一商品
grouponRulesId: 团购活动ID,如果是团购商品则需要设置具体团购活动ID
grouponRulesId: 团购规则ID,如果是团购商品则需要设置具体团购规则ID

响应内容

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,55 +84,4 @@ public void checkOrderComment() {
}
}
}

/**
* 团购订单拼团超期自动取消
*/
@Scheduled(initialDelay = 5000, fixedDelay = 10 * 60 * 1000)
@Transactional(rollbackFor = Exception.class)
public void checkGrouponOrderTimeout() {
logger.info("系统开启定时任务检查团购订单是否已经拼团超期自动取消订单");

List<LitemallGroupon> grouponList = grouponService.queryJoinRecord(0);
for (LitemallGroupon groupon : grouponList) {
LitemallGrouponRules rules = rulesService.queryById(groupon.getRulesId());
if (rulesService.isExpired(rules)) {
List<LitemallGroupon> subGrouponList = grouponService.queryJoinRecord(groupon.getId());
for (LitemallGroupon subGroupon : subGrouponList) {
cancelGrouponScope(subGroupon);
}

cancelGrouponScope(groupon);
}
}
}

private void cancelGrouponScope(LitemallGroupon groupon) {
LitemallOrder order = orderService.findById(groupon.getOrderId());
if (order.getOrderStatus().equals(OrderUtil.STATUS_PAY_GROUPON)) {
order.setOrderStatus(OrderUtil.STATUS_TIMEOUT_GROUPON);
order.setEndTime(LocalDateTime.now());

cancelOrderScope(order);

logger.info("团购订单 ID" + order.getId() + " 已经拼团超期自动取消订单");
}
}

private void cancelOrderScope(LitemallOrder order) {
if (orderService.updateWithOptimisticLocker(order) == 0) {
throw new RuntimeException("更新数据已失效");
}

// 商品货品数量增加
Integer orderId = order.getId();
List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
for (LitemallOrderGoods orderGoods : orderGoodsList) {
Integer productId = orderGoods.getProductId();
Short number = orderGoods.getNumber();
if (productService.addStock(productId, number) == 0) {
throw new RuntimeException("商品货品库存增加失败");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public Object refund(String body) {

// 设置订单取消状态
order.setOrderStatus(OrderUtil.STATUS_REFUND_CONFIRM);
order.setEndTime(LocalDateTime.now());
if (orderService.updateWithOptimisticLocker(order) == 0) {
throw new RuntimeException("更新数据已失效");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.linlinjava.litemall.admin.task;

import org.linlinjava.litemall.core.task.TaskService;
import org.linlinjava.litemall.db.domain.LitemallGrouponRules;
import org.linlinjava.litemall.db.service.LitemallGrouponRulesService;
import org.linlinjava.litemall.db.util.GrouponConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;

@Component
public class AdminTaskStartupRunner implements ApplicationRunner {

@Autowired
private LitemallGrouponRulesService rulesService;
@Autowired
private TaskService taskService;

@Override
public void run(ApplicationArguments args) throws Exception {
List<LitemallGrouponRules> grouponRulesList = rulesService.queryByStatus(GrouponConstant.RULE_STATUS_ON);
for(LitemallGrouponRules grouponRules : grouponRulesList){
LocalDateTime now = LocalDateTime.now();
LocalDateTime expire = grouponRules.getExpireTime();
if(expire.isBefore(now)) {
// 已经过期,则加入延迟队列
taskService.addTask(new GrouponRuleExpiredTask(grouponRules.getId(), 0));
}
else{
// 还没过期,则加入延迟队列
long delay = ChronoUnit.MILLIS.between(now, expire);
taskService.addTask(new GrouponRuleExpiredTask(grouponRules.getId(), delay));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.linlinjava.litemall.admin.task;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.task.Task;
import org.linlinjava.litemall.core.util.BeanUtil;
import org.linlinjava.litemall.db.domain.LitemallGroupon;
import org.linlinjava.litemall.db.domain.LitemallGrouponRules;
import org.linlinjava.litemall.db.domain.LitemallOrder;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.GrouponConstant;
import org.linlinjava.litemall.db.util.OrderUtil;

import java.util.List;

public class GrouponRuleExpiredTask extends Task {
private final Log logger = LogFactory.getLog(GrouponRuleExpiredTask.class);
private int grouponRuleId = -1;

public GrouponRuleExpiredTask(Integer grouponRuleId, long delayInMilliseconds){
super("GrouponRuleExpiredTask-" + grouponRuleId, delayInMilliseconds);
this.grouponRuleId = grouponRuleId;
}

@Override
public void run() {
logger.info("系统开始处理延时任务---团购规则过期---" + this.grouponRuleId);

LitemallOrderService orderService = BeanUtil.getBean(LitemallOrderService.class);
LitemallGrouponService grouponService = BeanUtil.getBean(LitemallGrouponService.class);
LitemallGrouponRulesService grouponRulesService = BeanUtil.getBean(LitemallGrouponRulesService.class);

LitemallGrouponRules grouponRules = grouponRulesService.findById(grouponRuleId);
if(grouponRules == null){
return;
}
if(!grouponRules.getStatus().equals(GrouponConstant.RULE_STATUS_ON)){
return;
}

// 团购活动取消
grouponRules.setStatus(GrouponConstant.RULE_STATUS_DOWN_EXPIRE);
grouponRulesService.updateById(grouponRules);

List<LitemallGroupon> grouponList = grouponService.queryByRuleId(grouponRuleId);
// 用户团购处理
for(LitemallGroupon groupon : grouponList){
Short status = groupon.getStatus();
LitemallOrder order = orderService.findById(groupon.getOrderId());
if(status.equals(GrouponConstant.STATUS_NONE)){
groupon.setStatus(GrouponConstant.STATUS_FAIL);
grouponService.updateById(groupon);
}
else if(status.equals(GrouponConstant.STATUS_ON)){
// 如果团购进行中
// (1) 团购设置团购失败等待退款状态
groupon.setStatus(GrouponConstant.STATUS_FAIL);
grouponService.updateById(groupon);
// (2) 团购订单申请退款
if(OrderUtil.isPayStatus(order)) {
order.setOrderStatus(OrderUtil.STATUS_REFUND);
orderService.updateWithOptimisticLocker(order);
}
}
}
logger.info("系统结束处理延时任务---团购规则过期---" + this.grouponRuleId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@ public class AdminResponseCode {
public static final Integer ROLE_NAME_EXIST = 640;
public static final Integer ROLE_SUPER_SUPERMISSION = 641;
public static final Integer ROLE_USER_EXIST = 642;
public static final Integer GROUPON_GOODS_UNKNOWN = 650;
public static final Integer GROUPON_GOODS_EXISTED = 651;
public static final Integer GROUPON_GOODS_OFFLINE = 652;

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.linlinjava.litemall.admin.annotation.RequiresPermissionsDesc;
import org.linlinjava.litemall.admin.task.GrouponRuleExpiredTask;
import org.linlinjava.litemall.admin.util.AdminResponseCode;
import org.linlinjava.litemall.core.task.TaskService;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.validator.Order;
import org.linlinjava.litemall.core.validator.Sort;
Expand All @@ -13,12 +16,15 @@
import org.linlinjava.litemall.db.service.LitemallGoodsService;
import org.linlinjava.litemall.db.service.LitemallGrouponRulesService;
import org.linlinjava.litemall.db.service.LitemallGrouponService;
import org.linlinjava.litemall.db.util.GrouponConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -36,6 +42,8 @@ public class AdminGrouponController {
private LitemallGoodsService goodsService;
@Autowired
private LitemallGrouponService grouponService;
@Autowired
private TaskService taskService;

@RequiresPermissions("admin:groupon:read")
@RequiresPermissionsDesc(menu = {"推广管理", "团购管理"}, button = "详情")
Expand All @@ -52,7 +60,7 @@ public Object listRecord(String grouponId,
try {
Map<String, Object> recordData = new HashMap<>();
List<LitemallGroupon> subGrouponList = grouponService.queryJoinRecord(groupon.getId());
LitemallGrouponRules rules = rulesService.queryById(groupon.getRulesId());
LitemallGrouponRules rules = rulesService.findById(groupon.getRulesId());
LitemallGoods goods = goodsService.findById(rules.getGoodsId());

recordData.put("groupon", groupon);
Expand Down Expand Up @@ -111,6 +119,14 @@ public Object update(@RequestBody LitemallGrouponRules grouponRules) {
return error;
}

LitemallGrouponRules rules = rulesService.findById(grouponRules.getId());
if(rules == null){
return ResponseUtil.badArgumentValue();
}
if(!rules.getStatus().equals(GrouponConstant.RULE_STATUS_ON)){
return ResponseUtil.fail(AdminResponseCode.GROUPON_GOODS_OFFLINE, "团购已经下线");
}

Integer goodsId = grouponRules.getGoodsId();
LitemallGoods goods = goodsService.findById(goodsId);
if (goods == null) {
Expand Down Expand Up @@ -139,14 +155,23 @@ public Object create(@RequestBody LitemallGrouponRules grouponRules) {
Integer goodsId = grouponRules.getGoodsId();
LitemallGoods goods = goodsService.findById(goodsId);
if (goods == null) {
return ResponseUtil.badArgumentValue();
return ResponseUtil.fail(AdminResponseCode.GROUPON_GOODS_UNKNOWN, "团购商品不存在");
}
if(rulesService.countByGoodsId(goodsId) > 0){
return ResponseUtil.fail(AdminResponseCode.GROUPON_GOODS_EXISTED, "团购商品已经存在");
}

grouponRules.setGoodsName(goods.getName());
grouponRules.setPicUrl(goods.getPicUrl());

grouponRules.setStatus(GrouponConstant.RULE_STATUS_ON);
rulesService.createRules(grouponRules);

LocalDateTime now = LocalDateTime.now();
LocalDateTime expire = grouponRules.getExpireTime();
long delay = ChronoUnit.MILLIS.between(now, expire);
// 团购过期任务
taskService.addTask(new GrouponRuleExpiredTask(grouponRules.getId(), delay));

return ResponseUtil.ok(grouponRules);
}

Expand Down
49 changes: 33 additions & 16 deletions litemall-admin/src/views/promotion/grouponRule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,44 @@

<!-- 查询和其他操作 -->
<div class="filter-container">
<el-input v-model="listQuery.goodsId" clearable class="filter-item" style="width: 200px;" placeholder="请输入商品编号"/>
<el-input v-model="listQuery.goodsId" clearable class="filter-item" style="width: 200px;" placeholder="请输入商品编号" />
<el-button v-permission="['GET /admin/groupon/list']" class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
<el-button v-permission="['POST /admin/groupon/create']" class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
<el-button
:loading="downloadLoading"
class="filter-item"
type="primary"
icon="el-icon-download"
@click="handleDownload">导出
@click="handleDownload"
>导出
</el-button>
</div>

<!-- 查询结果 -->
<el-table v-loading="listLoading" :data="list" element-loading-text="正在查询中。。。" border fit highlight-current-row>
<el-table-column align="center" label="商品ID" prop="goodsId"/>
<el-table-column align="center" label="团购规则ID" prop="id" />

<el-table-column align="center" min-width="100" label="名称" prop="goodsName"/>
<el-table-column align="center" label="商品ID" prop="goodsId" />

<el-table-column align="center" min-width="100" label="名称" prop="goodsName" />

<el-table-column align="center" property="picUrl" label="图片">
<template slot-scope="scope">
<img :src="scope.row.picUrl" width="40">
</template>
</el-table-column>

<el-table-column align="center" label="团购优惠" prop="discount"/>
<el-table-column align="center" label="团购优惠" prop="discount" />

<el-table-column align="center" label="团购要求" prop="discountMember"/>
<el-table-column align="center" label="团购要求" prop="discountMember" />

<el-table-column align="center" label="开始时间" prop="addTime"/>
<el-table-column align="center" label="状态" prop="status">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 0 ? 'success' : 'error' ">{{ statusMap[scope.row.status] }}</el-tag>
</template>
</el-table-column>

<el-table-column align="center" label="结束时间" prop="expireTime"/>
<el-table-column align="center" label="结束时间" prop="expireTime" />

<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
<template slot-scope="scope">
Expand All @@ -51,23 +58,25 @@
:model="dataForm"
status-icon
label-position="left"
label-width="100px"
style="width: 400px; margin-left:50px;">
label-width="120px"
style="width: 400px; margin-left:50px;"
>
<el-form-item label="商品ID" prop="goodsId">
<el-input v-model="dataForm.goodsId"/>
<el-input v-model="dataForm.goodsId" />
</el-form-item>
<el-form-item label="团购折扣" prop="discount">
<el-input v-model="dataForm.discount"/>
<el-input v-model="dataForm.discount" />
</el-form-item>
<el-form-item label="团购人数要求" prop="discountMember">
<el-input v-model="dataForm.discountMember"/>
<el-input v-model="dataForm.discountMember" />
</el-form-item>
<el-form-item label="过期时间" prop="expireTime">
<el-date-picker
v-model="dataForm.expireTime"
type="datetime"
placeholder="选择日期"
value-format="yyyy-MM-dd HH:mm:ss"/>
value-format="yyyy-MM-dd HH:mm:ss"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
Expand All @@ -80,7 +89,7 @@
<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />

<el-tooltip placement="top" content="返回顶部">
<back-to-top :visibility-height="100"/>
<back-to-top :visibility-height="100" />
</el-tooltip>

</div>
Expand Down Expand Up @@ -120,8 +129,16 @@ export default {
update: '编辑',
create: '创建'
},
statusMap: [
'正常',
'到期下线',
'提前下线'
],
rules: {
goodsId: [{ required: true, message: '商品不能为空', trigger: 'blur' }]
goodsId: [{ required: true, message: '商品不能为空', trigger: 'blur' }],
discount: [{ required: true, message: '团购折扣不能为空', trigger: 'blur' }],
discountMember: [{ required: true, message: '团购人数不能为空', trigger: 'blur' }],
expireTime: [{ required: true, message: '过期时间不能为空', trigger: 'blur' }]
}
}
},
Expand Down
Loading

0 comments on commit d6f243d

Please sign in to comment.