4 changed files with 185 additions and 0 deletions
-
8src/router/index.ts
-
11src/stores/auth.ts
-
1src/views/admin/AdminLayout.vue
-
165src/views/admin/UserListView.vue
@ -0,0 +1,165 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { ref, onMounted } from 'vue' |
||||
|
import { userApi } from '@/api/client' |
||||
|
import type { UserInfo } from '@/generated/api' |
||||
|
|
||||
|
const users = ref<UserInfo[]>([]) |
||||
|
const page = ref(1) |
||||
|
const size = 10 |
||||
|
const total = ref(0) |
||||
|
const loading = ref(false) |
||||
|
const error = ref<string | null>(null) |
||||
|
|
||||
|
function roleLabel(role: string): string { |
||||
|
switch (role) { |
||||
|
case 'ADMIN': |
||||
|
return '管理员' |
||||
|
case 'EDITOR': |
||||
|
return '编辑' |
||||
|
case 'VISITOR': |
||||
|
return '访客' |
||||
|
default: |
||||
|
return role |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function formatDate(iso: string): string { |
||||
|
const d = new Date(iso) |
||||
|
if (isNaN(d.getTime())) return iso |
||||
|
return d.toLocaleString('zh-CN', { hour12: false }) |
||||
|
} |
||||
|
|
||||
|
async function load() { |
||||
|
loading.value = true |
||||
|
error.value = null |
||||
|
try { |
||||
|
const resp = await userApi.apiAdminUsersGet(page.value, size) |
||||
|
const data = resp.data.data |
||||
|
users.value = data?.list as UserInfo[] ?? [] |
||||
|
total.value = Number(data?.total ?? 0) |
||||
|
} catch (e) { |
||||
|
console.error(e) |
||||
|
error.value = '用户列表加载失败' |
||||
|
} finally { |
||||
|
loading.value = false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMounted(load) |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div> |
||||
|
<h1 class="page-title">用户管理</h1> |
||||
|
<p v-if="error" class="error-text">{{ error }}</p> |
||||
|
<p v-else-if="loading" class="hint-text">加载中...</p> |
||||
|
<p v-else-if="users.length === 0" class="hint-text">暂无用户</p> |
||||
|
|
||||
|
<table v-else class="user-table"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>用户名</th> |
||||
|
<th>邮箱</th> |
||||
|
<th>角色</th> |
||||
|
<th>状态</th> |
||||
|
<th>注册时间</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<tr v-for="user in users" :key="user.id"> |
||||
|
<td>{{ user.username }}</td> |
||||
|
<td>{{ user.email || '-' }}</td> |
||||
|
<td> |
||||
|
<span class="role-badge" :class="user.role.toLowerCase()">{{ roleLabel(user.role) }}</span> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span class="status-badge" :class="user.enabled ? 'enabled' : 'disabled'"> |
||||
|
{{ user.enabled ? '启用' : '禁用' }} |
||||
|
</span> |
||||
|
</td> |
||||
|
<td>{{ formatDate(user.createdAt) }}</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
<p class="total-hint">共 {{ total }} 位用户</p> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped> |
||||
|
.page-title { |
||||
|
margin: 0 0 16px; |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
|
||||
|
.user-table { |
||||
|
width: 100%; |
||||
|
border-collapse: collapse; |
||||
|
background: #fff; |
||||
|
border: 1px solid #e5e5ea; |
||||
|
border-radius: 8px; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.user-table th, |
||||
|
.user-table td { |
||||
|
padding: 10px 14px; |
||||
|
text-align: left; |
||||
|
border-bottom: 1px solid #eee; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
.user-table th { |
||||
|
background: #f7f8fa; |
||||
|
color: #5c6470; |
||||
|
} |
||||
|
|
||||
|
.role-badge { |
||||
|
padding: 2px 10px; |
||||
|
border-radius: 12px; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.role-badge.admin { |
||||
|
background: #f8d7da; |
||||
|
color: #8f1f2b; |
||||
|
} |
||||
|
|
||||
|
.role-badge.editor { |
||||
|
background: #cce5ff; |
||||
|
color: #004a99; |
||||
|
} |
||||
|
|
||||
|
.role-badge.visitor { |
||||
|
background: #e9ecef; |
||||
|
color: #6c757d; |
||||
|
} |
||||
|
|
||||
|
.status-badge { |
||||
|
padding: 2px 10px; |
||||
|
border-radius: 12px; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.status-badge.enabled { |
||||
|
background: #d4edda; |
||||
|
color: #1e7e34; |
||||
|
} |
||||
|
|
||||
|
.status-badge.disabled { |
||||
|
background: #e9ecef; |
||||
|
color: #6c757d; |
||||
|
} |
||||
|
|
||||
|
.total-hint { |
||||
|
color: #8a93a3; |
||||
|
font-size: 13px; |
||||
|
} |
||||
|
|
||||
|
.error-text { |
||||
|
color: #d33c3c; |
||||
|
} |
||||
|
|
||||
|
.hint-text { |
||||
|
color: #8a93a3; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue