Files
course/frontend/src/views/admin/AdminUsersView.vue
T
nanxunandClaude Fable 5 cd486a36ef feat: UOOC/Zhihuishu dual-platform brushing platform
- ASP.NET Core 9 Web API backend with JWT auth, EF Core MySQL
- Vue 3 + Vite + Pinia + Ant Design Vue frontend
- Multi-platform connection management (UOOC & Zhihuishu)
- Video brushing with AES-CBC encryption for Zhihuishu
- Multi-task queue with cross-platform parallel execution
- Task persistence via MySQL database
- Progress tracking with inline catalog enrichment
- Mobile-responsive UI

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-24 15:31:32 +08:00

80 lines
3.2 KiB
Vue

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { message } from 'ant-design-vue';
import { getAdminUsers, updateAdminUser } from '../../lib/api';
import type { AuthUserDto } from '../../types/api';
const users = ref<AuthUserDto[]>([]);
const loading = ref(false);
const savingId = ref<number | null>(null);
async function load() {
loading.value = true;
try { users.value = await getAdminUsers(); }
catch (err) { message.error(err instanceof Error ? err.message : '加载失败。'); }
finally { loading.value = false; }
}
async function save(u: AuthUserDto) {
savingId.value = u.id;
try {
const updated = await updateAdminUser(u.id, { displayName: u.displayName, role: u.role, status: u.status });
users.value = users.value.map(x => x.id === updated.id ? updated : x);
message.success(`已更新 ${updated.displayName}。`);
} catch (err) { message.error(err instanceof Error ? err.message : '更新失败。'); }
finally { savingId.value = null; }
}
onMounted(load);
const columns = [
{ title: 'ID', dataIndex: 'id', width: 60 },
{ title: '用户名', dataIndex: 'username' },
{ title: '显示名', dataIndex: 'displayName', key: 'displayName' },
{ title: '角色', dataIndex: 'role', key: 'role' },
{ title: '状态', dataIndex: 'status', key: 'status' },
{ title: '创建时间', key: 'createdAt' },
{ title: '最近登录', key: 'lastLoginAt' },
{ title: '操作', key: 'action', width: 100 },
];
</script>
<template>
<a-card title="用户管理">
<template #extra>
<a-button @click="load" :loading="loading">刷新</a-button>
</template>
<a-table :data-source="users" :columns="columns" :loading="loading" row-key="id" size="small" :pagination="false">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'displayName'">
<a-input v-model:value="record.displayName" size="small" style="width: 120px;" />
</template>
<template v-else-if="column.key === 'role'">
<a-select v-model:value="record.role" size="small" style="width: 100px;">
<a-select-option value="user">普通用户</a-select-option>
<a-select-option value="admin">管理员</a-select-option>
</a-select>
</template>
<template v-else-if="column.key === 'status'">
<a-select v-model:value="record.status" size="small" style="width: 80px;">
<a-select-option value="active">启用</a-select-option>
<a-select-option value="disabled">停用</a-select-option>
</a-select>
</template>
<template v-else-if="column.key === 'createdAt'">
{{ new Date(record.createdAt).toLocaleString('zh-CN') }}
</template>
<template v-else-if="column.key === 'lastLoginAt'">
{{ record.lastLoginAt ? new Date(record.lastLoginAt).toLocaleString('zh-CN') : '-' }}
</template>
<template v-else-if="column.key === 'action'">
<a-button type="primary" size="small" :loading="savingId === record.id" @click="save(record)">
{{ savingId === record.id ? '...' : '保存' }}
</a-button>
</template>
</template>
</a-table>
</a-card>
</template>