增加优惠券相关页面

This commit is contained in:
zhl 2021-04-21 20:20:20 +08:00
parent 9127596f3f
commit 1b5dfd0bc7
9 changed files with 438 additions and 9 deletions

53
src/api/coupon.ts Normal file
View File

@ -0,0 +1,53 @@
import request from '@/utils/request'
export interface ICouponData {
_id?: string,
name: string,
createdAt?: Date,
shop: string,
content: string,
comment?: string,
total: number,
count: number,
validBegin?: number,
validEnd?: number,
limitOne: number,
}
export const defaultCouponData: ICouponData = {
shop: '',
name: '',
content: '',
total: 0,
count: 0,
limitOne: 1
}
export const getCoupons = (params: any) =>
request({
url: '/coupons',
method: 'post',
params
})
export const getCoupon = (id: string, params: any) =>
request({
url: `/coupon/${id}`,
method: 'get',
params
})
export const saveCoupon = (data: any) =>
request({
url: `/coupon/save`,
method: 'post',
data
})
export const deleteCoupon = (id: string) =>
request({
url: `/coupon/${id}/delete`,
method: 'post'
})

View File

@ -3,7 +3,6 @@ import { IShopData } from './types'
export const defaultShopData: IShopData = { export const defaultShopData: IShopData = {
name: '', name: '',
_id: '',
address: '', address: '',
logo: '' logo: ''
} }

2
src/api/types.d.ts vendored
View File

