首个可运行的版本
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user