|
|
@@ -1,42 +1,88 @@
|
|
|
<script setup lang="ts" name="aidopS8SoOrderExecutionPreview">
|
|
|
-// ORDER-FLOW-FIXTURE-STORE-1:fixture/store 落地预览页。
|
|
|
-// 仅用于本切片自检 105 订单 / 5 客户 / KPI 三均值;本轮不注册菜单 / 不接正式路由 / 不做完整 UI。
|
|
|
-import { computed, onMounted } from 'vue';
|
|
|
-import { useOrderExecutionStore } from '/@/stores/orderExecution';
|
|
|
+// ORDER-FLOW-S8-INTEGRATED-DOMAIN-RESET-1 t3f:前端首个正式 API 接入点。
|
|
|
+// 旧 store / fixture 保留不动;本页旁路 store,直接调用 s8OrderFlowDomainApi 验证:
|
|
|
+// 1. /api/aidop/s8/order-flow/orders 真实出现在 Network;
|
|
|
+// 2. 返回 baseline 订单数且关键字段可在 UI 显示;
|
|
|
+// 3. 客户数 / 订单数 / KPI 三均值由 list 自派生,不查 aggregate(按规约最小接口)。
|
|
|
+// 字段映射(旧 fixture/demo → 新正式):
|
|
|
+// soNo → orderCode
|
|
|
+// customerName → customerName
|
|
|
+// productName → productName
|
|
|
+// currentNode → currentOrderFlowName
|
|
|
+// exceptionCount → exceptionCount
|
|
|
+// kpi.avgResponse → mean(responseMinutes)
|
|
|
+// kpi.avgProcessing → mean(processingMinutes)
|
|
|
+// kpi.avgLoss → mean(totalLossMinutes)
|
|
|
+import { computed, onMounted, ref } from 'vue';
|
|
|
+import {
|
|
|
+ getOrderFlowOrders,
|
|
|
+ type OrderFlowOrderListItem,
|
|
|
+} from '/@/views/aidop/s8/api/s8OrderFlowDomainApi';
|
|
|
|
|
|
-const store = useOrderExecutionStore();
|
|
|
+const orders = ref<OrderFlowOrderListItem[]>([]);
|
|
|
+const loading = ref(false);
|
|
|
+const errorMsg = ref('');
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- store.loadFixture();
|
|
|
+onMounted(async () => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ const list = await getOrderFlowOrders({});
|
|
|
+ orders.value = Array.isArray(list) ? list : [];
|
|
|
+ } catch (err) {
|
|
|
+ errorMsg.value = err instanceof Error ? err.message : String(err);
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
-const customerCount = computed(() => store.customerGroups.length);
|
|
|
-const orderCount = computed(() => store.allOrders.length);
|
|
|
-const kpi = computed(() => store.kpiAverages);
|
|
|
-const observedAt = computed(() => store.currentObservationTime);
|
|
|
-const previewOrders = computed(() => store.filteredOrders.slice(0, 5));
|
|
|
+function avg(values: Array<number | null | undefined>): number {
|
|
|
+ const nums = values.filter((v): v is number => typeof v === 'number' && Number.isFinite(v));
|
|
|
+ if (nums.length === 0) return 0;
|
|
|
+ const sum = nums.reduce((a, b) => a + b, 0);
|
|
|
+ return sum / nums.length;
|
|
|
+}
|
|
|
+
|
|
|
+const orderCount = computed(() => orders.value.length);
|
|
|
+const customerCount = computed(() => {
|
|
|
+ const set = new Set<string>();
|
|
|
+ for (const o of orders.value) {
|
|
|
+ if (o.customerCode) set.add(o.customerCode);
|
|
|
+ }
|
|
|
+ return set.size;
|
|
|
+});
|
|
|
+const kpi = computed(() => ({
|
|
|
+ avgResponse: avg(orders.value.map((o) => o.responseMinutes)),
|
|
|
+ avgProcessing: avg(orders.value.map((o) => o.processingMinutes)),
|
|
|
+ avgLoss: avg(orders.value.map((o) => o.totalLossMinutes)),
|
|
|
+}));
|
|
|
+const previewOrders = computed(() => orders.value.slice(0, 5));
|
|
|
const fmt = (v: number) => v.toFixed(1);
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<div class="so-preview">
|
|
|
- <h2>SO 订单执行档案数据预览</h2>
|
|
|
- <p class="hint">本页仅用于 ORDER-FLOW-FIXTURE-STORE-1 自检;不在正式菜单中。</p>
|
|
|
+ <h2>SO 订单执行档案数据预览(正式 API)</h2>
|
|
|
+ <p class="hint">
|
|
|
+ t3f 切片:直接调用 /api/aidop/s8/order-flow/orders;
|
|
|
+ 客户数 / 订单数 / KPI 三均值由列表自派生。
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <el-alert v-if="errorMsg" :title="errorMsg" type="error" show-icon :closable="false" class="meta" />
|
|
|
|
|
|
- <el-descriptions :column="2" border size="small" class="meta">
|
|
|
+ <el-descriptions :column="2" border size="small" class="meta" v-loading="loading">
|
|
|
<el-descriptions-item label="客户数">{{ customerCount }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="订单数">{{ orderCount }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="平均响应时间">{{ fmt(kpi.avgResponse) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="平均处理时间">{{ fmt(kpi.avgProcessing) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="平均损失时间">{{ fmt(kpi.avgLoss) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="当前观测时间">{{ observedAt }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="平均响应时间(分钟)">{{ fmt(kpi.avgResponse) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="平均处理时间(分钟)">{{ fmt(kpi.avgProcessing) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="平均损失时间(分钟)">{{ fmt(kpi.avgLoss) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="数据源">正式 API</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
- <el-table :data="previewOrders" border size="small" class="orders">
|
|
|
- <el-table-column prop="soNo" label="SO 号" width="160" />
|
|
|
+ <el-table :data="previewOrders" border size="small" class="orders" v-loading="loading">
|
|
|
+ <el-table-column prop="orderCode" label="订单号" width="160" />
|
|
|
<el-table-column prop="customerName" label="客户" width="160" />
|
|
|
<el-table-column prop="productName" label="产品名称" width="180" show-overflow-tooltip />
|
|
|
- <el-table-column prop="currentNode" label="当前节点" width="140" />
|
|
|
+ <el-table-column prop="currentOrderFlowName" label="当前节点" width="140" />
|
|
|
<el-table-column prop="exceptionCount" label="异常数" width="80" />
|
|
|
</el-table>
|
|
|
</div>
|