perf: paginate admin audit lists
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { computed, onMounted, reactive, ref } from "vue";
|
||||
import { computed, onMounted, reactive, ref, watch } from "vue";
|
||||
|
||||
import AdminLoginView from "./components/AdminLoginView.vue";
|
||||
import AdminPagination from "./components/AdminPagination.vue";
|
||||
import KnowledgeManagementView from "./components/KnowledgeManagementView.vue";
|
||||
import TableRowActions from "./components/TableRowActions.vue";
|
||||
import { systemSettingDefinitions, systemSettingSections, type SystemSettingValue } from "./config/systemSettings";
|
||||
@@ -55,6 +56,14 @@ const chatDetailOpen = ref(false);
|
||||
const selectedAiLog = ref<AiLogRecord | null>(null);
|
||||
const aiLogDetailOpen = ref(false);
|
||||
const recordTab = ref("chats");
|
||||
const pagers = reactive({
|
||||
users: { page: 1, pageSize: 20, total: 0 },
|
||||
chats: { page: 1, pageSize: 20, total: 0 },
|
||||
aiLogs: { page: 1, pageSize: 20, total: 0 },
|
||||
operationLogs: { page: 1, pageSize: 20, total: 0 },
|
||||
retrievals: { page: 1, pageSize: 20, total: 0 },
|
||||
attention: { page: 1, pageSize: 20, total: 0 },
|
||||
});
|
||||
const editingModelId = ref<number | null>(null);
|
||||
const editingKnowledgeId = ref<number | null>(null);
|
||||
const batchNodeToken = ref("");
|
||||
@@ -210,6 +219,10 @@ const agentForm = reactive({
|
||||
question: "",
|
||||
});
|
||||
|
||||
watch(recordTab, async (tab) => {
|
||||
if (activeMenu.value === "records") await loadRecordTab(tab);
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
if (!getToken()) return;
|
||||
try {
|
||||
@@ -268,10 +281,9 @@ async function loadCurrentMenu() {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (activeMenu.value === "dashboard") await loadDashboard();
|
||||
if (activeMenu.value === "users") users.value = await api.users(userKeyword.value);
|
||||
if (activeMenu.value === "knowledge") knowledge.value = await api.knowledge();
|
||||
if (activeMenu.value === "users") await loadUsers(pagers.users.page, pagers.users.pageSize);
|
||||
if (activeMenu.value === "prompt") {
|
||||
const [prompt, modelRows, knowledgeRows] = await Promise.all([api.prompt(), api.models(), api.knowledge()]);
|
||||
const [prompt, modelRows, knowledgeRows] = await Promise.all([api.prompt(), api.models(), api.knowledgeOptions()]);
|
||||
promptContent.value = prompt.promptContent;
|
||||
models.value = modelRows;
|
||||
knowledge.value = knowledgeRows;
|
||||
@@ -285,18 +297,51 @@ async function loadCurrentMenu() {
|
||||
configs.value = await api.configs();
|
||||
hydrateSystemSettings();
|
||||
}
|
||||
if (activeMenu.value === "records") {
|
||||
chats.value = await api.chats(buildChatQuery());
|
||||
aiLogs.value = await api.aiLogs();
|
||||
operationLogs.value = await api.operationLogs();
|
||||
}
|
||||
if (activeMenu.value === "retrievals") { const [logs, retention] = await Promise.all([api.retrievalLogs(), api.retrievalRetention()]); retrievalLogs.value = logs; retentionDays.value = retention.retentionDays; retentionState.value = retention; }
|
||||
if (activeMenu.value === "attention") attentionRecords.value = await api.attentionList();
|
||||
if (activeMenu.value === "records") await loadRecordTab(recordTab.value);
|
||||
if (activeMenu.value === "retrievals") { const [logs, retention] = await Promise.all([api.retrievalLogs({ page: pagers.retrievals.page, pageSize: pagers.retrievals.pageSize }), api.retrievalRetention()]); retrievalLogs.value = logs.items; Object.assign(pagers.retrievals, { page: logs.page, pageSize: logs.pageSize, total: logs.total }); retentionDays.value = retention.retentionDays; retentionState.value = retention; }
|
||||
if (activeMenu.value === "attention") await loadAttention(pagers.attention.page, pagers.attention.pageSize);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadUsers(page = 1, pageSize = pagers.users.pageSize) {
|
||||
const result = await api.users({ keyword: userKeyword.value, page, pageSize });
|
||||
users.value = result.items;
|
||||
Object.assign(pagers.users, { page: result.page, pageSize: result.pageSize, total: result.total });
|
||||
}
|
||||
|
||||
async function loadRecordTab(tab = recordTab.value) {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (tab === "chats") {
|
||||
const result = await api.chats({ ...buildChatQuery(), page: pagers.chats.page, pageSize: pagers.chats.pageSize });
|
||||
chats.value = result.items; Object.assign(pagers.chats, { page: result.page, pageSize: result.pageSize, total: result.total });
|
||||
} else if (tab === "aiLogs") {
|
||||
const result = await api.aiLogs({ page: pagers.aiLogs.page, pageSize: pagers.aiLogs.pageSize });
|
||||
aiLogs.value = result.items; Object.assign(pagers.aiLogs, { page: result.page, pageSize: result.pageSize, total: result.total });
|
||||
} else {
|
||||
const result = await api.operationLogs({ page: pagers.operationLogs.page, pageSize: pagers.operationLogs.pageSize });
|
||||
operationLogs.value = result.items; Object.assign(pagers.operationLogs, { page: result.page, pageSize: result.pageSize, total: result.total });
|
||||
}
|
||||
} finally { loading.value = false; }
|
||||
}
|
||||
|
||||
async function changeRecordPage(tab: "chats" | "aiLogs" | "operationLogs", page: number, pageSize: number) {
|
||||
Object.assign(pagers[tab], { page, pageSize });
|
||||
await loadRecordTab(tab);
|
||||
}
|
||||
|
||||
async function loadRetrievals(page = 1, pageSize = pagers.retrievals.pageSize) {
|
||||
const result = await api.retrievalLogs({ page, pageSize });
|
||||
retrievalLogs.value = result.items; Object.assign(pagers.retrievals, { page: result.page, pageSize: result.pageSize, total: result.total });
|
||||
}
|
||||
|
||||
async function loadAttention(page = 1, pageSize = pagers.attention.pageSize) {
|
||||
const result = await api.attentionList({ page, pageSize });
|
||||
attentionRecords.value = result.items; Object.assign(pagers.attention, { page: result.page, pageSize: result.pageSize, total: result.total });
|
||||
}
|
||||
|
||||
async function saveUser(row: AdminUser) {
|
||||
await api.updateUser(row.id, { status: row.status, dailyChatLimit: row.dailyChatLimit });
|
||||
ElMessage.success("用户已更新");
|
||||
@@ -766,7 +811,7 @@ async function openRetrievalDetail(row: RetrievalLogItem) {
|
||||
async function updateAttentionStatus(row: AttentionItem, status: string) {
|
||||
await api.updateAttention(row.id, status);
|
||||
ElMessage.success("人工关注状态已更新");
|
||||
attentionRecords.value = await api.attentionList();
|
||||
await loadAttention(pagers.attention.page, pagers.attention.pageSize);
|
||||
}
|
||||
|
||||
async function deleteAttentionRecord(row: AttentionItem) {
|
||||
@@ -779,7 +824,7 @@ async function deleteAttentionRecord(row: AttentionItem) {
|
||||
}
|
||||
await api.deleteAttention(row.id);
|
||||
ElMessage.success("人工关注记录已删除");
|
||||
attentionRecords.value = await api.attentionList();
|
||||
await loadAttention(pagers.attention.page, pagers.attention.pageSize);
|
||||
}
|
||||
|
||||
function attentionPriorityLabel(priority: string) {
|
||||
@@ -796,7 +841,8 @@ async function clearFeishuCache() {
|
||||
}
|
||||
|
||||
async function searchChats() {
|
||||
chats.value = await api.chats(buildChatQuery());
|
||||
pagers.chats.page = 1;
|
||||
await loadRecordTab("chats");
|
||||
}
|
||||
|
||||
async function resetChatFilters() {
|
||||
@@ -900,7 +946,7 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
|
||||
<template v-if="activeMenu === 'users'">
|
||||
<div class="page-head inline">
|
||||
<div><h2>用户管理</h2><p>维护学员名单;只有名单内启用学员可以登录用户端。</p></div>
|
||||
<el-input v-model="userKeyword" placeholder="手机号或姓名" clearable @change="loadCurrentMenu" />
|
||||
<el-input v-model="userKeyword" placeholder="手机号或姓名" clearable @change="loadUsers(1)" />
|
||||
</div>
|
||||
<section class="student-tools">
|
||||
<div class="student-tool-panel">
|
||||
@@ -972,6 +1018,7 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<AdminPagination :page="pagers.users.page" :page-size="pagers.users.pageSize" :total="pagers.users.total" @change="loadUsers" />
|
||||
</template>
|
||||
|
||||
<template v-if="activeMenu === 'knowledge'">
|
||||
@@ -1260,6 +1307,7 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
|
||||
<el-table-column prop="createdAt" label="时间" width="180" />
|
||||
<el-table-column label="操作" width="90" fixed="right"><template #default="{ row }"><el-button link type="primary" @click="openRetrievalDetail(row)">详情</el-button></template></el-table-column>
|
||||
</el-table>
|
||||
<AdminPagination :page="pagers.retrievals.page" :page-size="pagers.retrievals.pageSize" :total="pagers.retrievals.total" @change="loadRetrievals" />
|
||||
</template>
|
||||
|
||||
<template v-if="activeMenu === 'attention'">
|
||||
@@ -1274,6 +1322,7 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
|
||||
<el-table-column prop="createdAt" label="创建时间" width="180" />
|
||||
<el-table-column label="操作" width="130" fixed="right"><template #default="{ row }"><el-button link type="primary" @click="openChatSession(row.sessionId)">原会话</el-button><el-button link type="danger" @click="deleteAttentionRecord(row)">删除</el-button></template></el-table-column>
|
||||
</el-table>
|
||||
<AdminPagination :page="pagers.attention.page" :page-size="pagers.attention.pageSize" :total="pagers.attention.total" @change="loadAttention" />
|
||||
</template>
|
||||
|
||||
<template v-if="activeMenu === 'records'">
|
||||
@@ -1307,7 +1356,7 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
|
||||
<el-button @click="exportChats">导出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="chats" stripe>
|
||||
<el-table v-loading="loading" :data="chats" stripe>
|
||||
<el-table-column prop="id" label="会话ID" width="90" />
|
||||
<el-table-column prop="userPhone" label="手机号" width="140" />
|
||||
<el-table-column prop="userName" label="用户" width="120" />
|
||||
@@ -1320,9 +1369,10 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<AdminPagination :page="pagers.chats.page" :page-size="pagers.chats.pageSize" :total="pagers.chats.total" @change="(page, pageSize) => changeRecordPage('chats', page, pageSize)" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="AI 请求" name="aiLogs">
|
||||
<el-table :data="aiLogs" stripe>
|
||||
<el-table v-loading="loading" :data="aiLogs" stripe>
|
||||
<el-table-column prop="sessionId" label="会话ID" width="90" />
|
||||
<el-table-column prop="modelName" label="模型" width="160" />
|
||||
<el-table-column prop="knowledgeIds" label="知识库" width="120" />
|
||||
@@ -1342,14 +1392,16 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<AdminPagination :page="pagers.aiLogs.page" :page-size="pagers.aiLogs.pageSize" :total="pagers.aiLogs.total" @change="(page, pageSize) => changeRecordPage('aiLogs', page, pageSize)" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="操作日志" name="operationLogs">
|
||||
<el-table :data="operationLogs" stripe>
|
||||
<el-table v-loading="loading" :data="operationLogs" stripe>
|
||||
<el-table-column prop="module" label="模块" />
|
||||
<el-table-column prop="action" label="动作" />
|
||||
<el-table-column prop="result" label="结果" />
|
||||
<el-table-column prop="createdAt" label="时间" />
|
||||
</el-table>
|
||||
<AdminPagination :page="pagers.operationLogs.page" :page-size="pagers.operationLogs.pageSize" :total="pagers.operationLogs.total" @change="(page, pageSize) => changeRecordPage('operationLogs', page, pageSize)" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user