Files
chat/frontend/src/views/admin/AdminUsersView.vue
T
2026-06-12 23:14:12 +08:00

95 lines
3.0 KiB
Vue

<template>
<div>
<h2 style="margin-top: 0; color: var(--color-primary-dark)">👥 用户管理</h2>
<div class="toolbar">
<n-input v-model:value="search" placeholder="搜索用户名..." style="width: 240px" @update:value="loadUsers" />
<n-select v-model:value="statusFilter" :options="statusOptions" style="width: 140px" @update:value="loadUsers" />
</div>
<n-data-table :columns="columns" :data="users" :pagination="{ pageSize: 20 }" :loading="loading" striped />
</div>
</template>
<script setup lang="ts">
import { ref, h, onMounted } from 'vue'
import { NButton, useMessage, useDialog } from 'naive-ui'
import { adminApi } from '@/api/admin'
const message = useMessage()
const dialog = useDialog()
const users = ref<any[]>([])
const loading = ref(false)
const search = ref('')
const statusFilter = ref<string | null>(null)
const statusOptions = [
{ label: '全部', value: null },
{ label: '在线', value: 'online' },
{ label: '已封禁', value: 'banned' },
]
const columns = [
{ title: '用户名', key: 'username', width: 120 },
{ title: '邮箱', key: 'email', width: 180 },
{ title: '状态', key: 'status', width: 80, render: (row: any) => row.is_banned ? '🚫 已封禁' : row.status === 'online' ? '🟢 在线' : '⚫ 离线' },
{ title: '注册时间', key: 'created_at', width: 160, render: (row: any) => new Date(row.created_at).toLocaleString('zh-CN') },
{
title: '操作', key: 'actions', width: 160,
render: (row: any) => [
h(NButton, {
size: 'small', type: row.is_banned ? 'success' : 'warning',
onClick: () => toggleBan(row),
}, { default: () => row.is_banned ? '解封' : '封禁' }),
h(NButton, {
size: 'small', type: 'error', style: 'margin-left: 8px',
onClick: () => deleteUser(row),
}, { default: () => '删除' }),
],
},
]
async function loadUsers() {
loading.value = true
try {
const { data } = await adminApi.getUsers({
search: search.value || undefined,
status: statusFilter.value || undefined,
})
users.value = data.items
} finally { loading.value = false }
}
function toggleBan(user: any) {
dialog.warning({
title: user.is_banned ? '解封用户' : '封禁用户',
content: `确定要${user.is_banned ? '解封' : '封禁'} ${user.username} 吗?`,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
await adminApi.banUser(user.id, !user.is_banned)
message.success('操作成功')
await loadUsers()
},
})
}
function deleteUser(user: any) {
dialog.error({
title: '⚠️ 删除用户',
content: `确定要永久删除 ${user.username} 吗?此操作不可撤销!`,
positiveText: '确定删除',
negativeText: '取消',
onPositiveClick: async () => {
await adminApi.deleteUser(user.id)
message.success('已删除')
await loadUsers()
},
})
}
onMounted(loadUsers)
</script>
<style scoped>
.toolbar { display: flex; gap: 12px; margin-bottom: 16px; }
</style>