|
|
@@ -1,334 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="service-contents admin-page">
|
|
|
- <el-card>
|
|
|
- <div slot="header" class="admin-page-header">
|
|
|
- <span class="admin-page-title">服务内容管理</span>
|
|
|
- <div class="admin-page-actions">
|
|
|
- <el-input v-model="keyword" placeholder="搜索内容..." prefix-icon="el-icon-search" clearable @keyup.enter.native="handleSearch" @clear="handleSearch" />
|
|
|
- <el-button type="primary" size="small" @click="handleCreate">+ 添加内容</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <el-form :inline="true">
|
|
|
- <el-form-item label="服务类型">
|
|
|
- <el-select v-model="query.typeId" placeholder="全部" clearable @change="handleQuery">
|
|
|
- <el-option v-for="t in serviceTypes" :key="t.id" :label="t.name" :value="t.id"></el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="状态">
|
|
|
- <el-select v-model="query.status" placeholder="全部" clearable @change="handleQuery">
|
|
|
- <el-option label="启用" value="ACTIVE"></el-option>
|
|
|
- <el-option label="停用" value="DISABLED"></el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item>
|
|
|
- <el-button @click="handleQuery">查询</el-button>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- <div class="table-scroll-wrap-sm">
|
|
|
- <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="title" label="标题"></el-table-column>
|
|
|
- <el-table-column prop="typeId" label="类型" width="120">
|
|
|
- <template slot-scope="scope">
|
|
|
- {{ getTypeName(scope.row.typeId) }}
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="duration" label="时长(分钟)" width="100"></el-table-column>
|
|
|
- <el-table-column prop="ageRange" label="适用年龄" width="100"></el-table-column>
|
|
|
- <el-table-column prop="price" label="参考价格" width="100">
|
|
|
- <template slot-scope="scope">{{ formatPriceWithSymbol(scope.row.price) }}</template>
|
|
|
- </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="preview" icon="el-icon-view">预览</el-dropdown-item>
|
|
|
- <el-dropdown-item :command="row.status === 'ACTIVE' ? 'disable' : 'enable'" icon="el-icon-switch-button">{{ row.status === 'ACTIVE' ? '停用' : '启用' }}</el-dropdown-item>
|
|
|
- </el-dropdown-menu>
|
|
|
- </el-dropdown>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table></div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
-
|
|
|
- <el-dialog :visible.sync="dialogVisible" :title="isEdit ? '编辑服务内容' : '添加服务内容'" width="800px">
|
|
|
- <el-form :model="form" label-width="100px">
|
|
|
- <el-form-item label="服务类型">
|
|
|
- <el-select v-model="form.typeId" placeholder="请选择服务类型">
|
|
|
- <el-option v-for="t in serviceTypes" :key="t.id" :label="t.name" :value="t.id"></el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="标题">
|
|
|
- <el-input v-model="form.title"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="服务详情">
|
|
|
- <div class="rich-editor">
|
|
|
- <div class="editor-toolbar">
|
|
|
- <el-button size="small" @click="insertTag('b')">B</el-button>
|
|
|
- <el-button size="small" @click="insertTag('i')">I</el-button>
|
|
|
- <el-button size="small" @click="insertTag('u')">U</el-button>
|
|
|
- <el-button size="small" @click="insertTag('h3')">标题</el-button>
|
|
|
- <el-button size="small" @click="insertTag('ul')">列表</el-button>
|
|
|
- <el-button size="small" @click="insertTag('img')">图片</el-button>
|
|
|
- </div>
|
|
|
- <el-input
|
|
|
- type="textarea"
|
|
|
- v-model="form.content"
|
|
|
- :rows="10"
|
|
|
- placeholder="请输入服务详情,支持HTML标签"
|
|
|
- ></el-input>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="建议时长(分钟)">
|
|
|
- <el-input-number v-model="form.duration" :min="0"></el-input-number>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="适用年龄">
|
|
|
- <el-input v-model="form.ageRange" placeholder="如: 3-12岁"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="参考价格(元)">
|
|
|
- <el-input-number v-model="form.price" :min="0" :precision="2"></el-input-number>
|
|
|
- </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="previewVisible" title="服务内容预览" width="600px">
|
|
|
- <div class="preview-content" v-html="previewContent"></div>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <el-dialog title="操作成功" :visible.sync="successDialogVisible" width="400px" :close-on-click-modal="false">
|
|
|
- <div style="text-align:center;padding:10px 0">
|
|
|
- <i class="el-icon-success" style="color:#67C23A;font-size:32px"></i>
|
|
|
- <p style="margin:12px 0 0;font-size:16px;color:#303133">保存成功</p>
|
|
|
- </div>
|
|
|
- <div slot="footer">
|
|
|
- <el-button type="primary" @click="handleContinue">继续添加</el-button>
|
|
|
- <el-button @click="handleClose">关闭</el-button>
|
|
|
- </div>
|
|
|
- </el-dialog>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script>
|
|
|
-import { getServiceContents, createServiceContent, updateServiceContent } from '@/api/adminService'
|
|
|
-import { getServiceTypes } from '@/api/adminService'
|
|
|
-
|
|
|
-export default {
|
|
|
- name: 'ServiceContents',
|
|
|
- data() {
|
|
|
- return {
|
|
|
- contents: [],
|
|
|
- keyword: '',
|
|
|
- serviceTypes: [],
|
|
|
- query: {
|
|
|
- typeId: null,
|
|
|
- status: null
|
|
|
- },
|
|
|
- dialogVisible: false,
|
|
|
- successDialogVisible: false,
|
|
|
- previewVisible: false,
|
|
|
- previewContent: '',
|
|
|
- isEdit: false,
|
|
|
- form: {
|
|
|
- id: null,
|
|
|
- typeId: null,
|
|
|
- title: '',
|
|
|
- content: '',
|
|
|
- duration: 0,
|
|
|
- ageRange: '',
|
|
|
- price: 0,
|
|
|
- status: 'ACTIVE'
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- created() {
|
|
|
- this.loadTypes()
|
|
|
- this.loadData()
|
|
|
- },
|
|
|
- computed: {
|
|
|
- filteredData() {
|
|
|
- if (!this.keyword) return this.contents
|
|
|
- var kw = this.keyword.toLowerCase()
|
|
|
- return this.contents.filter(function(item) {
|
|
|
- return item.title && item.title.toLowerCase().indexOf(kw) !== -1
|
|
|
- })
|
|
|
- }
|
|
|
- },
|
|
|
- methods: {
|
|
|
- async loadTypes() {
|
|
|
- try {
|
|
|
- const res = await getServiceTypes()
|
|
|
- if (res.data) {
|
|
|
- this.serviceTypes = res.data
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- this.serviceTypes = [
|
|
|
- { id: 1, name: 'DAN测评' },
|
|
|
- { id: 2, name: '专属咨询' },
|
|
|
- { id: 3, name: '成长报告' },
|
|
|
- { id: 4, name: '家庭培训' }
|
|
|
- ]
|
|
|
- }
|
|
|
- },
|
|
|
- async loadData() {
|
|
|
- try {
|
|
|
- const res = await getServiceContents(this.query)
|
|
|
- if (res.data) {
|
|
|
- this.contents = res.data
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- this.contents = [
|
|
|
- { id: 1, typeId: 1, title: '1对1 DAN测评', content: '<p>DAN测评是...</p>', duration: 60, ageRange: '3-12岁', price: 800, status: 'ACTIVE' },
|
|
|
- { id: 2, typeId: 1, title: 'DAN综合评估', content: '<p>综合评估...</p>', duration: 90, ageRange: '3-12岁', price: 1200, status: 'ACTIVE' },
|
|
|
- { id: 3, typeId: 2, title: '专属咨询', content: '<p>咨询服务...</p>', duration: 30, ageRange: '3-18岁', price: 580, status: 'ACTIVE' }
|
|
|
- ]
|
|
|
- }
|
|
|
- },
|
|
|
- getTypeName(typeId) {
|
|
|
- const type = this.serviceTypes.find(t => t.id === typeId)
|
|
|
- return type ? type.name : '-'
|
|
|
- },
|
|
|
- handleSearch() {},
|
|
|
- handleQuery() {
|
|
|
- this.loadData()
|
|
|
- },
|
|
|
- handleCreate() {
|
|
|
- this.isEdit = false
|
|
|
- this.form = {
|
|
|
- id: null,
|
|
|
- typeId: null,
|
|
|
- title: '',
|
|
|
- content: '',
|
|
|
- duration: 0,
|
|
|
- ageRange: '',
|
|
|
- price: 0,
|
|
|
- status: 'ACTIVE'
|
|
|
- }
|
|
|
- this.dialogVisible = true
|
|
|
- },
|
|
|
- handleEdit(row) {
|
|
|
- this.isEdit = true
|
|
|
- this.form = { ...row }
|
|
|
- this.dialogVisible = true
|
|
|
- },
|
|
|
- handlePreview(row) {
|
|
|
- this.previewContent = row.content
|
|
|
- this.previewVisible = true
|
|
|
- },
|
|
|
- async toggleStatus(row) {
|
|
|
- row.status = row.status === 'ACTIVE' ? 'DISABLED' : 'ACTIVE'
|
|
|
- try {
|
|
|
- await updateServiceContent(row.id, row)
|
|
|
- this.$message.success('状态已更新')
|
|
|
- } catch (e) {
|
|
|
- row.status = row.status === 'ACTIVE' ? 'DISABLED' : 'ACTIVE'
|
|
|
- this.$message.error('更新失败')
|
|
|
- }
|
|
|
- },
|
|
|
- async handleSubmit() {
|
|
|
- if (!this.form.typeId || !this.form.title) {
|
|
|
- this.$message.warning('请填写完整信息')
|
|
|
- return
|
|
|
- }
|
|
|
- try {
|
|
|
- if (this.isEdit) {
|
|
|
- await updateServiceContent(this.form.id, this.form)
|
|
|
- } else {
|
|
|
- await createServiceContent(this.form)
|
|
|
- }
|
|
|
- this.$message.success('保存成功')
|
|
|
- this.successDialogVisible = true
|
|
|
- } catch (e) {
|
|
|
- this.$message.error('保存失败')
|
|
|
- }
|
|
|
- },
|
|
|
- insertTag(tag) {
|
|
|
- const tags = {
|
|
|
- b: '<strong></strong>',
|
|
|
- i: '<em></em>',
|
|
|
- u: '<u></u>',
|
|
|
- h3: '<h3></h3>',
|
|
|
- ul: '<ul><li></li></ul>',
|
|
|
- img: '<img src="" alt=""/>'
|
|
|
- }
|
|
|
- this.form.content += tags[tag]
|
|
|
- },
|
|
|
- handleActionCmd(row, cmd) {
|
|
|
- switch (cmd) {
|
|
|
- case 'preview':
|
|
|
- this.handlePreview(row)
|
|
|
- break
|
|
|
- case 'disable':
|
|
|
- row.status = 'DISABLED'
|
|
|
- this.toggleStatus(row)
|
|
|
- break
|
|
|
- case 'enable':
|
|
|
- row.status = 'ACTIVE'
|
|
|
- this.toggleStatus(row)
|
|
|
- break
|
|
|
- }
|
|
|
- },
|
|
|
- handleContinue() {
|
|
|
- this.successDialogVisible = false
|
|
|
- this.isEdit = false
|
|
|
- this.form = { id: null, typeId: null, title: '', content: '', duration: 0, ageRange: '', price: null, status: 'ACTIVE' }
|
|
|
- this.dialogVisible = true
|
|
|
- },
|
|
|
- handleClose() {
|
|
|
- this.successDialogVisible = false
|
|
|
- this.dialogVisible = false
|
|
|
- this.loadData()
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.service-contents {
|
|
|
- padding: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.rich-editor {
|
|
|
- border: 1px solid #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.editor-toolbar {
|
|
|
- padding: 10px;
|
|
|
- border-bottom: 1px solid #dcdfe6;
|
|
|
- background: #f5f7fa;
|
|
|
-}
|
|
|
-
|
|
|
-.preview-content {
|
|
|
- padding: 20px;
|
|
|
- line-height: 1.8;
|
|
|
-}
|
|
|
-
|
|
|
-.preview-content h3 {
|
|
|
- margin: 16px 0 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.preview-content ul {
|
|
|
- padding-left: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.preview-content img {
|
|
|
- max-width: 100%;
|
|
|
-}
|
|
|
-</style>
|