Files
hfb_sys/frontend/src/views/admin/AdminUsersView.vue
T
2026-05-27 01:14:03 +08:00

115 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { ref } from 'vue'
import { fetchAdminUsers, freezeAdminUser, unfreezeAdminUser, type AdminUserItem } from '@/api/adminUsers'
import { useAdminPaginatedTable } from '@/composables/useAdminPaginatedTable'
import { userStatusLabel } from '@/utils/statusLabels'
import { formatDateTime } from '@/utils/time'
const submitting = ref(false)
const activeUser = ref<AdminUserItem | null>(null)
const freezeReason = ref('')
const { loading, data: users, total, currentPage, currentPageSize, load: loadUsers, handleSizeChange } = useAdminPaginatedTable<AdminUserItem>({
fetchFn: fetchAdminUsers,
})
function openFreeze(row: AdminUserItem) {
activeUser.value = row
freezeReason.value = ''
}
async function handleFreeze() {
if (!activeUser.value) return
submitting.value = true
try {
await freezeAdminUser(activeUser.value.id, freezeReason.value)
ElMessage.success('用户已冻结')
activeUser.value = null
await loadUsers()
} catch (error) {
ElMessage.error(readError(error, '冻结失败'))
} finally {
submitting.value = false
}
}
async function handleUnfreeze(row: AdminUserItem) {
submitting.value = true
try {
await unfreezeAdminUser(row.id)
ElMessage.success('用户已解冻')
await loadUsers()
} catch (error) {
ElMessage.error(readError(error, '解冻失败'))
} finally {
submitting.value = false
}
}
function readError(error: unknown, fallback: string) {
if (typeof error === 'object' && error && 'response' in error) {
const response = (error as { response?: { data?: { message?: string } } }).response
return response?.data?.message || fallback
}
return fallback
}
</script>
<template>
<section class="page">
<div class="page-header-row">
<div class="page-header">
<p class="eyebrow">Users</p>
<h1>用户管理</h1>
<p>查看用户信息和状态处理冻结与解冻</p>
</div>
<el-button @click="loadUsers">刷新</el-button>
</div>
<el-table v-loading="loading" class="table-panel" :data="users">
<el-table-column prop="id" label="用户ID" width="80" />
<el-table-column prop="nickname" label="昵称" min-width="130" />
<el-table-column prop="phone" label="手机号" min-width="130" />
<el-table-column label="状态" width="110">
<template #default="{ row }">{{ userStatusLabel(row.status) }}</template>
</el-table-column>
<el-table-column label="注册时间" min-width="180">
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="{ row }">
<el-button v-if="row.status === 'active'" size="small" type="danger" :loading="submitting" @click="openFreeze(row)">
冻结
</el-button>
<el-button v-else size="small" type="primary" :loading="submitting" @click="handleUnfreeze(row)">解冻</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-wrap" v-if="total > 0">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="currentPageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
@current-change="loadUsers"
@size-change="handleSizeChange"
/>
</div>
<el-dialog :model-value="!!activeUser" title="冻结用户" width="560px" @update:model-value="activeUser = null">
<div v-if="activeUser" class="dialog-body">
<p><strong>{{ activeUser.phone }}</strong> · {{ activeUser.nickname }}</p>
<el-input v-model="freezeReason" type="textarea" :rows="4" placeholder="填写冻结原因,便于审计追踪" />
</div>
<template #footer>
<el-button @click="activeUser = null">取消</el-button>
<el-button type="danger" :loading="submitting" @click="handleFreeze">确认冻结</el-button>
</template>
</el-dialog>
</section>
</template>