fix: update stale labels and add callback backlog stats card

Fixed login page (removed I1 tag, updated demo accounts). Added backlog stats bar to CallbackInboxView. Fixed size:500 to size:200 across all list views to match backend @Max(200) validation.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-05-27 08:37:16 +08:00
parent 2e4caf72ce
commit 2609ea3f79
11 changed files with 48 additions and 16 deletions
@@ -20,6 +20,18 @@
</div>
</template>
<div v-if="backlog" class="backlog-bar">
<span :class="['bl-item', { 'bl-warn': backlog.totalPending > 0 }]">
待处理 <strong>{{ backlog.totalPending }}</strong>
</span>
<span :class="['bl-item', { 'bl-danger': backlog.totalFailed > 0 }]">
失败 <strong>{{ backlog.totalFailed }}</strong>
</span>
<span class="bl-item" v-if="backlog.oldestPendingHours > 0">
最久未处理 <strong>{{ backlog.oldestPendingHours }}h</strong>
</span>
</div>
<el-table v-loading="loading" :data="rows" stripe style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="sourceSystem" label="来源" width="120" show-overflow-tooltip />
@@ -84,6 +96,7 @@ import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import { useAuthStore } from "../stores/auth";
import axios from "axios";
import { listCallbackInbox, replayCallbackWebhookDelivery, simulateCallback } from "../api/platform";
import { apiErrorMessage } from "../utils/apiErrorMessage";
@@ -103,6 +116,7 @@ const selectedCallbacks = ref([]);
const simDialogVisible = ref(false);
const simulating = ref(false);
const simForm = ref({ eventType: 'sn:post_activate', snCode: '', rawPayload: '{}' });
const backlog = ref(null);
function handleSelectionChange(val) {
selectedCallbacks.value = val;
@@ -123,9 +137,16 @@ async function handleBatchRetry() {
load();
}
async function loadBacklog() {
try {
const { data } = await axios.get('/api/v1/callback-inbox/stats/backlog');
backlog.value = data;
} catch { /* non-critical */ }
}
onMounted(async () => {
auth.restoreAxiosAuth();
await load();
await Promise.all([load(), loadBacklog()]);
});
function onSizeChange() {
@@ -226,4 +247,10 @@ function goDetail(id) {
display: flex;
justify-content: flex-end;
}
.backlog-bar {
display: flex; gap: 24px; padding: 8px 0 12px; font-size: 13px; color: #606266;
}
.bl-item strong { font-size: 18px; margin: 0 2px; }
.bl-warn { color: #E6A23C; }
.bl-danger { color: #D54941; }
</style>
@@ -185,7 +185,7 @@ function onCustomerChange() {
async function loadCustomers() {
customersLoading.value = true;
try {
const { data } = await listCustomers({ page: 0, size: 500 });
const { data } = await listCustomers({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
customerOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) {
@@ -199,7 +199,7 @@ async function loadCustomers() {
async function loadAllProjects() {
projectsLoading.value = true;
try {
const { data } = await listProjects({ page: 0, size: 500 });
const { data } = await listProjects({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
projectOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) {
@@ -147,8 +147,8 @@ function formatDateTime(v) {
async function loadCustomerProjectMaps() {
try {
const [cRes, pRes] = await Promise.all([
listCustomers({ page: 0, size: 500 }),
listProjects({ page: 0, size: 500 }),
listCustomers({ page: 0, size: 200 }),
listProjects({ page: 0, size: 200 }),
]);
const cBody = cRes.data && typeof cRes.data === "object" ? cRes.data : {};
const pBody = pRes.data && typeof pRes.data === "object" ? pRes.data : {};
@@ -136,7 +136,7 @@ function formatDateTime(v) {
async function loadProjects() {
try {
const { data } = await listProjects({ page: 0, size: 500 });
const { data } = await listProjects({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
const list = Array.isArray(body.content) ? body.content : [];
projectOptions.value = list;
@@ -246,7 +246,7 @@ function formatDateTime(v) {
async function loadProjectMap() {
try {
const { data } = await listProjects({ page: 0, size: 500 });
const { data } = await listProjects({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
const list = Array.isArray(body.content) ? body.content : [];
const m = new Map();
@@ -127,7 +127,7 @@ function contractOptionLabel(c) {
async function loadProjects() {
projectsLoading.value = true;
try {
const { data } = await listProjects({ page: 0, size: 500 });
const { data } = await listProjects({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
projectOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) {
@@ -141,7 +141,7 @@ async function loadProjects() {
async function loadContracts() {
contractsLoading.value = true;
try {
const { data } = await listContracts({ page: 0, size: 500 });
const { data } = await listContracts({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
contractOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) {
@@ -204,7 +204,7 @@ function goList() {
async function loadProjects() {
projectsLoading.value = true;
try {
const { data } = await listProjects({ page: 0, size: 500 });
const { data } = await listProjects({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
projectOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) {
@@ -185,7 +185,7 @@ function formatDateTime(v) {
async function loadProjects() {
try {
const { data } = await listProjects({ page: 0, size: 500 });
const { data } = await listProjects({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
const list = Array.isArray(body.content) ? body.content : [];
projectOptions.value = list;
@@ -90,7 +90,7 @@ function goBack() {
async function loadProjects() {
projectsLoading.value = true;
try {
const { data } = await listProjects({ page: 0, size: 500 });
const { data } = await listProjects({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
projectOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) {
@@ -1,7 +1,7 @@
<template>
<div class="wrap">
<el-card class="card">
<template #header>客户商务与交付管理平台I1</template>
<template #header>客户商务与交付管理平台</template>
<el-form @submit.prevent="onSubmit">
<el-form-item label="用户名">
<el-input v-model="username" autocomplete="username" />
@@ -11,7 +11,7 @@
</el-form-item>
<el-button type="primary" native-type="submit" :loading="loading" block>登录</el-button>
</el-form>
<p class="hint">演示admin / adminSYS_ADMINdev / devDEVELOPERops / opsOPSCallback 运营</p>
<p class="hint">演示admin / admin123SYS_ADMINsales / salesSALESdelivery / deliveryDELIVERYops / opsLICENSE_OPS</p>
</el-card>
</div>
</template>
@@ -30,7 +30,12 @@ const router = useRouter();
const route = useRoute();
const auth = useAuthStore();
onMounted(() => auth.restoreAxiosAuth());
onMounted(() => {
auth.restoreAxiosAuth()
if (route.query.timeout === '1') {
ElMessage.warning('会话已超时,请重新登录')
}
});
async function onSubmit() {
loading.value = true;
@@ -391,7 +391,7 @@ async function loadPhaseDictionary() {
async function loadCustomersForSelect() {
customersLoading.value = true;
try {
const { data } = await listCustomers({ page: 0, size: 500 });
const { data } = await listCustomers({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {};
customerOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) {