386 lines
15 KiB
Vue
386 lines
15 KiB
Vue
<template>
|
||
<div class="content-view">
|
||
<div class="table-head-tool">
|
||
<Button type="primary" @click="showAddWarp">新增价格套餐</Button>
|
||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||
<FormItem :label-width="20" class="flex">
|
||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||
:placeholder="seachTypePlaceholder">
|
||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||
</Select>
|
||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||
placeholder="请输入关键字" @on-search="query(1)" />
|
||
</FormItem>
|
||
<FormItem label="状态">
|
||
<Select v-model="gridOption.param.seachOption.is_active" style="width: 120px" clearable
|
||
@on-change="query(1)">
|
||
<Option :value="1">启用</Option>
|
||
<Option :value="0">禁用</Option>
|
||
</Select>
|
||
</FormItem>
|
||
<FormItem>
|
||
<Button type="primary" @click="query(1)">查询</Button>
|
||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||
</FormItem>
|
||
</Form>
|
||
</div>
|
||
<div class="table-body">
|
||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||
@changePage="query"></tables>
|
||
</div>
|
||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules" @on-save="handleSaveSuccess">
|
||
</editModal>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import pricingPlansServer from '@/api/system/pricing_plans_server.js'
|
||
|
||
export default {
|
||
data() {
|
||
let rules = {}
|
||
rules["name"] = [{ required: true, message: '请填写套餐名称', trigger: 'blur' }]
|
||
rules["duration"] = [{ required: true, message: '请填写时长描述', trigger: 'blur' }]
|
||
rules["days"] = [{ required: true, message: '请填写天数', trigger: 'blur' }]
|
||
rules["price"] = [{ required: true, message: '请填写价格', trigger: 'blur' }]
|
||
|
||
return {
|
||
seachTypes: [
|
||
{ key: 'name', value: '套餐名称' },
|
||
{ key: 'duration', value: '时长' }
|
||
],
|
||
gridOption: {
|
||
param: {
|
||
seachOption: {
|
||
key: 'name',
|
||
value: '',
|
||
is_active: null
|
||
},
|
||
pageOption: {
|
||
page: 1,
|
||
pageSize: 20
|
||
}
|
||
},
|
||
data: [],
|
||
rules: rules
|
||
},
|
||
listColumns: [
|
||
{ title: 'ID', key: 'id', minWidth: 60 },
|
||
{ title: '套餐名称', key: 'name', minWidth: 120 },
|
||
{ title: '时长', key: 'duration', minWidth: 100 },
|
||
{ title: '天数', key: 'days', minWidth: 80 },
|
||
{
|
||
title: '价格',
|
||
key: 'price',
|
||
minWidth: 100,
|
||
render: (h, params) => {
|
||
return h('span', `¥${params.row.price}`)
|
||
}
|
||
},
|
||
{
|
||
title: '原价',
|
||
key: 'original_price',
|
||
minWidth: 100,
|
||
render: (h, params) => {
|
||
return h('span', params.row.original_price ? `¥${params.row.original_price}` : '-')
|
||
}
|
||
},
|
||
{ title: '折扣', key: 'discount', minWidth: 100 },
|
||
{
|
||
title: '推荐',
|
||
key: 'featured',
|
||
minWidth: 80,
|
||
render: (h, params) => {
|
||
return h('Tag', {
|
||
props: { color: params.row.featured === 1 ? 'warning' : 'default' }
|
||
}, params.row.featured === 1 ? '推荐' : '普通')
|
||
}
|
||
},
|
||
{
|
||
title: '状态',
|
||
key: 'is_active',
|
||
minWidth: 80,
|
||
render: (h, params) => {
|
||
const status = params.row.is_active === 1
|
||
return h('Tag', {
|
||
props: { color: status ? 'success' : 'default' }
|
||
}, status ? '启用' : '禁用')
|
||
}
|
||
},
|
||
{ title: '排序', key: 'sort_order', minWidth: 80 },
|
||
{
|
||
title: '操作',
|
||
key: 'action',
|
||
width: 200,
|
||
align: 'center',
|
||
render: (h, params) => {
|
||
return h('div', [
|
||
h('Button', {
|
||
props: {
|
||
type: 'primary',
|
||
size: 'small'
|
||
},
|
||
style: {
|
||
marginRight: '5px'
|
||
},
|
||
on: {
|
||
click: () => {
|
||
this.edit(params.row)
|
||
}
|
||
}
|
||
}, '编辑'),
|
||
h('Button', {
|
||
props: {
|
||
type: 'error',
|
||
size: 'small'
|
||
},
|
||
on: {
|
||
click: () => {
|
||
this.del(params.row)
|
||
}
|
||
}
|
||
}, '删除')
|
||
])
|
||
}
|
||
}
|
||
],
|
||
editColumns: [
|
||
{
|
||
title: '套餐名称',
|
||
key: 'name',
|
||
type: 'input',
|
||
required: true
|
||
},
|
||
{
|
||
title: '时长描述',
|
||
key: 'duration',
|
||
type: 'input',
|
||
required: true,
|
||
placeholder: '如:7天、30天、永久'
|
||
},
|
||
{
|
||
title: '天数',
|
||
key: 'days',
|
||
type: 'number',
|
||
required: true,
|
||
tooltip: '-1表示永久,0表示无限制'
|
||
},
|
||
{
|
||
title: '价格',
|
||
key: 'price',
|
||
type: 'number',
|
||
required: true
|
||
},
|
||
{
|
||
title: '原价',
|
||
key: 'original_price',
|
||
type: 'number',
|
||
required: false,
|
||
placeholder: '可留空,表示无原价'
|
||
},
|
||
{
|
||
title: '单位',
|
||
key: 'unit',
|
||
type: 'input',
|
||
required: false,
|
||
defaultValue: '元'
|
||
},
|
||
{
|
||
title: '折扣描述',
|
||
key: 'discount',
|
||
type: 'input',
|
||
required: false,
|
||
placeholder: '如:8.3折、超值'
|
||
},
|
||
{
|
||
title: '功能特性',
|
||
key: 'features',
|
||
com: 'TextArea',
|
||
required: false,
|
||
placeholder: '请输入JSON数组格式,例如:["功能1", "功能2", "功能3"]',
|
||
tooltip: '功能特性列表,JSON数组格式'
|
||
},
|
||
{
|
||
title: '是否推荐',
|
||
key: 'featured',
|
||
type: 'select',
|
||
required: true,
|
||
options: [
|
||
{ value: 1, label: '推荐' },
|
||
{ value: 0, label: '普通' }
|
||
]
|
||
},
|
||
{
|
||
title: '是否启用',
|
||
key: 'is_active',
|
||
type: 'select',
|
||
required: true,
|
||
options: [
|
||
{ value: 1, label: '启用' },
|
||
{ value: 0, label: '禁用' }
|
||
]
|
||
},
|
||
{
|
||
title: '排序顺序',
|
||
key: 'sort_order',
|
||
type: 'number',
|
||
required: false,
|
||
defaultValue: 0,
|
||
tooltip: '数字越小越靠前'
|
||
}
|
||
]
|
||
}
|
||
},
|
||
computed: {
|
||
seachTypePlaceholder() {
|
||
const item = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key)
|
||
return item ? `请输入${item.value}` : '请选择'
|
||
}
|
||
},
|
||
mounted() {
|
||
this.query(1)
|
||
},
|
||
methods: {
|
||
query(page) {
|
||
if (page) {
|
||
this.gridOption.param.pageOption.page = page
|
||
}
|
||
const param = {
|
||
pageOption: this.gridOption.param.pageOption,
|
||
seachOption: {}
|
||
}
|
||
if (this.gridOption.param.seachOption.key && this.gridOption.param.seachOption.value) {
|
||
param.seachOption[this.gridOption.param.seachOption.key] = this.gridOption.param.seachOption.value
|
||
}
|
||
if (this.gridOption.param.seachOption.is_active !== null) {
|
||
param.seachOption.is_active = this.gridOption.param.seachOption.is_active
|
||
}
|
||
pricingPlansServer.page(param).then(res => {
|
||
if (res.code === 0) {
|
||
const data = res.data
|
||
this.gridOption.data = data.rows
|
||
this.gridOption.param.pageOption.total = data.count || data.total || 0
|
||
} else {
|
||
this.$Message.error(res.message || '查询失败')
|
||
}
|
||
}).catch(err => {
|
||
this.$Message.error('查询失败:' + (err.message || '未知错误'))
|
||
})
|
||
},
|
||
resetQuery() {
|
||
this.gridOption.param.seachOption = {
|
||
key: 'name',
|
||
value: '',
|
||
is_active: null
|
||
}
|
||
this.query(1)
|
||
},
|
||
showAddWarp() {
|
||
this.$refs.editModal.show({
|
||
name: '',
|
||
duration: '',
|
||
days: 0,
|
||
price: 0,
|
||
original_price: null,
|
||
unit: '元',
|
||
discount: '',
|
||
features: '[]',
|
||
featured: 0,
|
||
is_active: 1,
|
||
sort_order: 0
|
||
})
|
||
},
|
||
edit(row) {
|
||
// 解析 JSON 字段
|
||
let features = row.features || '[]'
|
||
|
||
// 如果是字符串,尝试解析并格式化
|
||
if (typeof features === 'string') {
|
||
try {
|
||
const parsed = JSON.parse(features)
|
||
features = JSON.stringify(parsed, null, 2)
|
||
} catch (e) {
|
||
// 保持原样
|
||
}
|
||
} else {
|
||
features = JSON.stringify(features, null, 2)
|
||
}
|
||
|
||
this.$refs.editModal.editShow({
|
||
id: row.id,
|
||
name: row.name,
|
||
duration: row.duration || '',
|
||
days: row.days,
|
||
price: row.price,
|
||
original_price: row.original_price,
|
||
unit: row.unit || '元',
|
||
discount: row.discount || '',
|
||
features: features,
|
||
featured: row.featured,
|
||
is_active: row.is_active,
|
||
sort_order: row.sort_order || 0
|
||
})
|
||
},
|
||
del(row) {
|
||
this.$Modal.confirm({
|
||
title: '确认删除',
|
||
content: `确定要删除价格套餐"${row.name}"吗?`,
|
||
onOk: () => {
|
||
pricingPlansServer.del(row).then(res => {
|
||
if (res.code === 0) {
|
||
this.$Message.success('删除成功')
|
||
this.query(this.gridOption.param.pageOption.page)
|
||
} else {
|
||
this.$Message.error(res.message || '删除失败')
|
||
}
|
||
}).catch(err => {
|
||
this.$Message.error('删除失败:' + (err.message || '未知错误'))
|
||
})
|
||
}
|
||
})
|
||
},
|
||
handleSaveSuccess(data) {
|
||
// 处理 JSON 字段
|
||
const formData = { ...data }
|
||
|
||
// 处理 features
|
||
if (formData.features) {
|
||
try {
|
||
const parsed = typeof formData.features === 'string'
|
||
? JSON.parse(formData.features)
|
||
: formData.features
|
||
if (!Array.isArray(parsed)) {
|
||
this.$Message.warning('功能特性必须是数组格式,将使用空数组')
|
||
formData.features = []
|
||
} else {
|
||
formData.features = parsed
|
||
}
|
||
} catch (e) {
|
||
this.$Message.warning('功能特性格式错误,将使用空数组')
|
||
formData.features = []
|
||
}
|
||
}
|
||
|
||
const apiMethod = formData.id ? pricingPlansServer.update : pricingPlansServer.add
|
||
apiMethod(formData).then(res => {
|
||
if (res.code === 0) {
|
||
this.$Message.success(formData.id ? '更新成功' : '添加成功')
|
||
this.$refs.editModal.hide()
|
||
this.query(this.gridOption.param.pageOption.page)
|
||
} else {
|
||
this.$Message.error(res.message || (formData.id ? '更新失败' : '添加失败'))
|
||
}
|
||
}).catch(err => {
|
||
this.$Message.error((formData.id ? '更新失败' : '添加失败') + ':' + (err.message || '未知错误'))
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.content-view {
|
||
padding: 16px;
|
||
}
|
||
</style>
|