commit message

This commit is contained in:
Chopper
2021-05-13 10:56:04 +08:00
commit ec3e958037
728 changed files with 132685 additions and 0 deletions

View File

@@ -0,0 +1,467 @@
<template>
<div class="search">
<Card>
<Row>
<Form ref="searchForm" :model="searchForm" inline :label-width="70" class="search-form" >
<Form-item label="活动名称" prop="couponName">
<Input
type="text"
v-model="searchForm.couponName"
placeholder="请输入活动名称"
clearable
style="width: 200px"
/>
</Form-item>
<Form-item label="活动状态" prop="promotionStatus">
<Select
v-model="searchForm.promotionStatus"
placeholder="请选择"
clearable
style="width: 200px"
>
<Option value="NEW">未开始</Option>
<Option value="START">已开始/上架</Option>
<Option value="END">已结束/下架</Option>
<Option value="CLOSE">紧急关闭/作废</Option>
</Select>
</Form-item>
<Form-item label="活动时间">
<DatePicker
v-model="selectDate"
type="daterange"
clearable
placeholder="选择起始时间"
style="width: 200px"
></DatePicker>
</Form-item>
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
</Form>
</Row>
<Row class="operation padding-row">
<Button @click="add" type="primary">添加</Button>
<Button @click="delAll" >批量下架</Button>
<!-- <Button @click="upAll" >批量上架</Button> -->
</Row>
<Row>
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
sortable="custom"
@on-sort-change="changeSort"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="action">
<!-- <Button
type="info"
size="small"
style="margin-right: 10px"
@click="receiveInfo(row)"
>查看</Button
> -->
<Button
v-if="row.promotionStatus === 'NEW' || row.promotionStatus === 'CLOSE'"
type="primary"
size="small"
style="margin-right: 10px"
@click="edit(row)"
>编辑</Button
>
<Button
v-if="row.promotionStatus === 'START' || row.promotionStatus === 'NEW'"
type="error"
size="small"
style="margin-right: 10px"
@click="remove(row)"
>下架</Button
>
</template>
</Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber + 1"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</Card>
</div>
</template>
<script>
import {
getPlatformCouponList,
deletePlatformCoupon,
updatePlatformCouponStatus,
} from "@/api/promotion";
export default {
name: "coupon",
components: {},
data() {
return {
loading: true, // 表单加载状态
modalType: 0, // 添加或编辑标识
modalVisible: false, // 添加或编辑显示
modalTitle: "", // 添加或编辑标题
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageSize: 10, // 页面大小
sort: "startTime", // 默认排序字段
order: "desc", // 默认排序方式
},
form: {
// 添加或编辑表单对象初始化数据
promotionName: "",
},
// 表单验证规则
formValidate: {
promotionName: [
{ required: true, message: "不能为空", trigger: "blur" },
],
},
submitLoading: false, // 添加或编辑提交状态
selectList: [], // 多选数据
selectCount: 0, // 多选计数
columns: [
// 表头
{
type: "selection",
width: 60,
align: "center",
fixed: "left",
},
{
title: "活动名称",
key: "promotionName",
minWidth: 120,
fixed: "left",
},
{
title: "优惠券名称",
key: "couponName",
minWidth: 120,
tooltip: true
},
{
title: "面额",
key: "price",
width: 120,
render: (h, params) => {
if (params.row.price) {
return h(
"div",
this.$options.filters.unitPrice(params.row.price, "¥")
);
} else {
return h("div");
}
},
},
{
title: "折扣",
key: "couponDiscount",
minWidth: 60
},
{
title: "总数量",
key: "publishNum",
width: 100
},
{
title: "领取数量",
key: "receivedNum",
width: 100,
},
{
title: "优惠券类型",
key: "couponType",
width: 120,
render: (h, params) => {
let text = "未知";
if (params.row.couponType === "DISCOUNT") {
text = "打折";
} else if (params.row.couponType === "PRICE") {
text = "减免现金";
}
return h("div", [text]);
},
},
{
title: "品类描述",
key: "scopeType",
width: 100,
render: (h, params) => {
let text = "未知";
if (params.row.scopeType == "ALL") {
text = "全品类";
} else if (params.row.scopeType == "PORTION_GOODS_CATEGORY") {
text = "商品分类";
} else if (params.row.scopeType == "PORTION_SHOP_CATEGORY") {
text = "店铺分类";
} else if (params.row.scopeType == "PORTION_GOODS") {
text = "指定商品";
}
return h("div", [text]);
},
},
{
title: "开始时间",
key: "startTime",
minWidth: 120,
tooltip: true
},
{
title: "状态",
key: "promotionStatus",
minWidth: 90,
fixed: "right",
render: (h, params) => {
let text = "未知",
color = "";
if (params.row.promotionStatus == "NEW") {
text = "未开始";
color = "default";
} else if (params.row.promotionStatus == "START") {
text = "已开始";
color = "green";
} else if (params.row.promotionStatus == "END") {
text = "已结束";
color = "red";
} else if (params.row.promotionStatus == "CLOSE") {
text = "已关闭";
color = "red";
}
return h("div", [
h(
"Tag",
{
props: {
color: color,
},
},
text
),
]);
},
},
{
title: "操作",
slot: "action",
align: "center",
fixed: "right",
minWidth: 130
},
],
data: [], // 表单数据
total: 0, // 表单数据总数
};
},
watch: {
$route(to, from) {
if (to.fullPath == "/promotion/manager-coupon") {
this.init();
}
},
},
methods: {
init() {
this.getDataList();
},
add() {
this.$router.push({ name: "add-platform-coupon" });
},
/** 跳转至领取详情页面 */
receiveInfo(v) {
this.$router.push({ name: "member-receive-coupon", query: { id: v.id } });
},
info(v) {
this.$router.push({ name: "platform-coupon-info", query: { id: v.id } });
},
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 0;
this.searchForm.pageSize = 10;
this.getDataList();
},
changeSort(e) {
this.searchForm.sort = e.key;
this.searchForm.order = e.order;
if (e.order === "normal") {
this.searchForm.order = "";
}
this.getDataList();
},
clearSelectAll() {
this.$refs.table.selectAll(false);
},
changeSelect(e) {
this.selectList = e;
this.selectCount = e.length;
},
getDataList() {
this.loading = true;
if (this.selectDate && this.selectDate[0] && this.selectDate[1]) {
this.searchForm.startTime = this.selectDate[0].getTime();
this.searchForm.endTime = this.selectDate[1].getTime();
} else {
this.searchForm.startTime = null;
this.searchForm.endTime = null;
}
// 带多条件搜索参数获取表单数据 请自行修改接口
getPlatformCouponList(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
this.total = this.data.length;
this.loading = false;
},
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.submitLoading = true;
if (this.modalType === 0) {
// 添加 避免编辑后传入id等数据 记得删除
delete this.form.id;
this.postRequest("/coupon/insertOrUpdate", this.form).then(
(res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("操作成功");
this.getDataList();
this.modalVisible = false;
}
}
);
} else {
// 编辑
this.postRequest("/coupon/insertOrUpdate", this.form).then(
(res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("操作成功");
this.getDataList();
this.modalVisible = false;
}
}
);
}
}
});
},
edit(v) {
this.$router.push({ name: "edit-platform-coupon", query: { id: v.id } });
},
remove(v) {
this.$Modal.confirm({
title: "确认下架",
// 记得确认修改此处
content: "确认要下架此优惠券么?",
loading: true,
onOk: () => {
// 删除
updatePlatformCouponStatus({ couponIds: v.id, promotionStatus: "CLOSE" })
.then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("优惠券已作废");
this.getDataList();
}
})
.catch(() => {
this.$Modal;
});
},
});
},
delAll() {
if (this.selectCount <= 0) {
this.$Message.warning("您还未选择要下架的优惠券");
return;
}
this.$Modal.confirm({
title: "确认下架",
content: "您确认要下架所选的 " + this.selectCount + " 条数据?",
loading: true,
onOk: () => {
let ids = [];
this.selectList.forEach(function (e) {
ids.push(e.id);
});
let params = {
couponIds: ids.toString(),
promotionStatus: "CLOSE",
};
// 批量删除
updatePlatformCouponStatus(params).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("下架成功");
this.clearSelectAll();
this.getDataList();
}
});
},
});
},
upAll() {
if (this.selectCount <= 0) {
this.$Message.warning("请选择要上架的优惠券");
return;
}
this.$Modal.confirm({
title: "确认上架",
content: "您确认要上架所选的 " + this.selectCount + " 条数据?",
loading: true,
onOk: () => {
let ids = [];
this.selectList.forEach(function (e) {
ids.push(e.id);
});
let params = {
couponIds: ids.toString(),
promotionStatus: "START",
};
// 批量上架
updatePlatformCouponStatus(params).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("上架成功");
this.clearSelectAll();
this.getDataList();
}
});
},
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss">
@import "@/styles/table-common.scss";
</style>

View File

@@ -0,0 +1,246 @@
<template>
<div>
<div class="content-goods-publish">
<Form ref="form" :model="form" :label-width="130">
<div class="base-info-item">
<h4>平台券活动详情</h4>
<div class="form-item-view">
<FormItem label="活动名称">
<span class="goods-category-name">{{ form.promotionName }}</span>
</FormItem>
<FormItem label="活动类型">
<span class="goods-category-name">{{
getCouponType(form.couponType)
}}</span>
</FormItem>
<FormItem label="面额">
<span class="goods-category-name"> {{ form.price }}</span>
</FormItem>
<FormItem label="活动说明">
<span class="goods-category-name">{{ form.description }}</span>
</FormItem>
<FormItem label="发放总数">
<span class="goods-category-name">{{ form.publishNum }}</span>
</FormItem>
<FormItem label="领取限制">
<span class="goods-category-name">{{ form.limitNum }}</span>
</FormItem>
<FormItem label="活动开始时间">
<span class="goods-category-name">{{ form.startTime }}</span>
</FormItem>
<FormItem label="消费限额">
<span class="goods-category-name">{{
form.consumptionLimit
}}</span>
</FormItem>
<FormItem label="使用有效期">
<span class="goods-category-name">{{ form.startTime }} {{ form.endTime }}</span>
</FormItem>
<FormItem label="适用品类范围">
<span class="goods-category-name">{{
getScopeType(form.scopeType)
}}</span>
</FormItem>
<FormItem label="品类范围描述">
<span class="goods-category-name">{{ form.couponName }}</span>
</FormItem>
<FormItem label="状态">
<span class="goods-category-name">{{
getStatus(form.status)
}}</span>
</FormItem>
<FormItem label="优惠券类型">
<span class="goods-category-name">{{
getType(form.getType)
}}</span>
</FormItem>
<FormItem label="活动创建时间">
<span class="goods-category-name">{{ form.createTime }}</span>
</FormItem>
<FormItem label="活动最后更新时间">
<span class="goods-category-name">{{ form.updateTime }}</span>
</FormItem>
<FormItem label="更新管理员名称">
<span class="goods-category-name">{{ form.updateBy }}</span>
</FormItem>
<FormItem label="已发放数量">
<span class="goods-category-name">{{ form.receivedNum }}</span>
</FormItem>
<FormItem label="已使用数量">
<span class="goods-category-name">{{ form.usedNum }}</span>
</FormItem>
</div>
<h4>适用品类范围</h4>
<div>
<Row>
<Table :loading="loading" border :columns="columns1" :data="data1" ref="table" sortable="custom" @on-sort-change="changeSort" @on-selection-change="changeSelect"></Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]"
size="small" show-total show-elevator show-sizer></Page>
</Row>
</div>
</div>
</Form>
</div>
<div class="footer">
<Button type="primary" @click="back">返回活动列表</Button>
</div>
</div>
</template>
<script>
import { getPlatformCoupon } from "@/api/promotion";
import uploadPicThumb from "@/views/my-components/lili/upload-pic-thumb";
import editor from "@/views/my-components/lili/editor";
export default {
name: "addCoupon",
components: {
uploadPicThumb,
editor,
},
data() {
return {
maxHeight: "240px",
modalType: 0,
/** 当前状态/模式 默认发布商品0 编辑商品1 编辑草稿箱商品2 */
currentStatus: 0,
categoryId: 0,
loading: false, // 表单加载状态
searchForm: {
// 搜索框初始化对象
pageNumber: 1, // 当前页数
pageSize: 10, // 页面大小
sort: "createTime", // 默认排序字段
order: "desc", // 默认排序方式
},
form: {
/** 店铺承担比例 */
sellerCommission: 0,
/** 发行数量 */
publishNum: 1,
/** 运费承担者 */
scopeType: "ALL",
/** 消费限额 */
consumptionLimit: "",
/** 限领数量 */
limitNum: 1,
/** 活动类型 */
couponType: "",
/** 优惠券名称 */
couponName: "",
/** 已被使用数量 */
usedNum: 0,
/** 已被领取的数量 */
receivedNum: 0,
},
id: this.$route.query.id,
columns1: [
{
title: "一级类目",
key: "name",
},
{
title: "二级类目",
key: "age",
},
{
title: "三级类目",
key: "address",
},
],
data1: [
{
name: "王小明",
age: 18,
address: "北京市朝阳区芍药居",
},
{
name: "张小刚",
age: 25,
address: "北京市海淀区西二旗",
},
{
name: "李小红",
age: 30,
address: "上海市浦东新区世纪大道",
},
{
name: "周小伟",
age: 26,
address: "深圳市南山区深南大道",
},
],
submitLoading: false, // 添加或编辑提交状态
};
},
mounted() {
// 如果id不为空则查询信息
if (this.id) {
this.getCoupon();
this.modalType = 1;
}
},
methods: {
getCouponType(value) {
switch (value) {
case "POINT":
return "打折";
case "PRICE":
return "减免现金";
}
},
/** 获取状态 */
getStatus(value) {
switch (value) {
case "NEW":
return "新建";
case "START":
return "开始";
case "LOWER":
return "结束";
case "CANCEL":
return "作废";
}
},
/** 关联范围类型 */
getScopeType(value) {
switch (value) {
case "PORTION_CATEGORY":
return "部分商品分类";
case "PORTION_GOODS":
return "指定商品";
case "ALL":
return "全品类";
}
},
/** 优惠券类型 */
getType(value) {
switch (value) {
case "FREE":
return "免费获取";
case "ACTIVITY":
return "活动获取";
}
},
getCoupon() {
getPlatformCoupon(this.id).then((res) => {
this.form = res.result;
});
},
back() {
this.$store.commit("removeTag", "platform-coupon-info");
this.$router.go(-1);
},
},
};
</script>
<style lang="scss" scoped>
@import "couponPublish.scss";
</style>

