🎨 新增vip用户管理以及讲师包月服务管理功能
This commit is contained in:
		
							
								
								
									
										39
									
								
								src/api/goods/teacherVip.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/api/goods/teacherVip.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import service from '@/utils/request'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const list = (params) => {
 | 
				
			||||||
 | 
					    return service({
 | 
				
			||||||
 | 
					        url: '/app_user/teacher_vips',
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        params
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const add = (data) => {
 | 
				
			||||||
 | 
					    return service({
 | 
				
			||||||
 | 
					        url: '/app_user/teacher_vip',
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        data
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const edit = (data) => {
 | 
				
			||||||
 | 
					    return service({
 | 
				
			||||||
 | 
					        url: '/app_user/teacher_vip',
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        data
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const del = (data) => {
 | 
				
			||||||
 | 
					    return service({
 | 
				
			||||||
 | 
					        url: '/app_user/teacher_vip',
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        data
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const detail = (params) => {
 | 
				
			||||||
 | 
					    return service({
 | 
				
			||||||
 | 
					        url: '/app_user/teacher_vip',
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        params
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -85,3 +85,22 @@ export const getLoginInfo = (params) => {
 | 
				
			|||||||
    params
 | 
					    params
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoveUserVip
 | 
				
			||||||
 | 
					export const removeUserVip = (data) => {
 | 
				
			||||||
 | 
					  return service({
 | 
				
			||||||
 | 
					    url: '/app_user/vip',
 | 
				
			||||||
 | 
					    method: 'delete',
 | 
				
			||||||
 | 
					    data
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// getVipUserList
 | 
				
			||||||
 | 
					export const getVipUserList = (params) => {
 | 
				
			||||||
 | 
					  return service({
 | 
				
			||||||
 | 
					    url: '/app_user/vip/list',
 | 
				
			||||||
 | 
					    method: 'get',
 | 
				
			||||||
 | 
					    params
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -292,6 +292,90 @@ export const ORDER_TABLE_CONFIG = {
 | 
				
			|||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VIP用户搜索配置
 | 
				
			||||||
 | 
					export const VIP_USER_SEARCH_CONFIG = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    type: 'input',
 | 
				
			||||||
 | 
					    prop: 'user_id',
 | 
				
			||||||
 | 
					    label: '用户ID',
 | 
				
			||||||
 | 
					    placeholder: '请输入用户ID',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    type: 'input',
 | 
				
			||||||
 | 
					    prop: 'name',
 | 
				
			||||||
 | 
					    label: '用户名称',
 | 
				
			||||||
 | 
					    placeholder: '请输入用户名称',
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VIP用户表格配置
 | 
				
			||||||
 | 
					export const VIP_USER_TABLE_CONFIG = {
 | 
				
			||||||
 | 
					  index: true,
 | 
				
			||||||
 | 
					  schemes: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      attrs: {
 | 
				
			||||||
 | 
					        label: '头像',
 | 
				
			||||||
 | 
					        prop: 'avatar',
 | 
				
			||||||
 | 
					        align: 'center'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      slot: 'avatar'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      attrs: {
 | 
				
			||||||
 | 
					        label: '用户ID',
 | 
				
			||||||
 | 
					        prop: 'id',
 | 
				
			||||||
 | 
					        align: 'center'
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      attrs: {
 | 
				
			||||||
 | 
					        label: '用户名称',
 | 
				
			||||||
 | 
					        prop: 'nick_name',
 | 
				
			||||||
 | 
					        align: 'center'
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      attrs: {
 | 
				
			||||||
 | 
					        label: '手机号',
 | 
				
			||||||
 | 
					        prop: 'phone',
 | 
				
			||||||
 | 
					        align: 'center'
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      attrs: {
 | 
				
			||||||
 | 
					        label: 'VIP等级',
 | 
				
			||||||
 | 
					        prop: 'user_label',
 | 
				
			||||||
 | 
					        align: 'center'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      slot: 'user_label'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      attrs: {
 | 
				
			||||||
 | 
					        label: 'VIP到期时间',
 | 
				
			||||||
 | 
					        prop: 'vip_expire_time',
 | 
				
			||||||
 | 
					        align: 'center'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      slot: 'vip_expire_time'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      attrs: {
 | 
				
			||||||
 | 
					        label: '账户余额',
 | 
				
			||||||
 | 
					        prop: 'balance',
 | 
				
			||||||
 | 
					        align: 'center'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      slot: 'balance'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      attrs: {
 | 
				
			||||||
 | 
					        label: '操作',
 | 
				
			||||||
 | 
					        prop: 'operate',
 | 
				
			||||||
 | 
					        align: 'center'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      slot: 'operate'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 用户登录日志搜索配置
 | 
					// 用户登录日志搜索配置
 | 
				
			||||||
export const LOGIN_LOG_SEARCH_CONFIG = [
 | 
					export const LOGIN_LOG_SEARCH_CONFIG = [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@@ -371,17 +455,11 @@ export const LOGIN_LOG_TABLE_CONFIG = {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 用户列表
 | 
					// 用户列表
 | 
				
			||||||
export const USER_TABLE_CONFIG = {
 | 
					export const USER_TABLE_CONFIG = {
 | 
				
			||||||
  index: true,
 | 
					  index: true,
 | 
				
			||||||
  schemes: [
 | 
					  schemes: [
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      attrs: {
 | 
					 | 
				
			||||||
        label: 'ID',
 | 
					 | 
				
			||||||
        prop: 'ID',
 | 
					 | 
				
			||||||
        align: 'center'
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      attrs: {
 | 
					      attrs: {
 | 
				
			||||||
        label: '头像',
 | 
					        label: '头像',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,7 +90,9 @@
 | 
				
			|||||||
  "/src/view/systemTools/version/version.vue": "SysVersion",
 | 
					  "/src/view/systemTools/version/version.vue": "SysVersion",
 | 
				
			||||||
  "/src/view/user/index.vue": "UserManage",
 | 
					  "/src/view/user/index.vue": "UserManage",
 | 
				
			||||||
  "/src/view/user/user/index.vue": "Index",
 | 
					  "/src/view/user/user/index.vue": "Index",
 | 
				
			||||||
 | 
					  "/src/view/user/user/loginLog.vue": "LoginLog",
 | 
				
			||||||
  "/src/view/user/user/teacherApply.vue": "TeacherApply",
 | 
					  "/src/view/user/user/teacherApply.vue": "TeacherApply",
 | 
				
			||||||
 | 
					  "/src/view/user/user/vipUser.vue": "VipUser",
 | 
				
			||||||
  "/src/plugin/announcement/form/info.vue": "InfoForm",
 | 
					  "/src/plugin/announcement/form/info.vue": "InfoForm",
 | 
				
			||||||
  "/src/plugin/announcement/view/info.vue": "Info",
 | 
					  "/src/plugin/announcement/view/info.vue": "Info",
 | 
				
			||||||
  "/src/plugin/customerservice/view/chat/index.vue": "ServiceMain",
 | 
					  "/src/plugin/customerservice/view/chat/index.vue": "ServiceMain",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										279
									
								
								src/view/goods/teacher_vip/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								src/view/goods/teacher_vip/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,279 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <div class="gva-search-box">
 | 
				
			||||||
 | 
					      <el-form :inline="true" :model="searchInfo" class="demo-form-inline" @keyup.enter="onSubmit">
 | 
				
			||||||
 | 
					        <el-form-item label="讲师">
 | 
				
			||||||
 | 
					          <div style="display:flex;gap:8px;align-items:center">
 | 
				
			||||||
 | 
					            <el-input v-model="searchInfo.teacher_name" placeholder="请选择讲师" clearable style="width: 220px" readonly />
 | 
				
			||||||
 | 
					            <el-button type="primary" plain @click="openTeacherChoose('search')">选择讲师</el-button>
 | 
				
			||||||
 | 
					            <el-button @click="clearTeacher('search')">清空</el-button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					        <el-form-item>
 | 
				
			||||||
 | 
					          <el-button type="primary" icon="search" @click="onSubmit">查询</el-button>
 | 
				
			||||||
 | 
					          <el-button icon="refresh" @click="onReset">重置</el-button>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </el-form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="gva-table-box">
 | 
				
			||||||
 | 
					      <div class="gva-btn-list">
 | 
				
			||||||
 | 
					        <el-button type="primary" icon="plus" @click="openEdit('create')">新增</el-button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <el-table
 | 
				
			||||||
 | 
					        ref="multipleTable"
 | 
				
			||||||
 | 
					        style="width: 100%"
 | 
				
			||||||
 | 
					        tooltip-effect="dark"
 | 
				
			||||||
 | 
					        :data="tableData"
 | 
				
			||||||
 | 
					        row-key="ID"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <el-table-column type="index" label="#" width="60" />
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="ID" prop="ID" width="100" />
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="标题" prop="title" min-width="160" />
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="讲师ID" prop="teacher_id" width="110" />
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="讲师" prop="teacher_name" min-width="140" />
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="头像" width="120">
 | 
				
			||||||
 | 
					          <template #default="scope">
 | 
				
			||||||
 | 
					            <el-image
 | 
				
			||||||
 | 
					              v-if="scope.row.avatar"
 | 
				
			||||||
 | 
					              style="width: 60px; height: 60px"
 | 
				
			||||||
 | 
					              :src="scope.row.avatar"
 | 
				
			||||||
 | 
					              :preview-src-list="[scope.row.avatar]"
 | 
				
			||||||
 | 
					              fit="cover"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            <span v-else>无</span>
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </el-table-column>
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="价格" prop="price" width="120">
 | 
				
			||||||
 | 
					          <template #default="{ row }">
 | 
				
			||||||
 | 
					            {{ formatPrice(row.price) }}
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </el-table-column>
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="更新时间" prop="UpdatedAt" width="180">
 | 
				
			||||||
 | 
					          <template #default="{ row }">{{ formatDate(row.UpdatedAt) }}</template>
 | 
				
			||||||
 | 
					        </el-table-column>
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="描述" prop="desc" min-width="200" show-overflow-tooltip />
 | 
				
			||||||
 | 
					        <el-table-column align="left" label="操作" fixed="right" width="160">
 | 
				
			||||||
 | 
					          <template #default="{ row }">
 | 
				
			||||||
 | 
					            <el-button type="primary" link @click="openEdit('update', row)">编辑</el-button>
 | 
				
			||||||
 | 
					            <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </el-table-column>
 | 
				
			||||||
 | 
					      </el-table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="gva-pagination">
 | 
				
			||||||
 | 
					        <el-pagination
 | 
				
			||||||
 | 
					          layout="total, sizes, prev, pager, next, jumper"
 | 
				
			||||||
 | 
					          :current-page="page"
 | 
				
			||||||
 | 
					          :page-size="pageSize"
 | 
				
			||||||
 | 
					          :page-sizes="[10, 30, 50, 100]"
 | 
				
			||||||
 | 
					          :total="total"
 | 
				
			||||||
 | 
					          @current-change="handleCurrentChange"
 | 
				
			||||||
 | 
					          @size-change="handleSizeChange"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- 选择讲师弹窗 -->
 | 
				
			||||||
 | 
					    <userChoose ref="userChooseRef" title="选择讲师人员" @getRecipientInfo="onChooseTeacher" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- 新增/编辑 抽屉 -->
 | 
				
			||||||
 | 
					    <el-drawer destroy-on-close :size="'520px'" v-model="dialogVisible" :show-close="false" :before-close="closeDialog">
 | 
				
			||||||
 | 
					      <template #header>
 | 
				
			||||||
 | 
					        <div class="flex justify-between items-center">
 | 
				
			||||||
 | 
					          <span class="text-lg">{{ editType==='create'?'新增讲师包月':'编辑讲师包月' }}</span>
 | 
				
			||||||
 | 
					          <div>
 | 
				
			||||||
 | 
					            <el-button :loading="btnLoading" type="primary" @click="submitForm">确 定</el-button>
 | 
				
			||||||
 | 
					            <el-button @click="closeDialog">取 消</el-button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					      <el-form :model="formData" ref="formRef" label-position="top" :rules="rules">
 | 
				
			||||||
 | 
					        <el-form-item label="标题" prop="title">
 | 
				
			||||||
 | 
					          <el-input v-model="formData.title" placeholder="请输入标题" />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					        <el-form-item label="讲师" prop="teacher_id">
 | 
				
			||||||
 | 
					          <div style="display:flex;gap:8px;align-items:center;width:100%">
 | 
				
			||||||
 | 
					            <el-input v-model="formData.teacher_name" placeholder="请选择讲师" readonly />
 | 
				
			||||||
 | 
					            <el-button type="primary" plain @click="openTeacherChoose('form')">选择讲师</el-button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					        <el-form-item label="价格(元)" prop="price">
 | 
				
			||||||
 | 
					          <el-input v-model.number="formData.price" type="number" min="0" placeholder="请输入价格" />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					        <el-form-item label="描述" prop="desc">
 | 
				
			||||||
 | 
					          <el-input v-model="formData.desc" type="textarea" :rows="4" placeholder="请输入描述" />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </el-form>
 | 
				
			||||||
 | 
					    </el-drawer>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup>
 | 
				
			||||||
 | 
					import { ref } from 'vue'
 | 
				
			||||||
 | 
					import { list as getTeacherVipList, add as createTeacherVip, edit as updateTeacherVip, del as deleteTeacherVip, detail as getDetail } from '@/api/goods/teacherVip'
 | 
				
			||||||
 | 
					import { ElMessageBox, ElMessage } from 'element-plus'
 | 
				
			||||||
 | 
					import { formatDate } from '@/utils/format'
 | 
				
			||||||
 | 
					import userChoose from '@/components/userChoose/index.vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const page = ref(1)
 | 
				
			||||||
 | 
					const total = ref(0)
 | 
				
			||||||
 | 
					const pageSize = ref(10)
 | 
				
			||||||
 | 
					const tableData = ref([])
 | 
				
			||||||
 | 
					const searchInfo = ref({ teacher_id: undefined, teacher_name: '' })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 讲师选择
 | 
				
			||||||
 | 
					const userChooseRef = ref()
 | 
				
			||||||
 | 
					const chooseScene = ref('search')
 | 
				
			||||||
 | 
					const openTeacherChoose = (scene) => {
 | 
				
			||||||
 | 
					  chooseScene.value = scene
 | 
				
			||||||
 | 
					  userChooseRef.value && userChooseRef.value.open()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const clearTeacher = (scene) => {
 | 
				
			||||||
 | 
					  if (scene === 'search') {
 | 
				
			||||||
 | 
					    searchInfo.value.teacher_id = undefined
 | 
				
			||||||
 | 
					    searchInfo.value.teacher_name = ''
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    formData.value.teacher_id = undefined
 | 
				
			||||||
 | 
					    formData.value.teacher_name = ''
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const onChooseTeacher = (data) => {
 | 
				
			||||||
 | 
					  const id = data.id || data.ID
 | 
				
			||||||
 | 
					  const name = data.nick_name || data.username || data.name
 | 
				
			||||||
 | 
					  if (chooseScene.value === 'search') {
 | 
				
			||||||
 | 
					    searchInfo.value.teacher_id = id
 | 
				
			||||||
 | 
					    searchInfo.value.teacher_name = name
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    formData.value.teacher_id = id
 | 
				
			||||||
 | 
					    formData.value.teacher_name = name
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const formatPrice = (val) => {
 | 
				
			||||||
 | 
					  if (val === null || val === undefined) return '-'
 | 
				
			||||||
 | 
					  const yuan = Number(val) / 100
 | 
				
			||||||
 | 
					  return `${yuan.toFixed(2)} 元`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const onReset = () => {
 | 
				
			||||||
 | 
					  searchInfo.value = { teacher_id: undefined }
 | 
				
			||||||
 | 
					  page.value = 1
 | 
				
			||||||
 | 
					  getTableData()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const onSubmit = () => {
 | 
				
			||||||
 | 
					  page.value = 1
 | 
				
			||||||
 | 
					  getTableData()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const handleSizeChange = (val) => {
 | 
				
			||||||
 | 
					  pageSize.value = val
 | 
				
			||||||
 | 
					  getTableData()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const handleCurrentChange = (val) => {
 | 
				
			||||||
 | 
					  page.value = val
 | 
				
			||||||
 | 
					  getTableData()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getTableData = async () => {
 | 
				
			||||||
 | 
					  const params = { page: page.value, pageSize: pageSize.value }
 | 
				
			||||||
 | 
					  if (searchInfo.value.teacher_id !== undefined && searchInfo.value.teacher_id !== '' && searchInfo.value.teacher_id !== null) {
 | 
				
			||||||
 | 
					    params.teacher_id = searchInfo.value.teacher_id
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const res = await getTeacherVipList(params)
 | 
				
			||||||
 | 
					  if (res.code === 0) {
 | 
				
			||||||
 | 
					    tableData.value = res.data.list || []
 | 
				
			||||||
 | 
					    total.value = res.data.total || 0
 | 
				
			||||||
 | 
					    page.value = res.data.page || page.value
 | 
				
			||||||
 | 
					    pageSize.value = res.data.pageSize || pageSize.value
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					getTableData()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ============== 新增/编辑/删除 ==============
 | 
				
			||||||
 | 
					const dialogVisible = ref(false)
 | 
				
			||||||
 | 
					const formRef = ref()
 | 
				
			||||||
 | 
					const btnLoading = ref(false)
 | 
				
			||||||
 | 
					const editType = ref('create')
 | 
				
			||||||
 | 
					const formData = ref({
 | 
				
			||||||
 | 
					  ID: undefined,
 | 
				
			||||||
 | 
					  title: '',
 | 
				
			||||||
 | 
					  teacher_id: undefined,
 | 
				
			||||||
 | 
					  teacher_name: '',
 | 
				
			||||||
 | 
					  price: 0,
 | 
				
			||||||
 | 
					  desc: ''
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					const rules = {
 | 
				
			||||||
 | 
					  title: [{ required: true, message: '请输入标题', trigger: ['blur','input'] }],
 | 
				
			||||||
 | 
					  teacher_id: [{ required: true, message: '请选择讲师', trigger: ['change','blur'] }],
 | 
				
			||||||
 | 
					  price: [{ required: true, message: '请输入价格', trigger: ['blur','input'] }]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const resetForm = () => {
 | 
				
			||||||
 | 
					  formData.value = { ID: undefined, title: '', teacher_id: undefined, teacher_name: '', price: 0, desc: '' }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const openEdit = async(type, row) => {
 | 
				
			||||||
 | 
					  editType.value = type
 | 
				
			||||||
 | 
					  if (type === 'update' && row?.ID) {
 | 
				
			||||||
 | 
					    const res = await getDetail({ id: row.ID })
 | 
				
			||||||
 | 
					    if (res.code === 0) {
 | 
				
			||||||
 | 
					      const data = { ...res.data }
 | 
				
			||||||
 | 
					      if (data.price !== null && data.price !== undefined) {
 | 
				
			||||||
 | 
					        data.price = Number(data.price) / 100
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      formData.value = { ...formData.value, ...data }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    resetForm()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  dialogVisible.value = true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const closeDialog = () => {
 | 
				
			||||||
 | 
					  dialogVisible.value = false
 | 
				
			||||||
 | 
					  resetForm()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const submitForm = () => {
 | 
				
			||||||
 | 
					  formRef.value?.validate(async(valid)=>{
 | 
				
			||||||
 | 
					    if (!valid) return
 | 
				
			||||||
 | 
					    btnLoading.value = true
 | 
				
			||||||
 | 
					    const payload = { ...formData.value }
 | 
				
			||||||
 | 
					    // 元 -> 分
 | 
				
			||||||
 | 
					    if (payload.price !== null && payload.price !== undefined) {
 | 
				
			||||||
 | 
					      payload.price = Math.round(Number(payload.price) * 100)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let res
 | 
				
			||||||
 | 
					    if (editType.value === 'create') {
 | 
				
			||||||
 | 
					      res = await createTeacherVip(payload)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      res = await updateTeacherVip(payload)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    btnLoading.value = false
 | 
				
			||||||
 | 
					    if (res && res.code === 0) {
 | 
				
			||||||
 | 
					      ElMessage.success('保存成功')
 | 
				
			||||||
 | 
					      closeDialog()
 | 
				
			||||||
 | 
					      getTableData()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const handleDelete = async(row) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    await ElMessageBox.confirm('确定要删除该记录吗?','提示',{ type:'warning' })
 | 
				
			||||||
 | 
					    const res = await deleteTeacherVip({ ID: row.ID })
 | 
				
			||||||
 | 
					    if (res.code === 0) {
 | 
				
			||||||
 | 
					      ElMessage.success('删除成功')
 | 
				
			||||||
 | 
					      getTableData()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } catch { /* 用户取消 */ }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										106
									
								
								src/view/user/user/loginLog.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/view/user/user/loginLog.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <div class="searchForm">
 | 
				
			||||||
 | 
					      <searchForm
 | 
				
			||||||
 | 
					        :search="LOGIN_LOG_SEARCH_CONFIG"
 | 
				
			||||||
 | 
					        @searchData="searchData"
 | 
				
			||||||
 | 
					        @resetData="resetData"
 | 
				
			||||||
 | 
					        class="search-box searchForm"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="gva-table-box">
 | 
				
			||||||
 | 
					      <Content
 | 
				
			||||||
 | 
					        @changePage="changePage"
 | 
				
			||||||
 | 
					        :total="total"
 | 
				
			||||||
 | 
					        v-model:tabloading="tableLoading"
 | 
				
			||||||
 | 
					        v-model:currentPage="queryParams.page"
 | 
				
			||||||
 | 
					        v-model:pageSize="queryParams.pageSize"
 | 
				
			||||||
 | 
					        :data="tableData"
 | 
				
			||||||
 | 
					        :config="LOGIN_LOG_TABLE_CONFIG"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <template #login_time="{ row }">
 | 
				
			||||||
 | 
					          {{ row.login_time }}
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </Content>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup>
 | 
				
			||||||
 | 
					import { ElMessage } from 'element-plus'
 | 
				
			||||||
 | 
					import searchForm from '@/components/searchForm/index.vue'
 | 
				
			||||||
 | 
					import Content from '@/components/content/index.vue'
 | 
				
			||||||
 | 
					import { getLoginInfo } from '@/api/user/index.js'
 | 
				
			||||||
 | 
					import { ref, onMounted } from 'vue'
 | 
				
			||||||
 | 
					import { LOGIN_LOG_SEARCH_CONFIG, LOGIN_LOG_TABLE_CONFIG } from '@/config'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const tableLoading = ref(true)
 | 
				
			||||||
 | 
					const tableData = ref([])
 | 
				
			||||||
 | 
					const queryParams = ref({
 | 
				
			||||||
 | 
					  page: 1,
 | 
				
			||||||
 | 
					  pageSize: 10,
 | 
				
			||||||
 | 
					  user_id: '',
 | 
				
			||||||
 | 
					  user_name: ''
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					const total = ref(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 搜索数据
 | 
				
			||||||
 | 
					const searchData = (data) => {
 | 
				
			||||||
 | 
					  queryParams.value.page = 1
 | 
				
			||||||
 | 
					  queryParams.value = { ...queryParams.value, ...data }
 | 
				
			||||||
 | 
					  getList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 重置数据
 | 
				
			||||||
 | 
					const resetData = () => {
 | 
				
			||||||
 | 
					  queryParams.value = {
 | 
				
			||||||
 | 
					    page: 1,
 | 
				
			||||||
 | 
					    pageSize: 10,
 | 
				
			||||||
 | 
					    user_id: '',
 | 
				
			||||||
 | 
					    user_name: ''
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取登录日志列表
 | 
				
			||||||
 | 
					async function getList() {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    tableLoading.value = true
 | 
				
			||||||
 | 
					    const res = await getLoginInfo(queryParams.value)
 | 
				
			||||||
 | 
					    if (res.code === 0) {
 | 
				
			||||||
 | 
					      tableData.value = res.data.list || []
 | 
				
			||||||
 | 
					      total.value = res.data.total || 0
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      ElMessage.error(res.msg || '获取登录日志失败')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('获取登录日志失败:', error)
 | 
				
			||||||
 | 
					    ElMessage.error('获取登录日志失败')
 | 
				
			||||||
 | 
					  } finally {
 | 
				
			||||||
 | 
					    tableLoading.value = false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 分页处理
 | 
				
			||||||
 | 
					function changePage(data) {
 | 
				
			||||||
 | 
					  queryParams.value.page = data
 | 
				
			||||||
 | 
					  getList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 页面加载时获取数据
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  getList()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					.searchForm {
 | 
				
			||||||
 | 
					  margin-bottom: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.gva-table-box {
 | 
				
			||||||
 | 
					  background: white;
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  padding: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										186
									
								
								src/view/user/user/vipUser.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								src/view/user/user/vipUser.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,186 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <div class="searchForm">
 | 
				
			||||||
 | 
					      <searchForm
 | 
				
			||||||
 | 
					        :search="VIP_USER_SEARCH_CONFIG"
 | 
				
			||||||
 | 
					        @searchData="searchData"
 | 
				
			||||||
 | 
					        @resetData="resetData"
 | 
				
			||||||
 | 
					        class="search-box searchForm"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="gva-table-box">
 | 
				
			||||||
 | 
					      <Content
 | 
				
			||||||
 | 
					        @changePage="changePage"
 | 
				
			||||||
 | 
					        :total="total"
 | 
				
			||||||
 | 
					        v-model:tabloading="tableLoading"
 | 
				
			||||||
 | 
					        v-model:currentPage="queryParams.page"
 | 
				
			||||||
 | 
					        v-model:pageSize="queryParams.pageSize"
 | 
				
			||||||
 | 
					        :data="tableData"
 | 
				
			||||||
 | 
					        :config="VIP_USER_TABLE_CONFIG"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <template #avatar="{ row }">
 | 
				
			||||||
 | 
					          <el-image
 | 
				
			||||||
 | 
					            style="width: 60px; height: 60px"
 | 
				
			||||||
 | 
					            :src="row.avatar"
 | 
				
			||||||
 | 
					            :zoom-rate="1.2"
 | 
				
			||||||
 | 
					            :max-scale="7"
 | 
				
			||||||
 | 
					            :min-scale="0.2"
 | 
				
			||||||
 | 
					            :preview-src-list="[row.avatar]"
 | 
				
			||||||
 | 
					            show-progress
 | 
				
			||||||
 | 
					            :initial-index="4"
 | 
				
			||||||
 | 
					            fit="cover"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #user_label="{ row }">
 | 
				
			||||||
 | 
					          <el-tag :type="getVipLabelType(row.user_label)">
 | 
				
			||||||
 | 
					            {{ getVipLabelText(row.user_label) }}
 | 
				
			||||||
 | 
					          </el-tag>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #vip_expire_time="{ row }">
 | 
				
			||||||
 | 
					          {{ row.vip_expire_time || '-' }}
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #balance="{ row }">
 | 
				
			||||||
 | 
					          {{ formatBalance(row.balance) }}
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #operate="{ row }">
 | 
				
			||||||
 | 
					          <el-button type="danger" link @click="handleRemoveVip(row)">
 | 
				
			||||||
 | 
					            移除VIP
 | 
				
			||||||
 | 
					          </el-button>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </Content>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup>
 | 
				
			||||||
 | 
					import { ElMessage, ElMessageBox } from 'element-plus'
 | 
				
			||||||
 | 
					import searchForm from '@/components/searchForm/index.vue'
 | 
				
			||||||
 | 
					import Content from '@/components/content/index.vue'
 | 
				
			||||||
 | 
					import { getVipUserList, removeUserVip } from '@/api/user/index.js'
 | 
				
			||||||
 | 
					import { ref, onMounted } from 'vue'
 | 
				
			||||||
 | 
					import { VIP_USER_SEARCH_CONFIG, VIP_USER_TABLE_CONFIG } from '@/config'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const tableLoading = ref(true)
 | 
				
			||||||
 | 
					const tableData = ref([])
 | 
				
			||||||
 | 
					const queryParams = ref({
 | 
				
			||||||
 | 
					  page: 1,
 | 
				
			||||||
 | 
					  pageSize: 10,
 | 
				
			||||||
 | 
					  user_id: '',
 | 
				
			||||||
 | 
					  name: ''
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					const total = ref(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 搜索数据
 | 
				
			||||||
 | 
					const searchData = (data) => {
 | 
				
			||||||
 | 
					  queryParams.value.page = 1
 | 
				
			||||||
 | 
					  queryParams.value = { ...queryParams.value, ...data }
 | 
				
			||||||
 | 
					  getList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 重置数据
 | 
				
			||||||
 | 
					const resetData = () => {
 | 
				
			||||||
 | 
					  queryParams.value = {
 | 
				
			||||||
 | 
					    page: 1,
 | 
				
			||||||
 | 
					    pageSize: 10,
 | 
				
			||||||
 | 
					    user_id: '',
 | 
				
			||||||
 | 
					    name: ''
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取VIP用户列表
 | 
				
			||||||
 | 
					async function getList() {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    tableLoading.value = true
 | 
				
			||||||
 | 
					    const res = await getVipUserList(queryParams.value)
 | 
				
			||||||
 | 
					    if (res.code === 0) {
 | 
				
			||||||
 | 
					      tableData.value = res.data.list || []
 | 
				
			||||||
 | 
					      total.value = res.data.total || 0
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      ElMessage.error(res.msg || '获取VIP用户列表失败')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('获取VIP用户列表失败:', error)
 | 
				
			||||||
 | 
					    ElMessage.error('获取VIP用户列表失败')
 | 
				
			||||||
 | 
					  } finally {
 | 
				
			||||||
 | 
					    tableLoading.value = false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 分页处理
 | 
				
			||||||
 | 
					function changePage(data) {
 | 
				
			||||||
 | 
					  queryParams.value.page = data
 | 
				
			||||||
 | 
					  getList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 格式化余额显示
 | 
				
			||||||
 | 
					function formatBalance(balance) {
 | 
				
			||||||
 | 
					  if (!balance || balance === 0) return '0.00元'
 | 
				
			||||||
 | 
					  return (balance / 100).toFixed(2) + '元'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取VIP等级标签类型
 | 
				
			||||||
 | 
					function getVipLabelType(userLabel) {
 | 
				
			||||||
 | 
					  const typeMap = {
 | 
				
			||||||
 | 
					    1: 'info',    // 注册会员
 | 
				
			||||||
 | 
					    2: 'warning', // VIP
 | 
				
			||||||
 | 
					    3: 'success'  // SVIP
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return typeMap[userLabel] || 'info'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取VIP等级文本
 | 
				
			||||||
 | 
					function getVipLabelText(userLabel) {
 | 
				
			||||||
 | 
					  const textMap = {
 | 
				
			||||||
 | 
					    1: '注册会员',
 | 
				
			||||||
 | 
					    2: 'VIP',
 | 
				
			||||||
 | 
					    3: 'SVIP'
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return textMap[userLabel] || '未知'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 移除用户VIP
 | 
				
			||||||
 | 
					async function handleRemoveVip(row) {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    await ElMessageBox.confirm(
 | 
				
			||||||
 | 
					      `确定要移除用户 "${row.nick_name}" 的VIP身份吗?此操作不可撤销。`,
 | 
				
			||||||
 | 
					      '确认移除VIP',
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        confirmButtonText: '确定',
 | 
				
			||||||
 | 
					        cancelButtonText: '取消',
 | 
				
			||||||
 | 
					        type: 'warning',
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const res = await removeUserVip({ id: row.id })
 | 
				
			||||||
 | 
					    if (res.code === 0) {
 | 
				
			||||||
 | 
					      ElMessage.success('移除VIP成功')
 | 
				
			||||||
 | 
					      getList() // 刷新列表
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      ElMessage.error(res.msg || '移除VIP失败')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    // 取消操作时不需要提示
 | 
				
			||||||
 | 
					    if (error !== 'cancel') {
 | 
				
			||||||
 | 
					      ElMessage.error('移除VIP失败')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 页面加载时获取数据
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  getList()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					.searchForm {
 | 
				
			||||||
 | 
					  margin-bottom: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.gva-table-box {
 | 
				
			||||||
 | 
					  background: white;
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  padding: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
		Reference in New Issue
	
	Block a user