This commit is contained in:
fengchuanhn@gmail.com
2026-05-21 02:40:08 +08:00
parent 14cf9b7bf5
commit 426a69cd69
14 changed files with 754 additions and 45 deletions

View File

@@ -1,12 +1,12 @@
<script setup>
import { computed, onMounted, ref } from "vue";
import { useAuthStore, ROLE_ADMIN, ROLE_AGENT } from "../../stores/auth.js";
import { useAuthStore, ROLE_ADMIN, ROLE_AGENT,ROLE_OEM } from "../../stores/auth.js";
import {
listAdminUsersApi,
createAdminUserApi,
updateAdminUserApi,
deleteAdminUserApi,
} from "../../api/adminUsers.js";
listOemUsersApi,
createOemUserApi,
updateOemUserApi,
deleteOemUserApi,
} from "../../api/oemUsers.js";
const auth = useAuthStore();
@@ -14,12 +14,14 @@ const ROLE_OPTIONS = [
{ label: "普通用户", value: 0 },
{ label: "管理员", value: 1 },
{ label: "代理", value: 2 },
{ label: "OEM", value: 3 },
];
const ROLE_LABELS = {
0: "普通用户",
[ROLE_ADMIN]: "管理员",
[ROLE_AGENT]: "代理",
[ROLE_OEM]: "OEM",
};
const users = ref([]);
@@ -27,6 +29,14 @@ const total = ref(0);
const page = ref(1);
const pageSize = ref(20);
const loading = ref(false);
const oemOptions = ref([]);
const agentOptions = ref([]);
const filters = ref({
username: "",
oem_id: null,
agent_id: null,
});
const saving = ref(false);
const feedback = ref({ severity: "", message: "" });
@@ -71,19 +81,48 @@ function roleLabel(roleId) {
function roleSeverity(roleId) {
if (roleId === ROLE_ADMIN) return "info";
if (roleId === ROLE_AGENT) return "warn";
if (roleId === ROLE_OEM) return "success";
return "secondary";
}
const ownerNameById = computed(() => {
const map = new Map();
for (const u of oemOptions.value) map.set(u.id, u.username);
for (const u of agentOptions.value) map.set(u.id, u.username);
return map;
});
function ownerLabel(userId) {
if (userId == null) return "—";
return ownerNameById.value.get(userId) ?? `#${userId}`;
}
function showMessage(severity, message) {
feedback.value = { severity, message };
}
async function loadFilterOptions() {
const [oemRes, agentRes] = await Promise.all([
listOemUsersApi(auth.token, { page: 1, pageSize: 200, roleId: ROLE_OEM }),
listOemUsersApi(auth.token, { page: 1, pageSize: 200, roleId: ROLE_AGENT }),
]);
if (oemRes.ok && Array.isArray(oemRes.data?.items)) {
oemOptions.value = oemRes.data.items;
}
if (agentRes.ok && Array.isArray(agentRes.data?.items)) {
agentOptions.value = agentRes.data.items;
}
}
async function loadUsers() {
loading.value = true;
feedback.value = { severity: "", message: "" };
const res = await listAdminUsersApi(auth.token, {
const res = await listOemUsersApi(auth.token, {
page: page.value,
pageSize: pageSize.value,
username: filters.value.username,
oemId: filters.value.oem_id,
agentId: filters.value.agent_id,
});
loading.value = false;
@@ -105,6 +144,17 @@ async function onPage(event) {
await loadUsers();
}
async function applyFilters() {
page.value = 1;
await loadUsers();
}
async function resetFilters() {
filters.value = { username: "", oem_id: null, agent_id: null };
page.value = 1;
await loadUsers();
}
function openCreateDialog() {
dialogMode.value = "create";
editingId.value = null;
@@ -168,9 +218,9 @@ async function saveUser() {
showMessage("warn", "请设置初始密码");
return;
}
res = await createAdminUserApi(auth.token, payload);
res = await createOemUserApi(auth.token, payload);
} else {
res = await updateAdminUserApi(auth.token, editingId.value, payload);
res = await updateOemUserApi(auth.token, editingId.value, payload);
}
saving.value = false;
@@ -194,7 +244,7 @@ async function removeUser(row) {
const ok = window.confirm(`确定删除用户「${row.username}」?此操作不可恢复。`);
if (!ok) return;
const res = await deleteAdminUserApi(auth.token, row.id);
const res = await deleteOemUserApi(auth.token, row.id);
if (!res.ok) {
showMessage("error", res.message || "删除失败");
return;
@@ -207,8 +257,9 @@ async function removeUser(row) {
await loadUsers();
}
onMounted(() => {
loadUsers();
onMounted(async () => {
await loadFilterOptions();
await loadUsers();
});
</script>
@@ -217,11 +268,32 @@ onMounted(() => {
<div class="admin-users__header">
<div>
<h1 class="admin-page__title gradient-text">用户管理</h1>
</div>
<Button label="新建用户" @click="openCreateDialog" />
</div>
<div class="admin-users__filters">
<InputText
v-model="filters.username"
placeholder="搜索用户名"
class="admin-users__search"
@keyup.enter="applyFilters"
/>
<Select
v-model="filters.agent_id"
:options="agentOptions"
option-label="username"
option-value="id"
placeholder="全部代理"
show-clear
filter
class="admin-users__filter-select"
/>
<Button label="搜索" @click="applyFilters" />
<Button label="重置" severity="secondary" text @click="resetFilters" />
</div>
<Message
v-if="feedback.message"
:severity="feedback.severity"
@@ -261,6 +333,16 @@ onMounted(() => {
<Tag :value="roleLabel(data.role_id)" :severity="roleSeverity(data.role_id)" />
</template>
</Column>
<Column field="oem_id" header="OEM" style="width: 8rem">
<template #body="{ data }">
{{ ownerLabel(data.oem_id) }}
</template>
</Column>
<Column field="agent_id" header="代理" style="width: 8rem">
<template #body="{ data }">
{{ ownerLabel(data.agent_id) }}
</template>
</Column>
<Column field="vip_end_time" header="VIP 到期">
<template #body="{ data }">
{{ formatDateTime(data.vip_end_time) }}