@ -42,7 +42,7 @@ export interface IQuestionData {
} }
export interface IShopData { export interface IShopData {
_id: string, _id?: string,
name: string, name: string,
createdAt?: Date, createdAt?: Date,
areaCode?: number, areaCode?: number,

View File

@ -15,13 +15,15 @@
> >
<el-upload <el-upload
:multiple="true" :multiple="true"
:data="dataObj"
:file-list="defaultFileList" :file-list="defaultFileList"
:show-file-list="true" :show-file-list="true"
name="image-file"
:on-remove="handleRemove" :on-remove="handleRemove"
:on-success="handleSuccess" :on-success="handleSuccess"
:before-upload="beforeUpload" :before-upload="beforeUpload"
class="editor-slide-upload" class="editor-slide-upload"
action="https://httpbin.org/post" action="https://opm.kingsome.cn/api/upload"
list-type="picture-card" list-type="picture-card"
> >
<el-button <el-button
@ -66,6 +68,8 @@ export default class extends Vue {
private listObj: { [key: string]: IUploadObject } = {} private listObj: { [key: string]: IUploadObject } = {}
private defaultFileList = [] private defaultFileList = []
private dataObj = { sub_path: 'game', type: 'image' }
private checkAllSuccess() { private checkAllSuccess() {
return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess) return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
} }
@ -87,7 +91,7 @@ export default class extends Vue {
const objKeyArr = Object.keys(this.listObj) const objKeyArr = Object.keys(this.listObj)
for (let i = 0, len = objKeyArr.length; i < len; i++) { for (let i = 0, len = objKeyArr.length; i < len; i++) {
if (this.listObj[objKeyArr[i]].uid === uid) { if (this.listObj[objKeyArr[i]].uid === uid) {
this.listObj[objKeyArr[i]].url = response.files.file this.listObj[objKeyArr[i]].url = response.url_cdn
this.listObj[objKeyArr[i]].hasSuccess = true this.listObj[objKeyArr[i]].hasSuccess = true
return return
} }

View File

@ -68,6 +68,7 @@ export default {
article: 'Article', article: 'Article',
marketing: 'Marketing', marketing: 'Marketing',
marketing_coupon: 'Coupon', marketing_coupon: 'Coupon',
marketing_coupon_info: 'Coupon Info',
marketing_promo: 'Promo Code', marketing_promo: 'Promo Code',
marketing_points: 'Points Setting', marketing_points: 'Points Setting',
question: 'Question Set', question: 'Question Set',

View File

@ -68,6 +68,7 @@ export default {
article: '资讯管理', article: '资讯管理',
marketing: '营销管理', marketing: '营销管理',
marketing_coupon: '优惠券设置', marketing_coupon: '优惠券设置',
marketing_coupon_info: '编辑优惠券',
marketing_promo: '优惠码设置', marketing_promo: '优惠码设置',
marketing_points: '积分设置', marketing_points: '积分设置',
question: '题库管理', question: '题库管理',

View File

@ -20,6 +20,28 @@ const marketingRoutes: RouteConfig = {
icon: 'coupon' icon: 'coupon'
} }
}, },
{
path: 'edit_coupon',
component: () => import('@/views/marketing/coupon_edit.vue'),
name: 'CouponDetail',
meta: {
title: 'marketing_coupon_info',
permissions: ['coupon:read'],
icon: 'coupon',
hidden: true
}
},
{
path: 'edit_coupon/:id',
component: () => import('@/views/marketing/coupon_edit.vue'),
name: 'CouponDetail',
meta: {
title: 'marketing_coupon_info',
permissions: ['coupon:read'],
icon: 'coupon',
hidden: true
}
},
{ {
path: 'promo', path: 'promo',
component: () => import('@/views/marketing/promo.vue'), component: () => import('@/views/marketing/promo.vue'),

View File

@ -26,7 +26,7 @@
<el-button @click="resetFilterForm">重置</el-button> <el-button @click="resetFilterForm">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<router-link to="/system/create"> <router-link to="/marketing/edit_coupon">
<el-button <el-button
type="primary" type="primary"
icon="el-icon-edit" icon="el-icon-edit"
@ -51,13 +51,42 @@
<span>{{ row.createdAt | parseTime }}</span> <span>{{ row.createdAt | parseTime }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
min-width="200px"
label="名称"
>
<template slot-scope="{row}">
<router-link
:to="'/marketing/edit_coupon/'+row._id"
class="link-type"
>
<span>{{ row.name }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column
label="有效期"
>
<template slot-scope="{row}">
<span>{{ row.validBegin | parseDate }}</span>
<span>{{ row.validEnd | parseDate }}</span>
</template>
</el-table-column>
<el-table-column
label="库存"
>
<template slot-scope="{row}">
<el-tag>{{ row.count | formatCount}}</el-tag> /
<el-tag>{{ row.total | formatCount}}</el-tag>
</template>
</el-table-column>
<el-table-column <el-table-column
align="center" align="center"
label="操作" label="操作"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<router-link :to="'/system/edit/'+scope.row._id"> <router-link :to="'/marketing/edit_coupon/'+scope.row._id">
<el-button <el-button
type="primary" type="primary"
size="small" size="small"
@ -95,6 +124,7 @@ import Pagination from '@/components/Pagination/index.vue'
import { deleteShop, getShops } from '@/api/shop' import { deleteShop, getShops } from '@/api/shop'
import { parseTime } from '@/utils' import { parseTime } from '@/utils'
import { Form } from 'element-ui' import { Form } from 'element-ui'
import { deleteCoupon, getCoupons } from '@/api/coupon'
@Component({ @Component({
name: 'CouponList', name: 'CouponList',
@ -104,6 +134,18 @@ import { Form } from 'element-ui'
filters: { filters: {
parseTime: (timestamp: string) => { parseTime: (timestamp: string) => {
return parseTime(timestamp) return parseTime(timestamp)
},
parseDate: (timestamp: string) => {
if (!timestamp) {
return '-'
}
return parseTime(timestamp, '{y}-{m}-{d}')
},
formatCount: (count: string) => {
if (!count) {
return 0
}
return count
} }
} }
}) })
@ -130,19 +172,19 @@ export default class extends Vue {
private async getList() { private async getList() {
this.listLoading = true this.listLoading = true
const { data } = await getShops(this.listQuery) const { data } = await getCoupons(this.listQuery)
this.listLoading = false this.listLoading = false
this.list = data.records this.list = data.records
this.total = data.total this.total = data.total
} }
private async handleDelete(scope: any) { private async handleDelete(scope: any) {
const { $index, row } = scope const { $index, row } = scope
await this.$confirm('确认删除该店铺?', 'Warning', { await this.$confirm('确认删除该优惠券?', 'Warning', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })
await deleteShop(row._id) await deleteCoupon(row._id)
this.list.splice($index, 1) this.list.splice($index, 1)
this.$message({ this.$message({
type: 'success', type: 'success',

View File

@ -0,0 +1,307 @@
<template>
<div class="app-container">
<el-form
ref="postForm"
:model="postForm"
:rules="rules"
label-width="121px"
class="form-container"
>
<el-form-item label="店铺" prop="shop">
<el-select
v-model="postForm.shop"
placeholder="选择店铺"
name="shop"
required
class="w100"
>
<el-option
v-for="item in allDepts"
:key="item._id"
:label="item.name"
:value="item._id"
/>
</el-select>
</el-form-item>
<el-form-item
label="优惠券标题"
prop="name"
>
<el-input
v-model="postForm.name"
name="name"
style="width: 50%"
required
/>
</el-form-item>
<el-form-item
label="券描述"
prop="comment"
>
<el-input
v-model="postForm.comment"
name="comment"
style="width: 50%"
placeholder="只在后台显示, 区分相似券"
/>
</el-form-item>
<el-form-item
label="总数"
prop="total"
>
<el-input
v-model="postForm.total"
name="total"
style="width: 50%"
placeholder=""
/>
</el-form-item>
<el-form-item
label="已领取"
prop="count"
>
<el-input
v-model="postForm.count"
name="count"
style="width: 50%"
placeholder=""
readonly
/>
</el-form-item>
<el-form-item
label="每人限领"
prop="limitOne"
>
<el-input
v-model="postForm.limitOne"
name="limitOne"
style="width: 50%"
placeholder="0或不填表示不限制"
/>
</el-form-item>
<el-form-item
label="有效期"
prop="dataRange"
>
<el-date-picker
v-model="dataRange"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
>
</el-date-picker>
</el-form-item>
<el-form-item
prop="content"
style="margin-bottom: 30px;"
>
<tinymce
v-if="tinymceActive"
ref="editor"
v-model="postForm.content"
:height="600"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="submitForm"
>
保存
</el-button>
<el-button @click="onCancel">
取消
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator'
import { AppModule } from '@/store/modules/app'
import { ITagView, TagsViewModule } from '@/store/modules/tags-view'
import Sticky from '@/components/Sticky/index.vue'
import UploadImage from '@/components/UploadImage/index.vue'
import Tinymce from '@/components/Tinymce/index.vue'
import { Form } from 'element-ui'
import { getShop, getShops } from '@/api/shop'
import { defaultCouponData, getCoupon, saveCoupon } from '@/api/coupon'
@Component({
name: 'CouponEditor',
components: {
Sticky,
UploadImage,
Tinymce,
}
})
export default class extends Vue {
private validateRequire = (rule: any, value: string, callback: Function) => {
if (value === '') {
if (rule.field === 'imageURL') {
this.$message({
message: 'Upload cover image is required',
type: 'error'
})
} else {
this.$message({
message: rule.field + ' 是必填的',
type: 'error'
})
}
callback(new Error(rule.field + ' 是必填的'))
} else {
callback()
}
}
private postForm = Object.assign({}, defaultCouponData)
private loading = false
private tinymceActive = true
private rules = {
shop: [{ validator: this.validateRequire, trigger: ["blur",'change'] }],
name: [{ validator: this.validateRequire }],
}
private allDepts = []
private tempTagView?: ITagView
private dataRange = ''
get lang() {
return AppModule.language
}
created() {
const id = this.$route.params?.id
this.getRemoteDeptList()
if (id) {
this.fetchData(id)
}
this.tempTagView = Object.assign({}, this.$route)
}
deactivated() {
}
activated() {
}
@Watch('dataRange')
private onDataRangeChange(val: Date[]) {
console.log(`onDataRangeChange ${val}`)
if (!val) {
return
}
this.postForm.validBegin = val[0].getTime()
this.postForm.validEnd = val[1].getTime()
}
private async fetchData(id: string) {
try {
const { data } = await getCoupon(id, { /* Your params here */ })
console.log(data)
this.postForm = data
if (this.postForm.validBegin && this.postForm.validEnd) {
this.dataRange = [new Date(this.postForm.validBegin), new Date(this.postForm.validEnd)]
}
// Just for test
const title = this.lang === 'zh' ? '编辑优惠券' : 'Edit Coupon'
// Set tagsview title
this.setTagsViewTitle(title)
// Set page title
this.setPageTitle(title)
} catch (err) {
console.error(err)
}
}
private setTagsViewTitle(title: string) {
const tagView = this.tempTagView
if (tagView) {
tagView.title = `${title}-${this.postForm._id}`
TagsViewModule.updateVisitedView(tagView)
}
}
private setPageTitle(title: string) {
document.title = `${title} - ${this.postForm._id}`
}
private async submitForm() {
const form = <Form>this.$refs.postForm
try {
await form.validate()
this.loading = true
await saveCoupon(this.postForm)
this.loading = false
this.$notify({
title: 'Success',
message: 'The post published successfully',
type: 'success',
duration: 2000
})
} catch (err) {
console.error('Submit Error!')
return false
}
}
private async onCancel() {
await this.$confirm('确认不保存当前优惠券信息?', 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
this.$store.dispatch("delView", this.$route)
this.$router.go(-1)
}
private async getRemoteDeptList(name: string) {
const { data } = await getShops({ key: name })
if (!data.records) return
this.allDepts = data.records
}
}
</script>
<style lang="scss" scoped>
.createPost-container {
position: relative;
.createPost-main-container {
padding: 40px 45px 20px 50px;
.postInfo-container {
position: relative;
@include clearfix;
margin-bottom: 10px;
.postInfo-container-item {
float: left;
}
}
}
.word-counter {
width: 40px;
position: absolute;
right: 10px;
top: 0px;
}
}
</style>