173 lines
5.3 KiB
Vue
173 lines
5.3 KiB
Vue
<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>
|