456 lines
14 KiB
Vue
456 lines
14 KiB
Vue
<template>
|
|
<div >
|
|
<div class="searchForm">
|
|
<searchForm
|
|
:search="USER_SEARCH_CONFIG"
|
|
@searchData="searchData"
|
|
@resetData="resetData"
|
|
class="search-box searchForm"
|
|
/>
|
|
</div>
|
|
<div class="gva-table-box">
|
|
<div class="gva-btn-list">
|
|
<el-button type="primary" @click="handleAdd">新增用户</el-button>
|
|
</div>
|
|
<Content
|
|
@changePage="changePage"
|
|
:total="total"
|
|
v-model:tabloading="tableLoading"
|
|
v-model:currentPage="queryParams.page"
|
|
v-model:pageSize="queryParams.pageSize"
|
|
:data="tableData"
|
|
:config="USER_TABLE_CONFIG"
|
|
>
|
|
<template #avatar="{ row }">
|
|
<el-image
|
|
style="width: 100px; height: 100px"
|
|
: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 #status="{ row }">
|
|
<el-switch v-model="row.status"
|
|
:active-value="1"
|
|
:inactive-value="0"
|
|
:loading="row.loading"
|
|
:before-change="() => statusChangeBefore(row)" />
|
|
|
|
</template>
|
|
<template #CreatedAt="{ row }">
|
|
{{ formatDate(row.CreatedAt) }}
|
|
</template>
|
|
|
|
<!--user_type 1: 普通用户 2: 讲师-->
|
|
<template #user_type="{ row }">
|
|
{{ row.user_type === 1 ? '普通用户' : '讲师' }}
|
|
</template>
|
|
|
|
<!--user_label 1: 普通用户 2: VIP 3:SVIP-->
|
|
<template #user_label="{ row }">
|
|
{{ row.user_label === 1 ? '注册会员' : row.user_label === 2 ? 'VIP' : 'SVIP' }}
|
|
</template>
|
|
|
|
<!--balance 账户余额-->
|
|
<template #balance="{ row }">
|
|
{{ row.balance }}
|
|
</template>
|
|
|
|
<template #operate="{ row }">
|
|
<el-button type="text" @click="handleDetail(row)">详情</el-button>
|
|
<el-button type="text" @click="handleBalance(row)">修改余额</el-button>
|
|
<el-button type="text" @click="handleVip(row)">设置VIP</el-button>
|
|
</template>
|
|
</Content>
|
|
|
|
</div>
|
|
|
|
<!-- 修改余额弹窗 -->
|
|
<el-dialog
|
|
v-model="balanceDialogVisible"
|
|
title="修改余额"
|
|
width="400px"
|
|
:before-close="handleBalanceClose"
|
|
>
|
|
<el-form
|
|
ref="balanceFormRef"
|
|
:model="balanceForm"
|
|
:rules="balanceRules"
|
|
label-width="100px"
|
|
>
|
|
<el-form-item label="当前余额">
|
|
<span>{{ currentUser.balance }}</span>
|
|
</el-form-item>
|
|
<el-form-item label="新余额" prop="balance">
|
|
<el-input-number
|
|
v-model="balanceForm.balance"
|
|
:precision="2"
|
|
:step="0.01"
|
|
:min="0"
|
|
placeholder="请输入新余额"
|
|
/>
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<el-button @click="handleBalanceClose">取消</el-button>
|
|
<el-button type="primary" @click="submitBalance">确定</el-button>
|
|
</span>
|
|
</template>
|
|
</el-dialog>
|
|
|
|
<!-- 设置VIP弹窗 -->
|
|
<el-dialog
|
|
v-model="vipDialogVisible"
|
|
title="设置VIP"
|
|
width="400px"
|
|
:before-close="handleVipClose"
|
|
>
|
|
<el-form
|
|
ref="vipFormRef"
|
|
:model="vipForm"
|
|
:rules="vipRules"
|
|
label-width="100px"
|
|
>
|
|
<el-form-item label="当前标签">
|
|
<span>{{ currentUser.user_label === 1 ? '注册会员' : currentUser.user_label === 2 ? 'VIP' : 'SVIP' }}</span>
|
|
</el-form-item>
|
|
<el-form-item label="VIP类型" prop="user_label">
|
|
<el-select v-model="vipForm.user_label" placeholder="请选择VIP类型">
|
|
<el-option label="注册会员" :value="1" />
|
|
<el-option label="VIP" :value="2" />
|
|
<el-option label="SVIP" :value="3" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="到期时间" prop="vip_expire_time">
|
|
<el-date-picker
|
|
v-model="vipForm.vip_expire_time"
|
|
type="date"
|
|
placeholder="请选择到期时间"
|
|
format="YYYY-MM-DD"
|
|
value-format="YYYY-MM-DD"
|
|
style="width: 100%"
|
|
/>
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<el-button @click="handleVipClose">取消</el-button>
|
|
<el-button type="primary" @click="submitVip">确定</el-button>
|
|
</span>
|
|
</template>
|
|
</el-dialog>
|
|
|
|
<!-- 用户详情弹窗 -->
|
|
<el-dialog
|
|
v-model="dialogVisible"
|
|
title="用户详情"
|
|
width="50%"
|
|
:before-close="handleClose"
|
|
>
|
|
<el-descriptions :column="2" border>
|
|
<el-descriptions-item label="用户头像">
|
|
<el-image
|
|
style="width: 100px; height: 100px"
|
|
:src="userDetail.avatar"
|
|
:preview-src-list="[userDetail.avatar]"
|
|
fit="cover"
|
|
/>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="用户ID">{{ userDetail.ID }}</el-descriptions-item>
|
|
<el-descriptions-item label="用户名">{{ userDetail.nick_name }}</el-descriptions-item>
|
|
<el-descriptions-item label="用户类型">
|
|
{{ userDetail.user_type === 1 ? '普通用户' : '讲师' }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="用户标签">
|
|
{{ userDetail.user_label === 1 ? '注册会员' : userDetail.user_label === 2 ? 'VIP' : 'SVIP' }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="账户余额">{{ userDetail.balance }}</el-descriptions-item>
|
|
<el-descriptions-item label="状态">
|
|
{{ userDetail.status === 1 ? '启用' : '禁用' }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="创建时间">{{ formatDate(userDetail.CreatedAt) }}</el-descriptions-item>
|
|
<el-descriptions-item label="手机号">{{ userDetail.phone }}</el-descriptions-item>
|
|
<el-descriptions-item label="VIP到期时间">{{ userDetail.vip_expire_time }}</el-descriptions-item>
|
|
</el-descriptions>
|
|
</el-dialog>
|
|
|
|
<!-- 新增用户弹窗 -->
|
|
<el-dialog
|
|
v-model="addDialogVisible"
|
|
title="新增用户"
|
|
width="500px"
|
|
:before-close="handleAddClose"
|
|
>
|
|
<el-form
|
|
ref="addFormRef"
|
|
:model="addForm"
|
|
:rules="addRules"
|
|
label-width="100px"
|
|
>
|
|
<el-form-item label="手机号" prop="phone">
|
|
<el-input v-model="addForm.phone" placeholder="请输入手机号" />
|
|
</el-form-item>
|
|
<el-form-item label="密码" prop="password">
|
|
<el-input v-model="addForm.password" type="password" placeholder="请输入密码" />
|
|
</el-form-item>
|
|
<el-form-item label="用户类型" prop="user_type">
|
|
<el-select v-model="addForm.user_type" placeholder="请选择用户类型">
|
|
<el-option label="普通用户" :value="1" />
|
|
<el-option label="讲师" :value="2" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="用户标签" prop="user_label">
|
|
<el-select v-model="addForm.user_label" placeholder="请选择用户标签">
|
|
<el-option label="注册会员" :value="1" />
|
|
<el-option label="VIP" :value="2" />
|
|
<el-option label="SVIP" :value="3" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="昵称" prop="nick_name">
|
|
<el-input v-model="addForm.nick_name" placeholder="请输入昵称" />
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<el-button @click="handleAddClose">取消</el-button>
|
|
<el-button type="primary" @click="submitAdd">确定</el-button>
|
|
</span>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
<script setup>
|
|
import searchForm from '@/components/searchForm/index.vue'
|
|
import Content from '@/components/content/index.vue'
|
|
import {list, status, getUserDetail, register, setBalance, setVip} from '@/api/user/index.js'
|
|
import { ref, onMounted } from 'vue'
|
|
import {formatDate} from '@/utils/format'
|
|
import { USER_SEARCH_CONFIG, USER_TABLE_CONFIG } from '@/config'
|
|
import { ElMessage } from 'element-plus'
|
|
const tableLoading = ref(true), tableData = ref([])
|
|
const queryParams = ref({
|
|
page: 1,
|
|
pageSize: 10,
|
|
orderId: '',
|
|
startTime: '',
|
|
endTime: ''
|
|
}), total = ref(0)
|
|
// const EMPTY_STR = '- -'
|
|
const dialogVisible = ref(false)
|
|
const userDetail = ref({})
|
|
const addDialogVisible = ref(false)
|
|
const addFormRef = ref(null)
|
|
const addForm = ref({
|
|
phone: '',
|
|
password: '',
|
|
user_type: 1,
|
|
user_label: 1,
|
|
nick_name: ''
|
|
})
|
|
|
|
const addRules = {
|
|
phone: [
|
|
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
|
],
|
|
password: [
|
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
|
{ min: 6, message: '密码长度不能小于6位', trigger: 'blur' }
|
|
],
|
|
user_type: [
|
|
{ required: true, message: '请选择用户类型', trigger: 'change' }
|
|
],
|
|
user_label: [
|
|
{ required: true, message: '请选择用户标签', trigger: 'change' }
|
|
],
|
|
nick_name: [
|
|
{ required: true, message: '请输入昵称', trigger: 'blur' }
|
|
]
|
|
}
|
|
|
|
const searchData = (data) => {
|
|
if (data.times) {
|
|
data.startTime = data.times[0]
|
|
data.endTime = data.times[1]
|
|
}
|
|
queryParams.value.page = 1
|
|
queryParams.value = { ...queryParams.value, ...data }
|
|
delete queryParams.value.times
|
|
getList()
|
|
}
|
|
const resetData = () => {
|
|
queryParams.value = {
|
|
page: 1,
|
|
pageSize: 10,
|
|
}
|
|
getList()
|
|
}
|
|
onMounted(() => {
|
|
getList()
|
|
})
|
|
async function getList() {
|
|
const res = await list(queryParams.value)
|
|
if(res.code === 0) {
|
|
tableData.value = res.data.list
|
|
for(let item of tableData.value) {
|
|
item.loading = false
|
|
}
|
|
total.value = res.data.total
|
|
}
|
|
}
|
|
|
|
async function handleDetail(row) {
|
|
const res = await getUserDetail(row.ID)
|
|
if(res.code === 0) {
|
|
userDetail.value = res.data
|
|
dialogVisible.value = true
|
|
}
|
|
}
|
|
|
|
function handleClose() {
|
|
dialogVisible.value = false
|
|
userDetail.value = {}
|
|
}
|
|
|
|
function changePage(data) {
|
|
queryParams.value.pageNum = data
|
|
getList()
|
|
}
|
|
async function statusChangeBefore(row) {
|
|
row.loading = true
|
|
let params = JSON.parse(JSON.stringify(row))
|
|
params.status = row.status === 1 ? 0 : 0
|
|
const res = await status(params)
|
|
row.loading = false
|
|
if(res.code === 0) {
|
|
row.status = row.status === 1? 0 :1
|
|
}
|
|
}
|
|
|
|
function handleAdd() {
|
|
addDialogVisible.value = true
|
|
}
|
|
|
|
function handleAddClose() {
|
|
addDialogVisible.value = false
|
|
addFormRef.value?.resetFields()
|
|
}
|
|
|
|
async function submitAdd() {
|
|
if (!addFormRef.value) return
|
|
await addFormRef.value.validate(async (valid) => {
|
|
if (valid) {
|
|
const res = await register(addForm.value)
|
|
if (res.code === 0) {
|
|
ElMessage.success('添加成功')
|
|
handleAddClose()
|
|
getList()
|
|
} else {
|
|
ElMessage.error(res.msg || '添加失败')
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
const balanceDialogVisible = ref(false)
|
|
const balanceFormRef = ref(null)
|
|
const currentUser = ref({})
|
|
const balanceForm = ref({
|
|
ID: '',
|
|
balance: 0
|
|
})
|
|
|
|
const balanceRules = {
|
|
balance: [
|
|
{ required: true, message: '请输入余额', trigger: 'blur' },
|
|
{ type: 'number', min: 0, message: '余额不能小于0', trigger: 'blur' }
|
|
]
|
|
}
|
|
|
|
const vipDialogVisible = ref(false)
|
|
const vipFormRef = ref(null)
|
|
const vipForm = ref({
|
|
id: '',
|
|
user_label: 1,
|
|
vip_expire_time: ''
|
|
})
|
|
|
|
const vipRules = {
|
|
user_label: [
|
|
{ required: true, message: '请选择VIP类型', trigger: 'change' }
|
|
],
|
|
vip_expire_time: [
|
|
{ required: true, message: '请选择到期时间', trigger: 'change' }
|
|
]
|
|
}
|
|
|
|
function handleBalance(row) {
|
|
currentUser.value = row
|
|
balanceForm.value = {
|
|
ID: row.ID,
|
|
balance: row.balance
|
|
}
|
|
balanceDialogVisible.value = true
|
|
}
|
|
|
|
function handleBalanceClose() {
|
|
balanceDialogVisible.value = false
|
|
balanceFormRef.value?.resetFields()
|
|
}
|
|
|
|
async function submitBalance() {
|
|
if (!balanceFormRef.value) return
|
|
await balanceFormRef.value.validate(async (valid) => {
|
|
if (valid) {
|
|
const res = await setBalance(balanceForm.value)
|
|
if (res.code === 0) {
|
|
ElMessage.success('修改成功')
|
|
handleBalanceClose()
|
|
getList()
|
|
} else {
|
|
ElMessage.error(res.msg || '修改失败')
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
function handleVip(row) {
|
|
currentUser.value = row
|
|
vipForm.value = {
|
|
id: row.ID,
|
|
user_label: row.user_label,
|
|
vip_expire_time: row.vip_expire_time || ''
|
|
}
|
|
vipDialogVisible.value = true
|
|
}
|
|
|
|
function handleVipClose() {
|
|
vipDialogVisible.value = false
|
|
vipFormRef.value?.resetFields()
|
|
}
|
|
|
|
async function submitVip() {
|
|
if (!vipFormRef.value) return
|
|
await vipFormRef.value.validate(async (valid) => {
|
|
if (valid) {
|
|
const res = await setVip(vipForm.value)
|
|
if (res.code === 0) {
|
|
ElMessage.success('设置成功')
|
|
handleVipClose()
|
|
getList()
|
|
} else {
|
|
ElMessage.error(res.msg || '设置失败')
|
|
}
|
|
}
|
|
})
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
</style>
|