View File

@@ -0,0 +1,257 @@
/*选择商品品类*/
.content-goods-publish {
padding: 15px;
margin: 0 auto;
text-align: center;
border: 1px solid #ddd;
background: none repeat 0 0 #fff;
height: 100%;
margin-bottom: 20px;
/*商品品类*/
.goods-category {
text-align: left;
padding: 10px;
background: #fafafa;
border: 1px solid #e6e6e6;
ul {
padding: 8px 4px 8px 8px;
list-style: none;
width: 300px;
background: none repeat 0 0 #fff;
border: 1px solid #e6e6e6;
display: inline-block;
letter-spacing: normal;
margin-right: 15px;
vertical-align: top;
word-spacing: normal;
li {
line-height: 20px;
padding: 5px;
cursor: pointer;
color: #333;
font-size: 12px;
display: flex;
flex-wrap: nowrap;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
}
/** 当前品类被选中的样式 */
.activeClass {
background-color: #d9edf7;
border: 1px solid #bce8f1;
color: #3a87ad;
}
/*!*当前选择的商品品类文字*!*/
.current-goods-category {
text-align: left;
padding: 10px;
width: 100%;
border: 1px solid #fbeed5;
color: #c09853;
background-color: #fcf8e3;
margin: 10px auto;
padding: 8px 35px 8px 14px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
font-size: 12px;
font-weight: bold;
}
}
/*编辑基本信息*/
.el-form {
padding-bottom: 80px;
.el-form-item {
width: 100%;
color: gray;
text-align: left;
}
}
div.base-info-item {
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.form-item-view {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
padding-left: 80px;
.shop-category-text {
font-size: 12px;
}
}
.item-goods-properts-row {
display: flex;
flex-direction: row;
word-break: break-all;
white-space: normal;
width: 300px;
height: 100px;
}
.item-goods-properts {
display: flex;
flex-direction: row;
margin-bottom: 10px;
}
.form-item {
display: flex;
align-items: center;
}
/** 审核信息-拒绝原因 */
.auth-info {
color: red;
}
.el-form-item {
width: 30%;
min-width: 300px;
}
.goods-name-width {
width: 50%;
min-width: 300px;
}
.el-form-item__content {
margin-left: 120px;
text-align: left;
}
p.goods-group-manager {
padding-left: 7.5%;
text-align: left;
color: #999;
font-size: 13px;
}
/*teatarea*/
/deep/ .el-textarea {
width: 150%;
}
.seo-text {
width: 150%;
}
}
/*折叠面板*/
.el-collapse-item {
/deep/ .el-collapse-item__header {
text-align: left;
background-color: #f8f8f8;
padding: 0 10px;
font-weight: bold;
color: #333;
font-size: 14px;
}
.el-form-item {
margin-left: 5%;
width: 25%;
}
/deep/ .el-form-item__content {
margin-left: 120px;
text-align: left;
}
p.goods-group-manager {
padding-left: 12%;
text-align: left;
color: #999;
}
/deep/ .el-collapse-item__content {
padding: 10px 0;
text-align: left;
}
}
/*商品描述*/
.goods-intro {
line-height: 40;
}
/** 底部步骤 */
.footer {
width: 88.7%;
padding: 10px;
background-color: #ffc;
position: fixed;
bottom: 0px;
left: 10%;
text-align: center;
z-index: 9999;
}
/*图片上传组件第一张图设置封面*/
.goods-images {
/deep/ li.el-upload-list__item:first-child {
position: relative;
}
/deep/ li.el-upload-list__item:first-child:after {
content: "";
color: #fff;
font-weight: bold;
font-size: 12px;
position: absolute;
left: -15px;
top: -6px;
width: 40px;
height: 24px;
padding-top: 6px;
background: #13ce66;
text-align: center;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
}
}
.el-form-item__label {
word-break: break-all;
}
.step-view {
width: 33%;
height: 40px;
font-size: 19px;
text-align: center;
display: flex;
background-color: #fff;
justify-content: center;
align-items: center;
}
.page {
margin-top: 2vh;
margin-bottom: 5vh;
}

View File

@@ -0,0 +1,566 @@
<template>
<div>
<Card>
<Form ref="form" :model="form" :label-width="120" :rules="formRule">
<div class="base-info-item">
<h4>基本信息</h4>
<div class="form-item-view">
<FormItem label="活动名称" prop="promotionName">
<Input type="text" v-model="form.promotionName" placeholder="活动名称" clearable style="width: 260px" />
</FormItem>
<FormItem label="优惠券名称" prop="couponName">
<Input type="text" v-model="form.couponName" placeholder="优惠券名称" clearable style="width: 260px" />
</FormItem>
<FormItem label="优惠券类型" prop="couponType">
<Select v-model="form.couponType" style="width: 260px">
<Option value="DISCOUNT">打折</Option>
<Option value="PRICE">减免现金</Option>
</Select>
</FormItem>
<FormItem label="折扣" prop="couponDiscount" v-if="form.couponType == 'DISCOUNT'">
<Input type="number" v-model="form.couponDiscount" placeholder="折扣" clearable style="width: 260px" />
<span class="describe">请输入0-10之间数字可以输入一位小数</span>
</FormItem>
<FormItem label="面额" prop="price" v-if="form.couponType == 'PRICE'">
<Input type="text" v-model="form.price" placeholder="面额" clearable style="width: 260px" />
</FormItem>
<FormItem label="活动类型" prop="getType">
<Select v-model="form.getType" style="width: 260px">
<Option value="FREE">免费领取</Option>
<Option value="ACTIVITY">活动赠送</Option>
</Select>
</FormItem>
<FormItem label="店铺承担比例" prop="storeCommission">
<Input v-model="form.storeCommission" placeholder="店铺承担比例" style="width: 260px">
<span slot="append">%</span>
</Input>
<span class="describe">店铺承担比例输入0-100之间数值</span>
</FormItem>
<FormItem label="发放数量" prop="publishNum">
<Input v-model="form.publishNum" placeholder="发放数量" style="width: 260px" />
</FormItem>
</div>
<h4>使用限制</h4>
<div class="form-item-view">
<FormItem label="消费门槛" prop="consumeThreshold">
<Input type="text" v-model="form.consumeThreshold" placeholder="消费门槛" clearable style="width: 260px" />
</FormItem>
<FormItem label="领取限制" prop="couponLimitNum">
<Input v-model="form.couponLimitNum" placeholder="领取限制" clearable style="width: 260px" />
</FormItem>
<FormItem label="有效期" prop="startTime">
<DatePicker type="datetime" v-model="form.startTime" format="yyyy-MM-dd HH:mm:ss" placeholder="请选择" :options="options" clearable style="width: 200px">
</DatePicker>
-
<DatePicker type="datetime" v-model="form.endTime" format="yyyy-MM-dd HH:mm:ss" :options="options" placeholder="请选择" clearable style="width: 200px">
</DatePicker>
</FormItem>
<FormItem label="使用范围" prop="scopeType">
<RadioGroup v-model="form.scopeType">
<Radio label="ALL">全品类</Radio>
<Radio label="PORTION_GOODS">指定商品</Radio>
<Radio label="PORTION_GOODS_CATEGORY">部分商品分类</Radio>
</RadioGroup>
</FormItem>
<FormItem style="width: 100%" v-if="form.scopeType == 'PORTION_GOODS'">
<div style="display: flex; margin-bottom: 10px">
<Button type="primary" @click="$refs.skuSelect.open('goods')">选择商品</Button>
<Button type="error" ghost style="margin-left: 10px" @click="delSelectGoods">批量删除</Button>
</div>
<Table border :columns="columns" :data="form.promotionGoodsList" @on-selection-change="changeSelect">
<template slot-scope="{ row }" slot="QRCode">
<img :src="row.QRCode || '../../../assets/lili.png'" width="50px" height="50px" alt="" />
</template>
</Table>
</FormItem>
<FormItem v-if="form.scopeType == 'PORTION_GOODS_CATEGORY'">
<Cascader @on-change="getGoodsCategory" :data="goodsCategoryList" style="width:300px;" v-model="form.scopeIdGoods"></Cascader>
</FormItem>
<FormItem label="范围描述" prop="description">
<Input v-model="form.description" type="textarea" :rows="4" maxlength="50" show-word-limit clearable style="width: 260px" />
</FormItem>
<div>
<Button type="text" @click="closeCurrentPage">返回</Button>
<Button type="primary" :loading="submitLoading" @click="handleSubmit">提交</Button>
</div>
</div>
</div>
</Form>
</Card>
<sku-select ref="skuSelect" @selectedGoodsData="selectedGoodsData"></sku-select>
</div>
</template>
<script>
import {
savePlatformCoupon,
getPlatformCoupon,
editPlatformCoupon,
} from "@/api/promotion";
import { getCategoryTree } from "@/api/goods";
import { regular } from "@/utils";
import skuSelect from "@/views/lili-dialog";
export default {
name: "addCoupon",
components: {
skuSelect,
},
data() {
const checkPrice = (rule, value, callback) => {
if (!value && value !== 0) {
return callback(new Error("面额不能为空"));
} else if (!regular.money.test(value)) {
callback(new Error("请输入正整数或者两位小数"));
} else if (parseFloat(value) > 99999999) {
callback(new Error("面额设置超过上限值"));
} else {
callback();
}
};
const checkWeight = (rule, value, callback) => {
if (!value && typeof value !== "number") {
callback(new Error("消费门槛不能为空"));
} else if (!regular.money.test(value)) {
callback(new Error("请输入正整数或者两位小数"));
} else if (parseFloat(value) > 99999999) {
callback(new Error("消费门槛设置超过上限值"));
} else {
callback();
}
};
const isLtEndDate = (rule, value, callback) => {
if (new Date(value).getTime() > new Date(this.form.endTime).getTime()) {
callback(new Error());
} else {
callback();
}
};
const isGtStartDate = (rule, value, callback) => {
if (new Date(value).getTime() < new Date(this.form.startTime).getTime()) {
callback(new Error());
} else {
callback();
}
};
return {
arrScopeId: [],
maxHeight: "240px",
modalType: 0,
/** 当前状态/模式 默认发布商品0 编辑商品1 编辑草稿箱商品2 */
currentStatus: 0,
categoryId: 0,
form: {
/** 店铺承担比例 */
storeCommission: 0,
/** 发行数量 */
publishNum: 1,
/** 运费承担者 */
scopeType: "ALL",
/** 限领数量 */
couponLimitNum: 1,
/** 活动类型 */
couponType: "PRICE",
/** 优惠券名称 */
couponName: "",
getType: "FREE",
promotionGoodsList: [],
scopeIdGoods: [],
},
id: this.$route.query.id,
submitLoading: false, // 添加或编辑提交状态
selectedGoods: [], // 已选商品列表,便于删除
goodsCategoryList: [], // 商品分类列表
shopCategoryList: [], // 店铺分类列表
cascaderProps: {
multiple: true,
label: "name",
value: "id",
}, // 级联选择器配置项
formRule: {
promotionName: [{ required: true, message: "活动名称不能为空" }],
couponName: [{ required: true, message: "优惠券名称不能为空" }],
couponLimitNum: [{ required: true, message: "领取限制不能为空" }],
price: [
{ required: true, message: "请输入面额" },
{ validator: checkPrice },
],
consumeThreshold: [
{ required: true, message: "请输入消费门槛" },
{ validator: checkWeight },
],
startTime: [
{
required: true,
type: "date",
message: "请选择开始时间",
},
{
trigger: "change",
message: "开始时间要小于结束时间",
validator: isLtEndDate,
},
],
endTime: [
{
required: true,
type: "date",
message: "请选择结束时间",
},
{
trigger: "change",
message: "结束时间要大于开始时间",
validator: isGtStartDate,
},
],
couponDiscount: [
{ required: true, message: "请输入折扣" },
{
pattern: regular.discount,
message: "请输入0-10的数字,可有一位小数",
},
],
storeCommission: [
{ required: true, message: "请输入店铺承担比例" },
{ pattern: regular.rate, message: "请输入0-100的正整数" },
],
publishNum: [
{ required: true, message: "请输入发放数量" },
{ pattern: regular.integer, message: "请输入正整数" },
],
couponLimitNum: [
{ required: true, message: "请输入领取限制" },
{ pattern: regular.integer, message: "请输入正整数" },
],
description: [{ required: true, message: "请输入范围描述" }],
},
columns: [
{
type: "selection",
width: 60,
align: "center",
},
{
title: "商品名称",
key: "goodsName",
minWidth: 120,
},
{
title: "商品价格",
key: "price",
minWidth: 40,
render: (h, params) => {
return h(
"div",
this.$options.filters.unitPrice(params.row.price, "¥")
);
},
},
{
title: "库存",
key: "quantity",
minWidth: 40,
},
{
title: "操作",
key: "action",
minWidth: 50,
align: "center",
render: (h, params) => {
return h(
"Button",
{
props: {
size: "small",
type: "error",
ghost: true,
},
on: {
click: () => {
this.delGoods(params.index);
},
},
},
"删除"
);
},
},
],
options: {
disabledDate(date) {
return date && date.valueOf() < Date.now() - 86400000;
},
},
};
},
async mounted() {
await this.getCagetoryList();
// 如果id不为空则查询信息
if (this.id) {
this.getCoupon();
this.modalType = 1;
}
},
methods: {
getCoupon() {
getPlatformCoupon(this.id).then((res) => {
let data = res.result;
if (!data.promotionGoodsList) data.promotionGoodsList = [];
if (data.scopeType == "PORTION_GOODS_CATEGORY") {
let prevCascader = data.scopeId.split(",");
// console.log(prevCascader);
function next(params, prev) {
for (let i = 0; i < params.length; i++) {
const item = params[i];
console.log(item);
if (item.children) {
next(item.children, [...prev, item]);
} else {
if (prevCascader.includes(item.id)) {
prevCascader = prevCascader.map((key) => {
if (key === item.id) {
let result = prev.map((item) => item.id);
return [...result, item.id];
} else {
return key;
}
});
} else {
i === params.length - 1 && (prev = []);
}
}
}
}
next(this.goodsCategoryList, []);
data.scopeIdGoods = prevCascader;
}
this.form = data;
});
},
/** 保存平台优惠券 */
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
const params = JSON.parse(JSON.stringify(this.form));
const strat = this.$options.filters.unixToDate(
this.form.startTime / 1000
);
const end = this.$options.filters.unixToDate(
this.form.endTime / 1000
);
let scopeId = [];
params.startTime = strat;
params.endTime = end;
if (
params.scopeType == "PORTION_GOODS" &&
(!params.promotionGoodsList ||
params.promotionGoodsList.length == 0)
) {
this.$Modal.warning({ title: "提示", content: "请选择指定商品" });
return;
}
if (
params.scopeType == "PORTION_GOODS_CATEGORY" &&
(!params.scopeIdGoods || params.scopeIdGoods.length == 0)
) {
this.$Modal.warning({ title: "提示", content: "请选择商品分类" });
return;
}
if (params.scopeType == "PORTION_GOODS") {
//指定商品
params.promotionGoodsList.forEach((item) => {
scopeId.push(item.skuId);
});
params.scopeId = scopeId.toString();
} else if (params.scopeType == "ALL") {
delete params.promotionGoodsList;
} else if (params.scopeType == "PORTION_GOODS_CATEGORY") {
//部分商品分类
scopeId = this.filterCategoryId(params.scopeIdGoods, []);
params.scopeId = scopeId.toString();
delete params.promotionGoodsList;
}
delete params.scopeIdGoods;
this.submitLoading = true;
if (this.modalType === 0) {
// 添加 避免编辑后传入id等数据 记得删除
delete params.id;
savePlatformCoupon(params).then((res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("优惠券发送成功");
this.closeCurrentPage();
}
});
} else {
// 编辑
delete params.consumeLimit;
delete params.updateTime;
editPlatformCoupon(params).then((res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("优惠券修改成功");
this.closeCurrentPage();
}
});
}
}
});
},
// 关闭当前页面
closeCurrentPage() {
this.$store.commit("removeTag", "add-platform-coupon");
localStorage.pageOpenedList = JSON.stringify(
this.$store.state.app.pageOpenedList
);
this.$router.go(-1);
},
changeSelect(e) {
// 已选商品批量选择
this.selectedGoods = e;
},
delSelectGoods() {
// 多选删除商品
if (this.selectedGoods.length <= 0) {
this.$Message.warning("您还未选择要删除的数据");
return;
}
this.$Modal.confirm({
title: "确认删除",
content: "您确认要删除所选商品吗?",
onOk: () => {
let ids = [];
this.selectedGoods.forEach(function (e) {
ids.push(e.id);
});
this.form.promotionGoodsList = this.form.promotionGoodsList.filter(
(item) => {
return !ids.includes(item.id);
}
);
},
});
},
delGoods(index) {
// 删除商品
this.form.promotionGoodsList.splice(index, 1);
},
selectedGoodsData(item) {
// 回显已选商品
let ids = [];
let list = [];
this.form.promotionGoodsList.forEach((e) => {
ids.push(e.id);
});
item.forEach((e) => {
if (!ids.includes(e.id)) {
list.push({
goodsName: e.goodsName,
price: e.price,
originalPrice: e.price,
quantity: e.quantity,
storeId: e.storeId,
sellerName: e.sellerName,
skuId: e.id,
});
}
});
this.form.promotionGoodsList.push(...list);
},
getGoodsCategory(e) {
// 获取级联选择器商品分类id
console.log(e);
},
async getCagetoryList() {
// 获取全部商品分类
let data = await getCategoryTree();
this.goodsCategoryList = this.filterCategory(data.result);
// 过滤出可显示的值
this.goodsCategoryList = this.goodsCategoryList.map((item) => {
if (item.children) {
item.children = item.children.map((child) => {
if (child.children) {
child.children = child.children.map((son) => {
return {
value: son.id,
label: son.name,
};
});
return {
value: child.id,
label: child.name,
children: child.children,
};
} else {
return {
value: child.id,
label: child.name,
};
}
});
}
return { value: item.id, label: item.name, children: item.children };
});
},
filterCategory(list) {
// 递归删除空children
list.forEach((item) => {
if (item.children.length == 0) {
delete item.children;
} else {
this.filterCategory(item.children);
}
});
return list;
},
filterCategoryId(list, idArr) {
// 递归获取分类id
list.forEach((e) => {
if (e instanceof Array) {
this.filterCategoryId(e, idArr);
} else {
if (!idArr.includes(e)) idArr.push(e);
}
});
return idArr;
},
},
};
</script>
<style lang="scss" scpoed>
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.describe {
font-size: 12px;
margin-left: 10px;
color: #999;
}
</style>

