mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 10:00:30 +08:00
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:
@@ -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 / admin(SYS_ADMIN);dev / dev(DEVELOPER);ops / ops(OPS,Callback 运营)</p>
|
<p class="hint">演示:admin / admin123(SYS_ADMIN);sales / sales(SALES);delivery / delivery(DELIVERY);ops / ops(LICENSE_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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user