Skip to content

Commit

Permalink
优惠券支持分类和指定商品使用 (linlinjava#398)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyson0314 authored Jun 14, 2020
1 parent 92cfea6 commit d611977
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 26 deletions.
195 changes: 179 additions & 16 deletions litemall-admin/src/views/promotion/coupon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

<!-- 查询和其他操作 -->
<div class="filter-container">
<el-input v-model="listQuery.name" clearable class="filter-item" style="width: 200px;" placeholder="请输入优惠券标题"/>
<el-input v-model="listQuery.name" clearable class="filter-item" style="width: 200px;" placeholder="请输入优惠券标题" />
<el-select v-model="listQuery.type" clearable style="width: 200px" class="filter-item" placeholder="请选择优惠券类型">
<el-option v-for="type in typeOptions" :key="type.value" :label="type.label" :value="type.value"/>
<el-option v-for="type in typeOptions" :key="type.value" :label="type.label" :value="type.value" />
</el-select>
<el-select v-model="listQuery.status" clearable style="width: 200px" class="filter-item" placeholder="请选择优惠券状态">
<el-option v-for="type in statusOptions" :key="type.value" :label="type.label" :value="type.value"/>
<el-option v-for="type in statusOptions" :key="type.value" :label="type.label" :value="type.value" />
</el-select>
<el-button v-permission="['GET /admin/coupon/list']" class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
<el-button v-permission="['POST /admin/coupon/create']" class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
Expand All @@ -18,13 +18,13 @@
<!-- 查询结果 -->
<el-table v-loading="listLoading" :data="list" element-loading-text="正在查询中。。。" border fit highlight-current-row>

<el-table-column align="center" label="优惠券ID" prop="id" sortable/>
<el-table-column align="center" label="优惠券ID" prop="id" sortable />

<el-table-column align="center" label="优惠券名称" prop="name"/>
<el-table-column align="center" label="优惠券名称" prop="name" />

<el-table-column align="center" label="介绍" prop="desc"/>
<el-table-column align="center" label="介绍" prop="desc" />

<el-table-column align="center" label="标签" prop="tag"/>
<el-table-column align="center" label="标签" prop="tag" />

<el-table-column align="center" label="最低消费" prop="min">
<template slot-scope="scope">满{{ scope.row.min }}元可用</template>
Expand Down Expand Up @@ -69,13 +69,13 @@
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
<el-form ref="dataForm" :rules="rules" :model="dataForm" status-icon label-position="left" label-width="100px" style="width: 400px; margin-left:50px;">
<el-form-item label="优惠券名称" prop="name">
<el-input v-model="dataForm.name"/>
<el-input v-model="dataForm.name" />
</el-form-item>
<el-form-item label="介绍" prop="desc">
<el-input v-model="dataForm.desc"/>
<el-input v-model="dataForm.desc" />
</el-form-item>
<el-form-item label="标签" prop="tag">
<el-input v-model="dataForm.tag"/>
<el-input v-model="dataForm.tag" />
</el-form-item>
<el-form-item label="最低消费" prop="min">
<el-input v-model="dataForm.min">
Expand All @@ -98,7 +98,8 @@
v-for="type in typeOptions"
:key="type.value"
:label="type.label"
:value="type.value"/>
:value="type.value"
/>
</el-select>
</el-form-item>
<el-form-item label="优惠券数量" prop="total">
Expand All @@ -119,11 +120,11 @@
</el-form-item>
<el-form-item v-show="dataForm.timeType === 1">
<el-col :span="11">
<el-date-picker v-model="dataForm.startTime" type="datetime" placeholder="选择日期" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%;"/>
<el-date-picker v-model="dataForm.startTime" type="datetime" placeholder="选择日期" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%;" />
</el-col>
<el-col :span="2" class="line">至</el-col>
<el-col :span="11">
<el-date-picker v-model="dataForm.endTime" type="datetime" placeholder="选择日期" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%;"/>
<el-date-picker v-model="dataForm.endTime" type="datetime" placeholder="选择日期" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%;" />
</el-col>
</el-form-item>
<el-form-item label="商品限制范围">
Expand All @@ -134,10 +135,76 @@
</el-radio-group>
</el-form-item>
<el-form-item v-show="dataForm.goodsType === 1">
目前不支持
<el-cascader
v-model="selectGoodsCategory"
clearable
placeholder="请选择分类名称"
:options="goodsCategoryOptions"
/>
<el-button @click="handleAddGoodsCategory()">添加</el-button>
<el-table
ref="goodsCateRelationTable"
:data="couponCategoryList"
style="width: 100%;margin-top: 20px"
border
>
<el-table-column label="分类名称" align="center">
<template slot-scope="scope">{{ scope.row.parentCategoryName }}>{{ scope.row.goodsCategoryName }}</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
@click="handleDeleteGoodsCategory(scope.$index, scope.row)"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item v-show="dataForm.goodsType === 2">
目前不支持
<el-select
v-model="selectGoods"
filterable
remote
reserve-keyword
placeholder="商品名称/商品货号"
>
<el-option
v-for="item in goodsOptions"
:key="item.goodsId"
:label="item.goodsName"
:value="item.goodsId"
>
<span style="float: left">{{ item.goodsName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">NO.{{ item.goodsSn }}</span>
</el-option>
</el-select>
<el-button @click="handleAddGoods()">添加</el-button>
<el-table
ref="goodsRelationTable"
:data="couponGoodsList"
style="width: 100%;margin-top: 20px"
border
>
<el-table-column label="商品名称" align="center">
<template slot-scope="scope">{{ scope.row.goodsName }}</template>
</el-table-column>
<el-table-column label="商品编号" align="center" width="80">
<template slot-scope="scope">{{ scope.row.goodsSn }}</template>
</el-table-column>
<el-table-column label="操作" align="center" width="60">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
@click="handleDeleteGoods(scope.$index, scope.row)"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
Expand Down Expand Up @@ -178,6 +245,8 @@

<script>
import { listCoupon, createCoupon, updateCoupon, deleteCoupon } from '@/api/coupon'
import { listCategory } from '@/api/category.js'
import { listGoods } from '@/api/goods.js'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
const defaultTypeOptions = [
Expand Down Expand Up @@ -286,11 +355,19 @@ export default {
{ required: true, message: '优惠券标题不能为空', trigger: 'blur' }
]
},
downloadLoading: false
downloadLoading: false,
selectGoods: null,
goodsOptions: [],
selectGoodsCategory: null,
goodsCategoryOptions: [],
couponGoodsList: [],
couponCategoryList: []
}
},
created() {
this.getList()
this.getCategoryList()
this.getGoodsList()
},
methods: {
getList() {
Expand Down Expand Up @@ -330,6 +407,8 @@ export default {
startTime: null,
endTime: null
}
this.couponCategoryList = []
this.couponGoodsList = []
},
handleCreate() {
this.resetForm()
Expand All @@ -342,6 +421,12 @@ export default {
createData() {
this.$refs['dataForm'].validate(valid => {
if (valid) {
if (this.dataForm.goodsType === 1) {
this.dataForm.goodsValue = this.couponCategoryList.map(item => (item.goodsCategoryId))
}
if (this.dataForm.goodsType === 2) {
this.dataForm.goodsValue = this.couponGoodsList.map(item => (item.goodsId))
}
createCoupon(this.dataForm)
.then(response => {
this.list.unshift(response.data.data)
Expand Down Expand Up @@ -447,6 +532,84 @@ export default {
excel.export_json_to_excel2(tHeader, this.list, filterVal, '优惠券信息')
this.downloadLoading = false
})
},
getGoodsList() {
listGoods({ limit: 0 }).then(response => {
const goodsList = response.data.data.list
this.goodsOptions = []
for (let i = 0; i < goodsList.length; i++) {
const item = goodsList[i]
this.goodsOptions.push({ goodsId: item.id, goodsName: item.name, goodsSn: item.goodsSn })
}
}).catch(() => {
this.goodsOptions = []
})
},
handleAddGoods() {
if (this.selectGoods === null) {
this.$message({
message: '请先选择商品',
type: 'warning'
})
return
}
this.couponGoodsList.push(this.getGoodsById(this.selectGoods))
this.selectGoods = null
},
handleDeleteGoods(index, row) {
this.couponGoodsList.splice(index, 1)
},
handleAddGoodsCategory() {
if (this.selectGoodsCategory === null || this.selectGoodsCategory.length === 0) {
this.$message({
message: '请先选择商品分类',
type: 'warning'
})
return
}
this.couponCategoryList.push(this.getGoodsCategoryByIds(this.selectGoodsCategory))
this.selectGoodsCategory = []
},
handleDeleteGoodsCategory(index, row) {
this.couponCategoryList.splice(index, 1)
},
getGoodsById(id) {
for (let i = 0; i < this.goodsOptions.length; i++) {
if (id === this.goodsOptions[i].goodsId) {
return this.goodsOptions[i]
}
}
return null
},
getCategoryList() {
listCategory().then(response => {
const list = response.data.data.list
this.goodsCategoryOptions = []
for (let i = 0; i < list.length; i++) {
const children = []
if (list[i].children != null && list[i].children.length > 0) {
for (let j = 0; j < list[i].children.length; j++) {
children.push({ label: list[i].children[j].name, value: list[i].children[j].id })
}
}
this.goodsCategoryOptions.push({ label: list[i].name, value: list[i].id, children: children })
}
})
},
getGoodsCategoryByIds(ids) {
let name
let parentName
for (let i = 0; i < this.goodsCategoryOptions.length; i++) {
if (this.goodsCategoryOptions[i].value === ids[0]) {
parentName = this.goodsCategoryOptions[i].label
for (let j = 0; j < this.goodsCategoryOptions[i].children.length; j++) {
if (this.goodsCategoryOptions[i].children[j].value === ids[1]) {
name = this.goodsCategoryOptions[i].children[j].label
}
}
}
}
return { goodsCategoryId: ids[1], goodsCategoryName: name, parentCategoryName: parentName }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.linlinjava.litemall.db.service;

import org.linlinjava.litemall.db.domain.LitemallCart;
import org.linlinjava.litemall.db.domain.LitemallCoupon;
import org.linlinjava.litemall.db.domain.LitemallCouponUser;
import org.linlinjava.litemall.db.util.CouponConstant;
Expand All @@ -8,6 +9,10 @@

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CouponVerifyService {
Expand All @@ -16,6 +21,8 @@ public class CouponVerifyService {
private LitemallCouponUserService couponUserService;
@Autowired
private LitemallCouponService couponService;
@Autowired
private LitemallGoodsService goodsService;

/**
* 检测优惠券是否适合
Expand All @@ -25,7 +32,7 @@ public class CouponVerifyService {
* @param checkedGoodsPrice
* @return
*/
public LitemallCoupon checkCoupon(Integer userId, Integer couponId, Integer userCouponId, BigDecimal checkedGoodsPrice) {
public LitemallCoupon checkCoupon(Integer userId, Integer couponId, Integer userCouponId, BigDecimal checkedGoodsPrice, List<LitemallCart> cartList) {
LitemallCoupon coupon = couponService.findById(couponId);
if (coupon == null) {
return null;
Expand Down Expand Up @@ -62,10 +69,25 @@ else if(timeType.equals(CouponConstant.TIME_TYPE_DAYS)) {
}

// 检测商品是否符合
// TODO 目前仅支持全平台商品,所以不需要检测
List<Integer> goodsList = cartList.stream().map(item -> item.getGoodsId()).collect(Collectors.toList());
for (LitemallCart cart : cartList) {
goodsList.add(cart.getGoodsId());
}
List<Integer> goodsValueList = new ArrayList<>(Arrays.asList(coupon.getGoodsValue()));
Short goodType = coupon.getGoodsType();
if (!goodType.equals(CouponConstant.GOODS_TYPE_ALL)) {
return null;
if (goodType.equals(CouponConstant.GOODS_TYPE_ARRAY)) {
goodsValueList.retainAll(goodsList);
if (goodsValueList.size() <= 0) {
return null;
}
} else if (goodType.equals(CouponConstant.GOODS_TYPE_CATEGORY)) {
List<Integer> categoryList = cartList.stream()
.map(item -> goodsService.findById(item.getGoodsId())
.getCategoryId()).collect(Collectors.toList());
goodsValueList.retainAll(categoryList);
if (goodsValueList.size() <= 0) {
return null;
}
}

// 检测订单状态
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public Object submit(Integer userId, String body) {
BigDecimal couponPrice = new BigDecimal(0);
// 如果couponId=0则没有优惠券,couponId=-1则不使用优惠券
if (couponId != 0 && couponId != -1) {
LitemallCoupon coupon = couponVerifyService.checkCoupon(userId, couponId, userCouponId, checkedGoodsPrice);
LitemallCoupon coupon = couponVerifyService.checkCoupon(userId, couponId, userCouponId, checkedGoodsPrice, checkedGoodsList);
if (coupon == null) {
return ResponseUtil.badArgumentValue();
}
Expand Down Expand Up @@ -485,7 +485,7 @@ public Object submit(Integer userId, String body) {
* 1. 检测当前订单是否能够取消;
* 2. 设置订单取消状态;
* 3. 商品货品库存恢复;
* 4. TODO 优惠券
* 4. 返还优惠券
*
* @param userId 用户ID
* @param body 订单信息,{ orderId:xxx }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ public Object checkout(@LoginUser Integer userId, Integer cartId, Integer addres
int tmpCouponLength = 0;
List<LitemallCouponUser> couponUserList = couponUserService.queryAll(userId);
for(LitemallCouponUser couponUser : couponUserList){
LitemallCoupon coupon = couponVerifyService.checkCoupon(userId, couponUser.getCouponId(), couponUser.getId(), checkedGoodsPrice);
LitemallCoupon coupon = couponVerifyService.checkCoupon(userId, couponUser.getCouponId(), couponUser.getId(), checkedGoodsPrice, checkedGoodsList);
if(coupon == null){
continue;
}
Expand Down Expand Up @@ -498,7 +498,7 @@ else if (couponId.equals(0)) {
userCouponId = tmpUserCouponId;
}
else {
LitemallCoupon coupon = couponVerifyService.checkCoupon(userId, couponId, userCouponId, checkedGoodsPrice);
LitemallCoupon coupon = couponVerifyService.checkCoupon(userId, couponId, userCouponId, checkedGoodsPrice, checkedGoodsList);
// 用户选择的优惠券有问题,则选择合适优惠券,否则使用用户选择的优惠券
if(coupon == null){
couponPrice = tmpCouponPrice;
Expand Down
Loading

0 comments on commit d611977

Please sign in to comment.