View File

@@ -0,0 +1,257 @@
<template>
<div class="search">
<Row>
<Col>
<Card>
<Row>
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
sortable="custom"
@on-sort-change="changeSort"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="rangeTime">
<div>{{ row.startTime }} ~ {{ row.endTime }}</div>
</template>
<template slot-scope="{ row }" slot="action">
<Button
type="error"
ghost
size="small"
:disabled="row.memberCouponStatus != 'NEW'"
@click="remove(row)"
>作废</Button
>
</template>
</Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</Card>
</Col>
</Row>
</div>
</template>
<script>
import {
getMemberReceiveCouponList,
deleteMemberReceiveCoupon,
} from "@/api/promotion";
export default {
name: "memberReceiveCoupon",
components: {},
data() {
return {
loading: true, // 表单加载状态
modalType: 0, // 添加或编辑标识
searchForm: {
// 搜索框初始化对象
pageNumber: 1, // 当前页数
pageSize: 10, // 页面大小
sort: "createTime", // 默认排序字段
order: "desc", // 默认排序方式
},
id: this.$route.query.id,
submitLoading: false, // 添加或编辑提交状态
selectList: [], // 多选数据
columns: [
// 表头
{
title: "优惠券编号",
key: "couponId",
minWidth: 120,
},
{
title: "面额",
key: "price",
render: (h, params) => {
return h(
"div",
this.$options.filters.unitPrice(params.row.price, "¥")
);
},
},
{
title: "消费门槛",
key: "consumeThreshold",
render: (h, params) => {
return h(
"div",
this.$options.filters.unitPrice(params.row.consumeThreshold, "¥")
);
},
},
{
title: "有效期",
slot: "rangeTime",
minWidth: 120
},
{
title: "会员名称",
key: "memberName",
minWidth: 120
},
{
title: "适用范围",
key: "couponType",
minWidth: 50,
render: (h, params) => {
let text = "未知";
if (params.row.scopeType == "ALL") {
text = "全品类";
} else if (params.row.scopeType == "PORTION_CATEGORY") {
text = "部分商品分类";
} else if (params.row.scopeType == "PORTION_GOODS") {
text = "指定商品";
}
return h("div", [text]);
},
},
{
title: "会员名称",
key: "memberName",
},
{
title: "状态",
key: "memberCouponStatus",
minWidth: 50,
render: (h, params) => {
let text = "未知",
color = "";
if (params.row.memberCouponStatus == "NEW") {
text = "未使用";
color = "default";
} else if (params.row.memberCouponStatus == "USED") {
text = "已使用";
color = "green";
} else if (params.row.memberCouponStatus == "EXPIRE") {
text = "已过期";
color = "red";
} else if (params.row.memberCouponStatus == "CLOSED") {
text = "已作废";
color = "red";
}
return h("div", [
h(
"Tag",
{
props: {
color: color,
},
},
text
),
]);
},
},
{
title: "操作",
slot: "action",
align: "center",
width: 100,
},
],
data: [], // 表单数据
total: 0, // 表单数据总数
};
},
methods: {
init() {
this.getDataList();
},
changePage(v) {
this.searchForm.pageNumber = v;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 10;
this.getDataList();
},
handleReset() {
this.$refs.searchForm.resetFields();
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 10;
// 重新加载数据
this.getDataList();
},
changeSort(e) {
this.searchForm.sort = e.key;
this.searchForm.order = e.order;
if (e.order === "normal") {
this.searchForm.order = "";
}
this.getDataList();
},
clearSelectAll() {
this.$refs.table.selectAll(false);
},
changeSelect(e) {
this.selectList = e;
},
/** 查询单个优惠券领取详情 */
getDataList() {
this.loading = true;
// 带多条件搜索参数获取表单数据 请自行修改接口
getMemberReceiveCouponList(this.id).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
this.total = this.data.length;
this.loading = false;
},
/** 作废优惠券 */
remove(v) {
this.$Modal.confirm({
title: "确认作废",
content: "您确认要作废此优惠券?",
loading: true,
onOk: () => {
// 删除
deleteMemberReceiveCoupon(v.id).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("作废成功");
this.getDataList();
}
});
},
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss">
@import "@/styles/table-common.scss";
</style>

View File

@@ -0,0 +1,224 @@
<template>
<div class="full-cut">
<Card>
<Row>
<Form
ref="searchForm"
:model="searchForm"
inline
:label-width="70"
class="search-form"
>
<Form-item label="活动名称" prop="promotionName">
<Input
type="text"
v-model="searchForm.promotionName"
placeholder="请输入活动名称"
clearable
style="width: 200px"
/>
</Form-item>
<Form-item label="活动状态" prop="promotionStatus">
<Select
v-model="searchForm.promotionStatus"
placeholder="请选择"
clearable
style="width: 200px"
>
<Option value="NEW">未开始</Option>
<Option value="START">已开始/上架</Option>
<Option value="END">已结束/下架</Option>
<Option value="CLOSE">紧急关闭/作废</Option>
</Select>
</Form-item>
<Form-item label="活动时间">
<DatePicker
v-model="selectDate"
type="daterange"
clearable
placeholder="选择起始时间"
style="width: 200px"
></DatePicker>
</Form-item>
<Button @click="handleSearch" type="primary" class="search-btn" icon="ios-search">搜索</Button>
</Form>
</Row>
<Row class="padding-row">
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
sortable="custom"
>
<template slot-scope="{ row }" slot="applyEndTime">
{{ unixDate(row.applyEndTime) }}
</template>
<template slot-scope="{ row }" slot="promotionType">
{{ row.isFullMinus ? "满减" : "满折" }}
</template>
<template slot-scope="{ row }" slot="hours">
<Tag v-for="item in unixHours(row.hours)" :key="item">{{
item
}}</Tag>
</template>
<template slot-scope="{ row }" slot="action">
<div>
<Button type="success" size="small" @click="view(row)"
>查看</Button
>&nbsp;
</div>
</template>
</Table>
</Row>
<Row type="flex" justify="end" class="page operation">
<Page
:current="searchForm.pageNumber + 1"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</Card>
</div>
</template>
<script>
import { getFullDiscountList } from "@/api/promotion.js";
export default {
data() {
return {
loading: false, // 表单加载状态
searchForm: {
pageNumber: 0,
pageSize: 10,
sort: "startTime",
order: "desc",
},
columns: [
{
title: "活动名称",
key: "promotionName",
minWidth: 120,
},
{
title: "开始时间",
key: "startTime",
width: 170,
},
{
title: "结束时间",
key: "endTime",
width: 170,
},
{
title: "店铺名称",
key: "storeName",
minWidth: 60,
},
{
title: "活动类型",
slot: "promotionType",
minWidth: 60,
},
{
title: "活动状态",
key: "promotionStatus",
minWidth: 60,
render: (h, params) => {
let text = "未知",
color = "default";
if (params.row.promotionStatus == "NEW") {
text = "未开始";
color = "default";
} else if (params.row.promotionStatus == "START") {
text = "已开始";
color = "green";
} else if (params.row.promotionStatus == "END") {
text = "已结束";
color = "blue";
} else if (params.row.promotionStatus == "CLOSE") {
text = "已关闭";
color = "red";
}
return h("div", [
h(
"Tag",
{
props: {
color: color,
},
},
text
),
]);
},
},
{
title: "操作",
slot: "action",
align: "center",
width: 100,
},
],
data: [], // 列表数据
};
},
methods: {
init() {
this.getDataList();
},
changePage(v) {
// 改变页数
this.searchForm.pageNumber = v - 1;
this.getDataList();
},
changePageSize(v) {
// 改变页码
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
// 搜索
this.searchForm.pageNumber = 0;
this.searchForm.pageSize = 10;
this.getDataList();
},
getDataList() {
this.loading = true;
if (this.selectDate && this.selectDate[0] && this.selectDate[1]) {
this.searchForm.startTime = this.selectDate[0].getTime();
this.searchForm.endTime = this.selectDate[1].getTime();
} else {
this.searchForm.startTime = null;
this.searchForm.endTime = null;
}
getFullDiscountList(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
view(row) {
// 查看
this.$router.push({ name: "full-cut-detail", query: { id: row.id } });
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss">
// 建议引入通用样式 可删除下面样式代码
@import "@/styles/table-common.scss";
</style>

View File

@@ -0,0 +1,319 @@
<template>
<div>
<Card>
<Form ref="form" :model="form" :label-width="120" :rules="formRule">
<div class="base-info-item">
<h4>基本信息</h4>
<div class="form-item-view">
<FormItem label="活动名称" prop="promotionName">
<Input
type="text"
v-model="form.promotionName"
disabled
placeholder="活动名称"
clearable
style="width: 260px"
/>
</FormItem>
<FormItem label="活动时间" prop="rangeTime">
<DatePicker
type="datetimerange"
v-model="form.rangeTime"
disabled
format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择"
:options="options"
style="width: 320px"
>
</DatePicker>
</FormItem>
<FormItem label="活动描述" prop="description">
<Input
v-model="form.description"
disabled
type="textarea"
:rows="4"
clearable
style="width: 260px"
/>
</FormItem>
</div>
<h4>优惠设置</h4>
<div class="form-item-view">
<FormItem label="优惠门槛" prop="fullMoney">
<Input
type="text"
v-model="form.fullMoney"
disabled
placeholder="优惠门槛"
clearable
style="width: 260px"
/>
<span class="describe">消费达到当前金额可以参与优惠</span>
</FormItem>
<FormItem label="优惠方式">
<RadioGroup v-model="form.discountType">
<Radio label="isFullMinus" disabled>减现金</Radio>
<Radio label="isFullRate" disabled>打折</Radio>
</RadioGroup>
</FormItem>
<FormItem
v-if="form.discountType == 'isFullMinus'"
label="优惠金额"
prop="fullMinus"
>
<Input
type="text"
disabled
v-model="form.fullMinus"
placeholder="优惠金额"
clearable
style="width: 260px"
/>
</FormItem>
<FormItem
v-if="form.discountType == 'isFullRate'"
label="优惠折扣"
prop="fullRate"
>
<Input
type="text"
v-model="form.fullRate"
placeholder="优惠折扣"
disabled
clearable
style="width: 260px"
/>
<span class="describe">优惠折扣为0-10之间数字可有一位小数</span>
</FormItem>
<FormItem label="额外赠送">
<Checkbox v-model="form.isFreeFreight" disabled>免邮费</Checkbox
>&nbsp;
<Checkbox v-model="form.isCoupon" disabled>送优惠券</Checkbox
>&nbsp;
<Checkbox v-model="form.isGift" disabled>送赠品</Checkbox>&nbsp;
<Checkbox v-model="form.isPoint" disabled>送积分</Checkbox>
</FormItem>
<FormItem v-if="form.isCoupon" label="赠送优惠券" prop="couponId">
<Select
v-model="form.couponId"
filterable
:remote-method="getCouponList"
placeholder="输入优惠券名称搜索"
disabled
:loading="couponLoading"
style="width: 260px"
>
<Option
v-for="item in couponList"
:value="item.id"
:key="item.id"
>{{ item.couponName }}</Option
>
</Select>
</FormItem>
<FormItem v-if="form.isGift" label="赠品" prop="giftId">
<Select
v-model="form.giftId"
filterable
:remote-method="getGiftList"
placeholder="输入赠品名称搜索"
disabled
:loading="giftLoading"
style="width: 260px"
>
<Option
v-for="item in giftList"
:value="item.id"
:key="item.id"
>{{ item.goodsName }}</Option
>
</Select>
</FormItem>
<FormItem v-if="form.isPoint" label="赠积分" prop="point">
<Input
v-model="form.point"
type="number"
disabled
style="width: 260px"
/>
</FormItem>
<FormItem label="使用范围" prop="scopeType">
<RadioGroup v-model="form.scopeType">
<Radio label="ALL" disabled>全品类</Radio>
<Radio label="PORTION_GOODS" disabled>指定商品</Radio>
</RadioGroup>
</FormItem>
<FormItem
style="width: 100%"
v-if="form.scopeType == 'PORTION_GOODS'"
>
<Table
border
:columns="columns"
:data="form.promotionGoodsList"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="QRCode">
<img
:src="row.QRCode || '../../../assets/lili.png'"
width="50px"
height="50px"
alt=""
/>
</template>
</Table>
</FormItem>
<div>
<Button @click="$router.push({ name: 'fullCut' })">返回</Button>
</div>
</div>
</div>
</Form>
</Card>
</div>
</template>
<script>
import { getPlatformCouponList, getFullDiscountById } from "@/api/promotion";
import { getGoodsSkuData } from "@/api/goods";
export default {
name: "addFullCut",
data() {
return {
form: {
discountType: "isFullMinus",
scopeType: "ALL",
promotionGoodsList: [],
},
id: this.$route.query.id,
couponList: [],
giftList: [],
giftLoading: false,
couponList: false,
columns: [
{
type: "selection",
width: 60,
align: "center",
},
{
title: "商品名称",
key: "goodsName",
minWidth: 120,
},
{
title: "商品价格",
key: "price",
minWidth: 40,
render: (h, params) => {
return h(
"div",
this.$options.filters.unitPrice(params.row.price, "¥")
);
},
},
{
title: "库存",
key: "quantity",
minWidth: 40,
},
{
title: "商品二维码",
slot: "QRCode",
},
],
options: {
disabledDate(date) {
return date && date.valueOf() < Date.now() - 86400000;
},
},
};
},
async mounted() {
if (this.id) {
this.getDetail();
}
this.getCouponList();
this.getGiftList();
},
methods: {
getDetail() {
// 获取活动详情
getFullDiscountById(this.id).then((res) => {
let data = res.result;
if (!data.promotionGoodsList) {
data.promotionGoodsList = [];
data.scopeType = "ALL";
} else {
data.scopeType = "PORTION_GOODS";
}
if (data.isFullMinus) {
data.discountType = "isFullMinus";
delete data.isFullMinus;
} else {
data.discountType = "isFullMinus";
delete data.isFullRate;
}
data.rangeTime = [];
data.rangeTime.push(new Date(data.startTime), new Date(data.endTime));
this.form = data;
});
},
getCouponList(query) {
// 优惠券列表
let params = {
pageSize: 10,
pageNumber: 0,
couponName: query,
};
this.couponLoading = true;
getPlatformCouponList(params).then((res) => {
this.couponLoading = false;
if (res.success) {
this.couponList = res.result.records;
}
});
},
getGiftList(query) {
// 赠品列表
let params = {
pageSize: 10,
pageNumber: 1,
goodsName: query,
};
this.giftLoading = true;
getGoodsSkuData(params).then((res) => {
this.giftLoading = false;
if (res.success) {
this.giftList = res.result.records;
}
});
},
},
};
</script>
<style lang="scss" scoped>
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.describe {
font-size: 12px;
margin-left: 10px;
color: #999;
}
</style>

View File

@@ -0,0 +1,246 @@
<template>
<div class="search">
<Card>
<Row v-show="openSearch">
<Form
ref="searchForm"
:model="searchForm"
inline
:label-width="70"
class="search-form"
>
<Form-item label="活动名称" prop="promotionName">
<Input
type="text"
v-model="searchForm.promotionName"
placeholder="请输入活动名称"
clearable
style="width: 200px"
/>
</Form-item>
<Form-item label="活动状态" prop="promotionStatus">
<Select
v-model="searchForm.promotionStatus"
placeholder="请选择"
clearable
style="width: 200px"
>
<Option value="NEW">未开始</Option>
<Option value="START">已开始/上架</Option>
<Option value="END">已结束/下架</Option>
<Option value="CLOSE">紧急关闭/作废</Option>
</Select>
</Form-item>
<Form-item label="活动时间">
<DatePicker
v-model="selectDate"
type="daterange"
clearable
placeholder="选择起始时间"
style="width: 200px"
></DatePicker>
</Form-item>
<Button @click="handleSearch" type="primary" class="search-btn"
>搜索</Button
>
</Form>
</Row>
<Row class="padding-row">
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
>
<template slot-scope="{ row }" slot="action">
<Button
type="info"
size="small"
@click="view(row)"
style="margin-right: 5px"
>查看</Button
>
<Button
type="error"
size="small"
:disabled="
row.promotionStatus == 'END' || row.promotionStatus == 'CLOSE'
"
@click="close(row)"
>关闭
</Button>
</template>
</Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber + 1"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</Card>
</div>
</template>
<script>
import { getPintuanList, closePintuan } from "@/api/promotion";
export default {
name: "pintuan",
components: {},
data() {
return {
loading: true, // 表单加载状态
openSearch: true,
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageSize: 10, // 页面大小
sort: "startTime",
order: "desc", // 默认排序方式
},
columns: [
{
title: "活动名称",
key: "promotionName",
minWidth: 150,
tooltip: true,
},
{
title: "状态",
key: "promotionStatus",
width: 110,
render: (h, params) => {
let text = "未知",
color = "";
if (params.row.promotionStatus == "NEW") {
text = "未开始";
color = "default";
} else if (params.row.promotionStatus == "START") {
text = "已开始";
color = "green";
} else if (params.row.promotionStatus == "END") {
text = "已结束";
color = "blue";
} else if (params.row.promotionStatus == "CLOSE") {
text = "已关闭";
color = "red";
}
return h("div", [
h(
"Tag",
{
props: { color: color },
},
text
),
]);
},
},
{
title: "所属店铺",
key: "storeName",
minWidth: 120,
tooltip: true,
},
{
title: "活动开始时间",
key: "startTime",
width: 180
},
{
title: "活动结束时间",
key: "endTime",
width: 180
},
{
fixed: "right",
title: "操作",
slot: "action",
align: "center",
width: 200,
},
],
data: [], // 表单数据
total: 0, // 表单数据总数
};
},
methods: {
init() {
this.getDataList();
},
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 0;
this.searchForm.pageSize = 10;
this.getDataList();
},
getDataList() {
this.loading = true;
if (this.selectDate && this.selectDate[0] && this.selectDate[1]) {
this.searchForm.startTime = this.selectDate[0].getTime();
this.searchForm.endTime = this.selectDate[1].getTime();
} else {
this.searchForm.startTime = null;
this.searchForm.endTime = null;
}
getPintuanList(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
view(v) {
this.$router.push({ name: "pintuan-goods", query: { id: v.id } });
},
close(v) {
this.$Modal.confirm({
title: "确认关闭",
// 记得确认修改此处
content: "您确认要关闭此拼团活动?",
loading: true,
onOk: () => {
// 删除
closePintuan(v.id).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("操作成功");
this.getDataList();
}
});
},
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss" scoped>
@import "@/styles/table-common.scss";
.ivu-form-item{
margin-bottom: 0 !important;
}
</style>

View File

@@ -0,0 +1,255 @@
<template>
<div class="pintuan-goods">
<Card>
<h4>活动详情</h4>
<Table
style="margin: 10px 0"
border
:columns="columns"
:data="data"
></Table>
<h4>商品信息</h4>
<Row class="operation">
<Table
:loading="loading"
border
:columns="goodsColumns"
:data="goodsData"
ref="table"
sortable="custom"
@on-sort-change="changeSort"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="goodsName">
<span>{{ row.goodsName }}</span>
</template>
<template slot-scope="{ row }" slot="QRCode">
<Button @click="toBuyerGoods(row)" type="info">商品链接地址</Button>
<Button
v-if="row.QRCode != null"
type="success"
@click="viewImg(row.QRCode)"
>查看二维码</Button
>
</template>
</Table>
</Row>
<Row type="flex" justify="end" class="page operation">
<Page
:current="searchForm.pageNumber + 1"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</Card>
<Modal title="查看图片" v-model="visible">
<img
:src="showImg"
v-if="visible"
style="width: 200px; height: 200px; margin-left: 130px"
/>
</Modal>
</div>
</template>
<script>
import { getPintuanGoodsList, getPintuanDetail } from "@/api/promotion.js";
import config from "@/config";
const buyerUrl =
process.env.NODE_ENV === "development"
? config.api_dev.buyer
: config.api_prod.buyer;
export default {
data() {
return {
visible: false,
showImg: "",
openSearch: true, // 显示搜索
openTip: true, // 显示提示
loading: false, // 表单加载状态
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageSize: 10, // 页面大小
},
submitLoading: false, // 添加或编辑提交状态
selectList: [], // 多选数据
selectCount: 0, // 多选计数
data: [], // 表单数据
total: 0, // 表单数据总数
columns: [
{
title: "活动名称",
key: "promotionName",
minWidth: 120
},
{
title: "活动开始时间",
key: "startTime",
minWidth: 120
},
{
title: "活动结束时间",
key: "endTime",
minWidth: 120
},
{
title: "成团人数",
key: "requiredNum",
},
{
title: "限购数量",
key: "limitNum",
},
{
title: "状态",
key: "promotionStatus",
minWidth: 100,
render: (h, params) => {
let text = "未知",
color = "";
if (params.row.promotionStatus == "NEW") {
text = "未开始";
color = "default";
} else if (params.row.promotionStatus == "START") {
text = "已开始";
color = "green";
} else if (params.row.promotionStatus == "END") {
text = "已结束";
color = "blue";
} else if (params.row.promotionStatus == "CLOSE") {
text = "已关闭";
color = "red";
}
return h("div", [
h(
"Tag",
{
props: {
color: color,
},
},
text
),
]);
},
},
],
goodsColumns: [
{
title: "商品名称",
slot: "goodsName",
minWidth: 120,
},
{
title: "库存",
key: "quantity",
minWidth: 40,
},
{
title: "拼团价格",
key: "price",
minWidth: 50,
render: (h, params) => {
return h(
"div",
this.$options.filters.unitPrice(params.row.price, "¥")
);
},
},
],
goodsData: [],
};
},
methods: {
init() {
this.getDataList();
this.getPintuanMsg();
},
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
handleReset() {
// 重置
this.searchForm.pageNumber = 0;
this.searchForm.promotionName = "";
this.selectDate = null;
// 重新加载数据
this.getDataList();
},
getDataList() {
this.loading = true;
this.searchForm.pintuanId = this.$route.query.id;
getPintuanGoodsList(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.goodsData = res.result.records;
this.total = res.result.total;
}
});
},
getPintuanMsg() {
// 获取拼团详情
getPintuanDetail(this.$route.query.id).then((res) => {
if (res.success) this.data.push(res.result);
});
},
toBuyerGoods(row) {
window.open(
buyerUrl +
"/pages/product/product?id=" +
row.skuId +
"&goodsId=" +
row.goodsId
);
},
viewImg(img) {
this.showImg = img;
this.visible = true;
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss" scoped>
.operation {
margin-bottom: 10px;
}
h4 {
margin: 20px 0;
padding: 0 10px;
font-weight: bold;
color: #333;
font-size: 14px;
text-align: left;
border-left: 3px solid red;
}
</style>

View File

@@ -0,0 +1,458 @@
<template>
<div class="wrapper">
<Card>
<Form ref="form" :model="form" :rules="formRule">
<div class="base-info-item">
<h4>添加积分商品</h4>
<div class="form-item-view">
<FormItem astyle="width: 100%">
<div style="display: flex; margin-bottom: 10px">
<Button type="primary" @click="$refs.skuSelect.open('goods')"
>选择商品</Button
>
<Button
type="error"
ghost
style="margin-left: 10px"
@click="delSelectGoods"
>批量删除</Button
>
</div>
<Table
border
:columns="columns"
:data="form.promotionGoodsList"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="skuId">
<div>{{ row.skuId }}</div>
</template>
<template slot-scope="{ row, index }" slot="settlementPrice">
<Input
type="number"
v-model="row.settlementPrice"
@input="
pointsGoodsList[index].settlementPrice =
row.settlementPrice
"
/>
</template>
<template
slot-scope="{ row, index }"
slot="pointsGoodsCategory"
>
<Select
v-model="pointsGoodsList[index].pointsGoodsCategoryId"
transfer="true"
label-in-value="true"
@on-change="
(val) => {
changeCategory(val, index);
}
"
>
<Option
v-for="item in categoryList"
:value="item.id"
:key="item.id"
>{{ item.name }}</Option
>
</Select>
</template>
<template slot-scope="{ row, index }" slot="activeStock">
<Input
type="number"
v-model="row.activeStock"
@input="
pointsGoodsList[index].activeStock = row.activeStock
"
/>
</template>
<template slot-scope="{ row, index }" slot="points">
<Input
type="number"
v-model="row.points"
@input="pointsGoodsList[index].points = row.points"
/>
</template>
</Table>
</FormItem>
<FormItem label="兑换时间" prop="time">
<DatePicker
type="datetime"
v-model="form.startTime"
format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择"
:options="options"
clearable
style="width: 200px"
>
</DatePicker>
-
<DatePicker
type="datetime"
v-model="form.endTime"
format="yyyy-MM-dd HH:mm:ss"
:options="options"
placeholder="请选择"
clearable
style="width: 200px"
>
</DatePicker>
</FormItem>
<div>
<Button type="text" @click="closeCurrentPage">返回</Button>
<Button
type="primary"
:loading="submitLoading"
@click="handleSubmit"
>提交</Button
>
</div>
</div>
</div>
</Form>
</Card>
<sku-select
ref="skuSelect"
@selectedGoodsData="selectedGoodsData"
></sku-select>
</div>
</template>
<script>
import { addPointsGoods, getPointsGoodsCategoryList } from "@/api/promotion";
import { regular } from "@/utils";
import skuSelect from "@/views/lili-dialog";
export default {
name: "addPoinsGoods",
components: {
skuSelect,
},
data() {
const isLtEndDate = (rule, value, callback) => {
if (new Date(value).getTime() > new Date(this.form.endTime).getTime()) {
callback(new Error());
} else {
callback();
}
};
const isGtStartDate = (rule, value, callback) => {
if (new Date(value).getTime() < new Date(this.form.startTime).getTime()) {
callback(new Error());
} else {
callback();
}
};
return {
maxHeight: "240px",
modalType: 0,
/** 当前状态/模式 默认发布商品0 编辑商品1 编辑草稿箱商品2 */
currentStatus: 0,
categoryId: 0,
form: {
/** 店铺承担比例 */
sellerCommission: 0,
/** 发行数量 */
publishNum: 1,
/** 运费承担者 */
scopeType: "ALL",
/** 限领数量 */
couponLimitNum: 1,
/** 活动类型 */
couponType: "PRICE",
/** 优惠券名称 */
couponName: "",
getType: "FREE",
promotionGoodsList: [],
},
pointsGoodsList: [],
categoryList: [],
submitLoading: false, // 添加或编辑提交状态
selectedGoods: [], // 已选商品列表,便于删除
formRule: {
startTime: [
{
required: true,
type: "date",
message: "请选择开始时间",
},
{
trigger: "change",
message: "开始时间要小于结束时间",
validator: isLtEndDate,
},
],
endTime: [
{
required: true,
type: "date",
message: "请选择结束时间",
},
{
trigger: "change",
message: "结束时间要大于开始时间",
validator: isGtStartDate,
},
],
discount: [
{ required: true, message: "请输入折扣" },
{
pattern: regular.discount,
message: "请输入0-10的数字,可有一位小数",
},
],
sellerCommission: [
{ required: true, message: "请输入店铺承担比例" },
{ pattern: regular.rate, message: "请输入0-100的正整数" },
],
publishNum: [
{ required: true, message: "请输入发放数量" },
{ pattern: regular.integer, message: "请输入正整数" },
],
couponLimitNum: [
{ required: true, message: "请输入领取限制" },
{ pattern: regular.integer, message: "请输入正整数" },
],
description: [{ required: true, message: "请输入范围描述" }],
},
columns: [
{
type: "selection",
width: 60,
align: "center",
},
{
title: "商品名称",
key: "goodsName",
minWidth: 120,
},
{
title: "SKU编码",
slot: "skuId",
minWidth: 120,
},
{
title: "店铺名称",
key: "sellerName",
minWidth: 60,
},
{
title: "商品价格",
key: "price",
minWidth: 40,
render: (h, params) => {
return h(
"div",
this.$options.filters.unitPrice(params.row.price, "")
);
},
},
{
title: "库存",
key: "quantity",
minWidth: 20,
},
{
title: "结算价格",
slot: "settlementPrice",
minWidth: 40,
},
{
title: "分类",
slot: "pointsGoodsCategory",
minWidth: 60,
},
{
title: "活动库存",
slot: "activeStock",
minWidth: 40,
},
{
title: "兑换积分",
slot: "points",
minWidth: 40,
},
{
title: "操作",
key: "action",
minWidth: 50,
align: "center",
render: (h, params) => {
return h(
"Button",
{
props: {
size: "small",
type: "error",
ghost: true,
},
on: {
click: () => {
this.delGoods(params.index);
},
},
},
"删除"
);
},
},
],
options: {
disabledDate(date) {
return date && date.valueOf() < Date.now() - 86400000;
},
},
};
},
async mounted() {
await this.getCategory();
},
methods: {
async getCategory() {
let res = await getPointsGoodsCategoryList();
this.categoryList = res.result.records;
},
/** 保存平台优惠券 */
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
let params = this.pointsGoodsList;
const start = this.$options.filters.unixToDate(
this.form.startTime / 1000
);
const end = this.$options.filters.unixToDate(
this.form.endTime / 1000
);
if (!params || params.length == 0) {
this.$Modal.warning({ title: "提示", content: "请选择指定商品" });
return;
}
this.submitLoading = true;
params = params.map((j) => {
j.startTime = start;
j.endTime = end;
return j;
});
addPointsGoods(params).then((res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("积分商品创建成功");
this.closeCurrentPage();
}
});
}
});
},
// 关闭当前页面
closeCurrentPage() {
this.$store.commit("removeTag", "add-poonts-goods");
localStorage.pageOpenedList = JSON.stringify(
this.$store.state.app.pageOpenedList
);
this.$router.go(-1);
},
changeCategory(val, index) {
this.pointsGoodsList[index].pointsGoodsCategoryName = val.label;
},
changeSelect(e) {
// 已选商品批量选择
this.selectedGoods = e;
},
delSelectGoods() {
// 多选删除商品
if (this.pointsGoodsList.length <= 0) {
this.$Message.warning("您还未选择要删除的数据");
return;
}
this.$Modal.confirm({
title: "确认删除",
content: "您确认要删除所选商品吗?",
onOk: () => {
let ids = [];
this.selectedGoods.forEach(function (e) {
ids.push(e.id);
});
this.form.promotionGoodsList = this.form.promotionGoodsList.filter(
(item) => {
return !ids.includes(item.id);
}
);
this.pointsGoodsList = this.pointsGoodsList.filter((item) => {
return !ids.includes(item.id);
});
},
});
},
delGoods(index) {
// 删除商品
this.form.promotionGoodsList.splice(index, 1);
this.pointsGoodsList.splice(index, 1);
},
selectedGoodsData(item) {
// 回显已选商品
let ids = [];
let list = [];
this.form.promotionGoodsList.forEach((e) => {
ids.push(e.id);
});
item.forEach((e) => {
if (!ids.includes(e.id)) {
list.push({
goodsName: e.goodsName,
price: e.price,
originalPrice: e.price,
quantity: e.quantity,
storeId: e.storeId,
sellerName: e.sellerName,
skuId: e.id,
...e,
});
this.pointsGoodsList.push({
settlementPrice: 0,
pointsGoodsCategoryId: 0,
pointsGoodsCategoryName: "",
activeStock: 0,
points: 0,
goodsSku: {
...e,
},
skuId: e.id,
});
}
});
this.form.promotionGoodsList.push(...list);
},
},
};
</script>
<style lang="scss" scpoed>
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.describe {
font-size: 12px;
margin-left: 10px;
color: #999;
}
.wrapper{
min-height: 800px;
}
</style>

View File

@@ -0,0 +1,374 @@
<template>
<div>
<Card>
<Form ref="form" :model="form" :label-width="120" :rules="formRule">
<div class="base-info-item">
<h4>积分商品信息</h4>
<div class="form-item-view">
<FormItem label="商品名称" prop="goodsName">
<div>{{ form.goodsSku.goodsName }}</div>
</FormItem>
<FormItem label="SKU编码" prop="skuId">
<div>{{ form.goodsSku.id }}</div>
</FormItem>
<FormItem label="店铺名称" prop="sellerName">
<div>{{ form.goodsSku.sellerName }}</div>
</FormItem>
<FormItem label="商品价格" prop="goodsPrice">
<div>{{ form.goodsSku.price }}</div>
</FormItem>
<FormItem label="库存" prop="quantity">
<div>{{ form.goodsSku.quantity }}</div>
</FormItem>
<FormItem label="结算价格" prop="settlementPrice">
<Input
type="num"
v-model="form.settlementPrice"
placeholder="请填写结算价格"
clearable
style="width: 260px"
/>
</FormItem>
<FormItem label="分类" prop="pointsGoodsCategoryId">
<Select
v-model="form.pointsGoodsCategoryId"
label-in-value="true"
@on-change="
(val) => {
changeCategory(val, index);
}
"
>
<Option
v-for="item in categoryList"
:value="item.id"
:key="item.id"
>{{ item.name }}</Option
>
</Select>
</FormItem>
<FormItem label="活动库存" prop="activeStock">
<Input
type="number"
v-model="form.activeStock"
placeholder="请填写活动库存"
clearable
style="width: 260px"
/>
</FormItem>
<FormItem label="兑换积分" prop="points">
<Input
type="number"
v-model="form.points"
placeholder="请填写兑换积分"
clearable
style="width: 260px"
/>
</FormItem>
<FormItem label="活动开始时间" prop="startTime">
<DatePicker
type="datetime"
v-model="form.startTime"
format="yyyy-MM-dd HH:mm:ss"
:options="options"
placeholder="请选择"
clearable
style="width: 200px"
>
</DatePicker>
-
<DatePicker
type="datetime"
v-model="form.endTime"
format="yyyy-MM-dd HH:mm:ss"
:options="options"
placeholder="请选择"
clearable
style="width: 200px"
>
</DatePicker>
</FormItem>
</div>
<div class="footer">
<Button @click="closeCurrentPage" style="margin-right: 5px"
>返回</Button
>
<Button
type="primary"
:loading="submitLoading"
@click="handleSubmit"
>保存</Button
>
</div>
</div>
</Form>
</Card>
</div>
</template>
<script>
import {
updatePointsGoods,
getPointsGoodsById,
getPointsGoodsCategoryList,
} from "@/api/promotion";
import { format } from "date-fns";
export default {
name: "addCoupon",
data() {
return {
maxHeight: "240px",
modalType: 0,
/** 当前状态/模式 默认发布商品0 编辑商品1 编辑草稿箱商品2 */
currentStatus: 0,
categoryId: 0,
form: {
/** 活动名称 */
promotionName: "",
/** 报名截止时间 */
applyEndTime: "",
/** 活动开始时间 */
startTime: "",
/** 抢购时间段 */
seckillPeriod: [],
/** 申请规则 */
seckillRule: "",
goodsSku: {},
promotionStatus: "NEW",
},
categoryList: [],
id: this.$route.query.id,
periodTime: 0,
submitLoading: false, // 添加或编辑提交状态
formRule: {
settlementPrice: [{ required: true, message: "请填写结算价格" }],
pointsGoodsCategoryId: [
{ required: true, message: "请选择积分商品分类" },
],
points: [{ required: true, message: "请填写兑换积分" }],
startTime: [{ required: true, message: "请填写活动开始时间" }],
},
};
},
async mounted() {
await this.getCategory();
// 如果id不为空则查询信息
if (this.id) {
this.getData();
this.modalType = 1;
}
},
methods: {
// 关闭当前页面
closeCurrentPage() {
this.$store.commit("removeTag", "edit-points-goods");
localStorage.pageOpenedList = JSON.stringify(
this.$store.state.app.pageOpenedList
);
this.$router.go(-1);
},
getData() {
getPointsGoodsById(this.id).then((res) => {
if (res.success) {
let data = res.result;
this.form = data;
}
});
},
async getCategory() {
let res = await getPointsGoodsCategoryList();
this.categoryList = res.result.records;
},
/** 保存平台优惠券 */
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
const start = this.$options.filters.unixToDate(
this.form.startTime / 1000
);
const end = this.$options.filters.unixToDate(
this.form.endTime / 1000
);
this.form.startTime = start;
this.form.endTime = end;
this.submitLoading = true;
updatePointsGoods(this.form).then((res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("积分商品修改成功");
this.closeCurrentPage();
}
});
}
});
},
},
};
</script>
<style lang="scss" scoped>
/*编辑基本信息*/
.el-form {
padding-bottom: 80px;
.el-form-item {
width: 100%;
color: gray;
text-align: left;
}
}
/*平铺*/
div.base-info-item > div {
margin-left: 5%;
}
div.base-info-item {
margin-bottom: 10px;
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.form-item-view {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
padding-left: 80px;
.shop-category-text {
font-size: 12px;
}
}
.item-goods-properts-row {
display: flex;
flex-direction: row;
word-break: break-all;
white-space: normal;
width: 300px;
height: 100px;
}
.item-goods-properts {
display: flex;
flex-direction: row;
margin-bottom: 10px;
}
.form-item {
display: flex;
align-items: center;
}
/** 审核信息-拒绝原因 */
.auth-info {
color: red;
}
.el-form-item {
width: 30%;
min-width: 300px;
}
.goods-name-width {
width: 50%;
min-width: 300px;
}
.el-form-item__content {
margin-left: 120px;
text-align: left;
}
p.goods-group-manager {
padding-left: 7.5%;
text-align: left;
color: #999;
font-size: 13px;
}
/*teatarea*/
/deep/ .el-textarea {
width: 150%;
}
.seo-text {
width: 150%;
}
}
/*商品描述*/
.goods-intro {
line-height: 40;
}
/** 底部步骤 */
.footer {
width: 100%;
padding: 10px;
background-color: #ffc;
position: fixed;
bottom: 0px;
right: 0;
text-align: center;
z-index: 9999;
}
/*图片上传组件第一张图设置封面*/
.goods-images {
/deep/ li.el-upload-list__item:first-child {
position: relative;
}
/deep/ li.el-upload-list__item:first-child:after {
content: "";
color: #fff;
font-weight: bold;
font-size: 12px;
position: absolute;
left: -15px;
top: -6px;
width: 40px;
height: 24px;
padding-top: 6px;
background: #13ce66;
text-align: center;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
}
}
.el-form-item__label {
word-break: break-all;
}
.step-view {
width: 33%;
height: 40px;
font-size: 19px;
text-align: center;
display: flex;
background-color: #fff;
justify-content: center;
align-items: center;
}
.page {
margin-top: 2vh;
margin-bottom: 5vh;
}
</style>

