增加优惠券相关页面
This commit is contained in:
parent
9127596f3f
commit
1b5dfd0bc7
53
src/api/coupon.ts
Normal file
53
src/api/coupon.ts
Normal 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'
|
||||
})
|
@ -3,7 +3,6 @@ import { IShopData } from './types'
|
||||
|
||||
export const defaultShopData: IShopData = {
|
||||
name: '',
|
||||
_id: '',
|
||||
address: '',
|
||||
logo: ''
|
||||
}
|
||||
|
2
src/api/types.d.ts
vendored
2
src/api/types.d.ts
vendored
@ -42,7 +42,7 @@ export interface IQuestionData {
|
||||
}
|
||||
|
||||
export interface IShopData {
|
||||
_id: string,
|
||||
_id?: string,
|
||||
name: string,
|
||||
createdAt?: Date,
|
||||
areaCode?: number,
|
||||
|
@ -15,13 +15,15 @@
|
||||
>
|
||||
<el-upload
|
||||
:multiple="true"
|
||||
:data="dataObj"
|
||||
:file-list="defaultFileList"
|
||||
:show-file-list="true"
|
||||
name="image-file"
|
||||
:on-remove="handleRemove"
|
||||
:on-success="handleSuccess"
|
||||
:before-upload="beforeUpload"
|
||||
class="editor-slide-upload"
|
||||
action="https://httpbin.org/post"
|
||||
action="https://opm.kingsome.cn/api/upload"
|
||||
list-type="picture-card"
|
||||
>
|
||||
<el-button
|
||||
@ -66,6 +68,8 @@ export default class extends Vue {
|
||||
private listObj: { [key: string]: IUploadObject } = {}
|
||||
private defaultFileList = []
|
||||
|
||||
private dataObj = { sub_path: 'game', type: 'image' }
|
||||
|
||||
private checkAllSuccess() {
|
||||
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)
|
||||
for (let i = 0, len = objKeyArr.length; i < len; i++) {
|
||||
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
|
||||
return
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ export default {
|
||||
article: 'Article',
|
||||
marketing: 'Marketing',
|
||||
marketing_coupon: 'Coupon',
|
||||
marketing_coupon_info: 'Coupon Info',
|
||||
marketing_promo: 'Promo Code',
|
||||
marketing_points: 'Points Setting',
|
||||
question: 'Question Set',
|
||||
|
@ -68,6 +68,7 @@ export default {
|
||||
article: '资讯管理',
|
||||
marketing: '营销管理',
|
||||
marketing_coupon: '优惠券设置',
|
||||
marketing_coupon_info: '编辑优惠券',
|
||||
marketing_promo: '优惠码设置',
|
||||
marketing_points: '积分设置',
|
||||
question: '题库管理',
|
||||
|
@ -20,6 +20,28 @@ const marketingRoutes: RouteConfig = {
|
||||
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',
|
||||
component: () => import('@/views/marketing/promo.vue'),
|
||||
|
@ -26,7 +26,7 @@
|
||||
<el-button @click="resetFilterForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<router-link to="/system/create">
|
||||
<router-link to="/marketing/edit_coupon">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-edit"
|
||||
@ -51,13 +51,42 @@
|
||||
<span>{{ row.createdAt | parseTime }}</span>
|
||||
</template>
|
||||
</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
|
||||
align="center"
|
||||
label="操作"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<router-link :to="'/system/edit/'+scope.row._id">
|
||||
<router-link :to="'/marketing/edit_coupon/'+scope.row._id">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@ -95,6 +124,7 @@ import Pagination from '@/components/Pagination/index.vue'
|
||||
import { deleteShop, getShops } from '@/api/shop'
|
||||
import { parseTime } from '@/utils'
|
||||
import { Form } from 'element-ui'
|
||||
import { deleteCoupon, getCoupons } from '@/api/coupon'
|
||||
|
||||
@Component({
|
||||
name: 'CouponList',
|
||||
@ -104,6 +134,18 @@ import { Form } from 'element-ui'
|
||||
filters: {
|
||||
parseTime: (timestamp: string) => {
|
||||
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() {
|
||||
this.listLoading = true
|
||||
const { data } = await getShops(this.listQuery)
|
||||
const { data } = await getCoupons(this.listQuery)
|
||||
this.listLoading = false
|
||||
this.list = data.records
|
||||
this.total = data.total
|
||||
}
|
||||
private async handleDelete(scope: any) {
|
||||
const { $index, row } = scope
|
||||
await this.$confirm('确认删除该店铺?', 'Warning', {
|
||||
await this.$confirm('确认删除该优惠券?', 'Warning', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
await deleteShop(row._id)
|
||||
await deleteCoupon(row._id)
|
||||
this.list.splice($index, 1)
|
||||
this.$message({
|
||||
type: 'success',
|
||||
|
307
src/views/marketing/coupon_edit.vue
Normal file
307
src/views/marketing/coupon_edit.vue
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user