294 lines
8.8 KiB
Vue
294 lines
8.8 KiB
Vue
<template>
|
|
<div class="content-view">
|
|
<div class="table-head-tool">
|
|
<div class="table-title-row">
|
|
<Button type="primary" @click="openEdit(null)">新增套餐</Button>
|
|
</div>
|
|
|
|
<Form ref="formInline" :model="param.seachOption" inline :label-width="80">
|
|
<FormItem label="条件">
|
|
<Select v-model="param.seachOption.key" style="width: 140px">
|
|
<Option value="plan_code">编码</Option>
|
|
<Option value="plan_name">名称</Option>
|
|
<Option value="status">状态</Option>
|
|
</Select>
|
|
<Input
|
|
v-model="param.seachOption.value"
|
|
class="ml10"
|
|
style="width: 220px"
|
|
search
|
|
@on-search="load(1)"
|
|
/>
|
|
</FormItem>
|
|
<FormItem>
|
|
<Button type="primary" @click="load(1)">查询</Button>
|
|
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
|
<Button type="default" @click="doExport" class="ml10">导出 CSV</Button>
|
|
</FormItem>
|
|
</Form>
|
|
</div>
|
|
|
|
<div class="table-body">
|
|
<Table :columns="columns" :data="rows" border stripe />
|
|
<div class="table-page-bar">
|
|
<Page
|
|
:total="total"
|
|
:current="param.pageOption.page"
|
|
:page-size="param.pageOption.pageSize"
|
|
show-total
|
|
@on-change="onPage"
|
|
@on-page-size-change="onSize"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<Modal v-model="modal" :title="form.id ? '编辑套餐' : '新增套餐'" width="720" :loading="saving" @on-ok="save">
|
|
<Form ref="formRef" :model="form" :rules="rules" :label-width="120">
|
|
<FormItem label="套餐编码" prop="plan_code">
|
|
<Input v-model="form.plan_code" :disabled="!!form.id" />
|
|
</FormItem>
|
|
<FormItem label="套餐名称" prop="plan_name">
|
|
<Input v-model="form.plan_name" />
|
|
</FormItem>
|
|
<FormItem label="月费">
|
|
<Input v-model="form.monthly_price" type="number" />
|
|
</FormItem>
|
|
<FormItem label="授权费">
|
|
<Input v-model="form.auth_fee" type="number" />
|
|
</FormItem>
|
|
<FormItem label="账号上限">
|
|
<Input v-model="form.account_limit" type="number" />
|
|
</FormItem>
|
|
<FormItem label="活跃上限">
|
|
<Input v-model="form.active_user_limit" type="number" />
|
|
</FormItem>
|
|
<FormItem label="消息额度">
|
|
<Input v-model="form.msg_quota" type="number" />
|
|
</FormItem>
|
|
<FormItem label="群发额度">
|
|
<Input v-model="form.mass_quota" type="number" />
|
|
</FormItem>
|
|
<FormItem label="好友额度">
|
|
<Input v-model="form.friend_quota" type="number" />
|
|
</FormItem>
|
|
<FormItem label="朋友圈额度">
|
|
<Input v-model="form.sns_quota" type="number" />
|
|
</FormItem>
|
|
<FormItem label="功能点 JSON">
|
|
<Input v-model="featuresText" type="textarea" :rows="4" placeholder='如 {"msg":true} 或 ["msg","mass"]' />
|
|
</FormItem>
|
|
<FormItem label="状态" prop="status">
|
|
<Select v-model="form.status" style="width: 100%">
|
|
<Option value="active">上线</Option>
|
|
<Option value="inactive">下线</Option>
|
|
</Select>
|
|
</FormItem>
|
|
</Form>
|
|
</Modal>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import planServer from '@/api/subscription/plan_server.js'
|
|
import { downloadCsvFromRows } from '@/utils/csvExport.js'
|
|
|
|
export default {
|
|
name: 'SubscriptionPlans',
|
|
data() {
|
|
return {
|
|
rows: [],
|
|
total: 0,
|
|
param: {
|
|
seachOption: { key: 'plan_code', value: '' },
|
|
pageOption: { page: 1, pageSize: 20, total: 0 },
|
|
},
|
|
modal: false,
|
|
saving: false,
|
|
form: {},
|
|
featuresText: '{}',
|
|
rules: {
|
|
plan_code: [{ required: true, message: '必填', trigger: 'blur' }],
|
|
plan_name: [{ required: true, message: '必填', trigger: 'blur' }],
|
|
status: [{ required: true, message: '必选', trigger: 'change' }],
|
|
},
|
|
}
|
|
},
|
|
computed: {
|
|
columns() {
|
|
return [
|
|
{ title: 'ID', key: 'id', width: 70 },
|
|
{ title: '编码', key: 'plan_code', width: 120 },
|
|
{ title: '名称', key: 'plan_name', minWidth: 140 },
|
|
{ title: '月费', key: 'monthly_price', width: 90 },
|
|
{ title: '状态', key: 'status', width: 90 },
|
|
{
|
|
title: '操作',
|
|
key: 'a',
|
|
width: 260,
|
|
render: (h, p) =>
|
|
h('div', [
|
|
h('Button', { props: { type: 'info', size: 'small' }, on: { click: () => this.openEdit(p.row) } }, '编辑'),
|
|
h('Button', { props: { type: 'warning', size: 'small' }, class: { ml8: true }, on: { click: () => this.toggle(p.row) } }, '上下线'),
|
|
h('Button', { props: { type: 'error', size: 'small' }, class: { ml8: true }, on: { click: () => this.doDel(p.row) } }, '删除'),
|
|
]),
|
|
},
|
|
]
|
|
},
|
|
},
|
|
mounted() {
|
|
this.load(1)
|
|
},
|
|
methods: {
|
|
async load(page) {
|
|
if (page) this.param.pageOption.page = page
|
|
const res = await planServer.page({ param: this.param })
|
|
if (res && res.code === 0) {
|
|
this.rows = res.data.rows || []
|
|
this.total = res.data.count || 0
|
|
} else {
|
|
this.$Message.error((res && res.message) || '加载失败')
|
|
}
|
|
},
|
|
onPage(p) {
|
|
this.param.pageOption.page = p
|
|
this.load()
|
|
},
|
|
onSize(s) {
|
|
this.param.pageOption.pageSize = s
|
|
this.load(1)
|
|
},
|
|
openEdit(row) {
|
|
if (row) {
|
|
this.form = { ...row }
|
|
this.featuresText =
|
|
row.enabled_features == null
|
|
? ''
|
|
: typeof row.enabled_features === 'string'
|
|
? row.enabled_features
|
|
: JSON.stringify(row.enabled_features, null, 2)
|
|
} else {
|
|
this.form = {
|
|
plan_code: '',
|
|
plan_name: '',
|
|
monthly_price: 0,
|
|
auth_fee: 0,
|
|
account_limit: 0,
|
|
active_user_limit: 0,
|
|
msg_quota: 0,
|
|
mass_quota: 0,
|
|
friend_quota: 0,
|
|
sns_quota: 0,
|
|
status: 'active',
|
|
}
|
|
this.featuresText = '{}'
|
|
}
|
|
this.modal = true
|
|
},
|
|
save() {
|
|
this.saving = true
|
|
this.$refs.formRef.validate(async (ok) => {
|
|
if (!ok) {
|
|
this.saving = false
|
|
return
|
|
}
|
|
let enabled_features = null
|
|
const t = (this.featuresText || '').trim()
|
|
if (t) {
|
|
try {
|
|
enabled_features = JSON.parse(t)
|
|
} catch (e) {
|
|
this.$Message.error('功能点 JSON 格式错误')
|
|
this.saving = false
|
|
return
|
|
}
|
|
}
|
|
const payload = { ...this.form, enabled_features }
|
|
try {
|
|
const res = this.form.id ? await planServer.edit(payload) : await planServer.add(payload)
|
|
if (res && res.code === 0) {
|
|
this.$Message.success('保存成功')
|
|
this.modal = false
|
|
this.load(1)
|
|
} else {
|
|
this.$Message.error((res && res.message) || '保存失败')
|
|
}
|
|
} finally {
|
|
this.saving = false
|
|
}
|
|
})
|
|
},
|
|
async toggle(row) {
|
|
const res = await planServer.toggle({ id: row.id })
|
|
if (res && res.code === 0) {
|
|
this.$Message.success('状态已更新为 ' + (res.data && res.data.status))
|
|
this.load()
|
|
} else {
|
|
this.$Message.error((res && res.message) || '失败')
|
|
}
|
|
},
|
|
doDel(row) {
|
|
this.$Modal.confirm({
|
|
title: '删除套餐',
|
|
content: '确认删除?若已被订阅引用可能失败。',
|
|
onOk: async () => {
|
|
const res = await planServer.del({ id: row.id })
|
|
if (res && res.code === 0) {
|
|
this.$Message.success('已删除')
|
|
this.load(1)
|
|
} else {
|
|
this.$Message.error((res && res.message) || '删除失败')
|
|
}
|
|
},
|
|
})
|
|
},
|
|
async doExport() {
|
|
const res = await planServer.exportRows({ param: this.param })
|
|
if (res && res.code === 0 && res.data && res.data.rows) {
|
|
downloadCsvFromRows(res.data.rows, 'plans.csv')
|
|
this.$Message.success('已导出')
|
|
} else {
|
|
this.$Message.error((res && res.message) || '导出失败')
|
|
}
|
|
},
|
|
resetQuery() {
|
|
this.param.seachOption = { key: 'plan_code', value: '' }
|
|
this.load(1)
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.content-view {
|
|
width: 100%;
|
|
max-width: 1720px;
|
|
margin: 0 auto;
|
|
padding: 26px 36px 36px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.table-head-tool {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.table-title-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.ml10 {
|
|
margin-left: 10px;
|
|
}
|
|
|
|
.ml8 {
|
|
margin-left: 8px;
|
|
}
|
|
|
|
.table-page-bar {
|
|
margin-top: 12px;
|
|
text-align: right;
|
|
}
|
|
</style>
|