Files
number/frontend/src/views/admin/users.vue

173 lines
5.3 KiB
Vue
Raw Normal View History

2026-03-17 12:09:43 +08:00
<template>
<div class="admin-users-page">
<div class="page-header">
<h2 class="page-title">用户管理</h2>
<div class="header-actions">
<el-input
v-model="searchKeyword"
placeholder="搜索用户..."
clearable
style="width: 200px"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div>
</div>
<el-table :data="filteredUsers" style="width: 100%" v-loading="loading">
<el-table-column label="用户" width="250">
<template #default="{ row }">
<div class="user-cell">
<el-avatar :size="40" :src="row.avatar">{{ row.nickname?.charAt(0) }}</el-avatar>
<div class="user-info">
<span class="name">{{ row.nickname }}</span>
<span class="phone">{{ row.phone }}</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="levelName" label="等级" width="100">
<template #default="{ row }">
<el-tag type="warning" size="small">{{ row.levelName }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="points" label="积分" width="100" />
<el-table-column prop="inviteCount" label="邀请人数" width="100" />
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="row.status === 'active' ? 'success' : 'danger'" size="small">
{{ row.status === 'active' ? '正常' : '封禁' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="注册时间" width="180" />
<el-table-column label="操作" fixed="right" width="200">
<template #default="{ row }">
<el-button text type="primary" size="small" @click="viewUser(row)">查看</el-button>
<el-button
v-if="row.status === 'active'"
text
type="danger"
size="small"
@click="banUser(row)"
>
封禁
</el-button>
<el-button
v-else
text
type="success"
size="small"
@click="unbanUser(row)"
>
解封
</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="userDialogVisible" title="用户详情" width="500px">
<template v-if="currentUser">
<el-descriptions :column="1" border>
<el-descriptions-item label="用户ID">{{ currentUser.id }}</el-descriptions-item>
<el-descriptions-item label="昵称">{{ currentUser.nickname }}</el-descriptions-item>
<el-descriptions-item label="手机号">{{ currentUser.phone }}</el-descriptions-item>
<el-descriptions-item label="邮箱">{{ currentUser.email || '未设置' }}</el-descriptions-item>
<el-descriptions-item label="会员等级">{{ currentUser.levelName }}</el-descriptions-item>
<el-descriptions-item label="积分余额">{{ currentUser.points }}</el-descriptions-item>
<el-descriptions-item label="累计积分">{{ currentUser.totalPoints }}</el-descriptions-item>
<el-descriptions-item label="邀请人数">{{ currentUser.inviteCount }}</el-descriptions-item>
<el-descriptions-item label="邀请码">{{ currentUser.inviteCode }}</el-descriptions-item>
<el-descriptions-item label="注册时间">{{ currentUser.createdAt }}</el-descriptions-item>
<el-descriptions-item label="最后登录">{{ currentUser.lastLoginAt }}</el-descriptions-item>
</el-descriptions>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useAdminStore } from '@/stores'
import { ElMessage, ElMessageBox } from 'element-plus'
const adminStore = useAdminStore()
const loading = ref(false)
const searchKeyword = ref('')
const userDialogVisible = ref(false)
const currentUser = ref(null)
const users = computed(() => adminStore.users)
const filteredUsers = computed(() => {
if (!searchKeyword.value) return users.value
const keyword = searchKeyword.value.toLowerCase()
return users.value.filter(u =>
u.nickname?.toLowerCase().includes(keyword) ||
u.phone?.includes(keyword)
)
})
onMounted(() => {
adminStore.loadUsers()
})
const viewUser = (user) => {
currentUser.value = user
userDialogVisible.value = true
}
const banUser = (user) => {
ElMessageBox.confirm(`确定要封禁用户 ${user.nickname} 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
adminStore.banUser(user.id)
ElMessage.success('已封禁')
}).catch(() => {})
}
const unbanUser = (user) => {
adminStore.unbanUser(user.id)
ElMessage.success('已解封')
}
</script>
<style lang="scss" scoped>
.admin-users-page {
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
.page-title {
font-size: 20px;
color: #303133;
}
}
.user-cell {
display: flex;
align-items: center;
gap: 12px;
.user-info {
.name {
display: block;
color: #303133;
}
.phone {
font-size: 12px;
color: #909399;
}
}
}
}
</style>