View File

@@ -0,0 +1,336 @@
<template>
<div class="search">
<Card>
<Row>
<Form
ref="searchForm"
:model="searchForm"
inline
:label-width="70"
class="search-form"
>
<Form-item label="商品名称">
<Input
type="text"
v-model="searchForm.goodsName"
placeholder="请输入商品名称"
clearable
style="width: 200px"
/>
</Form-item>
<Form-item label="积分区间">
<Input
type="text"
v-model="searchForm.pointsS"
placeholder="请输入开始区间"
clearable
style="width: 200px"
/>
-
<Input
type="text"
v-model="searchForm.pointsE"
placeholder="请输入结束区间"
clearable
style="width: 200px"
/>
</Form-item>
<Form-item label="状态">
<Select v-model="searchForm.promotionStatus" style="width: 200px">
<Option
v-for="item in statusList"
:value="item.value"
:key="item.value"
>{{ item.label }}</Option
>
</Select>
</Form-item>
<Form-item label="SKU编码">
<Input
type="text"
v-model="searchForm.skuId"
placeholder="请输入SKU编码"
clearable
style="width: 200px"
/>
</Form-item>
<Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
</Form>
</Row>
<Row class="operation padding-row">
<Button @click="addPointsGoods" type="primary" >添加积分商品</Button>
</Row>
<Row>
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
>
<template slot-scope="{ row }" slot="goodsName">
<div class="div-zoom" >
<a>{{ row.goodsSku.goodsName }}</a>
</div>
</template>
<template slot-scope="{ row }" slot="price">
<div>{{ row.goodsSku.price | unitPrice("¥") }}</div>
</template>
<template slot-scope="{ row }" slot="settlementPrice">
<div>{{ row.settlementPrice | unitPrice("¥") }}</div>
</template>
<template slot-scope="{ row }" slot="quantity">
<div>{{ row.goodsSku.quantity }}</div>
</template>
<template slot-scope="{ row }" slot="action">
<Button
v-if="row.promotionStatus == 'NEW'"
type="info"
size="small"
@click="edit(row.id)"
style="margin-right: 5px"
>编辑</Button
>
<Button
v-if="row.promotionStatus == 'START'"
type="warning"
size="small"
@click="statusChanged(row.id, 'CLOSE')"
style="margin-right: 5px"
>停用</Button
>
<Button
v-if="row.promotionStatus == 'CLOSE'"
type="warning"
size="small"
@click="statusChanged(row.id, 'START')"
style="margin-right: 5px"
>启用</Button
>
<Button type="error" size="small" @click="close(row.id)"
>删除</Button
>
</template>
</Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber + 1"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</Card>
</div>
</template>
<script>
import {
getPointsGoodsList,
editPointsGoodsStatus,
deletePointsGoodsStatus,
} from "@/api/promotion";
export default {
name: "pointsGoods",
components: {},
data() {
return {
loading: true, // 表单加载状态
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageSize: 10, // 页面大小
order: "desc", // 默认排序方式
},
statusList: [
{ label: "未开始", value: "NEW" },
{ label: "已开始", value: "START" },
{ label: "已结束", value: "END" },
{ label: "已关闭", value: "CLOSE" },
],
columns: [
{
title: "商品名称",
slot: "goodsName",
minWidth: 120,
tooltip: true,
},
{
title: "市场价",
slot: "price",
minWidth: 60,
},
{
title: "结算价",
slot: "settlementPrice",
minWidth: 60,
},
{
title: "分类",
key: "pointsGoodsCategoryName",
minWidth: 60,
},
{
title: "库存数量",
slot: "quantity",
minWidth: 60,
},
{
title: "活动剩余库存",
key: "activeStock",
minWidth:90,
},
{
title: "兑换积分",
key: "points",
minWidth: 60,
},
{
title: "所属店铺",
key: "storeName",
minWidth: 60,
},
{
title: "活动开始时间",
key: "startTime",
minWidth: 140,
},
{
title: "活动结束时间",
key: "endTime",
minWidth: 140,
},
{
title: "状态",
key: "promotionStatus",
minWidth: 60,
render: (h, params) => {
let text = "未知",
color = "";
if (params.row.promotionStatus == "NEW") {
text = "未开始";
color = "default";
} else if (params.row.promotionStatus == "START") {
text = "已开始";
color = "green";
} else if (params.row.promotionStatus == "END") {
text = "已结束";
color = "blue";
} else if (params.row.promotionStatus == "CLOSE") {
text = "已关闭";
color = "red";
}
return h("div", [h("Tag", { props: { color: color } }, text)]);
},
},
{
title: "操作",
slot: "action",
align: "center",
width: 150,
},
],
data: [], // 表单数据
total: 0, // 表单数据总数
};
},
methods: {
init() {
this.getDataList();
},
addPointsGoods() {
this.$router.push({ name: "add-points-goods" });
},
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 0;
this.searchForm.pageSize = 10;
if (this.searchForm.pointsS !== "") {
this.searchForm.points =
this.searchForm.pointsS +
"_" +
(this.searchForm.pointsE ? this.searchForm.pointsE : "");
}
this.getDataList();
},
getDataList() {
this.loading = true;
getPointsGoodsList(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
edit(id) {
this.$router.push({ name: "edit-points-goods", query: { id: id } });
},
statusChanged(id, status) {
let text = "";
if (status == "START") {
text = "开启";
} else if (status == "CLOSE") {
text = "关闭";
}
this.$Modal.confirm({
title: "确认" + text,
content: "您确认要" + text + "此积分商品?",
loading: true,
onOk: () => {
editPointsGoodsStatus(id, {
promotionStatus: status,
}).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success(text + "成功");
this.getDataList();
}
});
},
});
},
close(id) {
this.$Modal.confirm({
title: "确认删除",
content: "您确认要删除此积分商品?",
loading: true,
onOk: () => {
// 删除
deletePointsGoodsStatus(id).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("操作成功");
this.getDataList();
}
});
},
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss">
@import "@/styles/table-common.scss";
</style>

