Przeglądaj źródła

chore(web): 删除服务类型/服务内容/套餐模板三个未使用的admin维护菜单

- 数据流转: BindController+ButlerCommissionService 等仍在使用 ServiceType/ServiceContent 的实体, 保留 Java 侧
- PackageTemplates 的 GuidePackageTemplateService 也被 GuidePackageController.getTemplates 复用, 保留 Java 侧
- 本提交仅移除 3 个 admin-only 维护菜单:
  * cfc-web/src/views/admin/ServiceTypes.vue
  * cfc-web/src/views/admin/ServiceContents.vue
  * cfc-web/src/views/admin/PackageTemplates.vue
  * cfc-web/src/api/adminService.js (无其他调用方)
  * Layout.vue 配置中心子菜单条目
  * router/index.js 路由项
Xiaogang Liao 2 miesięcy temu
rodzic
commit
bbb36015d2

+ 0 - 127
cfc-web/src/api/adminService.js

@@ -1,127 +0,0 @@
-import request from '@/utils/request'
-
-export function getServiceTypes() {
-  return request({
-    url: '/api/admin/service-types',
-    method: 'get'
-  })
-}
-
-export function getAllServiceTypes() {
-  return request({
-    url: '/api/admin/service-types/all',
-    method: 'get'
-  })
-}
-
-export function createServiceType(data) {
-  return request({
-    url: '/api/admin/service-types',
-    method: 'post',
-    data
-  })
-}
-
-export function updateServiceType(id, data) {
-  return request({
-    url: `/api/admin/service-types/${id}`,
-    method: 'put',
-    data
-  })
-}
-
-export function deleteServiceType(id) {
-  return request({
-    url: `/api/admin/service-types/${id}`,
-    method: 'delete'
-  })
-}
-
-export function getServiceContents(params) {
-  return request({
-    url: '/api/admin/service-contents',
-    method: 'get',
-    params
-  })
-}
-
-export function getActiveServiceContents() {
-  return request({
-    url: '/api/admin/service-contents/active',
-    method: 'get'
-  })
-}
-
-export function getServiceContent(id) {
-  return request({
-    url: `/api/admin/service-contents/${id}`,
-    method: 'get'
-  })
-}
-
-export function createServiceContent(data) {
-  return request({
-    url: '/api/admin/service-contents',
-    method: 'post',
-    data
-  })
-}
-
-export function updateServiceContent(id, data) {
-  return request({
-    url: `/api/admin/service-contents/${id}`,
-    method: 'put',
-    data
-  })
-}
-
-export function deleteServiceContent(id) {
-  return request({
-    url: `/api/admin/service-contents/${id}`,
-    method: 'delete'
-  })
-}
-
-export function getPackageTemplatesAdmin() {
-  return request({
-    url: '/api/admin/package-templates',
-    method: 'get'
-  })
-}
-
-export function getAllPackageTemplates() {
-  return request({
-    url: '/api/admin/package-templates/all',
-    method: 'get'
-  })
-}
-
-export function getPackageTemplate(id) {
-  return request({
-    url: `/api/admin/package-templates/${id}`,
-    method: 'get'
-  })
-}
-
-export function createPackageTemplate(data) {
-  return request({
-    url: '/api/admin/package-templates',
-    method: 'post',
-    data
-  })
-}
-
-export function updatePackageTemplate(id, data) {
-  return request({
-    url: `/api/admin/package-templates/${id}`,
-    method: 'put',
-    data
-  })
-}
-
-export function deletePackageTemplate(id) {
-  return request({
-    url: `/api/admin/package-templates/${id}`,
-    method: 'delete'
-  })
-}

+ 0 - 18
cfc-web/src/router/index.js

@@ -174,24 +174,6 @@ const routes = [
         meta: { title: '操作日志', perm: 'system:logs' }
       },
       // 服务管理(管理员)
-      {
-        path: 'service-types',
-        name: 'ServiceTypes',
-        component: () => import('@/views/admin/ServiceTypes.vue'),
-        meta: { title: '服务类型管理', perm: 'system:config' }
-      },
-      {
-        path: 'service-contents',
-        name: 'ServiceContents',
-        component: () => import('@/views/admin/ServiceContents.vue'),
-        meta: { title: '服务内容管理', perm: 'system:config' }
-      },
-      {
-        path: 'package-templates',
-        name: 'PackageTemplates',
-        component: () => import('@/views/admin/PackageTemplates.vue'),
-        meta: { title: '套餐模板管理', perm: 'system:config' }
-      },
       {
         path: 'teacher-messages',
         name: 'TeacherMessages',

+ 0 - 3
cfc-web/src/views/Layout.vue

@@ -265,9 +265,6 @@ export default {
               children: [
                 { path: '/dimension-config', label: '维度配置', icon: 'el-icon-data-line', perm: 'system:config' },
                 { path: '/relationship-types', label: '关系类型', icon: 'el-icon-share', perm: 'system:config' },
-                { path: '/service-types', label: '服务类型', icon: 'el-icon-s-management', perm: 'system:config' },
-                { path: '/service-contents', label: '服务内容', icon: 'el-icon-s-management', perm: 'system:config' },
-                { path: '/package-templates', label: '套餐模板', icon: 'el-icon-s-management', perm: 'system:config' },
               ]},
             // --- 教育体系 ---
             { title: '教育体系', icon: 'el-icon-s-management', perm: 'system:education',

+ 0 - 286
cfc-web/src/views/admin/PackageTemplates.vue

@@ -1,286 +0,0 @@
-<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() {},
-    handleContinue() {
-      this.successDialogVisible = false
-      this.isEdit = false
-      this.form = {
-        id: null,
-        name: '',
-        validityMonths: 12,
-        referencePrice: 0,
-        minPrice: 0,
-        description: '',
-        status: 'ACTIVE'
-      }
-      this.dialogVisible = true
-    },
-    handleClose() {
-      this.successDialogVisible = false
-      this.dialogVisible = false
-      this.loadData()
-    }
-  }
-}
-</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>

