- 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>
80 lines
3.2 KiB
Vue
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>
|