diff --git a/.env.base b/.env.base index 0552a5a..5a22736 100644 --- a/.env.base +++ b/.env.base @@ -6,9 +6,9 @@ VITE_DEV=true # 请求路径 # VITE_BASE_URL='http://localhost:48080' -# VITE_BASE_URL='http://47.98.161.246:48080' +VITE_BASE_URL='http://47.98.161.246:48080' # VITE_BASE_URL='http://114.55.169.15:48080' -VITE_BASE_URL='http://114.215.207.150:48080' +# VITE_BASE_URL='http://114.215.207.150:48080' # 上传路径 VITE_UPLOAD_URL='http://47.98.161.246:48080/admin-api/system/file/upload' diff --git a/src/api/customer/customer.js b/src/api/customer/customer.js index 8f040a0..16ed286 100644 --- a/src/api/customer/customer.js +++ b/src/api/customer/customer.js @@ -22,7 +22,8 @@ export const deleteCustomer = (userId) => { // 获取考试车型 export const getCustomerExamCarType = () => { - return request.get({ url: '/admin-api/applet/xunjia/car/simple-list' }) + return request.post({ url: 'https://cloud.ahduima.com//driver-api/tdTenantCar/list' }) + // return request.post({ url: import.meta.env.VITE_BASE_URL + '/driver-api/tdTenantCar/list' }) } // 导入学员 diff --git a/src/api/xjapplet/discount.js b/src/api/xjapplet/discount.js new file mode 100644 index 0000000..0956658 --- /dev/null +++ b/src/api/xjapplet/discount.js @@ -0,0 +1,48 @@ +import request from '@/config/axios' + +export const getVipDiscountList = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/member/discount/list', + params: params + }) +} + +export const addVipDiscount = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/member/discount/add', + data + }) +} + +export const updateVipDiscount = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/member/discount/update', + data + }) +} + +export const deleteVipDiscount = async (id) => { + return await request.delete({ + url: '/admin-api/applet/xunjia/member/discount/delete?discountId=' + id + }) +} + +export const getVipDiscountOptions = async () => { + return await request.get({ + url: '/admin-api/applet/xunjia/member/discount/simple-list' + }) +} + +export const getUserDiscountList = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/user/discount/list', + params: params + }) +} + +export const giveUserDiscount = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/user/discount/send', + data + }) +} diff --git a/src/api/xjapplet/resell.js b/src/api/xjapplet/resell.js new file mode 100644 index 0000000..4042167 --- /dev/null +++ b/src/api/xjapplet/resell.js @@ -0,0 +1,32 @@ +import request from '@/config/axios' + +export const getResellList = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/distribution/list', + params: params + }) +} + +export const addResell = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/distribution/add', + data + }) +} + +export const updateResell = async (data) => { + return await request.put({ + url: '/admin-api/applet/xunjia/distribution/update', + data + }) +} +export const deleteResell = async (id) => { + return await request.delete({ + url: '/admin-api/applet/xunjia/distribution/delete?distributionId=' + id + }) +} +export const getResellDetail = async (id) => { + return await request.get({ + url: '/admin-api/applet/xunjia/distribution/' + id + }) +} diff --git a/src/api/xjapplet/vip.js b/src/api/xjapplet/vip.js new file mode 100644 index 0000000..5581edd --- /dev/null +++ b/src/api/xjapplet/vip.js @@ -0,0 +1,49 @@ +import request from '@/config/axios' + +export const getUserMemberList = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/user/member/list', + params: params + }) +} + +export const giveUserMember = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/user/member/add', + data + }) +} + +export const getVipTypeList = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/member/list', + params: params + }) +} + +export const addVipType = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/member/add', + data + }) +} + +export const updateVipType = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/member/update', + data + }) +} + +export const deleteVipType = async (id) => { + return await request.delete({ + url: '/admin-api/applet/xunjia/member/memberId?id=' + id + }) +} + +export const getVipTypeOptions = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/member/simple-list', + params: params + }) +} diff --git a/src/api/xjapplet/vipdatabase.js b/src/api/xjapplet/vipdatabase.js new file mode 100644 index 0000000..2eca4d0 --- /dev/null +++ b/src/api/xjapplet/vipdatabase.js @@ -0,0 +1,67 @@ +import request from '@/config/axios' + +export const addJx = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/question/jx/add', + data: data + }) +} + +export const getJxQuestionList = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/question/jx/list', + params: params + }) +} + +export const delJxData = async (id) => { + return await request.delete({ + url: `/admin-api/applet/xunjia/question/jx/delete?id=${id}` + }) +} + +export const addMj = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/secret/add', + data: data + }) +} + +export const getMjList = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/secret/list', + params: params + }) +} + +export const delMj = async (secretId) => { + return await request.delete({ + url: `/admin-api/applet/xunjia/secret/delete?secretId=${secretId}` + }) +} + +export const clearMj = async (secretId) => { + return await request.delete({ + url: `/admin-api/applet/xunjia/secret/clear?secretId=${secretId}` + }) +} + +export const getMjQuestionList = async (params) => { + return await request.get({ + url: '/admin-api/applet/xunjia/secret/question/list', + params: params + }) +} + +export const addMjQuestion = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/secret/question/add', + data: data + }) +} + +export const delMjQuestion = async (id) => { + return await request.delete({ + url: `/admin-api/applet/xunjia/secret/question/delete?id=${id}` + }) +} diff --git a/src/api/xjapplet/xjdatabase.js b/src/api/xjapplet/xjdatabase.js new file mode 100644 index 0000000..3cebccf --- /dev/null +++ b/src/api/xjapplet/xjdatabase.js @@ -0,0 +1,48 @@ +import request from '@/config/axios' +export const searchQuestion = async (param) => { + return await request.get({ + url: '/admin-api/applet/xunjia/question/list', + params: param + }) +} + +export const updateQuestion = async (data) => { + return await request.put({ + url: '/admin-api/applet/xunjia/question/update', + data: data + }) +} + +export const addQuestion = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/question/add', + data: data + }) +} + +export const deleteQuestion = async (id) => { + return await request.delete({ + url: '/admin-api/applet/xunjia/question/delete?id=' + id + }) +} + +export const uploadFile = async (data) => { + return await request.post({ + url: '/admin-api/applet/xunjia/question/upload', + data: data + }) +} + +export const getQuestionSort = async (param) => { + return await request.get({ + url: '/admin-api/applet/xunjia/question/sort/list', + params: param + }) +} + +export const getMjList = async (params) => { + return await request.get({ + url: 'http://localhost/tiku-api/tiku/xunjia/secret/list', + params: params + }) +} diff --git a/src/config/axios/service.ts b/src/config/axios/service.ts index 620be60..0a0f094 100644 --- a/src/config/axios/service.ts +++ b/src/config/axios/service.ts @@ -202,7 +202,7 @@ service.interceptors.response.use( '<div>5 分钟搭建本地环境</div>' }) return Promise.reject(new Error(msg)) - } else if (code !== 200) { + } else if (code !== 200 && code !== '0000') { if (msg === '无效的刷新令牌') { // hard coding:忽略这个提示,直接登出 console.log(msg) diff --git a/src/permission.js b/src/permission.js index 991ff06..378929b 100644 --- a/src/permission.js +++ b/src/permission.js @@ -7,7 +7,8 @@ import { usePageLoading } from '@/hooks/web/usePageLoading' import { useDictStoreWithOut } from '@/store/modules/dict' import { useUserStoreWithOut } from '@/store/modules/user' import { usePermissionStoreWithOut } from '@/store/modules/permission' -import { getTenantId, getAppId } from '@/utils/auth' +import { useAppStoreWithOut } from '@/store/modules/app' +import { getTenantId, getAppId, setTenantId, setAppId } from '@/utils/auth' import cache from '@/plugins/cache' const { start, done } = useNProgress() @@ -30,6 +31,13 @@ router.beforeEach(async (to, from, next) => { } else { if (getAccessToken()) { if (to.path === '/login') { + // next({ path: '/' }) + if (to.query?.tenantId && to.query?.appId) { + setApp(to.query.tenantId, to.query.appId) + // setTimeout(() => { + // next({ path: '/' }) + // }, 1500) + } next({ path: '/' }) } else { // 获取所有字典 @@ -72,6 +80,14 @@ router.beforeEach(async (to, from, next) => { } }) +function setApp(tenantId, appId) { + setTenantId(tenantId) + + setAppId(appId) + const appStore = useAppStoreWithOut() + appStore.setAppInfo(appId) +} + router.afterEach((to) => { useTitle(to?.meta?.title) done() // 结束Progress diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 1d5f990..7c246dd 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -60,7 +60,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ }, children: [ { - path: '/index', + path: 'index', component: () => import('@/views/Home/index.vue'), name: 'Home', meta: { diff --git a/src/store/modules/dict.ts b/src/store/modules/dict.ts index 50a7ea3..a4d4d1c 100644 --- a/src/store/modules/dict.ts +++ b/src/store/modules/dict.ts @@ -75,7 +75,7 @@ export const useDictStore = defineStore('dict', { }, async resetDict() { cache.session.delete(CACHE_KEY.DICT_CACHE) - const res = await listSimpleDictData() + const res = (await listSimpleDictData()) || [] // 设置数据 const dictDataMap = new Map<string, any>() res.forEach((dictData: DictDataVO) => { diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 8ceb741..bf91499 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,6 +1,5 @@ import { TokenType } from '@/api/login/types' import { decrypt, encrypt } from '@/utils/jsencrypt' - import cache from '@/plugins/cache' const AccessTokenKey = 'ACCESS_TOKEN' @@ -9,26 +8,34 @@ const RefreshTokenKey = 'REFRESH_TOKEN' // 获取token export const getAccessToken = () => { // 此处与TokenKey相同,此写法解决初始化时Cookies中不存在TokenKey报错 - return cache.local.get(AccessTokenKey) - ? cache.local.get(AccessTokenKey) - : cache.local.get('ACCESS_TOKEN') + return localStorage.getItem(AccessTokenKey) + ? localStorage.getItem(AccessTokenKey) + : localStorage.getItem('ACCESS_TOKEN') + // return cache.local.get(AccessTokenKey) + // ? cache.local.get(AccessTokenKey) + // : cache.local.get('ACCESS_TOKEN') } // 刷新token export const getRefreshToken = () => { - return cache.local.get(RefreshTokenKey) + return localStorage.getItem(RefreshTokenKey) + // return cache.local.get(RefreshTokenKey) } // 设置token export const setToken = (token: TokenType) => { - cache.local.set(RefreshTokenKey, token.refreshToken) - cache.local.set(AccessTokenKey, token.accessToken) + localStorage.setItem(AccessTokenKey, token.accessToken) + localStorage.setItem(RefreshTokenKey, token.refreshToken) + // cache.local.set(RefreshTokenKey, token.refreshToken) + // cache.local.set(AccessTokenKey, token.accessToken) } // 删除token export const removeToken = () => { - cache.local.delete(AccessTokenKey) - cache.local.delete(RefreshTokenKey) + localStorage.removeItem(AccessTokenKey) + localStorage.removeItem(RefreshTokenKey) + // cache.local.delete(AccessTokenKey) + // cache.local.delete(RefreshTokenKey) } /** 格式化token(jwt格式) */ diff --git a/src/views/Customer/AppletUser/index.vue b/src/views/Customer/AppletUser/index.vue new file mode 100644 index 0000000..7a43666 --- /dev/null +++ b/src/views/Customer/AppletUser/index.vue @@ -0,0 +1,118 @@ +<template> + <div> + <el-form :model="searchForm" inline @submit.prevent> + <el-form-item> + <el-input + v-model="searchForm.phone" + placeholder="请输入手机号" + clearable + @keyup.enter="handleQuery" + /> + </el-form-item> + <el-form-item> + <el-select + v-model="searchForm.resellMan" + placeholder="选择分销人" + clearable + filterable + @change="handleQuery" + > + <el-option + v-for="item in resellOptions" + :key="item.distributionId" + :label="item.name" + :value="item.distributionId" + /> + </el-select> + </el-form-item> + <el-form-item> + <el-date-picker + v-model="searchForm.createDate" + type="daterange" + range-separator="-" + start-placeholder="注册日期" + end-placeholder="注册日期" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery">搜索</el-button> + </el-form-item> + </el-form> + + <el-table v-loading="loading" :data="tableList" border stripe> + <el-table-column type="index" width="50" /> + <el-table-column label="手机号码" prop="phone" width="120" /> + <el-table-column label="分销人" prop="distributionName" min-width="120" /> + <el-table-column label="注册日期" prop="registerDate" min-width="120" /> + <el-table-column label="最近登陆日期" prop="lastLoginTime" min-width="120" /> + </el-table> + <Pagination + :total="total" + v-model:page="searchForm.pageNo" + v-model:limit="searchForm.pageSize" + @pagination="getList" + /> + </div> +</template> + +<script name="AppletUser" setup> +// import { removeNullField } from '@/utils' +// import * as CustomerApi from '@/api/customer/customer.js' + +const searchForm = ref({ + resellMan: undefined, + phone: '', + createDate: [], + pageNo: 1, + pageSize: 20 +}) + +const resellOptions = ref([]) + +onMounted(() => { + // CustomerApi.getCustomerExamCarType().then((res) => { + // carTypeOptions.value = res + // }) + handleQuery() +}) + +/** 搜索按钮操作 */ +const handleQuery = () => { + searchForm.value.pageNo = 1 + getList() +} + +const loading = ref(false) +const tableList = ref([]) +const total = ref(0) +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + // const data = await CustomerApi.getCustomerPage(removeNullField(searchForm.value)) + const data = { + list: [ + { + phone: '12345678901', + distributionName: '分销人A', + registerDate: '2023-10-01', + lastLoginTime: '2023-10-02' + }, + { + phone: '12345678902', + distributionName: '分销人B', + registerDate: '2023-10-03', + lastLoginTime: '2023-10-04' + } + ], + total: 2 + } + tableList.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} +</script> + +<style lang="scss" scoped></style> diff --git a/src/views/Customer/ExamRecord/index.vue b/src/views/Customer/ExamRecord/index.vue index a241973..38b20e4 100644 --- a/src/views/Customer/ExamRecord/index.vue +++ b/src/views/Customer/ExamRecord/index.vue @@ -103,7 +103,7 @@ const carTypeOptions = ref([]) const searchForm = ref({ userName: undefined, - carTypeId: 1011, + carTypeId: undefined, pageNo: 1, pageSize: 20 }) diff --git a/src/views/Customer/Resell/index.vue b/src/views/Customer/Resell/index.vue new file mode 100644 index 0000000..ba306b2 --- /dev/null +++ b/src/views/Customer/Resell/index.vue @@ -0,0 +1,194 @@ +<template> + <div> + <el-form :model="searchForm" label-width="0" inline @submit.prevent> + <el-form-item> + <el-input v-model="searchForm.phone" placeholder="请输入手机号" /> + </el-form-item> + <el-form-item> + <el-input v-model="searchForm.name" placeholder="请输入姓名" /> + </el-form-item> + <el-form-item> + <el-button @click="searchList" v-hasPermi="['customer:resell:search']">查询</el-button> + <el-button type="primary" @click="handleAdd" v-hasPermi="['customer:resell:add']"> + 新增 + </el-button> + </el-form-item> + </el-form> + <el-table v-loading="loading" :data="tableData" max-height="calc(100vh - 200px)"> + <el-table-column type="index" width="50" /> + <el-table-column prop="phone" label="手机号" /> + <el-table-column prop="name" label="姓名" /> + <el-table-column prop="mark" label="标记" /> + <el-table-column prop="memberName" label="赠送会员" /> + <el-table-column prop="discountDiscription" label="赠送折扣" /> + <el-table-column label="小程序码" align="center" width="120px"> + <template #default="{ row }"> + <img :src="row.appletUrl" style="width: 80px; height: 80px" /> + </template> + </el-table-column> + <el-table-column label="操作" width="120px"> + <template #default="{ row }"> + <el-button + type="primary" + link + @click="handleEdit(row)" + v-hasPermi="['customer:resell:update']" + > + 修改 + </el-button> + </template> + </el-table-column> + </el-table> + <pagination + v-show="total > 0" + :total="total" + v-model:page="searchForm.pageNo" + v-model:limit="searchForm.pageSize" + @pagination="getList" + /> + + <el-dialog title="分销配置" v-model="showDialog" width="500px"> + <el-form :model="form" ref="formRef" :rules="rules" label-width="80px"> + <el-form-item label="手机号" prop="phone"> + <el-input v-model="form.phone" maxlength="11" /> + </el-form-item> + <el-form-item label="姓名" prop="name"> + <el-input v-model="form.name" /> + </el-form-item> + <el-form-item label="标记" prop="mark"> + <el-input v-model="form.mark" /> + </el-form-item> + <el-form-item label="赠送会员" prop="memberId"> + <el-select v-model="form.memberId" clearable filterable style="width: 100%"> + <el-option + v-for="item in vipOptions" + :key="item.memberId" + :label="item.memberName" + :value="item.memberId" + > + <span style="float: left">{{ item.memberName }}</span> + <span style="float: right; color: #aaa">{{ item.carName }}</span> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="赠送折扣" prop="discountId"> + <el-select v-model="form.discountId" clearable filterable style="width: 100%"> + <el-option + v-for="item in discountOptions" + :key="item.id" + :label="item.description" + :value="item.id" + /> + </el-select> + </el-form-item> + </el-form> + + <template #footer> + <span> + <el-button @click="showDialog = false">取消</el-button> + <el-button type="primary" @click="handleSave">确认</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script setup name="Resell"> +import { getResellList, addResell, updateResell } from '@/api/xjapplet/resell' +import { getVipDiscountOptions } from '@/api/xjapplet/discount' +import { getVipTypeOptions } from '@/api/xjapplet/vip' + +const message = useMessage() + +const searchForm = ref({ + pageNo: 1, + pageSize: 50, + phone: '', + name: '' +}) + +const tableData = ref([]) +const total = ref(0) + +const loading = ref(false) +const showDialog = ref(false) + +const form = ref({ + phone: '', + name: '', + mark: '', + discountId: undefined, + memberId: undefined +}) + +const rules = { + phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }], + name: [{ required: true, message: '请输入姓名', trigger: 'blur' }] +} + +const vipOptions = ref([]) +const discountOptions = ref([]) + +onMounted(() => { + searchList() + getVipDiscountOptions().then((response) => { + discountOptions.value = response + }) + getVipTypeOptions({ carTypeId: searchForm.value.carTypeId }).then((response) => { + vipOptions.value = response + }) +}) + +function searchList() { + searchForm.value.pageNo = 1 + getList() +} + +function getList() { + loading.value = true + getResellList(searchForm.value).then((response) => { + tableData.value = response.list + total.value = response.total + loading.value = false + }) +} + +function handleAdd() { + showDialog.value = true + form.value = { + phone: '', + name: '', + mark: '', + discountId: undefined, + memberId: undefined + } +} +function handleEdit(row) { + form.value = { ...row } + showDialog.value = true +} + +const formRef = ref(null) +async function handleSave() { + if (!formRef.value) return + const valid = await formRef.value.validate() + if (!valid) return + + // 调用接口 + if (form.value.distributionId) { + updateResell(form.value).then(() => { + message.success('修改成功') + showDialog.value = false + searchList() + }) + } else { + addResell(form.value).then(() => { + message.success('新增成功') + showDialog.value = false + searchList() + }) + } +} +</script> + +<style lang="scss" scoped></style> diff --git a/src/views/Customer/Vip/components/Recharge.vue b/src/views/Customer/Vip/components/Recharge.vue new file mode 100644 index 0000000..ad4f2ab --- /dev/null +++ b/src/views/Customer/Vip/components/Recharge.vue @@ -0,0 +1,157 @@ +<template> + <div> + <el-form :model="searchForm" inline @submit.prevent> + <el-form-item> + <el-input v-model="searchForm.phone" placeholder="学员手机号" /> + </el-form-item> + <el-form-item> + <el-select v-model="searchForm.memberId" placeholder="选择分销人" clearable filterable> + <el-option + v-for="item in vipOptions" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> + <el-form-item> + <el-date-picker + v-model="searchForm.createDate" + type="daterange" + range-separator="-" + start-placeholder="充值日期" + end-placeholder="充值日期" + /> + </el-form-item> + <el-form-item> + <el-button @click="searchList">查询</el-button> + </el-form-item> + </el-form> + <el-table v-loading="loading" :data="tableList" height="calc(100vh - 260px)"> + <el-table-column type="index" width="55" align="center" /> + <el-table-column label="手机号" align="left" prop="phone" width="140" /> + <el-table-column label="会员名" align="left" prop="memberName" min-width="140" /> + <el-table-column label="支付金额" align="left" prop="operUser" min-width="100" /> + <el-table-column label="车型" align="left" width="100"> + <template #default="{ row }"> + {{ row.carTypeId == 1001 ? '小车' : '摩托车' }} + </template> + </el-table-column> + <el-table-column label="科目" align="left" prop="subjects" width="100" /> + <el-table-column label="充值日期" align="left" prop="startDate" min-width="120" /> + <el-table-column label="截止日期" align="left" prop="endDate" min-width="120" /> + <el-table-column label="分销人" align="left" prop="useTypeName" min-width="100" /> + </el-table> + <pagination + v-show="total > 0" + :total="total" + v-model:page="searchForm.pageNo" + v-model:limit="searchForm.pageSize" + @pagination="getList" + /> + + <el-dialog title="赠送会员" v-model="showDialog" width="500px" :close-on-click-modal="false"> + <el-form :model="form" ref="formRef" :rules="rules" label-width="80px"> + <el-form-item label="手机号" prop="phone"> + <el-input v-model="form.phone" maxlength="11" /> + </el-form-item> + <el-form-item label="会员类型" prop="memberId"> + <el-select v-model="form.memberId" clearable filterable style="width: 100%"> + <el-option + v-for="item in vipOptions" + :key="item.memberId" + :label="item.memberName" + :value="item.memberId" + > + <span style="float: left">{{ item.memberName }}</span> + <span style="float: right; color: #aaa">{{ item.carName }}</span> + </el-option> + </el-select> + </el-form-item> + </el-form> + + <template #footer> + <span> + <el-button @click="showDialog = false">取消</el-button> + <el-button type="primary" @click="sureAdd">确定</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script setup name="Recharge"> +import { getUserMemberList, giveUserMember, getVipTypeOptions } from '@/api/xjapplet/vip' +const message = useMessage() +const searchForm = ref({ + carTypeId: '1001', + memberId: undefined, + phone: undefined, + pageNo: 1, + pageSize: 50 +}) + +const loading = ref(false) +const tableList = ref([]) +const total = ref(0) + +const vipOptions = ref([]) + +onMounted(() => { + changeCarType() +}) + +function changeCarType() { + getVipTypeOptions({ carTypeId: searchForm.value.carTypeId }).then((response) => { + vipOptions.value = response + }) + searchList() +} + +function searchList() { + searchForm.value.pageNo = 1 + getList() +} + +function getList() { + loading.value = true + getUserMemberList(searchForm.value).then((response) => { + tableList.value = response.list + total.value = response.total + loading.value = false + }) +} + +const showDialog = ref(false) +const form = ref({ + phone: '', + memberId: '' +}) +const rules = ref({ + phone: [{ required: true, message: '请输入用户手机号', trigger: 'blur' }], + memberId: [{ required: true, message: '请选择会员类型', trigger: 'change' }] +}) + +function addVipUser() { + showDialog.value = true +} + +const formRef = ref(null) +async function sureAdd() { + if (!formRef.value) return + const valid = await formRef.value.validate() + if (!valid) return + + giveUserMember(form.value).then((response) => { + if (response) { + message.success('赠送成功') + showDialog.value = false + searchList() + } else { + message.error('赠送失败') + } + }) +} +</script> + +<style lang="scss" scoped></style> diff --git a/src/views/Customer/Vip/components/UserDiscount.vue b/src/views/Customer/Vip/components/UserDiscount.vue new file mode 100644 index 0000000..bee8940 --- /dev/null +++ b/src/views/Customer/Vip/components/UserDiscount.vue @@ -0,0 +1,144 @@ +<template> + <div> + <el-form :model="searchForm" inline @submit.prevent> + <el-form-item> + <el-input v-model="searchForm.phone" placeholder="学员手机号" /> + </el-form-item> + <el-form-item> + <el-button @click="searchList" v-hasPermi="['xj-applet:vip:user-discount:search']" + >查询</el-button + > + <el-button + type="primary" + @click="addVipUser" + v-hasPermi="['xj-applet:vip:user-discount:send']" + >赠送折扣</el-button + > + </el-form-item> + </el-form> + <el-table v-loading="loading" :data="tableList"> + <el-table-column type="index" width="55" align="center" /> + <el-table-column label="手机号" align="left" prop="phone" width="140" /> + <el-table-column label="折扣描述" align="left" prop="description" min-width="140" /> + <el-table-column label="折后价格" align="center" prop="discount" width="100" /> + <el-table-column + label="截止时间" + align="left" + prop="endTime" + :formatter="dateFormatter" + width="150" + /> + <el-table-column label="操作人" align="left" prop="operUser" width="100" /> + <el-table-column label="操作时间" align="left" prop="operTime" width="150" /> + </el-table> + <pagination + v-show="total > 0" + :total="total" + v-model:page="searchForm.pageNo" + v-model:limit="searchForm.pageSize" + @pagination="getList" + /> + + <el-dialog title="赠送折扣" v-model="showDialog" width="500px" :close-on-click-modal="false"> + <el-form :model="form" ref="formRef" :rules="rules" label-width="80px"> + <el-form-item label="手机号" prop="phone"> + <el-input v-model="form.phone" maxlength="11" /> + </el-form-item> + <el-form-item label="折扣描述" prop="discountId"> + <el-select v-model="form.discountId" clearable filterable style="width: 100%"> + <el-option + v-for="item in discountOptions" + :key="item.id" + :label="item.description" + :value="item.id" + /> + </el-select> + </el-form-item> + </el-form> + + <template #footer> + <span> + <el-button @click="showDialog = false">取消</el-button> + <el-button type="primary" @click="sureAdd">确定</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script setup name="UserDiscount"> +import { + getUserDiscountList, + giveUserDiscount, + getVipDiscountOptions +} from '@/api/xjapplet/discount' +import { dateFormatter } from '@/utils/formatTime' + +const message = useMessage() + +const searchForm = ref({ + phone: '', + pageNo: 1, + pageSize: 50 +}) + +const loading = ref(false) +const tableList = ref([]) +const total = ref(0) + +const discountOptions = ref([]) + +onMounted(() => { + searchList() + getVipDiscountOptions().then((response) => { + discountOptions.value = response + }) +}) +function searchList() { + searchForm.value.pageNo = 1 + getList() +} + +function getList() { + loading.value = true + getUserDiscountList(searchForm.value).then((response) => { + tableList.value = response.list + total.value = response.total + loading.value = false + }) +} + +const showDialog = ref(false) +const form = ref({ + phone: '', + discountId: '' +}) +const rules = ref({ + phone: [{ required: true, message: '请输入用户手机号', trigger: 'blur' }], + discountId: [{ required: true, message: '请选择会员类型', trigger: 'change' }] +}) + +function addVipUser() { + showDialog.value = true +} + +const formRef = ref(null) +async function sureAdd() { + if (!formRef.value) return + const valid = await formRef.value.validate() + if (!valid) return + + // 调用接口 + giveUserDiscount(form.value).then((response) => { + if (response) { + message.success('赠送成功') + showDialog.value = false + searchList() + } else { + message.error('赠送失败') + } + }) +} +</script> + +<style lang="scss" scoped></style> diff --git a/src/views/Customer/Vip/components/VipDiscount.vue b/src/views/Customer/Vip/components/VipDiscount.vue new file mode 100644 index 0000000..875e731 --- /dev/null +++ b/src/views/Customer/Vip/components/VipDiscount.vue @@ -0,0 +1,286 @@ +<template> + <div> + <el-row> + <el-button @click="searchList" v-hasPermi="['xj-applet:vip:vip-discount:search']" + >查询</el-button + > + <el-button type="primary" @click="addDiscount" v-hasPermi="['xj-applet:vip:vip-discount:add']" + >新增折扣</el-button + > + </el-row> + + <el-table v-loading="loading" :data="tableList"> + <el-table-column type="index" width="55" align="center" /> + <el-table-column label="折扣描述" align="center" prop="description" min-width="140" /> + <el-table-column label="折扣价" align="center" prop="discount" /> + <el-table-column label="有效期" align="center" prop="duration" /> + <el-table-column label="单位" align="center"> + <template #default="{ row }"> + <el-tag v-if="row.unit == 1">天</el-tag> + <el-tag v-else type="danger">年</el-tag> + </template> + </el-table-column> + <el-table-column label="操作" align="center"> + <template #default="{ row }"> + <el-button + type="primary" + link + @click="editDiscount(row)" + v-hasPermi="['xj-applet:vip:vip-discount:update']" + >修改</el-button + > + <el-button + type="primary" + link + @click="deleteDiscount(row)" + v-hasPermi="['xj-applet:vip:vip-discount:delete']" + >删除</el-button + > + </template> + </el-table-column> + </el-table> + <pagination + v-show="total > 0" + :total="total" + v-model:page="searchForm.pageNo" + v-model:limit="searchForm.pageSize" + @pagination="getList" + /> + + <el-dialog title="折扣详情" v-model="showDialog" width="500px" :close-on-click-modal="false"> + <el-form :model="form" ref="formRef" :rules="rules" label-width="80px"> + <el-form-item label="折扣类型" prop="discountType"> + <el-select v-model="form.discountType" style="width: 100%" :disabled="!!form.id"> + <el-option + v-for="item in discountTypeOptions" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> + <el-form-item label="折扣描述"> + {{ discountDesc }} + </el-form-item> + <el-form-item v-if="form.discountType == 1" label="科目" prop="subject"> + <el-select v-model="form.subject" style="width: 100%" :disabled="!!form.id"> + <el-option + v-for="item in subjectOptions" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> + <el-form-item label="变量1" prop="param1"> + <el-select v-model="form.param1" style="width: 100%" clearable :disabled="!!form.id"> + <el-option + v-for="item in vipTypeOptions" + :key="item.memberId" + :label="item.memberName" + :value="item.memberId" + > + <span style="float: left">{{ item.memberName }}</span> + <span style="float: right; color: #aaa">{{ item.carName }}</span> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="变量2" prop="param2"> + <el-select v-model="form.param2" style="width: 100%" :disabled="!!form.id"> + <el-option + v-for="item in vipTypeOptions" + :key="item.memberId" + :label="item.memberName" + :value="item.memberId" + > + <span style="float: left">{{ item.memberName }}</span> + <span style="float: right; color: #aaa">{{ item.carName }}</span> + </el-option> + </el-select> + </el-form-item> + <el-form-item label="折扣价" prop="discount"> + <el-input v-model="form.discount" type="number" /> + </el-form-item> + <el-form-item label="有效期" prop="duration"> + <el-input v-model="form.duration" type="number" /> + </el-form-item> + <el-form-item label="单位" prop="unit"> + <el-radio-group v-model="form.unit"> + <el-radio v-for="(item, index) in unitOptions" :key="index" :label="item.value">{{ + item.label + }}</el-radio> + </el-radio-group> + </el-form-item> + </el-form> + + <template #footer> + <span> + <el-button @click="showDialog = false">取消</el-button> + <el-button type="primary" @click="sureAdd">确定</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script setup name="VipDiscount"> +import { + getVipDiscountList, + addVipDiscount, + updateVipDiscount, + deleteVipDiscount +} from '@/api/xjapplet/discount' + +import { getVipTypeOptions } from '@/api/xjapplet/vip' + +const message = useMessage() + +const searchForm = ref({ + pageNo: 1, + pageSize: 50 +}) + +onMounted(() => { + searchList() + + getVipTypeOptions().then((response) => { + vipTypeOptions.value = response + }) +}) + +const loading = ref(false) +const tableList = ref([]) +const total = ref(0) + +const discountTypeOptions = [ + { + label: '【$科目】模考首次通过后,在拥有【$会员名1】的情况下,购买【$会员名2】,享折扣价', + value: '1' + }, + { label: '之前拥有过【$会员名1】,购买【$会员名2】,享折扣价', value: '2' } +] + +const subjectOptions = [ + { label: '科一', value: '1' }, + { label: '科四', value: '4' } +] + +const unitOptions = [ + { label: '天', value: '1' }, + { label: '年', value: '3' } +] + +const discountDesc = computed(() => { + const vipTypeObj = {} + vipTypeOptions.value.forEach((item) => { + vipTypeObj[item.memberId] = `${item.memberName}(${item.carName})` + }) + const { discountType, subject, param1, param2, discount, duration, unit } = form.value + let baseStr = discountTypeOptions.find((item) => item.value == discountType).label + const vip1 = param1 ? vipTypeObj[param1] : '无需会员' + const vip2 = param2 ? vipTypeObj[param2] : '会员名2' + return baseStr + .replace('$科目', subjectOptions.find((item) => item.value == subject).label) + .replace('$会员名1', vip1) + .replace('$会员名2', vip2) + .concat( + `${discount || ''},有效期${duration || 0}${ + unitOptions.find((item) => item.value == unit).label + }` + ) +}) + +onMounted(() => { + searchList() +}) + +const vipTypeOptions = ref([]) +function searchList() { + searchForm.value.pageNo = 1 + getList() +} + +function getList() { + loading.value = true + getVipDiscountList(searchForm.value).then((response) => { + tableList.value = response.list + total.value = response.total + loading.value = false + }) +} + +const showDialog = ref(false) +const form = ref({ + discountType: '1', + subject: '1', + param1: undefined, + param2: undefined, + discount: undefined, + duration: undefined, + unit: '1', + description: undefined +}) +const rules = ref({ + param2: [{ required: true, message: '请选择变量2', trigger: 'change' }], + discount: [{ required: true, message: '请输入折扣价', trigger: 'blur' }], + duration: [{ required: true, message: '请输入有效期', trigger: 'blur' }] +}) + +function addDiscount() { + showDialog.value = true + form.value = { + discountType: '1', + subject: '1', + param1: undefined, + param2: undefined, + discount: undefined, + duration: undefined, + unit: '1', + description: undefined + } +} + +function editDiscount(row) { + form.value = { + ...row, + param1: row.param1 ? Number(row.param1) : undefined, + param2: row.param2 ? Number(row.param2) : undefined + } + showDialog.value = true +} + +function deleteDiscount(row) { + message.confirm('确定删除该折扣?').then(() => { + deleteVipDiscount(row.id).then(() => { + message.success('删除成功') + searchList() + }) + }) +} + +const formRef = ref(null) +async function sureAdd() { + if (!formRef.value) return + const valid = await formRef.value.validate() + if (!valid) return + + form.value.description = discountDesc.value + + // 调用接口 + if (form.value.id) { + updateVipDiscount(form.value).then(() => { + showDialog.value = false + message.success('修改成功') + searchList() + }) + } else { + addVipDiscount(form.value).then(() => { + showDialog.value = false + message.success('新增成功') + searchList() + }) + } +} +</script> + +<style lang="scss" scoped></style> diff --git a/src/views/Customer/Vip/components/VipType.vue b/src/views/Customer/Vip/components/VipType.vue new file mode 100644 index 0000000..beb17b2 --- /dev/null +++ b/src/views/Customer/Vip/components/VipType.vue @@ -0,0 +1,213 @@ +<template> + <div> + <el-form :model="searchForm" inline @submit.prevent> + <el-form-item> + <el-input v-model="searchForm.memberName" placeholder="会员名称" /> + </el-form-item> + <el-form-item> + <el-radio-group v-model="searchForm.carTypeId" @change="searchList"> + <el-radio label="1001">小车</el-radio> + <el-radio label="1002">摩托车</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item> + <el-button @click="searchList">查询</el-button> + <el-button type="primary" @click="addVip">新增会员类型</el-button> + </el-form-item> + </el-form> + <el-table v-loading="loading" :data="tableList" height="calc(100vh - 260px)"> + <el-table-column type="index" width="55" align="center" /> + <el-table-column label="会员名" align="center" prop="memberName" min-width="140" /> + <el-table-column label="车型" align="center" prop="carName" /> + <el-table-column label="科目" align="center" prop="subjects" /> + <el-table-column label="原价" align="center" prop="price" /> + <el-table-column label="折扣价" align="center" prop="discount" /> + <el-table-column label="有效期" align="center" prop="duration" /> + <el-table-column label="单位" align="center"> + <template #default="{ row }"> + <el-tag v-if="row.unit == 1">天</el-tag> + <el-tag v-else type="danger">年</el-tag> + </template> + </el-table-column> + <el-table-column label="使用方式" align="center" prop="useTypeName" /> + <el-table-column label="操作" width="160"> + <template #default="{ row }"> + <el-button + type="primary" + link + @click="editVip(row)" + v-hasPermi="['xj-applet:vip:vip-type:update']" + >修改</el-button + > + <el-button + type="primary" + link + @click="handleDelete(row.memberId)" + v-hasPermi="['xj-applet:vip:vip-type:delete']" + >删除</el-button + > + </template> + </el-table-column> + </el-table> + <pagination + v-show="total > 0" + :total="total" + v-model:page="searchForm.pageNo" + v-model:limit="searchForm.pageSize" + @pagination="getList" + /> + + <el-dialog title="会员详情" v-model="showDialog" width="500px" :close-on-click-modal="false"> + <el-form :model="form" ref="formRef" :rules="rules" label-width="80px"> + <el-form-item label="会员名称" prop="memberName"> + <el-input v-model="form.memberName" /> + </el-form-item> + <el-form-item label="车型" prop="carTypeId"> + <el-select v-model="form.carTypeId" style="width: 100%"> + <el-option label="小车" value="1001" /> + <el-option label="摩托车" value="1002" /> + </el-select> + </el-form-item> + <el-form-item label="科目" prop="subjects"> + <el-select v-model="form.subjects" placeholder="多选" multiple style="width: 100%"> + <el-option label="科一" value="4" /> + <el-option label="科四" value="1" /> + </el-select> + </el-form-item> + <el-form-item label="原价" prop="price"> + <el-input v-model="form.price" type="number" /> + </el-form-item> + <el-form-item label="折扣价" prop="discount"> + <el-input v-model="form.discount" type="number" /> + </el-form-item> + <el-form-item label="有效期" prop="duration"> + <el-input v-model="form.duration" type="number" /> + </el-form-item> + <el-form-item label="单位" prop="unit"> + <el-radio-group v-model="form.unit"> + <el-radio :label="1">天</el-radio> + <el-radio :label="3">年</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="使用方式" prop="useTypes"> + <el-checkbox-group v-model="form.useTypes"> + <el-checkbox :label="1"> 用户购买 </el-checkbox> + <el-checkbox :label="2"> 客服赠送 </el-checkbox> + </el-checkbox-group> + </el-form-item> + </el-form> + + <template #footer> + <span> + <el-button @click="showDialog = false">取消</el-button> + <el-button type="primary" @click="sureAdd">确定</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script setup name="VipType"> +import { getVipTypeList, addVipType, updateVipType, deleteVipType } from '@/api/xjapplet/vip' +const message = useMessage() +const searchForm = ref({ + memberName: undefined, + carTypeId: '1001', + pageNo: 1, + pageSize: 50 +}) + +const loading = ref(false) +const tableList = ref([]) +const total = ref(0) + +onMounted(() => { + searchList() +}) +function searchList() { + searchForm.value.pageNo = 1 + getList() +} + +function getList() { + loading.value = true + getVipTypeList(searchForm.value).then((response) => { + tableList.value = response.list + total.value = response.total + loading.value = false + }) +} + +const showDialog = ref(false) +const form = ref({ + memberName: '', + carTypeId: undefined, + subjects: [], + price: '', + discount: '', + duration: '', + unit: 1, + useTypes: [1] +}) +const rules = ref({ + memberName: [{ required: true, message: '请输入会员名称', trigger: 'blur' }], + carTypeId: [{ required: true, message: '请输入车型', trigger: 'change' }], + subjects: [{ required: true, message: '请输入科目', trigger: 'blur' }], + price: [{ required: true, message: '请输入价格', trigger: 'blur' }], + discount: [{ required: true, message: '请输入折扣价', trigger: 'blur' }], + duration: [{ required: true, message: '请输入有效期', trigger: 'blur' }] +}) + +function addVip() { + showDialog.value = true + + form.value.carTypeId = { + memberName: '', + carTypeId: searchForm.value.carTypeId, + subjects: [], + price: '', + discount: '', + duration: '', + unit: 1, + useTypes: [1] + } +} + +function editVip(row) { + form.value = { ...row, subjects: row.subjects.split(','), unit: Number(row.unit) } + showDialog.value = true +} + +const formRef = ref(null) +async function sureAdd() { + if (!formRef.value) return + const valid = await formRef.value.validate() + if (!valid) return + + // 调用接口 + if (form.value.memberId) { + updateVipType(form.value).then(() => { + message.success('修改成功') + showDialog.value = false + searchList() + }) + } else { + addVipType(form.value).then(() => { + message.success('添加成功') + showDialog.value = false + searchList() + }) + } +} + +function handleDelete(id) { + message.confirm('是否确认删除该会员?').then(() => { + deleteVipType(id).then(() => { + message.success('删除成功') + searchList() + }) + }) +} +</script> + +<style lang="scss" scoped></style> diff --git a/src/views/Customer/Vip/components/VipUser.vue b/src/views/Customer/Vip/components/VipUser.vue new file mode 100644 index 0000000..fe5401f --- /dev/null +++ b/src/views/Customer/Vip/components/VipUser.vue @@ -0,0 +1,155 @@ +<template> + <div> + <el-form :model="searchForm" inline @submit.prevent> + <el-form-item> + <el-input v-model="searchForm.phone" placeholder="学员手机号" /> + </el-form-item> + <el-form-item> + <el-radio-group v-model="searchForm.carTypeId" @change="changeCarType"> + <el-radio label="1001">小车</el-radio> + <el-radio label="1002">摩托车</el-radio> + </el-radio-group> + </el-form-item> + <!-- <el-form-item> + <el-select v-model="searchForm.memberId" placeholder="选择会员类型" clearable filterable> + <el-option + v-for="item in vipOptions" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + </el-form-item> --> + <el-form-item> + <el-button @click="searchList">查询</el-button> + <el-button type="primary" @click="addVipUser">赠送会员</el-button> + </el-form-item> + </el-form> + <el-table v-loading="loading" :data="tableList" height="calc(100vh - 260px)"> + <el-table-column type="index" width="55" align="center" /> + <el-table-column label="手机号" align="left" prop="phone" min-width="140" /> + <el-table-column label="会员名" align="left" prop="memberName" min-width="140" /> + <el-table-column label="车型" align="left" min-width="100"> + <template #default="{ row }"> + {{ row.carTypeId == 1001 ? '小车' : '摩托车' }} + </template> + </el-table-column> + <el-table-column label="科目" align="left" prop="subjects" min-width="100" /> + <el-table-column label="来源" align="left" prop="useTypeName" min-width="100" /> + <el-table-column label="截止日期" align="left" prop="endDate" min-width="120" /> + <el-table-column label="操作人" align="left" prop="operUser" min-width="100" /> + <el-table-column label="操作时间" align="left" prop="createTime" min-width="120" /> + </el-table> + <pagination + v-show="total > 0" + :total="total" + v-model:page="searchForm.pageNo" + v-model:limit="searchForm.pageSize" + @pagination="getList" + /> + + <el-dialog title="赠送会员" v-model="showDialog" width="500px" :close-on-click-modal="false"> + <el-form :model="form" ref="formRef" :rules="rules" label-width="80px"> + <el-form-item label="手机号" prop="phone"> + <el-input v-model="form.phone" maxlength="11" /> + </el-form-item> + <el-form-item label="会员类型" prop="memberId"> + <el-select v-model="form.memberId" clearable filterable style="width: 100%"> + <el-option + v-for="item in vipOptions" + :key="item.memberId" + :label="item.memberName" + :value="item.memberId" + > + <span style="float: left">{{ item.memberName }}</span> + <span style="float: right; color: #aaa">{{ item.carName }}</span> + </el-option> + </el-select> + </el-form-item> + </el-form> + + <template #footer> + <span> + <el-button @click="showDialog = false">取消</el-button> + <el-button type="primary" @click="sureAdd">确定</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script setup name="VipUser"> +import { getUserMemberList, giveUserMember, getVipTypeOptions } from '@/api/xjapplet/vip' +const message = useMessage() +const searchForm = ref({ + carTypeId: '1001', + memberId: undefined, + phone: undefined, + pageNo: 1, + pageSize: 50 +}) + +const loading = ref(false) +const tableList = ref([]) +const total = ref(0) + +const vipOptions = ref([]) + +onMounted(() => { + changeCarType() +}) + +function changeCarType() { + getVipTypeOptions({ carTypeId: searchForm.value.carTypeId }).then((response) => { + vipOptions.value = response + }) + searchList() +} + +function searchList() { + searchForm.value.pageNo = 1 + getList() +} + +function getList() { + loading.value = true + getUserMemberList(searchForm.value).then((response) => { + tableList.value = response.list + total.value = response.total + loading.value = false + }) +} + +const showDialog = ref(false) +const form = ref({ + phone: '', + memberId: '' +}) +const rules = ref({ + phone: [{ required: true, message: '请输入用户手机号', trigger: 'blur' }], + memberId: [{ required: true, message: '请选择会员类型', trigger: 'change' }] +}) + +function addVipUser() { + showDialog.value = true +} + +const formRef = ref(null) +async function sureAdd() { + if (!formRef.value) return + const valid = await formRef.value.validate() + if (!valid) return + + giveUserMember(form.value).then((response) => { + if (response) { + message.success('赠送成功') + showDialog.value = false + searchList() + } else { + message.error('赠送失败') + } + }) +} +</script> + +<style lang="scss" scoped></style> diff --git a/src/views/Customer/Vip/index.vue b/src/views/Customer/Vip/index.vue new file mode 100644 index 0000000..3eef263 --- /dev/null +++ b/src/views/Customer/Vip/index.vue @@ -0,0 +1,42 @@ +<template> + <div> + <el-tabs v-model="tabIndex"> + <el-tab-pane label="会员用户" :name="1" v-if="checkPermi(['customer:applet:vip:vip-user'])"> + <VipUser v-if="tabIndex == 1" /> + </el-tab-pane> + <el-tab-pane label="会员类型" :name="2" v-if="checkPermi(['customer:applet:vip:vip-type'])"> + <VipType v-if="tabIndex == 2" /> + </el-tab-pane> + <!-- <el-tab-pane + label="会员折扣" + :name="3" + v-if="checkPermi(['customer-applet:vip:vip-discount'])" + > + <VipDiscount v-if="tabIndex == 3" /> + </el-tab-pane> + <el-tab-pane + label="用户折扣" + :name="4" + v-if="checkPermi(['customer-applet:vip:user-discount'])" + > + <UserDiscount v-if="tabIndex == 4" /> + </el-tab-pane> --> + <el-tab-pane label="充值记录" :name="5" v-if="checkPermi(['customer:applet:vip:recharge'])"> + <Recharge v-if="tabIndex == 5" /> + </el-tab-pane> + </el-tabs> + </div> +</template> + +<script setup name="Vip"> +import { checkPermi } from '@/utils/permission' +// import UserDiscount from './components/UserDiscount.vue' +// import VipDiscount from './components/VipDiscount.vue' +import VipType from './components/VipType.vue' +import VipUser from './components/VipUser.vue' +import Recharge from './components/Recharge.vue' + +const tabIndex = ref(1) +</script> + +<style lang="scss" scoped></style>