| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- <template>
- <div class="package-templates admin-page">
- <el-card>
- <div slot="header">
- <span>套餐模板管理</span>
- <el-input v-model="keyword" placeholder="搜索套餐..." prefix-icon="el-icon-search" style="width:200px" clearable @keyup.enter.native="handleSearch" @clear="handleSearch" />
- <el-button style="float: right" type="primary" size="small" @click="handleCreate">+ 添加模板</el-button>
- <div style="overflow:auto;max-height:calc(100vh - 300px);">
- <el-table style="max-height:calc(100vh - 300px);" :data="filteredData" stripe>
- <el-table-column prop="id" label="ID" width="80"></el-table-column>
- <el-table-column prop="name" label="模板名称"></el-table-column>
- <el-table-column prop="validityMonths" label="有效期(月)" width="100"></el-table-column>
- <el-table-column prop="referencePrice" label="参考价格" width="100">
- <template slot-scope="scope">{{ formatPriceWithSymbol(scope.row.referencePrice) }}</template>
- </el-table-column>
- <el-table-column prop="minPrice" label="最低售价" width="100">
- <template slot-scope="scope">{{ formatPriceWithSymbol(scope.row.minPrice) }}</template>
- </el-table-column>
- <el-table-column prop="description" label="描述"></el-table-column>
- <el-table-column prop="status" label="状态" width="100">
- <template slot-scope="scope">
- <el-tag :type="scope.row.status === 'ACTIVE' ? 'success' : 'danger'">
- {{ scope.row.status === 'ACTIVE' ? '启用' : '停用' }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="操作" width="200" fixed="right">
- <template slot-scope="{ row }">
- <el-button size="mini" type="primary" @click="handleEdit(row)">编辑</el-button>
- <el-dropdown trigger="hover" @command="(cmd) => handleActionCmd(row, cmd)">
- <el-button size="mini">
- 更多<i class="el-icon-arrow-down el-icon--right"></i>
- </el-button>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="viewServices" icon="el-icon-document">服务项</el-dropdown-item>
- <el-dropdown-item command="toggleStatus" :icon="row.status === 'ACTIVE' ? 'el-icon-close' : 'el-icon-check'">{{ row.status === 'ACTIVE' ? '停用' : '启用' }}</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </template>
- </el-table-column>
- </el-table></div>
- </el-card>
- <el-dialog :visible.sync="dialogVisible" :title="isEdit ? '编辑套餐模板' : '添加套餐模板'" width="600px">
- <el-form :model="form" label-width="120px">
- <el-form-item label="模板名称">
- <el-input v-model="form.name"></el-input>
- </el-form-item>
- <el-form-item label="有效期(月)">
- <el-input-number v-model="form.validityMonths" :min="1"></el-input-number>
- </el-form-item>
- <el-form-item label="参考价格(元)">
- <el-input-number v-model="form.referencePrice" :min="0" :precision="2"></el-input-number>
- </el-form-item>
- <el-form-item label="最低售价(元)">
- <el-input-number v-model="form.minPrice" :min="0" :precision="2"></el-input-number>
- <div class="form-tip">成长规划师定价不能低于此价格</div>
- </el-form-item>
- <el-form-item label="描述">
- <el-input type="textarea" v-model="form.description" :rows="3"></el-input>
- </el-form-item>
- </el-form>
- <div slot="footer">
- <el-button @click="dialogVisible = false">取消</el-button>
- <el-button type="primary" @click="handleSubmit">保存</el-button>
- </div>
- </el-dialog>
- <el-dialog :visible.sync="servicesVisible" title="套餐服务项" width="600px">
- <div class="services-list">
- <div v-if="currentServices.length === 0" class="empty-tip">暂无服务项</div>
- <div class="service-item" v-for="(service, index) in currentServices" :key="index">
- <div class="service-info">
- <span class="service-name">{{ service.serviceName }}</span>
- <span class="service-qty">{{ service.quantity }} {{ service.unit }}</span>
- </div>
- <span class="service-price">{{ formatPriceWithSymbol(service.unitPrice) }}</span>
- </div>
- </div>
- <div slot="footer">
- <el-button @click="servicesVisible = false">关闭</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import { getAllPackageTemplates, createPackageTemplate, updatePackageTemplate } from '@/api/adminService'
- export default {
- name: 'PackageTemplates',
- data() {
- return {
- templates: [],
- keyword: '',
- dialogVisible: false,
- servicesVisible: false,
- currentServices: [],
- isEdit: false,
- form: {
- id: null,
- name: '',
- validityMonths: 12,
- referencePrice: 0,
- minPrice: 0,
- description: '',
- status: 'ACTIVE'
- }
- }
- },
- computed: {
- filteredData() {
- if (!this.keyword) return this.templates
- const kw = this.keyword.toLowerCase()
- return this.templates.filter(item =>
- [item.name, item.description].some(v => (v||'').toLowerCase().includes(kw))
- )
- }
- },
- created() {
- this.loadData()
- },
- methods: {
- async loadData() {
- try {
- const res = await getAllPackageTemplates()
- if (res.data) {
- this.templates = res.data
- }
- } catch (e) {
- this.templates = [
- { id: 1, name: '年度旗舰版', validityMonths: 12, referencePrice: 1980, minPrice: 1280, description: '全年度服务', status: 'ACTIVE', services: [
- { serviceName: '1对1 DAN测评', quantity: 2, unit: '次/年', unitPrice: 800 },
- { serviceName: '成长报告', quantity: 12, unit: '份/年', unitPrice: 600 },
- { serviceName: '专属咨询', quantity: 999, unit: '次/年', unitPrice: 580 }
- ]},
- { id: 2, name: '季度体验版', validityMonths: 3, referencePrice: 580, minPrice: 380, description: '季度服务', status: 'ACTIVE', services: [
- { serviceName: '1对1 DAN测评', quantity: 1, unit: '次', unitPrice: 800 },
- { serviceName: '成长报告', quantity: 3, unit: '份', unitPrice: 50 }
- ]},
- { id: 3, name: '月度试用版', validityMonths: 1, referencePrice: 99, minPrice: 99, description: '月度试用', status: 'ACTIVE', services: [
- { serviceName: '1对1 DAN测评', quantity: 1, unit: '次', unitPrice: 800 }
- ]}
- ]
- }
- },
- handleCreate() {
- this.isEdit = false
- this.form = {
- id: null,
- name: '',
- validityMonths: 12,
- referencePrice: 0,
- minPrice: 0,
- description: '',
- status: 'ACTIVE'
- }
- this.dialogVisible = true
- },
- handleEdit(row) {
- this.isEdit = true
- this.form = { ...row }
- this.dialogVisible = true
- },
- handleViewServices(row) {
- this.currentServices = row.services || []
- this.servicesVisible = true
- },
- async toggleStatus(row) {
- row.status = row.status === 'ACTIVE' ? 'DISABLED' : 'ACTIVE'
- try {
- await updatePackageTemplate(row.id, row)
- this.$message.success('状态已更新')
- } catch (e) {
- row.status = row.status === 'ACTIVE' ? 'DISABLED' : 'ACTIVE'
- this.$message.error('更新失败')
- }
- },
- async handleSubmit() {
- if (!this.form.name || !this.form.validityMonths) {
- this.$message.warning('请填写完整信息')
- return
- }
- if (this.form.minPrice > this.form.referencePrice) {
- this.$message.warning('最低售价不能大于参考价格')
- return
- }
- try {
- if (this.isEdit) {
- await updatePackageTemplate(this.form.id, this.form)
- } else {
- await createPackageTemplate(this.form)
- }
- this.$message.success('保存成功')
- this.dialogVisible = false
- this.loadData()
- } catch (e) {
- this.$message.error('保存失败')
- }
- },
- handleActionCmd(row, cmd) {
- switch (cmd) {
- case 'viewServices': this.handleViewServices(row); break
- case 'toggleStatus': this.toggleStatus(row); break
- }
- },
- handleSearch() {}
- }
- }
- </script>
- <style scoped>
- .package-templates {
- padding: 20px;
- }
- .form-tip {
- font-size: 12px;
- color: #909399;
- margin-top: 4px;
- }
- .services-list {
- max-height: 400px;
- overflow-y: auto;
- }
- .service-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 15px;
- border-bottom: 1px solid #eee;
- }
- .service-item:last-child {
- border-bottom: none;
- }
- .service-info {
- display: flex;
- flex-direction: column;
- }
- .service-name {
- font-size: 14px;
- color: #333;
- }
- .service-qty {
- font-size: 12px;
- color: #999;
- margin-top: 4px;
- }
- .service-price {
- font-size: 16px;
- font-weight: bold;
- color: #409EFF;
- }
- .empty-tip {
- text-align: center;
- color: #909399;
- padding: 40px 0;
- }
- </style>
|