View File

@@ -0,0 +1,217 @@
<template>
<div>
<div class="operation">
<Button @click="addParent" icon="md-add">添加积分商品分类</Button>
<Button icon="md-refresh" @click="refresh">刷新</Button>
</div>
<tree-table
ref="treeTable"
size="default"
:loading="loading"
:data="tableData"
:columns="columns"
:border="true"
:show-index="false"
:is-fold="true"
:expand-type="false"
primary-key="id"
>
<template slot="action" slot-scope="scope">
<Dropdown transfer="true" trigger="click">
<Button type="primary" size="small">
操作
<Icon type="ios-arrow-down"></Icon>
</Button>
<DropdownMenu slot="list">
<DropdownItem @click.native="edit(scope.row)">编辑</DropdownItem>
<DropdownItem @click.native="remove(scope.row)">删除</DropdownItem>
</DropdownMenu>
</Dropdown>
</template>
</tree-table>
<Modal
:title="modalTitle"
v-model="modalVisible"
:mask-closable="false"
:width="500"
>
<Form
ref="form"
:model="formAdd"
:label-width="100"
:rules="formValidate"
>
<FormItem label="分类名称" prop="name">
<Input v-model="formAdd.name" clearable style="width: 100%" />
</FormItem>
<FormItem label="排序值" prop="sortOrder">
<Input v-model="formAdd.sortOrder" clearable style="width: 100%" />
</FormItem>
</Form>
<div slot="footer">
<Button type="text" @click="modalVisible = false">取消</Button>
<Button type="primary" :loading="submitLoading" @click="Submit"
>提交</Button
>
</div>
</Modal>
</div>
</template>
<script>
import {
getPointsGoodsCategoryList,
addPointsGoodsCategory,
updatePointsGoodsCategory,
deletePointsGoodsCategoryById,
} from "@/api/promotion";
import TreeTable from "@/views/my-components/tree-table/Table/Table";
import uploadPicInput from "@/views/my-components/lili/upload-pic-input";
export default {
name: "pointsGoodsCategory",
components: {
TreeTable,
uploadPicInput,
},
data() {
return {
currView: "index",
loading: false,
selectCount: 0,
categoryId: "",
expandLevel: 1,
modalType: 0, // 添加或编辑标识
modalVisible: false, // 添加或编辑显示
modalTitle: "", // 添加或编辑标题
showParent: false, // 是否展示上级菜单
parentTitle: "", // 父级菜单名称
formAdd: {
// 添加或编辑表单对象初始化数据
parentId: 0,
name: "",
deleteFlag: 0,
level: 0,
},
// 表单验证规则
formValidate: {
name: [{ required: true, message: "商品分类名称不能为空" }],
},
columns: [
{
title: "分类名称",
key: "name",
minWidth: "120px",
},
{
title: "操作",
key: "action",
align: "center",
headerAlign: "center",
width: "400px",
type: "template",
template: "action",
},
],
tableData: [],
};
},
methods: {
init() {
this.getAllList();
},
refresh() {
this.loading = true;
let that = this;
setTimeout(function () {
that.loading = false;
}, 1000);
},
edit(v) {
this.modalType = 1;
this.modalTitle = "编辑";
this.formAdd.id = v.id;
this.formAdd.name = v.name;
this.formAdd.sortOrder = v.sortOrder;
this.showParent = false;
this.modalVisible = true;
},
addParent() {
this.modalType = 0;
this.modalTitle = "添加积分商品分类";
this.parentTitle = "顶级分类";
this.showParent = true;
this.$refs.form.resetFields();
delete this.formAdd.id;
this.formAdd.parentId = 0;
this.modalVisible = true;
},
Submit() {
this.$refs.form.validate((valid) => {
console.log(valid);
if (valid) {
this.submitLoading = true;
if (this.modalType === 0) {
// 添加 避免编辑后传入id等数据 记得删除
delete this.formAdd.id;
addPointsGoodsCategory(this.formAdd).then((res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("添加成功");
this.getAllList();
this.modalVisible = false;
this.$refs.form.resetFields();
}
});
} else {
// 编辑
updatePointsGoodsCategory(this.formAdd).then((res) => {
this.submitLoading = false;
if (res.success) {
this.$Message.success("修改成功");
this.getAllList();
this.modalVisible = false;
this.$refs.form.resetFields();
}
});
}
}
});
},
remove(v) {
this.$Modal.confirm({
title: "确认删除",
// 记得确认修改此处
content: "您确认要删除 " + v.name + " ?",
loading: true,
onOk: () => {
// 删除
deletePointsGoodsCategoryById(v.id).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("操作成功");
this.getAllList();
}
});
},
});
},
getAllList() {
this.loading = true;
getPointsGoodsCategoryList().then((res) => {
this.loading = false;
if (res.success) {
this.tableData = res.result.records;
}
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,264 @@
/*选择商品品类*/
.content-goods-publish {
padding: 15px;
margin: 0 auto;
text-align: center;
border: 1px solid #ddd;
background: none repeat 0 0 #fff;
height: 100%;
margin-bottom: 20px;
/*商品品类*/
.goods-category {
text-align: left;
padding: 10px;
background: #fafafa;
border: 1px solid #e6e6e6;
ul {
padding: 8px 4px 8px 8px;
list-style: none;
width: 300px;
background: none repeat 0 0 #fff;
border: 1px solid #e6e6e6;
display: inline-block;
letter-spacing: normal;
margin-right: 15px;
vertical-align: top;
word-spacing: normal;
li {
line-height: 20px;
padding: 5px;
cursor: pointer;
color: #333;
font-size: 12px;
display: flex;
flex-wrap: nowrap;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
}
/** 当前品类被选中的样式 */
.activeClass {
background-color: #d9edf7;
border: 1px solid #bce8f1;
color: #3a87ad;
}
/*!*当前选择的商品品类文字*!*/
.current-goods-category {
text-align: left;
padding: 10px;
width: 100%;
border: 1px solid #fbeed5;
color: #c09853;
background-color: #fcf8e3;
margin: 10px auto;
padding: 8px 35px 8px 14px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
font-size: 12px;
font-weight: bold;
}
}
/*编辑基本信息*/
.el-form {
padding-bottom: 80px;
.el-form-item {
width: 100%;
color: gray;
text-align: left;
}
}
getGoodsCategoryLevelList
/*平铺*/
div.base-info-item>div {
margin-left: 5%;
}
div.base-info-item {
h4 {
margin-bottom: 10px;
padding: 0 10px;
border: 1px solid #ddd;
background-color: #f8f8f8;
font-weight: bold;
color: #333;
font-size: 14px;
line-height: 40px;
text-align: left;
}
.form-item-view {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
padding-left: 80px;
.shop-category-text {
font-size: 12px;
}
}
.item-goods-properts-row {
display: flex;
flex-direction: row;
word-break: break-all;
white-space: normal;
width: 300px;
height: 100px;
}
.item-goods-properts {
display: flex;
flex-direction: row;
margin-bottom: 10px;
}
.form-item {
display: flex;
align-items: center;
}
/** 审核信息-拒绝原因 */
.auth-info {
color: red;
}
.el-form-item {
width: 30%;
min-width: 300px;
}
.goods-name-width {
width: 50%;
min-width: 300px;
}
.el-form-item__content {
margin-left: 120px;
text-align: left;
}
p.goods-group-manager {
padding-left: 7.5%;
text-align: left;
color: #999;
font-size: 13px;
}
/*teatarea*/
/deep/ .el-textarea {
width: 150%;
}
.seo-text {
width: 150%;
}
}
/*折叠面板*/
.el-collapse-item {
/deep/ .el-collapse-item__header {
text-align: left;
background-color: #f8f8f8;
padding: 0 10px;
font-weight: bold;
color: #333;
font-size: 14px;
}
.el-form-item {
margin-left: 5%;
width: 25%;
}
/deep/ .el-form-item__content {
margin-left: 120px;
text-align: left;
}
p.goods-group-manager {
padding-left: 12%;
text-align: left;
color: #999;
}
/deep/ .el-collapse-item__content {
padding: 10px 0;
text-align: left;
}
}
/*商品描述*/
.goods-intro {
line-height: 40;
}
/** 底部步骤 */
.footer {
width: 88.7%;
padding: 10px;
background-color: #ffc;
position: fixed;
bottom: 0px;
left: 10%;
text-align: center;
z-index: 9999;
}
/*图片上传组件第一张图设置封面*/
.goods-images {
/deep/ li.el-upload-list__item:first-child {
position: relative;
}
/deep/ li.el-upload-list__item:first-child:after {
content: "";
color: #fff;
font-weight: bold;
font-size: 12px;
position: absolute;
left: -15px;
top: -6px;
width: 40px;
height: 24px;
padding-top: 6px;
background: #13ce66;
text-align: center;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
}
}
.el-form-item__label {
word-break: break-all;
}
.step-view {
width: 33%;
height: 40px;
font-size: 19px;
text-align: center;
display: flex;
background-color: #fff;
justify-content: center;
align-items: center;
}
.page {
margin-top: 2vh;
margin-bottom: 5vh;
}

View File

@@ -0,0 +1,222 @@
<template>
<div>
<Card>
<Form ref="form" :model="form" :label-width="120" :rules="formRule">
<div class="base-info-item">
<h4>基本信息</h4>
<div class="form-item-view">
<FormItem label="活动名称" prop="promotionName">
<Input
type="text"
v-model="form.promotionName"
placeholder="请填写活动名称"
clearable
:disabled="form.promotionStatus != 'NEW'"
style="width: 260px"
/>
</FormItem>
<FormItem label="报名截止时间" prop="applyEndTime">
<DatePicker
type="datetime"
v-model="form.applyEndTime"
format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择"
clearable
:disabled="form.promotionStatus != 'NEW'"
style="width: 200px"
>
</DatePicker>
</FormItem>
<FormItem label="活动开始时间" prop="startTime">
<DatePicker
type="datetime"
v-model="form.startTime"
:disabled="form.promotionStatus != 'NEW'"
format="yyyy-MM-dd"
placeholder="请选择"
clearable
style="width: 200px"
>
</DatePicker>
</FormItem>
<FormItem label="抢购时间段" prop="seckillPeriod">
<Tag
v-for="item in form.seckillPeriod"
:key="item"
:name="item"
closable
style="marrgin-left: 10px"
@on-close="removePeriodTime"
>{{ item >= 10 ? item : "0" + item }}:00</Tag
>
<InputNumber
:max="23"
:min="0"
v-model="periodTime"
v-show="showAddPeriod"
@on-blur="addPeriodTime"
></InputNumber>
<Button
type="default"
@click="addPeriod"
v-if="form.promotionStatus == 'NEW'"
>添加时间段</Button
>
</FormItem>
<FormItem label="申请规则" prop="seckillRule">
<Input
type="text"
v-model="form.seckillRule"
placeholder="申请规则"
clearable
:disabled="form.promotionStatus != 'NEW'"
style="width: 260px"
/>
</FormItem>
</div>
<div class="foot-btn">
<Button @click="closeCurrentPage" style="margin-right: 5px">返回</Button>
<Button
type="primary"
:loading="submitLoading"
v-if="form.promotionStatus == 'NEW'"
@click="handleSubmit"
>提交</Button
>
</div>
</div>
</Form>
</Card>
</div>
</template>
<script>
import { saveSeckill, updateSeckill, seckillDetail } from "@/api/promotion";
export default {
name: "addSeckill",
data() {
return {
maxHeight: "240px",
modalType: 0,
/** 当前状态/模式 默认发布商品0 编辑商品1 编辑草稿箱商品2 */
currentStatus: 0,
categoryId: 0,
form: {
/** 活动名称 */
promotionName: "",
/** 报名截止时间 */
applyEndTime: "",
/** 活动开始时间 */
startTime: "",
/** 抢购时间段 */
seckillPeriod: [],
/** 申请规则 */
seckillRule: "",
promotionStatus: "NEW",
},
id: this.$route.query.id,
periodTime: null,
showAddPeriod: false,
submitLoading: false, // 添加或编辑提交状态
formRule: {
promotionName: [{ required: true, message: "请填写活动名称" }],
applyEndTime: [{ required: true, message: "请填写报名截止时间" }],
seckillPeriod: [{ required: true, message: "请填写抢购时间段" }],
startTime: [{ required: true, message: "请填写活动开始时间" }],
seckillRule: [{ required: true, message: "请输入申请规则" }],
},
};
},
mounted() {
// 如果id不为空则查询信息
if (this.id) {
this.getData();
this.modalType = 1;
}
},
methods: {
// 关闭当前页面
closeCurrentPage() {
this.$store.commit("removeTag", "manager-seckill-add");
localStorage.pageOpenedList = JSON.stringify(this.$store.state.app.pageOpenedList);
this.$router.go(-1);
},
getData() {
seckillDetail(this.id).then((res) => {
if (res.success) {
let data = res.result;
data.seckillPeriod = res.result.hours.split(",");
this.form = data;
}
});
},
addPeriod() {
this.addPeriodTime();
this.showAddPeriod = true;
},
addPeriodTime() {
this.showAddPeriod = false;
if (
this.periodTime !== null &&
!this.form.seckillPeriod.includes(this.periodTime)
) {
this.form.seckillPeriod.push(this.periodTime);
}
},
removePeriodTime(event, name) {
this.form.seckillPeriod = this.form.seckillPeriod.filter((i) => i !== name);
},
handleSelectLink(item, index) {
// 调起选择链接弹窗
if (item) this.selectedNav = item;
this.$refs.liliDialog.open('link')
},
changeScope(val) {
if (val === "PORTION_GOODS") {
this.handleSelectLink();
}
},
/** 保存平台优惠券 */
handleSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.submitLoading = true;
this.form.hours = this.form.seckillPeriod.toString();
if (this.modalType === 0) {
// 添加 避免编辑后传入id等数据 记得删除
delete this.form.id;
saveSeckill(this.form).then((res) => {
this.submitLoading = false;
if (res && res.success) {
this.$Message.success("限时抢购活动添加成功");
this.closeCurrentPage();
}
});
} else {
delete this.form.createTime;
delete this.form.updateTime;
delete this.form.endTime;
// 编辑
updateSeckill(this.form).then((res) => {
this.submitLoading = false;
if (res && res.success) {
this.$Message.success("限时抢购活动修改成功");
this.closeCurrentPage();
}
});
}
}
});
},
},
};
</script>
<style lang="scss" scoped>
@import "addSeckill.scss";
.ivu-form-item{
margin-bottom: 30px;
}
</style>

View File

@@ -0,0 +1,318 @@
<template>
<div class="seckill">
<Card>
<Row>
<Form
ref="searchForm"
:model="searchForm"
inline
:label-width="70"
class="search-form"
>
<Form-item label="活动名称" prop="promotionName">
<Input
type="text"
v-model="searchForm.promotionName"
placeholder="请输入活动名称"
clearable
style="width: 200px"
/>
</Form-item>
<Form-item label="活动状态" prop="promotionStatus">
<Select
v-model="searchForm.promotionStatus"
placeholder="请选择"
clearable
style="width: 200px"
>
<Option value="NEW">未开始</Option>
<Option value="START">已开始/上架</Option>
<Option value="END">已结束/下架</Option>
<Option value="CLOSE">紧急关闭/作废</Option>
</Select>
</Form-item>
<Form-item label="活动时间">
<DatePicker
v-model="selectDate"
type="daterange"
clearable
placeholder="选择起始时间"
style="width: 200px"
></DatePicker>
</Form-item>
<Button
@click="handleSearch"
type="primary"
icon="ios-search"
class="search-btn"
>搜索</Button
>
</Form>
</Row>
<Row class="operation padding-row">
<Button type="primary" @click="add">添加活动</Button>
</Row>
<Row>
<Table
:loading="loading"
border
:columns="columns"
:data="data"
ref="table"
class="page"
>
<template slot-scope="{ row }" slot="action">
<Button
type="info"
size="small"
class="mr_5"
v-if="row.promotionStatus == 'NEW'"
@click="edit(row)"
>编辑</Button
>
&nbsp;
<Button
type="info"
size="small"
class="mr_5"
v-else
@click="manage(row)"
>查看</Button
>
&nbsp;
<Button
type="primary"
size="small"
class="mr_5"
v-if="row.promotionStatus == 'NEW'"
@click="manage(row)"
>管理</Button
>
&nbsp;
<!-- <Button type="success" size="small" class="mr_5" v-if="row.promotionStatus == 'NEW' || row.promotionStatus == 'END'" @click="upper(row)">上架</Button> -->
<Button
type="error"
size="small"
v-if="
row.promotionStatus == 'START' || row.promotionStatus == 'NEW'
"
class="mr_5"
@click="off(row)"
>下架</Button
>
&nbsp;
<Button
type="error"
size="small"
v-if="row.promotionStatus == 'CLOSE'"
ghost
@click="expire(row)"
>删除</Button
>
</template>
</Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber + 1"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</Card>
</div>
</template>
<script>
import { getSeckillList, delSeckill, closeSeckill } from "@/api/promotion";
export default {
name: "seckill",
data() {
return {
loading: true, // 表单加载状态
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageSize: 10, // 页面大小
sort: "startTime",
order: "desc", // 默认排序方式
},
selectList: [], // 多选数据
selectCount: 0, // 多选计数
columns: [
{
title: "活动名称",
key: "promotionName",
minWidth: 130,
tooltip: true,
},
{
title: "开始时间",
key: "startTime",
width: 180,
},
{
title: "申请截止时间",
key: "applyEndTime",
width: 180,
},
{
title: "活动状态",
key: "promotionStatus",
width: 100,
render: (h, params) => {
if (params.row.promotionStatus == "NEW") {
return h("div", [
h("Badge", {
props: {
status: "error",
text: "新建",
},
}),
]);
} else if (params.row.promotionStatus == "START") {
return h("div", [
h("Badge", {
props: {
status: "success",
text: "开始",
},
}),
]);
} else if (params.row.promotionStatus == "END") {
return h("div", [
h("Badge", {
props: {
status: "error",
text: "结束",
},
}),
]);
} else if (params.row.promotionStatus == "CLOSE") {
return h("div", [
h("Badge", {
props: {
status: "error",
text: "废弃",
},
}),
]);
}
},
},
{
title: "申请规则",
key: "seckillRule",
minWidth: 120,
tooltip: true,
},
{
title: "操作",
slot: "action",
align: "center",
width: 250,
},
],
data: [], // 表单数据
total: 0, // 表单数据总数
};
},
methods: {
init() {
this.getDataList();
},
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 0;
this.searchForm.pageSize = 10;
this.getDataList();
},
add() {
// 添加
this.$router.push({ name: "manager-seckill-add" });
},
edit(v) {
// 编辑
this.$router.push({ name: "manager-seckill-add", query: { id: v.id } });
},
manage(v) {
// 管理
this.$router.push({ name: "seckill-goods", query: { id: v.id } });
},
off(v) {
// 下架
this.$Modal.confirm({
title: "提示",
content: "您确定要下架该活动吗?",
onOk: () => {
closeSeckill(v.id).then((res) => {
if (res.success) {
this.$Message.success("下架成功");
this.getDataList();
}
});
},
});
},
expire(v) {
// 作废
this.$Modal.confirm({
title: "提示",
content: "您确定要作废该活动吗?",
onOk: () => {
delSeckill(v.id).then((res) => {
if (res.success) {
this.$Message.success("作废成功");
this.getDataList();
}
});
},
});
},
getDataList() {
this.loading = true;
if (this.selectDate && this.selectDate[0] && this.selectDate[1]) {
this.searchForm.startTime = this.selectDate[0].getTime();
this.searchForm.endTime = this.selectDate[1].getTime();
} else {
this.searchForm.startTime = null;
this.searchForm.endTime = null;
}
// 带多条件搜索参数获取表单数据
getSeckillList(this.searchForm).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
}
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss">
@import "@/styles/table-common.scss";
</style>

View File

@@ -0,0 +1,479 @@
<template>
<div class="seckill-goods">
<Card>
<Table border :columns="columns" :data="data">
<template slot-scope="{ row }" slot="applyEndTime">
{{ unixDate(row.applyEndTime) }}
</template>
<template slot-scope="{ row }" slot="hours">
<Tag v-for="item in unixHours(row.hours)" :key="item">{{ item }}</Tag>
</template>
</Table>
<Row class="operation">
<Button @click="auditAll">批量审核</Button>
<Button
type="dashed"
@click="
() => {
openTip = !openTip;
}
"
>{{ openTip ? "关闭提示" : "开启提示" }}
</Button
>
</Row>
<Row v-show="openTip">
<Alert show-icon>
已选择 <span class="select-count">{{ selectCount }}</span>
<a class="select-clear" @click="clearSelectAll">清空</a>
</Alert>
</Row>
<Row class="operation">
<Table
:loading="loading"
border
:columns="goodsColumns"
:data="goodsList"
ref="table"
sortable="custom"
@on-selection-change="changeSelect"
>
<template slot-scope="{ row }" slot="originalPrice">
<div>{{ row.originalPrice | unitPrice("¥") }}</div>
</template>
<template slot-scope="{ row }" slot="quantity">
<div>{{ row.quantity }}</div>
</template>
<template slot-scope="{ row }" slot="price">
<div>{{ row.price | unitPrice("¥") }}</div>
</template>
<template slot-scope="{ row }" slot="promotionApplyStatus">
<Badge
status="success"
v-if="row.promotionApplyStatus == 'PASS'"
:text="promotionApplyStatus(row.promotionApplyStatus)"
/>
<Badge
status="blue"
v-if="row.promotionApplyStatus == 'APPLY'"
:text="promotionApplyStatus(row.promotionApplyStatus)"
/>
<Badge
status="error"
v-if="row.promotionApplyStatus == 'REFUSE'"
:text="promotionApplyStatus(row.promotionApplyStatus)"
/>
<span
v-if="row.promotionApplyStatus == 'REFUSE'"
@click="showReason(row.failReason)"
class="reason"
>拒绝原因</span
>
</template>
<template slot-scope="{ row }" slot="time">
<Tag>{{ row.timeLine + ":00" }}</Tag>
</template>
<template slot-scope="{ row }" slot="QRCode">
<img
v-if="row.QRCode"
:src="row.QRCode || '../../../assets/lili.png'"
width="50px"
height="50px"
alt=""
/>
</template>
<template slot-scope="{ row }" slot="action">
<Button
type="success"
size="small"
style="margin-right: 10px"
:disabled="row.promotionApplyStatus != 'APPLY'"
@click="pass(row)"
>通过
</Button
>
<Button
type="error"
size="small"
:disabled="row.promotionApplyStatus != 'APPLY'"
@click="refuse(row)"
>拒绝
</Button
>
</template>
</Table>
</Row>
<Row type="flex" justify="end" class="page">
<Page
:current="searchForm.pageNumber + 1"
:total="total"
:page-size="searchForm.pageSize"
@on-change="changePage"
@on-page-size-change="changePageSize"
:page-size-opts="[10, 20, 50]"
size="small"
show-total
show-elevator
show-sizer
></Page>
</Row>
</Card>
<Modal v-model="showModal" title="审核商品">
<Form ref="form" :model="params" :rules="rules">
<FormItem label="审核状态">
<RadioGroup v-model="params.applyStatus">
<Radio label="PASS">通过</Radio>
<Radio label="REFUSE">拒绝</Radio>
</RadioGroup>
</FormItem>
<FormItem
label="拒绝原因"
prop="failReason"
v-if="params.applyStatus == 'REFUSE'"
>
<Input
type="textarea"
v-model="params.failReason"
maxlength="50"
style="width: 260px"
show-word-limit
/>
</FormItem>
</Form>
<div slot="footer">
<Button size="small" @click="showModal = false">取消</Button>
<Button
size="small"
type="primary"
:loading="submitLoading"
@click="sureAudit"
>确定
</Button
>
</div>
</Modal>
</div>
</template>
<script>
import {
seckillGoodsList,
seckillDetail,
auditApplySeckill,
} from "@/api/promotion.js";
export default {
data() {
return {
promotionStatus: "",
showModal: false,
openTip: true,
loading: false, // 表单加载状态
submitLoading: false,
searchForm: {
// 搜索框初始化对象
pageNumber: 0, // 当前页数
pageSize: 100, // 页面大小
},
total: 0,
selectList: [], // 多选数据
selectCount: 0, // 多选计数
data: [], // 表单数据
columns: [
{
title: "活动名称",
key: "promotionName",
minWidth: 120,
},
{
title: "活动开始时间",
key: "startTime",
},
{
title: "报名截止时间",
slot: "applyEndTime",
},
{
title: "时间场次",
slot: "hours",
},
{
title: "活动状态",
key: "promotionStatus",
minWidth: 80,
sortable: false,
render: (h, params) => {
if (params.row.promotionStatus == "NEW") {
return h("div", [
h("Badge", {
props: {
status: "error",
text: "新建",
},
}),
]);
} else if (params.row.promotionStatus == "START") {
return h("div", [
h("Badge", {
props: {
status: "success",
text: "开始",
},
}),
]);
} else if (params.row.promotionStatus == "END") {
return h("div", [
h("Badge", {
props: {
status: "error",
text: "结束",
},
}),
]);
} else if (params.row.promotionStatus == "CLOSE") {
return h("div", [
h("Badge", {
props: {
status: "error",
text: "废弃",
},
}),
]);
}
},
},
],
goodsColumns: [
{type: "selection", width: 60, align: "center"},
{
title: "商品名称",
key: "goodsName",
minWidth: 120,
tooltip: true
},
{
title: "商品价格",
slot: "originalPrice",
width: 110,
},
{
title: "库存",
slot: "quantity",
minWidth: 30,
width: 90
},
{
title: "活动价格",
slot: "price",
width: 100,
},
{
title: "商家名称",
key: "storeName",
minWidth: 100,
tooltip: true
},
{
title: "活动场次",
width: 100,
slot: "time",
},
{
title: "状态",
slot: "promotionApplyStatus",
minWidth: 30,
width: 90,
},
{
title: "操作",
slot: "action",
width: 150,
align: "center",
},
],
goodsList: [],
params: {
seckillId: this.$route.query.id,
applyStatus: "PASS",
failReason: "",
ids: "",
},
rules: {
failReason: [{required: true, message: "请输入拒绝原因"}],
},
};
},
methods: {
init() {
this.getSeckillMsg();
},
changePage(v) {
this.searchForm.pageNumber = v - 1;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.getDataList();
},
clearSelectAll() {
this.$refs.table.selectAll(false);
},
changeSelect(e) {
// 获取选择数据
this.selectList = e;
this.selectCount = e.length;
let ids = [];
this.selectList.forEach((item) => {
ids.push(e.id);
});
this.params.ids = ids.toString();
},
getDataList() {
// 获取商品详情
this.loading = true;
this.searchForm.seckillId = this.$route.query.id;
seckillGoodsList(this.searchForm).then((res) => {
this.loading = false;
if (res.success && res.result) {
this.goodsList = res.result.records;
this.total = res.result.total;
}
});
},
getSeckillMsg() {
// 获取活动详情
seckillDetail(this.$route.query.id).then((res) => {
if (res.success && res.result) {
this.data = [];
this.data.push(res.result);
this.promotionStatus = res.result.promotionStatus;
this.getDataList();
}
});
},
delGoods(index) {
// 删除商品
this.goodsList.list.splice(index, 1);
},
unixDate(time) {
// 处理报名截止时间
return this.$options.filters.unixToDate(new Date(time) / 1000);
},
unixHours(item) {
// 处理小时场次
let hourArr = item.split(",");
for (let i = 0; i < hourArr.length; i++) {
hourArr[i] += ":00";
}
return hourArr;
},
promotionApplyStatus(key) {
switch (key) {
case "APPLY":
return "申请";
break;
case "PASS":
return "通过";
break;
case "REFUSE":
return "拒绝";
break;
}
},
pass(row) {
// 通过
let params = {
seckillId: this.$route.query.id,
applyStatus: "PASS",
failReason: "",
ids: row.id,
};
auditApplySeckill(params).then((res) => {
if (res && res.success) {
this.$Message.success("已通过该商品审核");
this.getDataList();
}
});
},
refuse(row) {
// 拒绝
this.params.applyStatus = "REFUSE";
this.selectList.push(row);
this.showModal = true;
},
auditAll() {
// 批量审核
if (this.selectCount <= 0) {
this.$Message.warning("您还未选择要审核的商品");
return;
}
this.showModal = true;
},
sureAudit() {
this.selectCount = this.selectList.length;
// 批量审核
if (this.selectCount <= 0) {
this.$Message.warning("您还未选择要审核的商品");
return;
}
this.params.ids = this.selectList
.filter((i) => i.promotionApplyStatus === "APPLY")
.map((i) => i.id);
if (this.params.ids.length <= 0) {
this.$Message.warning("当前没有可审核的商品");
return;
}
if (
this.params.applyStatus == "REFUSE" &&
this.params.failReason === ""
) {
this.$Message.warning("审核拒绝理由不能为空");
return;
}
this.submitLoading = true;
auditApplySeckill(this.params).then((res) => {
this.submitLoading = false;
if (res.success) {
this.showModal = false;
this.$Message.success("审核成功");
this.selectList = [];
this.getDataList();
}
});
},
showReason(reason) {
this.$Modal.info({
title: "拒绝原因",
content: reason,
});
},
},
mounted() {
this.init();
},
};
</script>
<style lang="scss" scoped>
.operation {
margin: 10px 0;
}
.reason {
cursor: pointer;
color: #2d8cf0;
font-size: 12px;
}
</style>