+ 0 - 334
cfc-web/src/views/admin/ServiceContents.vue

@@ -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>

+ 0 - 186
cfc-web/src/views/admin/ServiceTypes.vue

@@ -1,186 +0,0 @@
-<template>
-  <div class="service-types admin-page">
-    <el-card>
-      <div slot="header" class="admin-page-header">
-        <span class="admin-page-title">服务类型管理</span>
-        <div class="flex items-center gap-sm">
-          <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>
-      <div class="table-scroll-wrap">
-        <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="icon" label="图标" width="100">
-          <template slot-scope="scope">{{ scope.row.icon }}</template>
-        </el-table-column>
-        <el-table-column prop="description" label="描述"></el-table-column>
-        <el-table-column prop="sortOrder" label="排序" width="80"></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="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="500px">
-      <el-form :model="form" label-width="80px">
-        <el-form-item label="类型名称">
-          <el-input v-model="form.name"></el-input>
-        </el-form-item>
-        <el-form-item label="图标">
-          <el-input v-model="form.icon" placeholder="如: 📊"></el-input>
-        </el-form-item>
-        <el-form-item label="描述">
-          <el-input v-model="form.description" type="textarea"></el-input>
-        </el-form-item>
-        <el-form-item label="排序">
-          <el-input-number v-model="form.sortOrder" :min="0"></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 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 { getAllServiceTypes, createServiceType, updateServiceType, deleteServiceType } from '@/api/adminService'
-
-export default {
-  name: 'ServiceTypes',
-  data() {
-    return {
-      types: [],
-      dialogVisible: false,
-      successDialogVisible: false,
-      isEdit: false,
-      form: {
-        id: null,
-        name: '',
-        icon: '',
-        description: '',
-        sortOrder: 0,
-        status: 'ACTIVE'
-      },
-      keyword: ''
-    }
-  },
-  computed: {
-    filteredData() {
-      if (!this.keyword) return this.types
-      const kw = this.keyword.toLowerCase()
-      return this.types.filter(item =>
-        [item.name, item.description].some(v => (v||'').toLowerCase().includes(kw))
-      )
-    }
-  },
-  created() {
-    this.loadData()
-  },
-  methods: {
-    handleSearch() {},
-    async loadData() {
-      try {
-        const res = await getAllServiceTypes()
-        if (res.data) {
-          this.types = res.data
-        }
-      } catch (e) {
-        console.error(e)
-      }
-    },
-    handleCreate() {
-      this.isEdit = false
-      this.form = { id: null, name: '', icon: '', description: '', sortOrder: 0, status: 'ACTIVE' }
-      this.dialogVisible = true
-    },
-    handleEdit(row) {
-      this.isEdit = true
-      this.form = { ...row }
-      this.dialogVisible = true
-    },
-    async toggleStatus(row) {
-      row.status = row.status === 'ACTIVE' ? 'DISABLED' : 'ACTIVE'
-      try {
-        await updateServiceType(row.id, row)
-        this.$message.success('状态已更新')
-      } catch (e) {
-        row.status = row.status === 'ACTIVE' ? 'DISABLED' : 'ACTIVE'
-        this.$message.error('更新失败')
-      }
-    },
-    async handleSubmit() {
-      try {
-        if (this.isEdit) {
-          await updateServiceType(this.form.id, this.form)
-        } else {
-          await createServiceType(this.form)
-        }
-        this.$message.success('保存成功')
-        this.successDialogVisible = true
-      } catch (e) {
-        this.$message.error('保存失败')
-      }
-    },
-    handleActionCmd(row, cmd) {
-      switch (cmd) {
-        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, name: '', icon: '', description: '', sortOrder: 0, status: 'ACTIVE' }
-      this.dialogVisible = true
-    },
-    handleClose() {
-      this.successDialogVisible = false
-      this.dialogVisible = false
-      this.loadData()
-    }
-  }
-}
-</script>
-
-<style scoped>
-</style>