deotalandAi/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUserInvites.vue

509 lines
14 KiB
Vue

<template>
<div class="user-invites">
<!-- 添加返回按钮 -->
<div class="page-header" style="margin-bottom: 20px;">
<el-button
type="primary"
:icon="ArrowLeft"
@click="handleBack"
>
返回
</el-button>
</div>
<!-- 标签页 -->
<el-tabs v-model="activeTab" type="card" @tab-change="handleTabChange">
<!-- 邀请码列表 -->
<el-tab-pane label="邀请码列表" name="inviteCode">
<!-- 邀请码列表内容 -->
<div class="invite-code-section">
<!-- 筛选和生成按钮区域 -->
<div class="filter-section">
<el-form :inline="true" :model="filterForm" class="filter-form">
<el-form-item label="用户ID" v-if="false">
<el-input v-model="filterForm.userId" placeholder="请输入用户ID" style="width: 150px;"></el-input>
</el-form-item>
<el-form-item label="邀请码">
<el-input v-model="filterForm.inviteCode" placeholder="请输入邀请码" style="width: 200px;"></el-input>
</el-form-item>
<el-form-item label="使用状态">
<el-select v-model="filterForm.isUsed" placeholder="请选择使用状态" style="width: 150px;">
<el-option label="全部" value=""></el-option>
<el-option label="已使用" :value="1"></el-option>
<el-option label="未使用" :value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<el-button type="success" @click="showGenerateDialog = true">生成邀请码</el-button>
</div>
<!-- 邀请码列表 -->
<div class="invite-table">
<!-- stripe -->
<el-table
:data="inviteCodeList"
style="width: 100%"
v-loading="loadingCode"
>
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="userNickname" label="用户名" min-width="120" align="center" />
<el-table-column prop="userEmail" label="邮箱" min-width="180" align="center" />
<el-table-column prop="inviteCode" label="邀请码" min-width="200" align="center" />
<el-table-column prop="isUsed" label="使用状态" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.isUsed ? 'success' : 'warning'">
{{ row.isUsed ? '已使用' : '未使用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="invitedUserNickname" label="邀请用户" min-width="120" align="center" />
<el-table-column prop="usedAt" label="使用时间" min-width="180" align="center">
<template #default="{ row }">
{{ formatDateTime(row.usedAt) }}
</template>
</el-table-column>
<el-table-column prop="createdAt" label="创建时间" min-width="180" align="center">
<template #default="{ row }">
{{ formatDateTime(row.createdAt) }}
</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default="{ row }">
<el-button
type="danger"
size="small"
@click="handleDeleteCode(row)"
:disabled="Boolean(row.isUsed)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination">
<el-pagination
v-model:current-page="currentPageCode"
v-model:page-size="pageSizeCode"
:page-sizes="[10, 20, 50, 100]"
:total="totalCodes"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChangeCode"
@current-change="handleCurrentChangeCode"
/>
</div>
</div>
<!-- 生成邀请码对话框 -->
<el-dialog
v-model="showGenerateDialog"
title="生成邀请码"
width="400px"
>
<el-form :model="generateForm" label-position="top">
<el-form-item label="生成数量" required>
<el-input-number
v-model="generateForm.count"
:min="1"
:max="100"
:step="1"
placeholder="请输入生成数量"
></el-input-number>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showGenerateDialog = false">取消</el-button>
<el-button type="primary" @click="handleGenerateCode">确认</el-button>
</span>
</template>
</el-dialog>
<!-- 删除确认对话框 -->
<el-dialog
v-model="showDeleteDialog"
title="确认删除"
width="400px"
>
<div>确定要删除邀请码 {{ deleteCodeInfo.inviteCode }} 吗?</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDeleteDialog = false">取消</el-button>
<el-button type="danger" @click="confirmDeleteCode">确认删除</el-button>
</span>
</template>
</el-dialog>
</el-tab-pane>
<!-- 邀请用户列表 -->
<el-tab-pane label="邀请用户列表" name="invitedUsers">
<!-- 列表区域 -->
<div class="invite-table">
<!-- stripe -->
<el-table
:data="inviteList"
style="width: 100%"
v-loading="loading"
>
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="nickname" label="用户名" min-width="120" align="center" />
<el-table-column prop="email" label="邮箱" min-width="180" align="center" />
<el-table-column prop="userRole" label="用户角色" min-width="120" align="center">
<template #default="{ row }">
{{ getUserRoleLabel(row.userRole) }}
</template>
</el-table-column>
<el-table-column prop="createdAt" label="注册日期" min-width="160" align="center">
<template #default="{ row }">
{{ formatDateTime(row.createdAt) }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="getStatusTagType(row.status)">
{{ getStatusLabel(row.status) }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="totalInvites"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { ElMessage } from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
import { AdminOrders } from './index.js'
const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const adminOrders = new AdminOrders()
// 响应式数据 - 标签页
const activeTab = ref('inviteCode')
// 响应式数据 - 邀请用户列表
const loading = ref(false)
const currentPage = ref(1)
const pageSize = ref(20)
const totalInvites = ref(0)
const inviteList = ref([])
const userId = ref(route.params.id)
// 响应式数据 - 邀请码列表
const loadingCode = ref(false)
const currentPageCode = ref(1)
const pageSizeCode = ref(20)
const totalCodes = ref(0)
const inviteCodeList = ref([])
// 筛选表单数据
const filterForm = ref({
userId: '',
inviteCode: '',
isUsed: ''
})
// 生成邀请码表单数据
const generateForm = ref({
count: 1
})
// 对话框显示状态
const showGenerateDialog = ref(false)
const showDeleteDialog = ref(false)
const deleteCodeInfo = ref({})
// 获取状态标签类型
const getStatusTagType = (status) => {
const typeMap = {
active: 'success',
disable: 'info',
banned: 'danger'
}
return typeMap[status] || 'info'
}
// 获取状态标签文本
const getStatusLabel = (status) => {
const labelMap = {
active: '活跃',
disable: '禁用',
banned: '已封禁'
}
return labelMap[status] || status
}
// 获取用户角色标签
const getUserRoleLabel = (userRole) => {
const roleMap = {
0: '候补中',
1: '免费会员',
2: '达人会员'
}
return roleMap[userRole] || '未知角色'
}
// 格式化日期时间
const formatDateTime = (dateTimeString) => {
if (!dateTimeString) return '-'
const date = new Date(dateTimeString)
return date.toLocaleString(
t('admin.review.dateFormat') === 'en-US' ? 'en-US' : 'zh-CN',
{
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
}
)
}
// 获取邀请列表
const getInviteList = async () => {
loading.value = true
try {
const result = await adminOrders.getUsersInvites({
id: userId.value,
pageSize: pageSize.value,
pageNum: currentPage.value
})
inviteList.value = result.rows || []
totalInvites.value = result.total || 0
} catch (error) {
console.error('获取邀请列表失败:', error)
ElMessage.error('获取邀请列表失败')
} finally {
loading.value = false
}
}
// 获取邀请码列表
const getInviteCodeList = async () => {
loadingCode.value = true
try {
const result = await adminOrders.getInviteCodeList({
id: filterForm.value.userId || userId.value,
inviteCode: filterForm.value.inviteCode,
isUsed: filterForm.value.isUsed,
pageSize: pageSizeCode.value,
pageNum: currentPageCode.value
})
const data = result.data;
inviteCodeList.value = data.rows || []
totalCodes.value = data.total || 0
} catch (error) {
console.error('获取邀请码列表失败:', error)
ElMessage.error('获取邀请码列表失败')
} finally {
loadingCode.value = false
}
}
// 生成邀请码
const handleGenerateCode = async () => {
try {
const result = await adminOrders.generateInviteCode({
id: userId.value,
count: generateForm.value.count
})
ElMessage.success('邀请码生成成功')
showGenerateDialog.value = false
// 重置表单
generateForm.value.count = 1
// 刷新邀请码列表
getInviteCodeList()
} catch (error) {
console.error('生成邀请码失败:', error)
ElMessage.error('生成邀请码失败')
}
}
// 删除邀请码 - 显示确认对话框
const handleDeleteCode = (row) => {
deleteCodeInfo.value = row
showDeleteDialog.value = true
}
// 删除邀请码 - 确认删除
const confirmDeleteCode = async () => {
try {
const result = await adminOrders.deleteInviteCode({
id: deleteCodeInfo.value.id
})
ElMessage.success('邀请码删除成功')
showDeleteDialog.value = false
// 刷新邀请码列表
getInviteCodeList()
} catch (error) {
console.error('删除邀请码失败:', error)
ElMessage.error('删除邀请码失败')
}
}
// 分页处理 - 邀请用户列表
const handleSizeChange = (size) => {
pageSize.value = size
currentPage.value = 1
getInviteList()
}
const handleCurrentChange = (page) => {
currentPage.value = page
getInviteList()
}
// 分页处理 - 邀请码列表
const handleSizeChangeCode = (size) => {
pageSizeCode.value = size
currentPageCode.value = 1
getInviteCodeList()
}
const handleCurrentChangeCode = (page) => {
currentPageCode.value = page
getInviteCodeList()
}
// 筛选处理
const handleSearch = () => {
currentPageCode.value = 1
getInviteCodeList()
}
const handleReset = () => {
filterForm.value = {
userId: '',
inviteCode: '',
isUsed: ''
}
currentPageCode.value = 1
getInviteCodeList()
}
// 标签页切换处理
const handleTabChange = (tabName) => {
if (tabName === 'inviteCode') {
getInviteCodeList()
} else if (tabName === 'invitedUsers') {
getInviteList()
}
}
// 返回上一页
const handleBack = () => {
router.push('/admin/users')
}
// 初始化
onMounted(() => {
// 默认加载邀请码列表
getInviteCodeList()
})
</script>
<style scoped>
.user-invites {
padding: 20px;
}
.invite-table {
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid #e5e7eb;
margin-bottom: 24px;
}
.invite-code-section {
margin-top: 20px;
}
.filter-section {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 16px;
background: white;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid #e5e7eb;
}
.filter-form {
display: flex;
gap: 16px;
}
.pagination {
display: flex;
justify-content: flex-end;
padding: 16px 0;
}
/* 表格样式优化 */
.invite-table :deep(.el-table) {
width: 100% !important;
table-layout: auto;
}
.invite-table :deep(.el-table__cell) {
padding: 8px 12px;
white-space: nowrap;
vertical-align: middle;
}
.invite-table :deep(.el-table__row) {
height: 66px;
}
.invite-table :deep(.el-table__header-wrapper) {
background-color: #f8fafc;
}
.invite-table :deep(.el-table__header th) {
background-color: #f8fafc;
color: #374151;
font-weight: 600;
border-bottom: 2px solid #e5e7eb;
white-space: nowrap !important;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
/* 标签页样式 */
:deep(.el-tabs__content) {
padding-top: 20px;
}
</style>