补充监查访视问题模块内容、翻页功能UI统一
This commit is contained in:
@@ -4,17 +4,30 @@
|
||||
<div class="audit-toolbar">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
<el-select v-model="filters.eventType" clearable :placeholder="TEXT.modules.adminAuditLogs.filterEvent" @change="loadLogs" class="filter-select-comp">
|
||||
<el-select
|
||||
v-model="filters.eventType"
|
||||
clearable
|
||||
:placeholder="TEXT.modules.adminAuditLogs.filterEvent"
|
||||
@change="onServerFilterChange"
|
||||
class="filter-select-comp"
|
||||
>
|
||||
<el-option v-for="opt in eventTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
<el-select v-model="filters.operatorId" clearable :placeholder="TEXT.modules.adminAuditLogs.filterOperator" filterable @change="loadLogs" class="filter-select-comp">
|
||||
<el-select
|
||||
v-model="filters.operatorId"
|
||||
clearable
|
||||
:placeholder="TEXT.modules.adminAuditLogs.filterOperator"
|
||||
filterable
|
||||
@change="onServerFilterChange"
|
||||
class="filter-select-comp"
|
||||
>
|
||||
<el-option v-for="u in userOptions" :key="u.value" :label="u.label" :value="u.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="" class="filter-item-form">
|
||||
<el-select v-model="filters.result" clearable :placeholder="TEXT.modules.adminAuditLogs.filterResult" @change="loadLogs" class="filter-select-result">
|
||||
<el-select v-model="filters.result" clearable :placeholder="TEXT.modules.adminAuditLogs.filterResult" @change="onLocalFilterChange" class="filter-select-result">
|
||||
<el-option :label="TEXT.audit.resultSuccess" value="SUCCESS" />
|
||||
<el-option :label="TEXT.audit.resultFail" value="FAIL" />
|
||||
</el-select>
|
||||
@@ -29,7 +42,7 @@
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
class="date-range-picker-comp"
|
||||
@change="loadLogs"
|
||||
@change="onLocalFilterChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="filter-spacer"></div>
|
||||
@@ -89,14 +102,18 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
layout="prev, pager, next"
|
||||
:page-size="pageSize"
|
||||
:current-page="page"
|
||||
:total="total"
|
||||
@current-change="onPageChange"
|
||||
/>
|
||||
<div class="pagination-wrap" v-if="total > 0">
|
||||
<el-pagination
|
||||
v-model:current-page="page"
|
||||
v-model:page-size="pageSize"
|
||||
:page-sizes="[5, 10, 20]"
|
||||
:total="total"
|
||||
layout="prev, pager, next, sizes, total"
|
||||
small
|
||||
@current-change="onPageChange"
|
||||
@size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
@@ -165,11 +182,11 @@ const router = useRouter();
|
||||
|
||||
const loading = ref(false);
|
||||
const exportLoading = ref(false);
|
||||
const rawLogs = ref<any[]>([]);
|
||||
const logs = ref<any[]>([]);
|
||||
const users = ref<any[]>([]);
|
||||
const allLogs = ref<any[]>([]);
|
||||
const page = ref(1);
|
||||
const pageSize = 20;
|
||||
const pageSize = ref(20);
|
||||
const total = ref(0);
|
||||
const detailVisible = ref(false);
|
||||
const selectedLog = ref<any | null>(null);
|
||||
@@ -224,17 +241,25 @@ const loadLogs = async () => {
|
||||
if (!study.currentStudy) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
const batchLimit = 500;
|
||||
let skip = 0;
|
||||
const allItems: any[] = [];
|
||||
const params: Record<string, any> = {
|
||||
skip: (page.value - 1) * pageSize,
|
||||
limit: pageSize,
|
||||
skip,
|
||||
limit: batchLimit,
|
||||
action: filters.value.eventType || undefined,
|
||||
operator_id: filters.value.operatorId || undefined,
|
||||
};
|
||||
const { data } = await fetchAuditLogs(study.currentStudy.id, params);
|
||||
const items = Array.isArray(data) ? data : (data as any).items || [];
|
||||
rawLogs.value = items;
|
||||
total.value = (data as any).total || items.length;
|
||||
enrichLogs();
|
||||
while (true) {
|
||||
params.skip = skip;
|
||||
const { data } = await fetchAuditLogs(study.currentStudy.id, params);
|
||||
const items = Array.isArray(data) ? data : (data as any).items || [];
|
||||
allItems.push(...items);
|
||||
if (items.length < batchLimit) break;
|
||||
skip += items.length;
|
||||
}
|
||||
enrichLogs(allItems);
|
||||
refreshPagedLogs();
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.message || TEXT.modules.adminAuditLogs.loadFailed);
|
||||
} finally {
|
||||
@@ -242,30 +267,17 @@ const loadLogs = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const enrichLogs = () => {
|
||||
const enrichLogs = (items: any[]) => {
|
||||
const userMap = users.value.reduce<Record<string, string>>((acc, cur) => {
|
||||
acc[cur.id] = resolveUserDisplayName(cur);
|
||||
return acc;
|
||||
}, {});
|
||||
const filtered = rawLogs.value.filter((log) => {
|
||||
if (filters.value.eventType && String(log.action || "") !== filters.value.eventType) return false;
|
||||
if (filters.value.operatorId && String(log.operator_id || "") !== filters.value.operatorId) return false;
|
||||
if (filters.value.result && (log.result || "SUCCESS") !== filters.value.result) return false;
|
||||
if (filters.value.range?.length === 2) {
|
||||
const ts = new Date(log.created_at);
|
||||
const start = new Date(filters.value.range[0]);
|
||||
const end = new Date(filters.value.range[1]);
|
||||
if (ts < start || ts > end) return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
logs.value = filtered
|
||||
allLogs.value = items
|
||||
.map((log) => normalizeAuditEvent(log, userMap))
|
||||
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
|
||||
.slice(0, pageSize);
|
||||
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
||||
if (users.value.length === 0) {
|
||||
const byActor = new Map<string, string>();
|
||||
logs.value.forEach((log) => {
|
||||
allLogs.value.forEach((log) => {
|
||||
if (!byActor.has(log.actorId)) {
|
||||
byActor.set(log.actorId, log.actorName || log.actorId);
|
||||
}
|
||||
@@ -274,9 +286,46 @@ const enrichLogs = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const filterLogs = (items: any[]) =>
|
||||
items.filter((log) => {
|
||||
if (filters.value.result && (log.result || "SUCCESS") !== filters.value.result) return false;
|
||||
if (filters.value.range?.length === 2) {
|
||||
const ts = new Date(log.timestamp);
|
||||
const start = new Date(filters.value.range[0]);
|
||||
const end = new Date(filters.value.range[1]);
|
||||
if (ts < start || ts > end) return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const refreshPagedLogs = () => {
|
||||
const filtered = filterLogs(allLogs.value);
|
||||
total.value = filtered.length;
|
||||
const maxPage = Math.max(1, Math.ceil(total.value / pageSize.value));
|
||||
if (page.value > maxPage) page.value = maxPage;
|
||||
const start = (page.value - 1) * pageSize.value;
|
||||
logs.value = filtered.slice(start, start + pageSize.value);
|
||||
};
|
||||
|
||||
const onServerFilterChange = () => {
|
||||
page.value = 1;
|
||||
loadLogs();
|
||||
};
|
||||
|
||||
const onLocalFilterChange = () => {
|
||||
page.value = 1;
|
||||
refreshPagedLogs();
|
||||
};
|
||||
|
||||
const onPageChange = (p: number) => {
|
||||
page.value = p;
|
||||
loadLogs();
|
||||
refreshPagedLogs();
|
||||
};
|
||||
|
||||
const onPageSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
page.value = 1;
|
||||
refreshPagedLogs();
|
||||
};
|
||||
|
||||
const getDiffPreview = (log: any) => {
|
||||
@@ -459,8 +508,8 @@ onMounted(async () => {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 12px;
|
||||
.pagination-wrap {
|
||||
margin-top: 14px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@@ -71,15 +71,18 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next, total"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
v-model:current-page="page"
|
||||
@current-change="loadUsers"
|
||||
class="pagination"
|
||||
/>
|
||||
<div class="pagination-wrap" v-if="total > 0">
|
||||
<el-pagination
|
||||
v-model:current-page="page"
|
||||
v-model:page-size="pageSize"
|
||||
:page-sizes="[5, 10, 20]"
|
||||
:total="total"
|
||||
layout="prev, pager, next, sizes, total"
|
||||
small
|
||||
@current-change="loadUsers"
|
||||
@size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<UserForm v-model:visible="formVisible" :user="editingUser" :admin-count="activeAdminCount" @saved="loadUsers" />
|
||||
@@ -170,6 +173,12 @@ const loadUsers = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const onPageSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
page.value = 1;
|
||||
loadUsers();
|
||||
};
|
||||
|
||||
const openCreate = () => {
|
||||
editingUser.value = null;
|
||||
formVisible.value = true;
|
||||
@@ -309,8 +318,8 @@ onMounted(() => {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 12px;
|
||||
.pagination-wrap {
|
||||
margin-top: 14px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user