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> </div>
</template> </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 v-loading="loading" :data="rows" stripe style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column prop="sourceSystem" label="来源" width="120" show-overflow-tooltip /> <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 { useRouter } from "vue-router";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useAuthStore } from "../stores/auth"; import { useAuthStore } from "../stores/auth";
import axios from "axios";
import { listCallbackInbox, replayCallbackWebhookDelivery, simulateCallback } from "../api/platform"; import { listCallbackInbox, replayCallbackWebhookDelivery, simulateCallback } from "../api/platform";
import { apiErrorMessage } from "../utils/apiErrorMessage"; import { apiErrorMessage } from "../utils/apiErrorMessage";
@@ -103,6 +116,7 @@ const selectedCallbacks = ref([]);
const simDialogVisible = ref(false); const simDialogVisible = ref(false);
const simulating = ref(false); const simulating = ref(false);
const simForm = ref({ eventType: 'sn:post_activate', snCode: '', rawPayload: '{}' }); const simForm = ref({ eventType: 'sn:post_activate', snCode: '', rawPayload: '{}' });
const backlog = ref(null);
function handleSelectionChange(val) { function handleSelectionChange(val) {
selectedCallbacks.value = val; selectedCallbacks.value = val;
@@ -123,9 +137,16 @@ async function handleBatchRetry() {
load(); load();
} }
async function loadBacklog() {
try {
const { data } = await axios.get('/api/v1/callback-inbox/stats/backlog');
backlog.value = data;
} catch { /* non-critical */ }
}
onMounted(async () => { onMounted(async () => {
auth.restoreAxiosAuth(); auth.restoreAxiosAuth();
await load(); await Promise.all([load(), loadBacklog()]);
}); });
function onSizeChange() { function onSizeChange() {
@@ -226,4 +247,10 @@ function goDetail(id) {
display: flex; display: flex;
justify-content: flex-end; 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> </style>
@@ -185,7 +185,7 @@ function onCustomerChange() {
async function loadCustomers() { async function loadCustomers() {
customersLoading.value = true; customersLoading.value = true;
try { try {
const { data } = await listCustomers({ page: 0, size: 500 }); const { data } = await listCustomers({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {}; const body = data && typeof data === "object" ? data : {};
customerOptions.value = Array.isArray(body.content) ? body.content : []; customerOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) { } catch (e) {
@@ -199,7 +199,7 @@ async function loadCustomers() {
async function loadAllProjects() { async function loadAllProjects() {
projectsLoading.value = true; projectsLoading.value = true;
try { 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 body = data && typeof data === "object" ? data : {};
projectOptions.value = Array.isArray(body.content) ? body.content : []; projectOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) { } catch (e) {
@@ -147,8 +147,8 @@ function formatDateTime(v) {
async function loadCustomerProjectMaps() { async function loadCustomerProjectMaps() {
try { try {
const [cRes, pRes] = await Promise.all([ const [cRes, pRes] = await Promise.all([
listCustomers({ page: 0, size: 500 }), listCustomers({ page: 0, size: 200 }),
listProjects({ page: 0, size: 500 }), listProjects({ page: 0, size: 200 }),
]); ]);
const cBody = cRes.data && typeof cRes.data === "object" ? cRes.data : {}; const cBody = cRes.data && typeof cRes.data === "object" ? cRes.data : {};
const pBody = pRes.data && typeof pRes.data === "object" ? pRes.data : {}; const pBody = pRes.data && typeof pRes.data === "object" ? pRes.data : {};
@@ -136,7 +136,7 @@ function formatDateTime(v) {
async function loadProjects() { async function loadProjects() {
try { 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 body = data && typeof data === "object" ? data : {};
const list = Array.isArray(body.content) ? body.content : []; const list = Array.isArray(body.content) ? body.content : [];
projectOptions.value = list; projectOptions.value = list;
@@ -246,7 +246,7 @@ function formatDateTime(v) {
async function loadProjectMap() { async function loadProjectMap() {
try { 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 body = data && typeof data === "object" ? data : {};
const list = Array.isArray(body.content) ? body.content : []; const list = Array.isArray(body.content) ? body.content : [];
const m = new Map(); const m = new Map();
@@ -127,7 +127,7 @@ function contractOptionLabel(c) {
async function loadProjects() { async function loadProjects() {
projectsLoading.value = true; projectsLoading.value = true;
try { 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 body = data && typeof data === "object" ? data : {};
projectOptions.value = Array.isArray(body.content) ? body.content : []; projectOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) { } catch (e) {
@@ -141,7 +141,7 @@ async function loadProjects() {
async function loadContracts() { async function loadContracts() {
contractsLoading.value = true; contractsLoading.value = true;
try { try {
const { data } = await listContracts({ page: 0, size: 500 }); const { data } = await listContracts({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {}; const body = data && typeof data === "object" ? data : {};
contractOptions.value = Array.isArray(body.content) ? body.content : []; contractOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) { } catch (e) {
@@ -204,7 +204,7 @@ function goList() {
async function loadProjects() { async function loadProjects() {
projectsLoading.value = true; projectsLoading.value = true;
try { 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 body = data && typeof data === "object" ? data : {};
projectOptions.value = Array.isArray(body.content) ? body.content : []; projectOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) { } catch (e) {
@@ -185,7 +185,7 @@ function formatDateTime(v) {
async function loadProjects() { async function loadProjects() {
try { 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 body = data && typeof data === "object" ? data : {};
const list = Array.isArray(body.content) ? body.content : []; const list = Array.isArray(body.content) ? body.content : [];
projectOptions.value = list; projectOptions.value = list;
@@ -90,7 +90,7 @@ function goBack() {
async function loadProjects() { async function loadProjects() {
projectsLoading.value = true; projectsLoading.value = true;
try { 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 body = data && typeof data === "object" ? data : {};
projectOptions.value = Array.isArray(body.content) ? body.content : []; projectOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) { } catch (e) {
@@ -1,7 +1,7 @@
<template> <template>
<div class="wrap"> <div class="wrap">
<el-card class="card"> <el-card class="card">
<template #header>客户商务与交付管理平台I1</template> <template #header>客户商务与交付管理平台</template>
<el-form @submit.prevent="onSubmit"> <el-form @submit.prevent="onSubmit">
<el-form-item label="用户名"> <el-form-item label="用户名">
<el-input v-model="username" autocomplete="username" /> <el-input v-model="username" autocomplete="username" />
@@ -11,7 +11,7 @@
</el-form-item> </el-form-item>
<el-button type="primary" native-type="submit" :loading="loading" block>登录</el-button> <el-button type="primary" native-type="submit" :loading="loading" block>登录</el-button>
</el-form> </el-form>
<p class="hint">演示admin / adminSYS_ADMINdev / devDEVELOPERops / opsOPSCallback 运营</p> <p class="hint">演示admin / admin123SYS_ADMINsales / salesSALESdelivery / deliveryDELIVERYops / opsLICENSE_OPS</p>
</el-card> </el-card>
</div> </div>
</template> </template>
@@ -30,7 +30,12 @@ const router = useRouter();
const route = useRoute(); const route = useRoute();
const auth = useAuthStore(); const auth = useAuthStore();
onMounted(() => auth.restoreAxiosAuth()); onMounted(() => {
auth.restoreAxiosAuth()
if (route.query.timeout === '1') {
ElMessage.warning('会话已超时,请重新登录')
}
});
async function onSubmit() { async function onSubmit() {
loading.value = true; loading.value = true;
@@ -391,7 +391,7 @@ async function loadPhaseDictionary() {
async function loadCustomersForSelect() { async function loadCustomersForSelect() {
customersLoading.value = true; customersLoading.value = true;
try { try {
const { data } = await listCustomers({ page: 0, size: 500 }); const { data } = await listCustomers({ page: 0, size: 200 });
const body = data && typeof data === "object" ? data : {}; const body = data && typeof data === "object" ? data : {};
customerOptions.value = Array.isArray(body.content) ? body.content : []; customerOptions.value = Array.isArray(body.content) ? body.content : [];
} catch (e) { } catch (e) {