Просмотр исходного кода

fix(s8): add order-level body production drilldown data

替换 ManufacturingDetailPanel 纯前端 fixture 为完整 DB→API→UI 链路:
- 新增 3 张本体生产订单级表(process / loss_factor / operator)+ 221 行 SEED 数据
- service GetManufacturingPivotAsync 支持 BASELINE_PPT / CURRENT_FILTERED 两 scope
- TOTAL.achievement_rate / status 锚定 fixture 0.90 / yellow,不做 plan_qty 加权
- pending 订单(016/017/018/019)返回空骨架,不 fallback baseline / fixture
- 单订单守恒:Σ(P10/P20/P30/P40 actual) = stage.actual_days
- 多订单:actual=AVG / plan_qty=SUM / TOTAL.rate=0.9 锚定

后端版本号 1.0.149 → 1.0.150(含 SQL 1.0.150.sql 已注册 csproj Copy)
前端版本号 2.4.177 → 2.4.178
YY968XX 3 дней назад
Родитель
Сommit
84bfdea807

+ 1 - 1
Web/package.json

@@ -1,7 +1,7 @@
 {
 	"name": "admin.net",
 	"type": "module",
-	"version": "2.4.177",
+	"version": "2.4.178",
 	"packageManager": "pnpm@10.32.1",
 	"lastBuildTime": "2026.03.15",
 	"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",

+ 62 - 0
Web/src/views/aidop/s8/api/s8OrderFlowDomainApi.ts

@@ -272,6 +272,61 @@ export interface OrderFlowProductDesignDrawings {
 	drawings: OrderFlowProductDesignDrawingItem[];
 }
 
+// ────────────────────────────────────────────────────────────
+// Manufacturing pivot (S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1)
+// 本体生产「工序明细 / 损失因素 / 操作员表现」三表透视。
+// scope=BASELINE_PPT 直接读 baseline;scope=CURRENT_FILTERED 走订单级行聚合。
+// ────────────────────────────────────────────────────────────
+
+export interface OrderFlowManufacturingPivotQuery {
+	tenantId?: number;
+	factoryId?: number;
+	/** BASELINE_PPT | CURRENT_FILTERED */
+	scope: string;
+	/**
+	 * 订单编码 CSV(与产品设计 drawings / 采购透视 API 对齐):
+	 * 单订单 "SO-2026-001";多订单 "SO-2026-001,SO-2026-002,SO-2026-006"。
+	 * 不使用数组以避免 axios 默认 brackets 序列化与 ASP.NET Core List 绑定二义性。
+	 */
+	orderCodes?: string;
+}
+
+export interface OrderFlowManufacturingProcess {
+	processCode: string;
+	processName: string;
+	piDays: number;
+	actualDays: number;
+	cycleStatus: string;
+	planQty: number | null;
+	achievementRate: number | null;
+	achievementStatus: string;
+	sortNo: number;
+}
+
+export interface OrderFlowManufacturingLossFactor {
+	factorCode: string;
+	factorName: string;
+	countValue: number | null;
+	ratioPct: number | null;
+	lossHours: number | null;
+	sortNo: number;
+}
+
+export interface OrderFlowManufacturingOperator {
+	operatorCode: string;
+	operatorName: string;
+	avgHours: number;
+	status: string;
+	sortNo: number;
+}
+
+export interface OrderFlowManufacturingPivot {
+	scope: string;
+	processes: OrderFlowManufacturingProcess[];
+	lossFactors: OrderFlowManufacturingLossFactor[];
+	operators: OrderFlowManufacturingOperator[];
+}
+
 // ────────────────────────────────────────────────────────────
 // API methods
 // ────────────────────────────────────────────────────────────
@@ -318,6 +373,12 @@ export function getOrderFlowProductDesignDrawings(query: OrderFlowProductDesignD
 		.then(unwrap);
 }
 
+export function getOrderFlowManufacturingPivot(query: OrderFlowManufacturingPivotQuery) {
+	return service
+		.get<OrderFlowManufacturingPivot>(`${BASE}/manufacturing-pivot`, { params: query })
+		.then(unwrap);
+}
+
 export const s8OrderFlowDomainApi = {
 	getOrderFlowOrders,
 	getOrderFlowOrder,
@@ -325,4 +386,5 @@ export const s8OrderFlowDomainApi = {
 	getOrderFlowAggregate,
 	getOrderFlowProcurementPivot,
 	getOrderFlowProductDesignDrawings,
+	getOrderFlowManufacturingPivot,
 };

+ 70 - 4
Web/src/views/aidop/s8/monitoring/OrderChainOverviewPage.vue

@@ -21,13 +21,17 @@ import ProcurementDetailPanel from './components/order-execution/ProcurementDeta
 import ManufacturingDetailPanel from './components/order-execution/ManufacturingDetailPanel.vue';
 import FinalAssemblyCollabPanel from './components/order-execution/FinalAssemblyCollabPanel.vue';
 import {
-	MANUFACTURING_DETAIL_FIXTURE,
 	adaptProcurementPivotFromApi,
+	adaptManufacturingPivotFromApi,
 	type ProcurementDetailFromApi,
+	type ManufacturingDetailFromApi,
 } from '/@/views/aidop/s8/monitoring/data/order-execution/stage-detail';
 // S8-ORDER-CHAIN-PRODUCT-DESIGN-PPT-STATIC-AND-SINGLE-ORDER-ALIGN-1:默认不勾选态产品设计业务基线数据。
 import { PRODUCT_DESIGN_BASELINE_DETAIL } from '/@/views/aidop/s8/monitoring/data/order-execution/product-design-baseline';
-import { getOrderFlowProcurementPivot } from '/@/views/aidop/s8/api/s8OrderFlowDomainApi';
+import {
+	getOrderFlowProcurementPivot,
+	getOrderFlowManufacturingPivot,
+} from '/@/views/aidop/s8/api/s8OrderFlowDomainApi';
 // ORDER-FLOW-CHAIN-PAGE2-ORIGINAL-LOGIC-RESTORE-1:baseline (isUnfiltered) 态下 L2/L3 使用 PPT 常量。
 import {
 	PPT_REVIEW_SUBSTEPS,
@@ -404,6 +408,58 @@ watch(
 	{ immediate: true },
 );
 
+// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:本体生产矩阵按订单粒度二态加载。
+//   默认(isUnfiltered=true)→ scope=BASELINE_PPT,不传 orderCodes,显示 baseline (5 工序 + 5 损失 + 3 操作员)。
+//   单订单态 → scope=CURRENT_FILTERED,orderCodes=[detailOrder.soNo]:
+//     - 非 pending 单:显示该订单 13 行订单级数据。
+//     - pending 单(016/017/018/019):返回空骨架 → 面板展示「暂无本体生产数据」。
+//   多订单态 → scope=CURRENT_FILTERED,orderCodes=filteredChainOrders.map(soNo),
+//     后端按工序/因素/操作员聚合(actual_days AVG / plan_qty SUM / loss count SUM / 操作员 AVG)。
+//   不使用全局 load-once guard;每次 isUnfiltered / filteredChainOrders / showManufacturingDetail 任一变化重新拉取。
+//   in-flight 请求用 seq 去重,防止旧响应覆盖新响应;失败仅显示错误态,不静默回退 fixture / baseline。
+const manufacturingApiDetail = ref<ManufacturingDetailFromApi | null>(null);
+const manufacturingApiLoading = ref(false);
+const manufacturingApiError = ref<string | null>(null);
+let manufacturingRequestSeq = 0;
+
+async function loadManufacturingPivot() {
+	const mySeq = ++manufacturingRequestSeq;
+	const isBaseline = isUnfiltered.value;
+	const scope = isBaseline ? 'BASELINE_PPT' : 'CURRENT_FILTERED';
+	// CSV 字符串与产品设计 drawings / 采购透视 API 一致。
+	const orderCodes = isBaseline
+		? undefined
+		: filteredChainOrders.value.map((o) => o.soNo).join(',');
+
+	manufacturingApiLoading.value = true;
+	manufacturingApiError.value = null;
+	try {
+		const pivot = await getOrderFlowManufacturingPivot({ scope, orderCodes });
+		if (mySeq !== manufacturingRequestSeq) return;
+		manufacturingApiDetail.value = adaptManufacturingPivotFromApi(pivot);
+	} catch (e) {
+		if (mySeq !== manufacturingRequestSeq) return;
+		manufacturingApiError.value = '本体生产数据加载失败,请稍后重试';
+		manufacturingApiDetail.value = null;
+	} finally {
+		if (mySeq === manufacturingRequestSeq) {
+			manufacturingApiLoading.value = false;
+		}
+	}
+}
+
+watch(
+	[
+		() => showManufacturingDetail.value,
+		() => isUnfiltered.value,
+		() => filteredChainOrders.value,
+	],
+	([active]) => {
+		if (active) void loadManufacturingPivot();
+	},
+	{ immediate: true },
+);
+
 // S8-ORDER-CHAIN-PRODUCT-DESIGN-PPT-STATIC-AND-SINGLE-ORDER-ALIGN-1:产品设计阶段二态数据源。
 // 默认不勾选态(isUnfiltered=true)→ 直接使用前端业务基线数据 PRODUCT_DESIGN_BASELINE_DETAIL,
 //   不调用 /api/aidop/s8/order-flow/product-design/drawings 接口。
@@ -530,7 +586,12 @@ watch(
 				:loading="procurementApiLoading"
 				:error-message="procurementApiError"
 			/>
-			<ManufacturingDetailPanel v-if="showManufacturingDetail" :detail="MANUFACTURING_DETAIL_FIXTURE" />
+			<ManufacturingDetailPanel
+				v-if="showManufacturingDetail"
+				:api-detail="manufacturingApiDetail"
+				:loading="manufacturingApiLoading"
+				:error-message="manufacturingApiError"
+			/>
 			<FinalAssemblyCollabPanel
 				v-if="showFinalAssemblyCollab"
 				:aggregate-final="finalStageSnapshot"
@@ -596,7 +657,12 @@ watch(
 				:loading="procurementApiLoading"
 				:error-message="procurementApiError"
 			/>
-			<ManufacturingDetailPanel v-if="showManufacturingDetail" :detail="MANUFACTURING_DETAIL_FIXTURE" />
+			<ManufacturingDetailPanel
+				v-if="showManufacturingDetail"
+				:api-detail="manufacturingApiDetail"
+				:loading="manufacturingApiLoading"
+				:error-message="manufacturingApiError"
+			/>
 			<FinalAssemblyCollabPanel
 				v-if="showFinalAssemblyCollab"
 				:aggregate-final="finalStageSnapshot"

+ 205 - 49
Web/src/views/aidop/s8/monitoring/components/order-execution/ManufacturingDetailPanel.vue

@@ -1,17 +1,66 @@
 <script setup lang="ts" name="ManufacturingDetailPanel">
-// ORDER-FLOW-CHAIN-STAGE-DETAIL-MIGRATE-1:设备制造(本体生产)阶段结构化详情。fixture 来源 ecc-sandbox 硬编码;非真实数据。
+// ORDER-FLOW-CHAIN-STAGE-DETAIL-MIGRATE-1:设备制造(本体生产)阶段结构化详情。
+// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:默认走真实 API(apiDetail),
+// fixture 仅在 demoMode=true 时显示;与 ProcurementDetailPanel 一致的双模式。
+import { computed } from 'vue';
 import type {
 	ManufacturingDetail,
+	ManufacturingDetailFromApi,
+	ProcurementApiStatusTone,
 	StageDetailStatus,
 } from '/@/views/aidop/s8/monitoring/data/order-execution/stage-detail';
 
-defineProps<{ detail: ManufacturingDetail }>();
+type PanelMode = 'api' | 'fixture';
 
-function statusColor(s: StageDetailStatus): string {
+const props = defineProps<{
+	/** API 模式:真实数据;优先使用。 */
+	apiDetail?: ManufacturingDetailFromApi | null;
+	/** 显式演示数据模式:仅当 demoMode=true 时使用 fixture,否则 fixture 不进入渲染。 */
+	detail?: ManufacturingDetail;
+	/** 显式演示数据模式开关;默认 false。 */
+	demoMode?: boolean;
+	/** API 加载中。 */
+	loading?: boolean;
+	/** API 加载失败时的错误信息(任意非空字符串触发错误态)。 */
+	errorMessage?: string | null;
+}>();
+
+const mode = computed<PanelMode>(() => (props.demoMode && props.detail ? 'fixture' : 'api'));
+
+// ────────────────────────────────────────────────────────────
+// fixture 模式(演示数据;非默认)
+// ────────────────────────────────────────────────────────────
+function fixtureStatusColor(s: StageDetailStatus): string {
 	if (s === 'red') return '#ff4d4f';
 	if (s === 'yellow') return '#ffc107';
 	return '#88fd54';
 }
+
+// ────────────────────────────────────────────────────────────
+// API 模式(真实数据;默认)
+// ────────────────────────────────────────────────────────────
+function apiToneColor(tone: ProcurementApiStatusTone): string {
+	if (tone === 'red') return '#ff4d4f';
+	if (tone === 'yellow') return '#ffc107';
+	if (tone === 'green') return '#88fd54';
+	return '#909097';
+}
+
+const isApiLoading = computed(() => mode.value === 'api' && !!props.loading);
+const apiErrorText = computed(() => (mode.value === 'api' ? (props.errorMessage ?? '').trim() : ''));
+const isApiError = computed(() => apiErrorText.value.length > 0);
+const isApiEmpty = computed(() => {
+	if (mode.value !== 'api') return false;
+	if (isApiLoading.value || isApiError.value) return false;
+	const d = props.apiDetail;
+	if (!d) return true;
+	return d.processes.length === 0 && d.lossFactors.length === 0 && d.operators.length === 0;
+});
+
+// 「作业效率损失」高亮:与 fixture 视觉一致;用 factorCode 而非 factorName 判定,避免后端名称变更打破样式。
+function highlightLossRow(factorCode: string): boolean {
+	return factorCode === 'EFFICIENCY';
+}
 </script>
 
 <template>
@@ -19,61 +68,155 @@ function statusColor(s: StageDetailStatus): string {
 		<header class="mfg-panel__head">
 			<span class="mfg-panel__bar" />
 			<h2 class="mfg-panel__title">设备制造(本体生产) · 阶段详情</h2>
+			<span v-if="mode === 'fixture'" class="mfg-panel__demo">演示数据</span>
 		</header>
 
-		<div class="mfg-panel__block">
-			<div class="mfg-panel__caption">工序明细</div>
-			<table class="mfg-panel__table">
-				<thead>
-					<tr><th>工序</th><th>PI</th><th>平均周期</th><th>周期状态</th><th>影响台次</th><th>计划达成率</th><th>计划状态</th></tr>
-				</thead>
-				<tbody>
-					<tr v-for="row in detail.processRows" :key="row.process">
-						<td>{{ row.process }}</td>
-						<td>{{ row.pi }}</td>
-						<td :style="{ color: statusColor(row.cycleStatus), fontWeight: 600 }">{{ row.avgCycle }}</td>
-						<td><span class="mfg-panel__dot" :style="{ background: statusColor(row.cycleStatus) }" /></td>
-						<td>{{ row.impactCount ?? '—' }}</td>
-						<td :style="{ color: statusColor(row.planRateStatus), fontWeight: 600 }">{{ row.planRate }}</td>
-						<td><span class="mfg-panel__dot" :style="{ background: statusColor(row.planRateStatus) }" /></td>
-					</tr>
-				</tbody>
-			</table>
-		</div>
-
-		<div class="mfg-panel__split">
-			<div class="mfg-panel__block mfg-panel__block--half">
-				<div class="mfg-panel__caption">10 工序 · 操作员表现</div>
+		<!-- fixture 模式(演示数据;非默认) -->
+		<template v-if="mode === 'fixture' && detail">
+			<div class="mfg-panel__block">
+				<div class="mfg-panel__caption">工序明细</div>
 				<table class="mfg-panel__table">
-					<thead><tr><th>操作员</th><th>平均工时</th><th>达标</th></tr></thead>
+					<thead>
+						<tr><th>工序</th><th>PI</th><th>平均周期</th><th>周期状态</th><th>影响台次</th><th>计划达成率</th><th>计划状态</th></tr>
+					</thead>
 					<tbody>
-						<tr v-for="row in detail.operators" :key="row.name">
-							<td>{{ row.name }}</td>
-							<td :style="{ color: statusColor(row.status), fontWeight: 600 }">{{ row.avgHours }}</td>
-							<td><span class="mfg-panel__dot" :style="{ background: statusColor(row.status) }" /></td>
+						<tr v-for="row in detail.processRows" :key="row.process">
+							<td>{{ row.process }}</td>
+							<td>{{ row.pi }}</td>
+							<td :style="{ color: fixtureStatusColor(row.cycleStatus), fontWeight: 600 }">{{ row.avgCycle }}</td>
+							<td><span class="mfg-panel__dot" :style="{ background: fixtureStatusColor(row.cycleStatus) }" /></td>
+							<td>{{ row.impactCount ?? '—' }}</td>
+							<td :style="{ color: fixtureStatusColor(row.planRateStatus), fontWeight: 600 }">{{ row.planRate }}</td>
+							<td><span class="mfg-panel__dot" :style="{ background: fixtureStatusColor(row.planRateStatus) }" /></td>
 						</tr>
 					</tbody>
 				</table>
 			</div>
-			<div class="mfg-panel__block mfg-panel__block--half">
-				<div class="mfg-panel__caption">10 工序 · 损失因素</div>
-				<table class="mfg-panel__table">
-					<thead><tr><th>因素</th><th>件数</th><th>占比</th><th>损失工时</th></tr></thead>
-					<tbody>
-						<tr
-							v-for="row in detail.lossFactors"
-							:key="row.factor"
-							:style="row.factor === '作业效率损失' ? { color: '#ff4d4f', fontWeight: 700 } : undefined"
-						>
-							<td>{{ row.factor }}</td>
-							<td>{{ row.count }}</td>
-							<td>{{ row.ratio }}</td>
-							<td>{{ row.lossHours }}</td>
-						</tr>
-					</tbody>
-				</table>
+
+			<div class="mfg-panel__split">
+				<div class="mfg-panel__block mfg-panel__block--half">
+					<div class="mfg-panel__caption">10 工序 · 操作员表现</div>
+					<table class="mfg-panel__table">
+						<thead><tr><th>操作员</th><th>平均工时</th><th>达标</th></tr></thead>
+						<tbody>
+							<tr v-for="row in detail.operators" :key="row.name">
+								<td>{{ row.name }}</td>
+								<td :style="{ color: fixtureStatusColor(row.status), fontWeight: 600 }">{{ row.avgHours }}</td>
+								<td><span class="mfg-panel__dot" :style="{ background: fixtureStatusColor(row.status) }" /></td>
+							</tr>
+						</tbody>
+					</table>
+				</div>
+				<div class="mfg-panel__block mfg-panel__block--half">
+					<div class="mfg-panel__caption">10 工序 · 损失因素</div>
+					<table class="mfg-panel__table">
+						<thead><tr><th>因素</th><th>件数</th><th>占比</th><th>损失工时</th></tr></thead>
+						<tbody>
+							<tr
+								v-for="row in detail.lossFactors"
+								:key="row.factor"
+								:style="row.factor === '作业效率损失' ? { color: '#ff4d4f', fontWeight: 700 } : undefined"
+							>
+								<td>{{ row.factor }}</td>
+								<td>{{ row.count }}</td>
+								<td>{{ row.ratio }}</td>
+								<td>{{ row.lossHours }}</td>
+							</tr>
+						</tbody>
+					</table>
+				</div>
+			</div>
+		</template>
+
+		<!-- API 模式(真实数据;默认) -->
+		<template v-else>
+			<div v-if="isApiLoading" class="mfg-panel__placeholder">本体生产数据加载中…</div>
+			<div v-else-if="isApiError" class="mfg-panel__placeholder mfg-panel__placeholder--error">
+				{{ apiErrorText || '本体生产数据加载失败,请稍后重试' }}
 			</div>
-		</div>
+			<div v-else-if="isApiEmpty" class="mfg-panel__placeholder">暂无本体生产数据</div>
+
+			<template v-else-if="apiDetail">
+				<div class="mfg-panel__block">
+					<div class="mfg-panel__caption">工序明细</div>
+					<table class="mfg-panel__table">
+						<thead>
+							<tr><th>工序</th><th>PI</th><th>平均周期</th><th>周期状态</th><th>计划台次</th><th>计划达成率</th><th>达成状态</th></tr>
+						</thead>
+						<tbody>
+							<tr v-if="apiDetail.processes.length === 0">
+								<td colspan="7" class="mfg-panel__cell-empty">暂无数据</td>
+							</tr>
+							<tr
+								v-for="row in apiDetail.processes"
+								:key="`api-proc-${row.processCode}`"
+								:style="{ fontWeight: row.isTotal ? 700 : 500 }"
+							>
+								<td>{{ row.processName }}</td>
+								<td>{{ row.pi || '—' }}</td>
+								<td :style="{ color: apiToneColor(row.cycleStatusTone), fontWeight: 600 }">
+									{{ row.avgCycle || '—' }}
+								</td>
+								<td><span class="mfg-panel__dot" :style="{ background: apiToneColor(row.cycleStatusTone) }" /></td>
+								<td>{{ row.planQty || '—' }}</td>
+								<td :style="{ color: apiToneColor(row.achievementStatusTone), fontWeight: 600 }">
+									{{ row.achievementRate || '—' }}
+								</td>
+								<td><span class="mfg-panel__dot" :style="{ background: apiToneColor(row.achievementStatusTone) }" /></td>
+							</tr>
+						</tbody>
+					</table>
+				</div>
+
+				<div class="mfg-panel__split">
+					<div class="mfg-panel__block mfg-panel__block--half">
+						<div class="mfg-panel__caption">10 工序 · 操作员表现</div>
+						<table class="mfg-panel__table">
+							<thead><tr><th>操作员</th><th>平均工时</th><th>达标</th></tr></thead>
+							<tbody>
+								<tr v-if="apiDetail.operators.length === 0">
+									<td colspan="3" class="mfg-panel__cell-empty">暂无数据</td>
+								</tr>
+								<tr v-for="row in apiDetail.operators" :key="`api-op-${row.operatorCode}`">
+									<td>{{ row.operatorName }}</td>
+									<td :style="{ color: apiToneColor(row.statusTone), fontWeight: 600 }">
+										{{ row.avgHours || '—' }}
+									</td>
+									<td><span class="mfg-panel__dot" :style="{ background: apiToneColor(row.statusTone) }" /></td>
+								</tr>
+							</tbody>
+						</table>
+					</div>
+					<div class="mfg-panel__block mfg-panel__block--half">
+						<div class="mfg-panel__caption">10 工序 · 损失因素</div>
+						<table class="mfg-panel__table">
+							<thead><tr><th>因素</th><th>件数</th><th>占比</th><th>损失工时</th></tr></thead>
+							<tbody>
+								<tr v-if="apiDetail.lossFactors.length === 0">
+									<td colspan="4" class="mfg-panel__cell-empty">暂无数据</td>
+								</tr>
+								<tr
+									v-for="row in apiDetail.lossFactors"
+									:key="`api-loss-${row.factorCode}`"
+									:style="
+										highlightLossRow(row.factorCode)
+											? { color: '#ff4d4f', fontWeight: 700 }
+											: row.isSubtotal
+												? { fontWeight: 700 }
+												: undefined
+									"
+								>
+									<td>{{ row.factorName }}</td>
+									<td>{{ row.count || '—' }}</td>
+									<td>{{ row.ratio || '—' }}</td>
+									<td>{{ row.lossHours || '—' }}</td>
+								</tr>
+							</tbody>
+						</table>
+					</div>
+				</div>
+			</template>
+		</template>
 	</section>
 </template>
 
@@ -82,6 +225,10 @@ function statusColor(s: StageDetailStatus): string {
 .mfg-panel__head { display: flex; align-items: center; gap: 10px; }
 .mfg-panel__bar { width: 5px; height: 18px; border-radius: 999px; background: var(--order-accent, #7bd0ff); }
 .mfg-panel__title { margin: 0; font-size: 16px; font-weight: 700; }
+.mfg-panel__demo {
+	margin-left: 6px; padding: 2px 10px; border-radius: 999px; font-size: 11px;
+	color: #ffc107; background: rgba(255,193,7,0.1); border: 1px solid rgba(255,193,7,0.32);
+}
 .mfg-panel__block { background: rgba(25, 28, 34, 0.55); border: 1px solid rgba(69, 70, 77, 0.28); border-radius: 10px; padding: 12px; overflow-x: auto; }
 .mfg-panel__split { display: flex; gap: 12px; }
 .mfg-panel__block--half { flex: 1; min-width: 0; }
@@ -94,4 +241,13 @@ function statusColor(s: StageDetailStatus): string {
 }
 .mfg-panel__table th { background: rgba(15, 19, 26, 0.7); font-weight: 600; font-family: 'PingFang SC', sans-serif; }
 .mfg-panel__dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; }
+.mfg-panel__cell-empty { color: var(--order-text-muted, #909097); font-style: italic; }
+.mfg-panel__placeholder {
+	padding: 24px; text-align: center; font-size: 13px;
+	color: var(--order-text-muted, #909097);
+	background: rgba(25, 28, 34, 0.55);
+	border: 1px solid rgba(69, 70, 77, 0.28);
+	border-radius: 10px;
+}
+.mfg-panel__placeholder--error { color: #ff4d4f; }
 </style>

+ 172 - 0
Web/src/views/aidop/s8/monitoring/data/order-execution/stage-detail.ts

@@ -386,3 +386,175 @@ export function isProcurementDetailEmpty(detail: ProcurementDetailFromApi | null
 	if (!detail) return true;
 	return detail.keyMaterials.length === 0 && detail.sections.length === 0;
 }
+
+// ============================================================
+// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:本体生产 API 适配层。
+// 把后端 OrderFlowManufacturingPivot 转换为 ManufacturingDetailPanel 可消费的视图结构。
+// 单位渲染:actualDays/piDays → "X天";achievementRate(0~1) → "XX%";avgHours → "XH";
+// lossHours → "X.XXH";ratioPct(0~100) → "XX%";TOTAL 占位统一展示为「合计」。
+// status tone 复用 procurement 的映射;未识别值返回 'pending'。
+// ============================================================
+
+import type {
+	OrderFlowManufacturingPivot,
+	OrderFlowManufacturingProcess,
+	OrderFlowManufacturingLossFactor,
+	OrderFlowManufacturingOperator,
+} from '/@/views/aidop/s8/api/s8OrderFlowDomainApi';
+
+/** 后端 process_code / factor_code 中的 TOTAL/SUBTOTAL 占位 */
+export const MANUFACTURING_PIVOT_TOTAL_PROCESS_CODE = 'TOTAL';
+export const MANUFACTURING_PIVOT_SUBTOTAL_FACTOR_CODE = 'SUBTOTAL';
+
+export interface ManufacturingApiProcessRow {
+	processCode: string;
+	processName: string;
+	pi: string;
+	avgCycle: string;
+	cycleStatus: string;
+	cycleStatusTone: ProcurementApiStatusTone;
+	planQty: string;
+	achievementRate: string;
+	achievementStatus: string;
+	achievementStatusTone: ProcurementApiStatusTone;
+	sortNo: number;
+	isTotal: boolean;
+}
+
+export interface ManufacturingApiLossFactorRow {
+	factorCode: string;
+	factorName: string;
+	count: string;
+	ratio: string;
+	lossHours: string;
+	sortNo: number;
+	isSubtotal: boolean;
+}
+
+export interface ManufacturingApiOperatorRow {
+	operatorCode: string;
+	operatorName: string;
+	avgHours: string;
+	status: string;
+	statusTone: ProcurementApiStatusTone;
+	sortNo: number;
+}
+
+export interface ManufacturingDetailFromApi {
+	processes: ManufacturingApiProcessRow[];
+	lossFactors: ManufacturingApiLossFactorRow[];
+	operators: ManufacturingApiOperatorRow[];
+}
+
+function formatDaysWithUnit(value: number | null | undefined): string {
+	if (value == null || Number.isNaN(value)) return '';
+	const num = typeof value === 'number' ? value : Number(value);
+	if (Number.isNaN(num)) return '';
+	// 保留至多 3 位小数;整数不带小数点;尾随 "天"。
+	const rounded = Math.round(num * 1000) / 1000;
+	const text = Number.isInteger(rounded) ? String(rounded) : String(rounded);
+	return `${text}天`;
+}
+
+function formatHoursWithUnit(value: number | null | undefined, decimals: number = 2): string {
+	if (value == null || Number.isNaN(value)) return '';
+	const num = typeof value === 'number' ? value : Number(value);
+	if (Number.isNaN(num)) return '';
+	const factor = Math.pow(10, decimals);
+	const rounded = Math.round(num * factor) / factor;
+	if (Number.isInteger(rounded)) return `${rounded}H`;
+	return `${rounded}H`;
+}
+
+function formatPercentRate01(value: number | null | undefined): string {
+	if (value == null || Number.isNaN(value)) return '';
+	const num = typeof value === 'number' ? value : Number(value);
+	if (Number.isNaN(num)) return '';
+	const pct = num <= 1 ? num * 100 : num;
+	return `${Math.round(pct)}%`;
+}
+
+function formatPercentPct(value: number | null | undefined): string {
+	if (value == null || Number.isNaN(value)) return '';
+	const num = typeof value === 'number' ? value : Number(value);
+	if (Number.isNaN(num)) return '';
+	// ratio_pct 已经是 0~100 范围;不再 *100。
+	return `${Math.round(num)}%`;
+}
+
+function formatIntegerOrEmpty(value: number | null | undefined): string {
+	if (value == null || Number.isNaN(value)) return '';
+	return String(value);
+}
+
+function adaptManufacturingProcessRow(row: OrderFlowManufacturingProcess): ManufacturingApiProcessRow {
+	const isTotal = row.processCode === MANUFACTURING_PIVOT_TOTAL_PROCESS_CODE;
+	return {
+		processCode: row.processCode,
+		processName: row.processName,
+		pi: formatDaysWithUnit(row.piDays),
+		avgCycle: formatDaysWithUnit(row.actualDays),
+		cycleStatus: row.cycleStatus ?? '',
+		cycleStatusTone: mapProcurementStatusTone(row.cycleStatus),
+		planQty: isTotal ? '' : formatIntegerOrEmpty(row.planQty),
+		achievementRate: formatPercentRate01(row.achievementRate),
+		achievementStatus: row.achievementStatus ?? '',
+		achievementStatusTone: mapProcurementStatusTone(row.achievementStatus),
+		sortNo: row.sortNo,
+		isTotal,
+	};
+}
+
+function adaptManufacturingLossRow(row: OrderFlowManufacturingLossFactor): ManufacturingApiLossFactorRow {
+	const isSubtotal = row.factorCode === MANUFACTURING_PIVOT_SUBTOTAL_FACTOR_CODE;
+	return {
+		factorCode: row.factorCode,
+		factorName: row.factorName,
+		count: formatIntegerOrEmpty(row.countValue),
+		ratio: formatPercentPct(row.ratioPct),
+		lossHours: formatHoursWithUnit(row.lossHours),
+		sortNo: row.sortNo,
+		isSubtotal,
+	};
+}
+
+function adaptManufacturingOperatorRow(row: OrderFlowManufacturingOperator): ManufacturingApiOperatorRow {
+	return {
+		operatorCode: row.operatorCode,
+		operatorName: row.operatorName,
+		avgHours: formatHoursWithUnit(row.avgHours, 2),
+		status: row.status ?? '',
+		statusTone: mapProcurementStatusTone(row.status),
+		sortNo: row.sortNo,
+	};
+}
+
+export function adaptManufacturingPivotFromApi(
+	pivot: OrderFlowManufacturingPivot | null | undefined,
+): ManufacturingDetailFromApi | null {
+	if (!pivot) return null;
+	const processes = (pivot.processes ?? [])
+		.slice()
+		.sort((a, b) => a.sortNo - b.sortNo)
+		.map(adaptManufacturingProcessRow);
+	const lossFactors = (pivot.lossFactors ?? [])
+		.slice()
+		.sort((a, b) => a.sortNo - b.sortNo)
+		.map(adaptManufacturingLossRow);
+	const operators = (pivot.operators ?? [])
+		.slice()
+		.sort((a, b) => a.sortNo - b.sortNo)
+		.map(adaptManufacturingOperatorRow);
+	return { processes, lossFactors, operators };
+}
+
+export function isManufacturingDetailEmpty(
+	detail: ManufacturingDetailFromApi | null | undefined,
+): boolean {
+	if (!detail) return true;
+	return (
+		detail.processes.length === 0 &&
+		detail.lossFactors.length === 0 &&
+		detail.operators.length === 0
+	);
+}

+ 6 - 3
server/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj

@@ -11,9 +11,9 @@
     <GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
     <Copyright>Admin.NET</Copyright>
     <Description>Admin.NET 通用权限开发平台</Description>
-    <AssemblyVersion>1.0.149</AssemblyVersion>
-    <FileVersion>1.0.149</FileVersion>
-    <Version>1.0.149</Version>
+    <AssemblyVersion>1.0.150</AssemblyVersion>
+    <FileVersion>1.0.150</FileVersion>
+    <Version>1.0.150</Version>
   </PropertyGroup>
 
   <ItemGroup>
@@ -103,6 +103,9 @@
     <None Update="UpdateScripts\1.0.148.sql">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
+    <None Update="UpdateScripts\1.0.150.sql">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
   </ItemGroup>
 
   <ItemGroup>

+ 360 - 0
server/Admin.NET.Web.Entry/UpdateScripts/1.0.150.sql

@@ -0,0 +1,360 @@
+-- 1.0.150.sql
+-- S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1
+-- 本体生产「工序明细 / 损失因素 / 操作员表现」三表 DDL + 幂等 DELETE + 221 行 INSERT SEED。
+--
+-- DDL:3 个 CREATE TABLE IF NOT EXISTS(与 CodeFirst 实体一致;CodeFirst 已建表时 no-op)。
+-- DML:3 个幂等 DELETE(仅本批 SEED,保护 IMPORT/AGG)+ 3 个 INSERT(baseline 13 行 + order-level 208 行 = 221 行)。
+-- 与 procurement 1.0.148.sql 同模式;启动时由 Admin.NET UpdateScripts 模块自动按版本号执行。
+--
+-- 字段精度与实体一致:
+--   process.pi_days / actual_days  DECIMAL(6,3)
+--   process.achievement_rate       DECIMAL(5,4)
+--   loss_factor.ratio_pct          DECIMAL(5,2)
+--   loss_factor.loss_hours         DECIMAL(8,2)
+--   operator.avg_hours             DECIMAL(6,2)
+--
+-- order_id IS NULL 表示 baseline 行(scenario_code=BASELINE_PPT);
+-- order_id IS NOT NULL 表示订单级行(scenario_code=ORDER_LEVEL)。
+
+CREATE TABLE IF NOT EXISTS ado_s8_order_flow_manufacturing_process (
+    id BIGINT NOT NULL,
+    order_id BIGINT NULL,
+    order_code VARCHAR(64) NULL,
+    process_code VARCHAR(16) NOT NULL,
+    process_name VARCHAR(32) NOT NULL,
+    pi_days DECIMAL(6,3) NOT NULL DEFAULT 0,
+    actual_days DECIMAL(6,3) NOT NULL DEFAULT 0,
+    cycle_status VARCHAR(16) NOT NULL DEFAULT 'green',
+    plan_qty INT NULL,
+    achievement_rate DECIMAL(5,4) NULL,
+    achievement_status VARCHAR(16) NOT NULL DEFAULT '',
+    sort_no INT NOT NULL DEFAULT 0,
+    scenario_code VARCHAR(16) NOT NULL DEFAULT 'BASELINE_PPT',
+    data_source VARCHAR(16) NOT NULL DEFAULT 'SEED',
+    tenant_id BIGINT NOT NULL DEFAULT 1,
+    factory_id BIGINT NOT NULL DEFAULT 1,
+    created_at DATETIME NOT NULL,
+    updated_at DATETIME NULL,
+    is_deleted TINYINT(1) NOT NULL DEFAULT 0,
+    PRIMARY KEY (id),
+    KEY idx_order_flow_mfg_process_baseline (tenant_id, factory_id, process_code),
+    KEY idx_order_flow_mfg_process_order    (tenant_id, factory_id, order_code),
+    KEY idx_order_flow_mfg_process_scenario (tenant_id, factory_id, scenario_code, is_deleted)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
+  COMMENT='S8 订单执行链路本体生产工序明细';
+
+CREATE TABLE IF NOT EXISTS ado_s8_order_flow_manufacturing_loss_factor (
+    id BIGINT NOT NULL,
+    order_id BIGINT NULL,
+    order_code VARCHAR(64) NULL,
+    factor_code VARCHAR(32) NOT NULL,
+    factor_name VARCHAR(32) NOT NULL,
+    count_value INT NULL,
+    ratio_pct DECIMAL(5,2) NULL,
+    loss_hours DECIMAL(8,2) NULL,
+    sort_no INT NOT NULL DEFAULT 0,
+    scenario_code VARCHAR(16) NOT NULL DEFAULT 'BASELINE_PPT',
+    data_source VARCHAR(16) NOT NULL DEFAULT 'SEED',
+    tenant_id BIGINT NOT NULL DEFAULT 1,
+    factory_id BIGINT NOT NULL DEFAULT 1,
+    created_at DATETIME NOT NULL,
+    updated_at DATETIME NULL,
+    is_deleted TINYINT(1) NOT NULL DEFAULT 0,
+    PRIMARY KEY (id),
+    KEY idx_order_flow_mfg_loss_baseline (tenant_id, factory_id, factor_code),
+    KEY idx_order_flow_mfg_loss_order    (tenant_id, factory_id, order_code),
+    KEY idx_order_flow_mfg_loss_scenario (tenant_id, factory_id, scenario_code, is_deleted)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
+  COMMENT='S8 订单执行链路本体生产损失因素';
+
+CREATE TABLE IF NOT EXISTS ado_s8_order_flow_manufacturing_operator (
+    id BIGINT NOT NULL,
+    order_id BIGINT NULL,
+    order_code VARCHAR(64) NULL,
+    operator_code VARCHAR(32) NOT NULL,
+    operator_name VARCHAR(64) NOT NULL,
+    avg_hours DECIMAL(6,2) NOT NULL DEFAULT 0,
+    status VARCHAR(16) NOT NULL DEFAULT 'green',
+    sort_no INT NOT NULL DEFAULT 0,
+    scenario_code VARCHAR(16) NOT NULL DEFAULT 'BASELINE_PPT',
+    data_source VARCHAR(16) NOT NULL DEFAULT 'SEED',
+    tenant_id BIGINT NOT NULL DEFAULT 1,
+    factory_id BIGINT NOT NULL DEFAULT 1,
+    created_at DATETIME NOT NULL,
+    updated_at DATETIME NULL,
+    is_deleted TINYINT(1) NOT NULL DEFAULT 0,
+    PRIMARY KEY (id),
+    KEY idx_order_flow_mfg_operator_baseline (tenant_id, factory_id, operator_code),
+    KEY idx_order_flow_mfg_operator_order    (tenant_id, factory_id, order_code),
+    KEY idx_order_flow_mfg_operator_scenario (tenant_id, factory_id, scenario_code, is_deleted)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
+  COMMENT='S8 订单执行链路本体生产操作员表现';
+
+-- ============================================================
+-- 幂等 DELETE:仅本批 SEED(BASELINE_PPT + ORDER_LEVEL);不触 IMPORT/AGG。
+-- 重复 source 此 SQL 不会重复堆叠。
+-- ============================================================
+
+DELETE FROM ado_s8_order_flow_manufacturing_process
+WHERE tenant_id = 1 AND factory_id = 1 AND is_deleted = 0
+  AND data_source = 'SEED'
+  AND scenario_code IN ('BASELINE_PPT', 'ORDER_LEVEL');
+
+DELETE FROM ado_s8_order_flow_manufacturing_loss_factor
+WHERE tenant_id = 1 AND factory_id = 1 AND is_deleted = 0
+  AND data_source = 'SEED'
+  AND scenario_code IN ('BASELINE_PPT', 'ORDER_LEVEL');
+
+DELETE FROM ado_s8_order_flow_manufacturing_operator
+WHERE tenant_id = 1 AND factory_id = 1 AND is_deleted = 0
+  AND data_source = 'SEED'
+  AND scenario_code IN ('BASELINE_PPT', 'ORDER_LEVEL');
+
+-- ============================================================
+-- INSERT:baseline (5+5+3) + order-level (16 单 × (5+5+3) = 208) = 221 行
+-- 数据由 /tmp/gen_s8_body_production_seed_sql.py 生成(严格复刻
+-- S8OrderFlowManufacturingSeedData.cs 算法 + S8-...-FIX-1R TOTAL.rate 锚定)。
+--
+-- baseline 行:order_id=NULL,scenario_code='BASELINE_PPT',与 MANUFACTURING_DETAIL_FIXTURE 逐字段一致。
+-- order-level 行:order_id=OrderIdBase+spec.Idx,scenario_code='ORDER_LEVEL';
+--   每非 pending 单按 ratio=A/6.8 缩放 process/loss/operator;
+--   process TOTAL.rate=0.9000/yellow 锚定 fixture(不再 plan_qty 加权);
+--   守恒:Σ(P10..P40 actual) = TOTAL.actual = stage.actual_days;
+--   pending 单 016/017/018/019 不生成 order-level 行。
+-- ============================================================
+
+-- ─── ado_s8_order_flow_manufacturing_process: 85 行 ───
+INSERT INTO ado_s8_order_flow_manufacturing_process
+  (id, order_id, order_code, process_code, process_name, pi_days, actual_days, cycle_status, plan_qty, achievement_rate, achievement_status, sort_no, scenario_code, data_source, tenant_id, factory_id, created_at, updated_at, is_deleted)
+VALUES
+  (1329909160001, NULL, NULL, 'P10', '10工序', 1.000, 2.400, 'red', 45, 0.5500, 'red', 1, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909160002, NULL, NULL, 'P20', '20工序', 1.000, 0.800, 'green', 3, 0.9700, 'yellow', 2, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909160003, NULL, NULL, 'P30', '30工序', 2.500, 3.000, 'yellow', 15, 0.8500, 'green', 3, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909160004, NULL, NULL, 'P40', '40工序', 1.500, 0.600, 'green', 2, 0.9800, 'red', 4, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909160005, NULL, NULL, 'TOTAL', '合计', 6.000, 6.800, 'yellow', NULL, 0.9000, 'yellow', 5, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170001, 1329909100001, 'SO-2026-001', 'P10', '10工序', 1.000, 1.765, 'red', 33, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170002, 1329909100001, 'SO-2026-001', 'P20', '20工序', 1.000, 0.588, 'green', 2, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170003, 1329909100001, 'SO-2026-001', 'P30', '30工序', 2.500, 2.206, 'green', 11, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170004, 1329909100001, 'SO-2026-001', 'P40', '40工序', 1.500, 0.441, 'green', 1, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170005, 1329909100001, 'SO-2026-001', 'TOTAL', '合计', 6.000, 5.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170006, 1329909100002, 'SO-2026-002', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170007, 1329909100002, 'SO-2026-002', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170008, 1329909100002, 'SO-2026-002', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170009, 1329909100002, 'SO-2026-002', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170010, 1329909100002, 'SO-2026-002', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170011, 1329909100003, 'SO-2026-003', 'P10', '10工序', 1.000, 2.824, 'red', 53, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170012, 1329909100003, 'SO-2026-003', 'P20', '20工序', 1.000, 0.941, 'green', 4, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170013, 1329909100003, 'SO-2026-003', 'P30', '30工序', 2.500, 3.529, 'red', 18, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170014, 1329909100003, 'SO-2026-003', 'P40', '40工序', 1.500, 0.706, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170015, 1329909100003, 'SO-2026-003', 'TOTAL', '合计', 6.000, 8.000, 'red', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170016, 1329909100004, 'SO-2026-004', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170017, 1329909100004, 'SO-2026-004', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170018, 1329909100004, 'SO-2026-004', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170019, 1329909100004, 'SO-2026-004', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170020, 1329909100004, 'SO-2026-004', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170021, 1329909100005, 'SO-2026-005', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170022, 1329909100005, 'SO-2026-005', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170023, 1329909100005, 'SO-2026-005', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170024, 1329909100005, 'SO-2026-005', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170025, 1329909100005, 'SO-2026-005', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170026, 1329909100006, 'SO-2026-006', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170027, 1329909100006, 'SO-2026-006', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170028, 1329909100006, 'SO-2026-006', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170029, 1329909100006, 'SO-2026-006', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170030, 1329909100006, 'SO-2026-006', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170031, 1329909100007, 'SO-2026-007', 'P10', '10工序', 1.000, 2.824, 'red', 53, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170032, 1329909100007, 'SO-2026-007', 'P20', '20工序', 1.000, 0.941, 'green', 4, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170033, 1329909100007, 'SO-2026-007', 'P30', '30工序', 2.500, 3.529, 'red', 18, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170034, 1329909100007, 'SO-2026-007', 'P40', '40工序', 1.500, 0.706, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170035, 1329909100007, 'SO-2026-007', 'TOTAL', '合计', 6.000, 8.000, 'red', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170036, 1329909100008, 'SO-2026-008', 'P10', '10工序', 1.000, 2.824, 'red', 53, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170037, 1329909100008, 'SO-2026-008', 'P20', '20工序', 1.000, 0.941, 'green', 4, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170038, 1329909100008, 'SO-2026-008', 'P30', '30工序', 2.500, 3.529, 'red', 18, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170039, 1329909100008, 'SO-2026-008', 'P40', '40工序', 1.500, 0.706, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170040, 1329909100008, 'SO-2026-008', 'TOTAL', '合计', 6.000, 8.000, 'red', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170041, 1329909100009, 'SO-2026-009', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170042, 1329909100009, 'SO-2026-009', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170043, 1329909100009, 'SO-2026-009', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170044, 1329909100009, 'SO-2026-009', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170045, 1329909100009, 'SO-2026-009', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170046, 1329909100010, 'SO-2026-010', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170047, 1329909100010, 'SO-2026-010', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170048, 1329909100010, 'SO-2026-010', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170049, 1329909100010, 'SO-2026-010', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170050, 1329909100010, 'SO-2026-010', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170051, 1329909100011, 'SO-2026-011', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170052, 1329909100011, 'SO-2026-011', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170053, 1329909100011, 'SO-2026-011', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170054, 1329909100011, 'SO-2026-011', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170055, 1329909100011, 'SO-2026-011', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170056, 1329909100012, 'SO-2026-012', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170057, 1329909100012, 'SO-2026-012', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170058, 1329909100012, 'SO-2026-012', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170059, 1329909100012, 'SO-2026-012', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170060, 1329909100012, 'SO-2026-012', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170061, 1329909100013, 'SO-2026-013', 'P10', '10工序', 1.000, 2.824, 'red', 53, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170062, 1329909100013, 'SO-2026-013', 'P20', '20工序', 1.000, 0.941, 'green', 4, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170063, 1329909100013, 'SO-2026-013', 'P30', '30工序', 2.500, 3.529, 'red', 18, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170064, 1329909100013, 'SO-2026-013', 'P40', '40工序', 1.500, 0.706, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170065, 1329909100013, 'SO-2026-013', 'TOTAL', '合计', 6.000, 8.000, 'red', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170066, 1329909100014, 'SO-2026-014', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170067, 1329909100014, 'SO-2026-014', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170068, 1329909100014, 'SO-2026-014', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170069, 1329909100014, 'SO-2026-014', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170070, 1329909100014, 'SO-2026-014', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170071, 1329909100015, 'SO-2026-015', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170072, 1329909100015, 'SO-2026-015', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170073, 1329909100015, 'SO-2026-015', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170074, 1329909100015, 'SO-2026-015', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170075, 1329909100015, 'SO-2026-015', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170076, 1329909100020, 'SO-2026-020', 'P10', '10工序', 1.000, 2.118, 'red', 40, 0.5500, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170077, 1329909100020, 'SO-2026-020', 'P20', '20工序', 1.000, 0.706, 'green', 3, 0.9700, 'green', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170078, 1329909100020, 'SO-2026-020', 'P30', '30工序', 2.500, 2.647, 'yellow', 13, 0.8500, 'yellow', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170079, 1329909100020, 'SO-2026-020', 'P40', '40工序', 1.500, 0.529, 'green', 2, 0.9800, 'green', 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909170080, 1329909100020, 'SO-2026-020', 'TOTAL', '合计', 6.000, 6.000, 'green', NULL, 0.9000, 'yellow', 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0);
+
+-- ─── ado_s8_order_flow_manufacturing_loss_factor: 85 行 ───
+INSERT INTO ado_s8_order_flow_manufacturing_loss_factor
+  (id, order_id, order_code, factor_code, factor_name, count_value, ratio_pct, loss_hours, sort_no, scenario_code, data_source, tenant_id, factory_id, created_at, updated_at, is_deleted)
+VALUES
+  (1329909180001, NULL, NULL, 'MATERIAL', '材料影响', 9, 30.00, 9.00, 1, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909180002, NULL, NULL, 'EQUIPMENT', '设备影响', 6, 20.00, 4.50, 2, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909180003, NULL, NULL, 'QUALITY', '质量影响', 3, 10.00, 3.40, 3, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909180004, NULL, NULL, 'EFFICIENCY', '作业效率损失', 12, 40.00, 9.25, 4, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909180005, NULL, NULL, 'SUBTOTAL', '损失小计', 30, 100.00, 7.50, 5, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190001, 1329909100001, 'SO-2026-001', 'MATERIAL', '材料影响', 7, 30.00, 6.62, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190002, 1329909100001, 'SO-2026-001', 'EQUIPMENT', '设备影响', 4, 20.00, 3.31, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190003, 1329909100001, 'SO-2026-001', 'QUALITY', '质量影响', 2, 10.00, 2.50, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190004, 1329909100001, 'SO-2026-001', 'EFFICIENCY', '作业效率损失', 9, 40.00, 6.80, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190005, 1329909100001, 'SO-2026-001', 'SUBTOTAL', '损失小计', 22, 100.00, 5.51, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190006, 1329909100002, 'SO-2026-002', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190007, 1329909100002, 'SO-2026-002', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190008, 1329909100002, 'SO-2026-002', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190009, 1329909100002, 'SO-2026-002', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190010, 1329909100002, 'SO-2026-002', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190011, 1329909100003, 'SO-2026-003', 'MATERIAL', '材料影响', 11, 30.00, 10.59, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190012, 1329909100003, 'SO-2026-003', 'EQUIPMENT', '设备影响', 7, 20.00, 5.29, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190013, 1329909100003, 'SO-2026-003', 'QUALITY', '质量影响', 4, 10.00, 4.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190014, 1329909100003, 'SO-2026-003', 'EFFICIENCY', '作业效率损失', 14, 40.00, 10.88, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190015, 1329909100003, 'SO-2026-003', 'SUBTOTAL', '损失小计', 35, 100.00, 8.82, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190016, 1329909100004, 'SO-2026-004', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190017, 1329909100004, 'SO-2026-004', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190018, 1329909100004, 'SO-2026-004', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190019, 1329909100004, 'SO-2026-004', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190020, 1329909100004, 'SO-2026-004', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190021, 1329909100005, 'SO-2026-005', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190022, 1329909100005, 'SO-2026-005', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190023, 1329909100005, 'SO-2026-005', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190024, 1329909100005, 'SO-2026-005', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190025, 1329909100005, 'SO-2026-005', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190026, 1329909100006, 'SO-2026-006', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190027, 1329909100006, 'SO-2026-006', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190028, 1329909100006, 'SO-2026-006', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190029, 1329909100006, 'SO-2026-006', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190030, 1329909100006, 'SO-2026-006', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190031, 1329909100007, 'SO-2026-007', 'MATERIAL', '材料影响', 11, 30.00, 10.59, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190032, 1329909100007, 'SO-2026-007', 'EQUIPMENT', '设备影响', 7, 20.00, 5.29, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190033, 1329909100007, 'SO-2026-007', 'QUALITY', '质量影响', 4, 10.00, 4.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190034, 1329909100007, 'SO-2026-007', 'EFFICIENCY', '作业效率损失', 14, 40.00, 10.88, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190035, 1329909100007, 'SO-2026-007', 'SUBTOTAL', '损失小计', 35, 100.00, 8.82, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190036, 1329909100008, 'SO-2026-008', 'MATERIAL', '材料影响', 11, 30.00, 10.59, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190037, 1329909100008, 'SO-2026-008', 'EQUIPMENT', '设备影响', 7, 20.00, 5.29, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190038, 1329909100008, 'SO-2026-008', 'QUALITY', '质量影响', 4, 10.00, 4.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190039, 1329909100008, 'SO-2026-008', 'EFFICIENCY', '作业效率损失', 14, 40.00, 10.88, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190040, 1329909100008, 'SO-2026-008', 'SUBTOTAL', '损失小计', 35, 100.00, 8.82, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190041, 1329909100009, 'SO-2026-009', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190042, 1329909100009, 'SO-2026-009', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190043, 1329909100009, 'SO-2026-009', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190044, 1329909100009, 'SO-2026-009', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190045, 1329909100009, 'SO-2026-009', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190046, 1329909100010, 'SO-2026-010', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190047, 1329909100010, 'SO-2026-010', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190048, 1329909100010, 'SO-2026-010', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190049, 1329909100010, 'SO-2026-010', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190050, 1329909100010, 'SO-2026-010', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190051, 1329909100011, 'SO-2026-011', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190052, 1329909100011, 'SO-2026-011', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190053, 1329909100011, 'SO-2026-011', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190054, 1329909100011, 'SO-2026-011', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190055, 1329909100011, 'SO-2026-011', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190056, 1329909100012, 'SO-2026-012', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190057, 1329909100012, 'SO-2026-012', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190058, 1329909100012, 'SO-2026-012', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190059, 1329909100012, 'SO-2026-012', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190060, 1329909100012, 'SO-2026-012', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190061, 1329909100013, 'SO-2026-013', 'MATERIAL', '材料影响', 11, 30.00, 10.59, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190062, 1329909100013, 'SO-2026-013', 'EQUIPMENT', '设备影响', 7, 20.00, 5.29, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190063, 1329909100013, 'SO-2026-013', 'QUALITY', '质量影响', 4, 10.00, 4.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190064, 1329909100013, 'SO-2026-013', 'EFFICIENCY', '作业效率损失', 14, 40.00, 10.88, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190065, 1329909100013, 'SO-2026-013', 'SUBTOTAL', '损失小计', 35, 100.00, 8.82, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190066, 1329909100014, 'SO-2026-014', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190067, 1329909100014, 'SO-2026-014', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190068, 1329909100014, 'SO-2026-014', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190069, 1329909100014, 'SO-2026-014', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190070, 1329909100014, 'SO-2026-014', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190071, 1329909100015, 'SO-2026-015', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190072, 1329909100015, 'SO-2026-015', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190073, 1329909100015, 'SO-2026-015', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190074, 1329909100015, 'SO-2026-015', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190075, 1329909100015, 'SO-2026-015', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190076, 1329909100020, 'SO-2026-020', 'MATERIAL', '材料影响', 8, 30.00, 7.94, 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190077, 1329909100020, 'SO-2026-020', 'EQUIPMENT', '设备影响', 5, 20.00, 3.97, 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190078, 1329909100020, 'SO-2026-020', 'QUALITY', '质量影响', 3, 10.00, 3.00, 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190079, 1329909100020, 'SO-2026-020', 'EFFICIENCY', '作业效率损失', 11, 40.00, 8.16, 4, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909190080, 1329909100020, 'SO-2026-020', 'SUBTOTAL', '损失小计', 26, 100.00, 6.62, 5, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0);
+
+-- ─── ado_s8_order_flow_manufacturing_operator: 51 行 ───
+INSERT INTO ado_s8_order_flow_manufacturing_operator
+  (id, order_id, order_code, operator_code, operator_name, avg_hours, status, sort_no, scenario_code, data_source, tenant_id, factory_id, created_at, updated_at, is_deleted)
+VALUES
+  (1329909200001, NULL, NULL, 'OP_ZHANG', '张师傅', 20.00, 'red', 1, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909200002, NULL, NULL, 'OP_LI', '李师傅', 10.00, 'yellow', 2, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909200003, NULL, NULL, 'OP_WANG', '王师傅', 8.00, 'green', 3, 'BASELINE_PPT', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210001, 1329909100001, 'SO-2026-001', 'OP_ZHANG', '张师傅', 14.71, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210002, 1329909100001, 'SO-2026-001', 'OP_LI', '李师傅', 7.35, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210003, 1329909100001, 'SO-2026-001', 'OP_WANG', '王师傅', 5.88, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210004, 1329909100002, 'SO-2026-002', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210005, 1329909100002, 'SO-2026-002', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210006, 1329909100002, 'SO-2026-002', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210007, 1329909100003, 'SO-2026-003', 'OP_ZHANG', '张师傅', 23.53, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210008, 1329909100003, 'SO-2026-003', 'OP_LI', '李师傅', 11.76, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210009, 1329909100003, 'SO-2026-003', 'OP_WANG', '王师傅', 9.41, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210010, 1329909100004, 'SO-2026-004', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210011, 1329909100004, 'SO-2026-004', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210012, 1329909100004, 'SO-2026-004', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210013, 1329909100005, 'SO-2026-005', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210014, 1329909100005, 'SO-2026-005', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210015, 1329909100005, 'SO-2026-005', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210016, 1329909100006, 'SO-2026-006', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210017, 1329909100006, 'SO-2026-006', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210018, 1329909100006, 'SO-2026-006', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210019, 1329909100007, 'SO-2026-007', 'OP_ZHANG', '张师傅', 23.53, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210020, 1329909100007, 'SO-2026-007', 'OP_LI', '李师傅', 11.76, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210021, 1329909100007, 'SO-2026-007', 'OP_WANG', '王师傅', 9.41, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210022, 1329909100008, 'SO-2026-008', 'OP_ZHANG', '张师傅', 23.53, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210023, 1329909100008, 'SO-2026-008', 'OP_LI', '李师傅', 11.76, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210024, 1329909100008, 'SO-2026-008', 'OP_WANG', '王师傅', 9.41, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210025, 1329909100009, 'SO-2026-009', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210026, 1329909100009, 'SO-2026-009', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210027, 1329909100009, 'SO-2026-009', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210028, 1329909100010, 'SO-2026-010', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210029, 1329909100010, 'SO-2026-010', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210030, 1329909100010, 'SO-2026-010', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210031, 1329909100011, 'SO-2026-011', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210032, 1329909100011, 'SO-2026-011', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210033, 1329909100011, 'SO-2026-011', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210034, 1329909100012, 'SO-2026-012', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210035, 1329909100012, 'SO-2026-012', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210036, 1329909100012, 'SO-2026-012', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210037, 1329909100013, 'SO-2026-013', 'OP_ZHANG', '张师傅', 23.53, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210038, 1329909100013, 'SO-2026-013', 'OP_LI', '李师傅', 11.76, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210039, 1329909100013, 'SO-2026-013', 'OP_WANG', '王师傅', 9.41, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210040, 1329909100014, 'SO-2026-014', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210041, 1329909100014, 'SO-2026-014', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210042, 1329909100014, 'SO-2026-014', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210043, 1329909100015, 'SO-2026-015', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210044, 1329909100015, 'SO-2026-015', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210045, 1329909100015, 'SO-2026-015', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210046, 1329909100020, 'SO-2026-020', 'OP_ZHANG', '张师傅', 17.65, 'red', 1, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210047, 1329909100020, 'SO-2026-020', 'OP_LI', '李师傅', 8.82, 'yellow', 2, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0),
+  (1329909210048, 1329909100020, 'SO-2026-020', 'OP_WANG', '王师傅', 7.06, 'green', 3, 'ORDER_LEVEL', 'SEED', 1, 1, '2026-05-12 00:00:00', NULL, 0);

+ 10 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Controllers/S8/AdoS8OrderFlowController.cs

@@ -60,4 +60,14 @@ public class AdoS8OrderFlowController : ControllerBase
     public async Task<IActionResult> ProductDesignDrawingsAsync(
         [FromQuery] AdoS8OrderFlowProductDesignDrawingsQueryDto query)
         => Ok(await _svc.GetProductDesignDrawingsAsync(query));
+
+    /// <summary>
+    /// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:本体生产透视。
+    /// scope=BASELINE_PPT 读三表 baseline 行;scope=CURRENT_FILTERED 按 orderCodes CSV 取订单级行并聚合。
+    /// orderCodes 为空(CURRENT_FILTERED)时返回空骨架,不静默 fallback baseline。
+    /// </summary>
+    [HttpGet("manufacturing-pivot")]
+    public async Task<IActionResult> ManufacturingPivotAsync(
+        [FromQuery] AdoS8OrderFlowManufacturingPivotQueryDto query)
+        => Ok(await _svc.GetManufacturingPivotAsync(query));
 }

+ 68 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Dto/S8/OrderFlow/AdoS8OrderFlowDtos.cs

@@ -351,3 +351,71 @@ public class AdoS8OrderFlowProductDesignDrawingsDto
 }
 
 #endregion
+
+#region 本体生产(设备制造) — S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1
+
+/// <summary>
+/// 本体生产「工序明细 / 损失因素 / 操作员表现」三表透视查询入参。
+/// orderCodes CSV:与产品设计 drawings API、采购透视 API 对齐,避免 axios brackets 与 ASP.NET Core List 绑定二义性。
+/// scope=BASELINE_PPT 时 orderCodes 忽略;scope=CURRENT_FILTERED 时 orderCodes 为空返回空骨架(不静默 fallback baseline)。
+/// </summary>
+public class AdoS8OrderFlowManufacturingPivotQueryDto
+{
+    public long? TenantId { get; set; }
+    public long? FactoryId { get; set; }
+    /// <summary>BASELINE_PPT | CURRENT_FILTERED</summary>
+    public string Scope { get; set; } = string.Empty;
+    /// <summary>逗号分隔订单号;scope=CURRENT_FILTERED 时使用。</summary>
+    public string? OrderCodes { get; set; }
+}
+
+/// <summary>
+/// 工序明细行:P10 / P20 / P30 / P40 / TOTAL。
+/// pi_days / actual_days 保留 decimal(6,3) 精度;plan_qty 在 TOTAL 行为 null。
+/// achievement_rate 在 TOTAL 行 baseline 来自 fixture(0.9000)、订单级按 plan_qty 加权平均;其它行 baseline 复用。
+/// </summary>
+public class AdoS8OrderFlowManufacturingProcessDto
+{
+    public string ProcessCode { get; set; } = string.Empty;
+    public string ProcessName { get; set; } = string.Empty;
+    public decimal PiDays { get; set; }
+    public decimal ActualDays { get; set; }
+    public string CycleStatus { get; set; } = string.Empty;
+    public int? PlanQty { get; set; }
+    public decimal? AchievementRate { get; set; }
+    public string AchievementStatus { get; set; } = string.Empty;
+    public int SortNo { get; set; }
+}
+
+/// <summary>损失因素行:MATERIAL / EQUIPMENT / QUALITY / EFFICIENCY / SUBTOTAL。</summary>
+public class AdoS8OrderFlowManufacturingLossFactorDto
+{
+    public string FactorCode { get; set; } = string.Empty;
+    public string FactorName { get; set; } = string.Empty;
+    public int? CountValue { get; set; }
+    public decimal? RatioPct { get; set; }
+    public decimal? LossHours { get; set; }
+    public int SortNo { get; set; }
+}
+
+/// <summary>操作员表现行:OP_ZHANG / OP_LI / OP_WANG。</summary>
+public class AdoS8OrderFlowManufacturingOperatorDto
+{
+    public string OperatorCode { get; set; } = string.Empty;
+    public string OperatorName { get; set; } = string.Empty;
+    public decimal AvgHours { get; set; }
+    public string Status { get; set; } = string.Empty;
+    public int SortNo { get; set; }
+}
+
+/// <summary>本体生产透视聚合结果:scope + 工序 / 损失 / 操作员 三组。</summary>
+public class AdoS8OrderFlowManufacturingPivotDto
+{
+    /// <summary>BASELINE_PPT | CURRENT_FILTERED</summary>
+    public string Scope { get; set; } = string.Empty;
+    public List<AdoS8OrderFlowManufacturingProcessDto> Processes { get; set; } = new();
+    public List<AdoS8OrderFlowManufacturingLossFactorDto> LossFactors { get; set; } = new();
+    public List<AdoS8OrderFlowManufacturingOperatorDto> Operators { get; set; } = new();
+}
+
+#endregion

+ 75 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S8/OrderFlow/AdoS8OrderFlowManufacturingLossFactor.cs

@@ -0,0 +1,75 @@
+namespace Admin.NET.Plugin.AiDOP.Entity.S8.OrderFlow;
+
+/// <summary>
+/// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:
+/// S8 订单执行链路本体生产「损失因素」表(baseline + 订单级 SEED)。
+///
+/// factor_code 取值:MATERIAL / EQUIPMENT / QUALITY / EFFICIENCY / SUBTOTAL(小计行 sort_no=5)。
+///   - count_value:baseline 9/6/3/12/30;订单级 round(baseline * ratio)。
+///   - ratio_pct:baseline 30/20/10/40/100,订单级保持结构(按用户规则原值复制)。
+///   - loss_hours:baseline 9.00/4.50/3.40/9.25/7.50(SUBTOTAL 7.50 来自 fixture,不是 4 因素之和);订单级 round(baseline*ratio,2)。
+/// </summary>
+[SugarTable("ado_s8_order_flow_manufacturing_loss_factor", "S8 订单执行链路本体生产损失因素")]
+[SugarIndex("idx_order_flow_mfg_loss_baseline", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(FactorCode), OrderByType.Asc)]
+[SugarIndex("idx_order_flow_mfg_loss_order", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(OrderCode), OrderByType.Asc)]
+[SugarIndex("idx_order_flow_mfg_loss_scenario", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(ScenarioCode), OrderByType.Asc, nameof(IsDeleted), OrderByType.Asc)]
+public class AdoS8OrderFlowManufacturingLossFactor
+{
+    [SugarColumn(ColumnName = "id", IsPrimaryKey = true, ColumnDataType = "bigint")]
+    public long Id { get; set; }
+
+    /// <summary>NULL = baseline 行;非 NULL = 订单级行。</summary>
+    [SugarColumn(ColumnName = "order_id", ColumnDataType = "bigint", IsNullable = true)]
+    public long? OrderId { get; set; }
+
+    /// <summary>NULL = baseline 行;非 NULL = 订单业务键。</summary>
+    [SugarColumn(ColumnName = "order_code", Length = 64, IsNullable = true)]
+    public string? OrderCode { get; set; }
+
+    /// <summary>因素编码:MATERIAL / EQUIPMENT / QUALITY / EFFICIENCY / SUBTOTAL。</summary>
+    [SugarColumn(ColumnName = "factor_code", Length = 32)]
+    public string FactorCode { get; set; } = string.Empty;
+
+    /// <summary>因素名称:材料影响 / 设备影响 / 质量影响 / 作业效率损失 / 损失小计。</summary>
+    [SugarColumn(ColumnName = "factor_name", Length = 32)]
+    public string FactorName { get; set; } = string.Empty;
+
+    /// <summary>件数。baseline 9/6/3/12/30;订单级 round(baseline*ratio)。SUBTOTAL = 30*ratio。</summary>
+    [SugarColumn(ColumnName = "count_value", ColumnDataType = "int", IsNullable = true)]
+    public int? CountValue { get; set; }
+
+    /// <summary>占比百分比(0~100)。baseline 30/20/10/40/100;订单级保持结构(复制 baseline 值)。decimal(5,2)。</summary>
+    [SugarColumn(ColumnName = "ratio_pct", DecimalDigits = 2, Length = 5, IsNullable = true)]
+    public decimal? RatioPct { get; set; }
+
+    /// <summary>损失工时(小时)。baseline 9.00/4.50/3.40/9.25/7.50;订单级 round(baseline*ratio,2)。decimal(8,2)。</summary>
+    [SugarColumn(ColumnName = "loss_hours", DecimalDigits = 2, Length = 8, IsNullable = true)]
+    public decimal? LossHours { get; set; }
+
+    /// <summary>排序号 1..5(材料/设备/质量/效率/小计)。</summary>
+    [SugarColumn(ColumnName = "sort_no", ColumnDataType = "int")]
+    public int SortNo { get; set; }
+
+    /// <summary>BASELINE_PPT / ORDER_LEVEL。</summary>
+    [SugarColumn(ColumnName = "scenario_code", Length = 16)]
+    public string ScenarioCode { get; set; } = "BASELINE_PPT";
+
+    /// <summary>SEED / IMPORT / AGG。</summary>
+    [SugarColumn(ColumnName = "data_source", Length = 16)]
+    public string DataSource { get; set; } = "SEED";
+
+    [SugarColumn(ColumnName = "tenant_id", ColumnDataType = "bigint")]
+    public long TenantId { get; set; }
+
+    [SugarColumn(ColumnName = "factory_id", ColumnDataType = "bigint")]
+    public long FactoryId { get; set; }
+
+    [SugarColumn(ColumnName = "created_at")]
+    public DateTime CreatedAt { get; set; } = DateTime.Now;
+
+    [SugarColumn(ColumnName = "updated_at", IsNullable = true)]
+    public DateTime? UpdatedAt { get; set; }
+
+    [SugarColumn(ColumnName = "is_deleted", ColumnDataType = "boolean")]
+    public bool IsDeleted { get; set; }
+}

+ 70 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S8/OrderFlow/AdoS8OrderFlowManufacturingOperator.cs

@@ -0,0 +1,70 @@
+namespace Admin.NET.Plugin.AiDOP.Entity.S8.OrderFlow;
+
+/// <summary>
+/// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:
+/// S8 订单执行链路本体生产「操作员表现」表(baseline + 订单级 SEED)。
+///
+/// operator_code 取值:OP_ZHANG / OP_LI / OP_WANG(演示固定 3 个操作员)。
+///   - avg_hours:baseline 20.00/10.00/8.00;订单级 round(baseline*ratio,2)。
+///   - status:baseline red/yellow/green(按 fixture 颜色固化);订单级保持每个操作员的 status(按用户规则结构保留)。
+/// </summary>
+[SugarTable("ado_s8_order_flow_manufacturing_operator", "S8 订单执行链路本体生产操作员表现")]
+[SugarIndex("idx_order_flow_mfg_operator_baseline", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(OperatorCode), OrderByType.Asc)]
+[SugarIndex("idx_order_flow_mfg_operator_order", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(OrderCode), OrderByType.Asc)]
+[SugarIndex("idx_order_flow_mfg_operator_scenario", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(ScenarioCode), OrderByType.Asc, nameof(IsDeleted), OrderByType.Asc)]
+public class AdoS8OrderFlowManufacturingOperator
+{
+    [SugarColumn(ColumnName = "id", IsPrimaryKey = true, ColumnDataType = "bigint")]
+    public long Id { get; set; }
+
+    /// <summary>NULL = baseline 行;非 NULL = 订单级行。</summary>
+    [SugarColumn(ColumnName = "order_id", ColumnDataType = "bigint", IsNullable = true)]
+    public long? OrderId { get; set; }
+
+    /// <summary>NULL = baseline 行;非 NULL = 订单业务键。</summary>
+    [SugarColumn(ColumnName = "order_code", Length = 64, IsNullable = true)]
+    public string? OrderCode { get; set; }
+
+    /// <summary>操作员编码:OP_ZHANG / OP_LI / OP_WANG。</summary>
+    [SugarColumn(ColumnName = "operator_code", Length = 32)]
+    public string OperatorCode { get; set; } = string.Empty;
+
+    /// <summary>操作员姓名:张师傅 / 李师傅 / 王师傅。</summary>
+    [SugarColumn(ColumnName = "operator_name", Length = 64)]
+    public string OperatorName { get; set; } = string.Empty;
+
+    /// <summary>平均工时(小时)。baseline 20.00/10.00/8.00;订单级 round(baseline*ratio,2)。decimal(6,2)。</summary>
+    [SugarColumn(ColumnName = "avg_hours", DecimalDigits = 2, Length = 6)]
+    public decimal AvgHours { get; set; }
+
+    /// <summary>状态:green / yellow / red(按操作员固化;订单级复用 baseline 同色)。</summary>
+    [SugarColumn(ColumnName = "status", Length = 16)]
+    public string Status { get; set; } = "green";
+
+    /// <summary>排序号 1..3。</summary>
+    [SugarColumn(ColumnName = "sort_no", ColumnDataType = "int")]
+    public int SortNo { get; set; }
+
+    /// <summary>BASELINE_PPT / ORDER_LEVEL。</summary>
+    [SugarColumn(ColumnName = "scenario_code", Length = 16)]
+    public string ScenarioCode { get; set; } = "BASELINE_PPT";
+
+    /// <summary>SEED / IMPORT / AGG。</summary>
+    [SugarColumn(ColumnName = "data_source", Length = 16)]
+    public string DataSource { get; set; } = "SEED";
+
+    [SugarColumn(ColumnName = "tenant_id", ColumnDataType = "bigint")]
+    public long TenantId { get; set; }
+
+    [SugarColumn(ColumnName = "factory_id", ColumnDataType = "bigint")]
+    public long FactoryId { get; set; }
+
+    [SugarColumn(ColumnName = "created_at")]
+    public DateTime CreatedAt { get; set; } = DateTime.Now;
+
+    [SugarColumn(ColumnName = "updated_at", IsNullable = true)]
+    public DateTime? UpdatedAt { get; set; }
+
+    [SugarColumn(ColumnName = "is_deleted", ColumnDataType = "boolean")]
+    public bool IsDeleted { get; set; }
+}

+ 91 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S8/OrderFlow/AdoS8OrderFlowManufacturingProcess.cs

@@ -0,0 +1,91 @@
+namespace Admin.NET.Plugin.AiDOP.Entity.S8.OrderFlow;
+
+/// <summary>
+/// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:
+/// S8 订单执行链路本体生产「工序明细」表(baseline + 订单级 SEED)。
+///
+/// order_id / order_code 允许为空:
+///   - NULL → baseline / PPT 级别基线行(scenario_code=BASELINE_PPT)
+///   - 非 NULL → 订单级行(scenario_code=ORDER_LEVEL)
+///
+/// process_code 取值:P10 / P20 / P30 / P40 / TOTAL(合计行 sort_no=5)。
+/// pi_days / actual_days 使用 decimal(6,3) 承载 1 工序 0.441 等尾差修正后的 3 位小数精度。
+/// achievement_rate 使用 decimal(5,4),取值范围 0.0000~1.0000;TOTAL 行 baseline 来自 fixture(0.90 黄)、订单级按 plan_qty 加权平均。
+/// achievement_status 来自 fixture 表格颜色(baseline)或 ≥0.95 green / ≥0.80 yellow / 否则 red(订单级派生)。
+/// </summary>
+[SugarTable("ado_s8_order_flow_manufacturing_process", "S8 订单执行链路本体生产工序明细")]
+[SugarIndex("idx_order_flow_mfg_process_baseline", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(ProcessCode), OrderByType.Asc)]
+[SugarIndex("idx_order_flow_mfg_process_order", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(OrderCode), OrderByType.Asc)]
+[SugarIndex("idx_order_flow_mfg_process_scenario", nameof(TenantId), OrderByType.Asc, nameof(FactoryId), OrderByType.Asc, nameof(ScenarioCode), OrderByType.Asc, nameof(IsDeleted), OrderByType.Asc)]
+public class AdoS8OrderFlowManufacturingProcess
+{
+    [SugarColumn(ColumnName = "id", IsPrimaryKey = true, ColumnDataType = "bigint")]
+    public long Id { get; set; }
+
+    /// <summary>NULL = baseline 行;非 NULL = 订单级行。</summary>
+    [SugarColumn(ColumnName = "order_id", ColumnDataType = "bigint", IsNullable = true)]
+    public long? OrderId { get; set; }
+
+    /// <summary>NULL = baseline 行;非 NULL = 订单业务键。</summary>
+    [SugarColumn(ColumnName = "order_code", Length = 64, IsNullable = true)]
+    public string? OrderCode { get; set; }
+
+    /// <summary>工序编码:P10 / P20 / P30 / P40 / TOTAL。</summary>
+    [SugarColumn(ColumnName = "process_code", Length = 16)]
+    public string ProcessCode { get; set; } = string.Empty;
+
+    /// <summary>工序名称:10工序 / 20工序 / 30工序 / 40工序 / 合计。</summary>
+    [SugarColumn(ColumnName = "process_name", Length = 32)]
+    public string ProcessName { get; set; } = string.Empty;
+
+    /// <summary>PI 标准工时(天)。常量:1.0 / 1.0 / 2.5 / 1.5;TOTAL=6。decimal(6,3)。</summary>
+    [SugarColumn(ColumnName = "pi_days", DecimalDigits = 3, Length = 6)]
+    public decimal PiDays { get; set; }
+
+    /// <summary>实际工时(天)。订单级按 stage.actual_days 守恒尾差修正;TOTAL = stage.actual_days。decimal(6,3)。</summary>
+    [SugarColumn(ColumnName = "actual_days", DecimalDigits = 3, Length = 6)]
+    public decimal ActualDays { get; set; }
+
+    /// <summary>周期状态:green / yellow / red。actual ≤ pi green / ≤ pi*1.2 yellow / 否则 red(seed 时固化,运行期不重判)。</summary>
+    [SugarColumn(ColumnName = "cycle_status", Length = 16)]
+    public string CycleStatus { get; set; } = "green";
+
+    /// <summary>计划台次。baseline fixture: 45/3/15/2/NULL;订单级 round(baseline*ratio);TOTAL 行 NULL。</summary>
+    [SugarColumn(ColumnName = "plan_qty", ColumnDataType = "int", IsNullable = true)]
+    public int? PlanQty { get; set; }
+
+    /// <summary>计划达成率。decimal(5,4),取值 0.0000~1.0000;TOTAL baseline=0.9000(fixture 锚),订单级 TOTAL 由 plan_qty 加权平均。</summary>
+    [SugarColumn(ColumnName = "achievement_rate", DecimalDigits = 4, Length = 5, IsNullable = true)]
+    public decimal? AchievementRate { get; set; }
+
+    /// <summary>达成状态:green / yellow / red;baseline 由 fixture 颜色固定,订单级由 rate 阈值派生(≥0.95 green / ≥0.80 yellow / 否则 red)。</summary>
+    [SugarColumn(ColumnName = "achievement_status", Length = 16)]
+    public string AchievementStatus { get; set; } = string.Empty;
+
+    /// <summary>排序号 1..5(10工序/20工序/30工序/40工序/合计)。</summary>
+    [SugarColumn(ColumnName = "sort_no", ColumnDataType = "int")]
+    public int SortNo { get; set; }
+
+    /// <summary>BASELINE_PPT / ORDER_LEVEL。</summary>
+    [SugarColumn(ColumnName = "scenario_code", Length = 16)]
+    public string ScenarioCode { get; set; } = "BASELINE_PPT";
+
+    /// <summary>SEED / IMPORT / AGG。同 (order_code, process_code) IMPORT/AGG 行存在时优先采用,SEED 仅兜底。</summary>
+    [SugarColumn(ColumnName = "data_source", Length = 16)]
+    public string DataSource { get; set; } = "SEED";
+
+    [SugarColumn(ColumnName = "tenant_id", ColumnDataType = "bigint")]
+    public long TenantId { get; set; }
+
+    [SugarColumn(ColumnName = "factory_id", ColumnDataType = "bigint")]
+    public long FactoryId { get; set; }
+
+    [SugarColumn(ColumnName = "created_at")]
+    public DateTime CreatedAt { get; set; } = DateTime.Now;
+
+    [SugarColumn(ColumnName = "updated_at", IsNullable = true)]
+    public DateTime? UpdatedAt { get; set; }
+
+    [SugarColumn(ColumnName = "is_deleted", ColumnDataType = "boolean")]
+    public bool IsDeleted { get; set; }
+}

+ 423 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/SeedData/S8OrderFlowManufacturingSeedData.cs

@@ -0,0 +1,423 @@
+using Admin.NET.Plugin.AiDOP.Entity.S8.OrderFlow;
+
+namespace Admin.NET.Plugin.AiDOP.SeedData;
+
+/// <summary>
+/// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:本体生产「工序明细」/「损失因素」/「操作员表现」三表 seed。
+///
+/// ──────────────────────────────────────────────────────────────────────
+/// S8-...-FIX-1S(阶段 2 失败修正):本项目实际 SEED 数据落地路径是 UpdateScripts SQL
+///   的 DELETE+INSERT(与 procurement 1.0.148.sql 模式一致),不是 SqlSugar IncreSeed
+///   自动写入。阶段 2 实测启动后三表创建成功但 IncreSeed 0 行写入。
+/// 处理:移除 IncreSeed attribute,保留本算法 SOT 作为 SQL 生成依据与未来 IMPORT/AGG
+///   接入的算法 owner;本批次 221 行 SEED 数据由 WIP-S8-BODY-PRODUCTION-ORDER-LEVEL-SEED.sql
+///   的 INSERT 语句落地。
+/// ──────────────────────────────────────────────────────────────────────
+///
+/// baseline 行(order_id=NULL)来自 MANUFACTURING_DETAIL_FIXTURE 逐字段对齐:
+///   - process:(P10/P20/P30/P40/TOTAL) × (pi, actual, plan_qty, rate, status)
+///   - loss factor:(MATERIAL/EQUIPMENT/QUALITY/EFFICIENCY/SUBTOTAL) × (count, ratio_pct, loss_hours)
+///   - operator:(张/李/王) × (avg_hours, status)
+///
+/// 订单级行(order_id≠NULL,scenario=ORDER_LEVEL):
+///   对每个 BODY_PRODUCTION stage.status != "pending" 的订单(16 单),按 A=stage.actualDays 与 baseline 比例派生:
+///     ratio = A / 6.8
+///   process 行:
+///     baseline_actuals = [2.4, 0.8, 3.0, 0.6]
+///     actual[0..2] = round(baseline_actuals[i] * A / 6.8, 3)
+///     actual[3] = A - sum(actual[0..2])    // 守恒尾差修正
+///     plan_qty[i] = round(baseline_plan[i] * ratio)
+///     achievement_rate[i] = baseline_rate[i] (per-process 固定属性)
+///     achievement_status[i] = ≥0.95 green / ≥0.80 yellow / 否则 red (由 rate 派生)
+///     cycle_status[i] = ≤pi green / ≤pi*1.2 yellow / 否则 red (由 actual vs pi 派生)
+///     TOTAL 行:pi=6, actual=A, plan_qty=NULL,
+///               rate=0.9000 / status="yellow" 锚定 fixture (S8-...-FIX-1R),
+///               不再做 plan_qty 加权计算,与 baseline TOTAL 一致;
+///               cycle_status 仍由 actual vs 6 派生。SEED 过渡口径,IMPORT/AGG 接入后替换。
+///   loss factor 行:
+///     count[i] = round(baseline_count[i] * ratio)
+///     ratio_pct[i] = baseline_ratio_pct[i]    // 结构保留
+///     loss_hours[i] = round(baseline_loss_hours[i] * ratio, 2)
+///     SUBTOTAL: count=round(30*ratio), ratio_pct=100, loss_hours=round(7.5*ratio,2)  // fixture-pinned 比例缩放
+///   operator 行:
+///     avg_hours[i] = round(baseline_hours[i] * ratio, 2)
+///     status[i] = baseline_status[i]    // 每操作员固定 status
+///
+/// 真实数据源(IMPORT / AGG)接入后,service 优先采用 IMPORT/AGG,同 (order_code, process/factor/operator) SEED 行仅兜底。
+/// </summary>
+// S8-...-FIX-1S:[IncreSeed] 已移除(项目实际不通过 SqlSugar IncreSeed 自动写入)。
+// 数据落地见 UpdateScripts/WIP-S8-BODY-PRODUCTION-ORDER-LEVEL-SEED.sql 的 INSERT。
+public class S8OrderFlowManufacturingProcessSeedData : ISqlSugarEntitySeedData<AdoS8OrderFlowManufacturingProcess>
+{
+    public IEnumerable<AdoS8OrderFlowManufacturingProcess> HasData()
+        => S8OrderFlowManufacturingDataset.BuildProcessBaselineRows()
+            .Concat(S8OrderFlowManufacturingDataset.BuildProcessOrderLevelRows());
+}
+
+// S8-...-FIX-1S:[IncreSeed] 已移除(项目实际不通过 SqlSugar IncreSeed 自动写入)。
+// 数据落地见 UpdateScripts/WIP-S8-BODY-PRODUCTION-ORDER-LEVEL-SEED.sql 的 INSERT。
+public class S8OrderFlowManufacturingLossFactorSeedData : ISqlSugarEntitySeedData<AdoS8OrderFlowManufacturingLossFactor>
+{
+    public IEnumerable<AdoS8OrderFlowManufacturingLossFactor> HasData()
+        => S8OrderFlowManufacturingDataset.BuildLossFactorBaselineRows()
+            .Concat(S8OrderFlowManufacturingDataset.BuildLossFactorOrderLevelRows());
+}
+
+// S8-...-FIX-1S:[IncreSeed] 已移除(项目实际不通过 SqlSugar IncreSeed 自动写入)。
+// 数据落地见 UpdateScripts/WIP-S8-BODY-PRODUCTION-ORDER-LEVEL-SEED.sql 的 INSERT。
+public class S8OrderFlowManufacturingOperatorSeedData : ISqlSugarEntitySeedData<AdoS8OrderFlowManufacturingOperator>
+{
+    public IEnumerable<AdoS8OrderFlowManufacturingOperator> HasData()
+        => S8OrderFlowManufacturingDataset.BuildOperatorBaselineRows()
+            .Concat(S8OrderFlowManufacturingDataset.BuildOperatorOrderLevelRows());
+}
+
+internal static class S8OrderFlowManufacturingDataset
+{
+    // ─────────────── ID base ranges(与 procurement-pivot 同号段策略) ───────────────
+    internal const long ProcessBaselineIdBase            = 1329909160000L;
+    internal const long ProcessOrderLevelIdBase          = 1329909170000L;
+    internal const long LossFactorBaselineIdBase         = 1329909180000L;
+    internal const long LossFactorOrderLevelIdBase       = 1329909190000L;
+    internal const long OperatorBaselineIdBase           = 1329909200000L;
+    internal const long OperatorOrderLevelIdBase         = 1329909210000L;
+
+    internal const string ScenarioBaseline   = "BASELINE_PPT";
+    internal const string ScenarioOrderLevel = "ORDER_LEVEL";
+
+    // BODY_PRODUCTION 在 5 阶段流水中固定为索引 3(order_review→product_design→material_procurement→body_production→final_assembly_shipping)。
+    private const int BodyProductionStageIndex = 3;
+
+    // ─────────────── baseline 真值(与 MANUFACTURING_DETAIL_FIXTURE 逐字段对齐) ───────────────
+    private sealed record ProcessBaseline(
+        int SortNo, string Code, string Name,
+        decimal Pi, decimal Actual,
+        int? PlanQty, decimal? Rate, string AchStatus);
+
+    /// <summary>fixture 工序基线:(sort, code, name, pi, actual, plan, rate, ach_status)。</summary>
+    private static readonly ProcessBaseline[] ProcessBaselines =
+    {
+        new(1, "P10",   "10工序", 1.0m, 2.4m, 45,   0.5500m, "red"),
+        new(2, "P20",   "20工序", 1.0m, 0.8m, 3,    0.9700m, "yellow"),
+        new(3, "P30",   "30工序", 2.5m, 3.0m, 15,   0.8500m, "green"),
+        new(4, "P40",   "40工序", 1.5m, 0.6m, 2,    0.9800m, "red"),
+        // TOTAL:pi=6, actual=6.8, plan_qty=NULL, rate=0.90 (fixture-pinned), achievement_status=yellow(来自 fixture 表格颜色)。
+        new(5, "TOTAL", "合计",   6.0m, 6.8m, null, 0.9000m, "yellow"),
+    };
+
+    private sealed record LossFactorBaseline(
+        int SortNo, string Code, string Name,
+        int? Count, decimal? RatioPct, decimal? LossHours);
+
+    /// <summary>fixture 损失因素基线:(sort, code, name, count, ratio_pct, loss_hours)。</summary>
+    /// <remarks>SUBTOTAL loss_hours=7.50 来自 fixture,不等于 4 因素之和 26.15;保留 fixture 锚定。</remarks>
+    private static readonly LossFactorBaseline[] LossFactorBaselines =
+    {
+        new(1, "MATERIAL",   "材料影响",       9,  30.00m, 9.00m),
+        new(2, "EQUIPMENT",  "设备影响",       6,  20.00m, 4.50m),
+        new(3, "QUALITY",    "质量影响",       3,  10.00m, 3.40m),
+        new(4, "EFFICIENCY", "作业效率损失",   12, 40.00m, 9.25m),
+        new(5, "SUBTOTAL",   "损失小计",       30, 100.00m, 7.50m),
+    };
+
+    private sealed record OperatorBaseline(int SortNo, string Code, string Name, decimal Hours, string Status);
+
+    /// <summary>fixture 操作员基线:(sort, code, name, avg_hours, status)。</summary>
+    private static readonly OperatorBaseline[] OperatorBaselines =
+    {
+        new(1, "OP_ZHANG", "张师傅", 20.00m, "red"),
+        new(2, "OP_LI",    "李师傅", 10.00m, "yellow"),
+        new(3, "OP_WANG",  "王师傅", 8.00m,  "green"),
+    };
+
+    /// <summary>baseline TOTAL.actual_days(6.8)作为订单级 ratio = A/6.8 的归一化分母。</summary>
+    private const decimal BaselineTotalActualDays = 6.8m;
+    private const decimal BaselineTotalPiDays = 6.0m;
+
+    // ────────────────────────────────────────────────────────────
+    // Process 行
+    // ────────────────────────────────────────────────────────────
+    public static IEnumerable<AdoS8OrderFlowManufacturingProcess> BuildProcessBaselineRows()
+    {
+        long seq = 0;
+        foreach (var b in ProcessBaselines)
+        {
+            yield return new AdoS8OrderFlowManufacturingProcess
+            {
+                Id = ProcessBaselineIdBase + (++seq),
+                OrderId = null,
+                OrderCode = null,
+                ProcessCode = b.Code,
+                ProcessName = b.Name,
+                PiDays = b.Pi,
+                ActualDays = b.Actual,
+                CycleStatus = ClassifyCycleStatus(b.Actual, b.Pi),
+                PlanQty = b.PlanQty,
+                AchievementRate = b.Rate,
+                AchievementStatus = b.AchStatus,
+                SortNo = b.SortNo,
+                ScenarioCode = ScenarioBaseline,
+                DataSource = "SEED",
+                TenantId = 1,
+                FactoryId = 1,
+                CreatedAt = S8OrderFlowDataset.CreatedAt,
+                UpdatedAt = null,
+                IsDeleted = false,
+            };
+        }
+    }
+
+    public static IEnumerable<AdoS8OrderFlowManufacturingProcess> BuildProcessOrderLevelRows()
+    {
+        long seq = 0;
+        foreach (var spec in S8OrderFlowDataset.Specs)
+        {
+            var lifecycle = S8OrderFlowStageDataset.BuildLifecycleValues(spec);
+            var stage = lifecycle[BodyProductionStageIndex];
+            if (stage.status == "pending") continue;
+
+            var A = stage.actualDays;
+            var ratio = A / BaselineTotalActualDays;
+            var orderId = S8OrderFlowDataset.OrderIdBase + spec.Idx;
+
+            // 4 个工序 actual:前 3 个直接缩放,第 4 个尾差修正以满足 sum == A。
+            var actuals = new decimal[4];
+            decimal sumFirstThree = 0m;
+            for (var i = 0; i < 3; i++)
+            {
+                actuals[i] = decimal.Round(ProcessBaselines[i].Actual * ratio, 3);
+                sumFirstThree += actuals[i];
+            }
+            actuals[3] = decimal.Round(A - sumFirstThree, 3);
+
+            // 4 工序 plan_qty(TOTAL 行不计入;取 baseline.PlanQty 非 null 即可,TOTAL 是第 5 行)
+            var planQtys = new int[4];
+            for (var i = 0; i < 4; i++)
+            {
+                var basePlan = ProcessBaselines[i].PlanQty ?? 0;
+                planQtys[i] = (int)decimal.Round(basePlan * ratio, MidpointRounding.AwayFromZero);
+            }
+
+            // 4 工序行
+            for (var i = 0; i < 4; i++)
+            {
+                var baseRow = ProcessBaselines[i];
+                var rate = baseRow.Rate!.Value;
+                yield return new AdoS8OrderFlowManufacturingProcess
+                {
+                    Id = ProcessOrderLevelIdBase + (++seq),
+                    OrderId = orderId,
+                    OrderCode = spec.OrderCode,
+                    ProcessCode = baseRow.Code,
+                    ProcessName = baseRow.Name,
+                    PiDays = baseRow.Pi,
+                    ActualDays = actuals[i],
+                    CycleStatus = ClassifyCycleStatus(actuals[i], baseRow.Pi),
+                    PlanQty = planQtys[i],
+                    AchievementRate = rate,
+                    AchievementStatus = ClassifyAchievementStatus(rate),
+                    SortNo = baseRow.SortNo,
+                    ScenarioCode = ScenarioOrderLevel,
+                    DataSource = "SEED",
+                    TenantId = 1,
+                    FactoryId = 1,
+                    CreatedAt = S8OrderFlowDataset.CreatedAt,
+                    UpdatedAt = null,
+                    IsDeleted = false,
+                };
+            }
+
+            // TOTAL 行:plan_qty=NULL。
+            // S8-...-FIX-1R:achievement_rate / achievement_status 锚定 fixture(ProcessBaselines[4],
+            // 即 0.9000 / yellow),不再用 4 工序 plan_qty 加权计算,与 baseline TOTAL 保持一致。
+            // SEED 过渡口径;真实 IMPORT/AGG 接入后由真实生产达成数据替换。
+            var fixtureTotalRate = ProcessBaselines[4].Rate!.Value;       // 0.9000m
+            var fixtureTotalStatus = ProcessBaselines[4].AchStatus;       // "yellow"
+
+            yield return new AdoS8OrderFlowManufacturingProcess
+            {
+                Id = ProcessOrderLevelIdBase + (++seq),
+                OrderId = orderId,
+                OrderCode = spec.OrderCode,
+                ProcessCode = ProcessBaselines[4].Code,
+                ProcessName = ProcessBaselines[4].Name,
+                PiDays = BaselineTotalPiDays,
+                ActualDays = decimal.Round(A, 3),
+                CycleStatus = ClassifyCycleStatus(A, BaselineTotalPiDays),
+                PlanQty = null,
+                AchievementRate = fixtureTotalRate,
+                AchievementStatus = fixtureTotalStatus,
+                SortNo = ProcessBaselines[4].SortNo,
+                ScenarioCode = ScenarioOrderLevel,
+                DataSource = "SEED",
+                TenantId = 1,
+                FactoryId = 1,
+                CreatedAt = S8OrderFlowDataset.CreatedAt,
+                UpdatedAt = null,
+                IsDeleted = false,
+            };
+        }
+    }
+
+    // ────────────────────────────────────────────────────────────
+    // Loss factor 行
+    // ────────────────────────────────────────────────────────────
+    public static IEnumerable<AdoS8OrderFlowManufacturingLossFactor> BuildLossFactorBaselineRows()
+    {
+        long seq = 0;
+        foreach (var b in LossFactorBaselines)
+        {
+            yield return new AdoS8OrderFlowManufacturingLossFactor
+            {
+                Id = LossFactorBaselineIdBase + (++seq),
+                OrderId = null,
+                OrderCode = null,
+                FactorCode = b.Code,
+                FactorName = b.Name,
+                CountValue = b.Count,
+                RatioPct = b.RatioPct,
+                LossHours = b.LossHours,
+                SortNo = b.SortNo,
+                ScenarioCode = ScenarioBaseline,
+                DataSource = "SEED",
+                TenantId = 1,
+                FactoryId = 1,
+                CreatedAt = S8OrderFlowDataset.CreatedAt,
+                UpdatedAt = null,
+                IsDeleted = false,
+            };
+        }
+    }
+
+    public static IEnumerable<AdoS8OrderFlowManufacturingLossFactor> BuildLossFactorOrderLevelRows()
+    {
+        long seq = 0;
+        foreach (var spec in S8OrderFlowDataset.Specs)
+        {
+            var lifecycle = S8OrderFlowStageDataset.BuildLifecycleValues(spec);
+            var stage = lifecycle[BodyProductionStageIndex];
+            if (stage.status == "pending") continue;
+
+            var A = stage.actualDays;
+            var ratio = A / BaselineTotalActualDays;
+            var orderId = S8OrderFlowDataset.OrderIdBase + spec.Idx;
+
+            foreach (var b in LossFactorBaselines)
+            {
+                int? count = b.Count.HasValue
+                    ? (int)decimal.Round(b.Count.Value * ratio, MidpointRounding.AwayFromZero)
+                    : null;
+                decimal? hours = b.LossHours.HasValue
+                    ? decimal.Round(b.LossHours.Value * ratio, 2)
+                    : null;
+
+                yield return new AdoS8OrderFlowManufacturingLossFactor
+                {
+                    Id = LossFactorOrderLevelIdBase + (++seq),
+                    OrderId = orderId,
+                    OrderCode = spec.OrderCode,
+                    FactorCode = b.Code,
+                    FactorName = b.Name,
+                    CountValue = count,
+                    RatioPct = b.RatioPct, // 结构保留:baseline ratio_pct 原值复制
+                    LossHours = hours,
+                    SortNo = b.SortNo,
+                    ScenarioCode = ScenarioOrderLevel,
+                    DataSource = "SEED",
+                    TenantId = 1,
+                    FactoryId = 1,
+                    CreatedAt = S8OrderFlowDataset.CreatedAt,
+                    UpdatedAt = null,
+                    IsDeleted = false,
+                };
+            }
+        }
+    }
+
+    // ────────────────────────────────────────────────────────────
+    // Operator 行
+    // ────────────────────────────────────────────────────────────
+    public static IEnumerable<AdoS8OrderFlowManufacturingOperator> BuildOperatorBaselineRows()
+    {
+        long seq = 0;
+        foreach (var b in OperatorBaselines)
+        {
+            yield return new AdoS8OrderFlowManufacturingOperator
+            {
+                Id = OperatorBaselineIdBase + (++seq),
+                OrderId = null,
+                OrderCode = null,
+                OperatorCode = b.Code,
+                OperatorName = b.Name,
+                AvgHours = b.Hours,
+                Status = b.Status,
+                SortNo = b.SortNo,
+                ScenarioCode = ScenarioBaseline,
+                DataSource = "SEED",
+                TenantId = 1,
+                FactoryId = 1,
+                CreatedAt = S8OrderFlowDataset.CreatedAt,
+                UpdatedAt = null,
+                IsDeleted = false,
+            };
+        }
+    }
+
+    public static IEnumerable<AdoS8OrderFlowManufacturingOperator> BuildOperatorOrderLevelRows()
+    {
+        long seq = 0;
+        foreach (var spec in S8OrderFlowDataset.Specs)
+        {
+            var lifecycle = S8OrderFlowStageDataset.BuildLifecycleValues(spec);
+            var stage = lifecycle[BodyProductionStageIndex];
+            if (stage.status == "pending") continue;
+
+            var A = stage.actualDays;
+            var ratio = A / BaselineTotalActualDays;
+            var orderId = S8OrderFlowDataset.OrderIdBase + spec.Idx;
+
+            foreach (var b in OperatorBaselines)
+            {
+                var hours = decimal.Round(b.Hours * ratio, 2);
+                yield return new AdoS8OrderFlowManufacturingOperator
+                {
+                    Id = OperatorOrderLevelIdBase + (++seq),
+                    OrderId = orderId,
+                    OrderCode = spec.OrderCode,
+                    OperatorCode = b.Code,
+                    OperatorName = b.Name,
+                    AvgHours = hours,
+                    Status = b.Status, // 结构保留:每操作员固定 status
+                    SortNo = b.SortNo,
+                    ScenarioCode = ScenarioOrderLevel,
+                    DataSource = "SEED",
+                    TenantId = 1,
+                    FactoryId = 1,
+                    CreatedAt = S8OrderFlowDataset.CreatedAt,
+                    UpdatedAt = null,
+                    IsDeleted = false,
+                };
+            }
+        }
+    }
+
+    // ────────────────────────────────────────────────────────────
+    // status classifiers(seed-time 一次性,运行期不再重判)
+    // ────────────────────────────────────────────────────────────
+
+    /// <summary>cycle_status:actual ≤ pi → green;≤ pi*1.2 → yellow;否则 red。</summary>
+    private static string ClassifyCycleStatus(decimal actual, decimal pi)
+    {
+        if (actual <= pi) return "green";
+        if (actual <= pi * 1.2m) return "yellow";
+        return "red";
+    }
+
+    /// <summary>achievement_status:rate ≥ 0.95 green / ≥ 0.80 yellow / 否则 red。</summary>
+    private static string ClassifyAchievementStatus(decimal rate)
+    {
+        if (rate >= 0.95m) return "green";
+        if (rate >= 0.80m) return "yellow";
+        return "red";
+    }
+}

+ 341 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Service/S8/OrderFlow/S8OrderFlowService.cs

@@ -45,6 +45,10 @@ public class S8OrderFlowService : ITransient
     private readonly SqlSugarRepository<AdoS8OrderFlowProcurementPivot> _pivotRep;
     private readonly SqlSugarRepository<AdoS8Exception> _exceptionRep;
     private readonly SqlSugarRepository<AdoS8OrderFlowProductDesignDrawing> _pddRep;
+    // S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:本体生产 3 表 repository。
+    private readonly SqlSugarRepository<AdoS8OrderFlowManufacturingProcess> _mfgProcessRep;
+    private readonly SqlSugarRepository<AdoS8OrderFlowManufacturingLossFactor> _mfgLossRep;
+    private readonly SqlSugarRepository<AdoS8OrderFlowManufacturingOperator> _mfgOperatorRep;
 
     public S8OrderFlowService(
         SqlSugarRepository<AdoS8OrderFlowOrder> orderRep,
@@ -54,7 +58,10 @@ public class S8OrderFlowService : ITransient
         SqlSugarRepository<AdoS8OrderFlowSnapshot> snapshotRep,
         SqlSugarRepository<AdoS8OrderFlowProcurementPivot> pivotRep,
         SqlSugarRepository<AdoS8Exception> exceptionRep,
-        SqlSugarRepository<AdoS8OrderFlowProductDesignDrawing> pddRep)
+        SqlSugarRepository<AdoS8OrderFlowProductDesignDrawing> pddRep,
+        SqlSugarRepository<AdoS8OrderFlowManufacturingProcess> mfgProcessRep,
+        SqlSugarRepository<AdoS8OrderFlowManufacturingLossFactor> mfgLossRep,
+        SqlSugarRepository<AdoS8OrderFlowManufacturingOperator> mfgOperatorRep)
     {
         _orderRep = orderRep;
         _stageRep = stageRep;
@@ -64,6 +71,9 @@ public class S8OrderFlowService : ITransient
         _pivotRep = pivotRep;
         _exceptionRep = exceptionRep;
         _pddRep = pddRep;
+        _mfgProcessRep = mfgProcessRep;
+        _mfgLossRep = mfgLossRep;
+        _mfgOperatorRep = mfgOperatorRep;
     }
 
     /// <summary>订单档案列表(无分页)。当前 baseline 20 单。</summary>
@@ -968,4 +978,334 @@ public class S8OrderFlowService : ITransient
             Status = d.Status,
             ProductQuantity = d.ProductQuantity,
         };
+
+    // ──────────────────────────────────────────────────────────────────────
+    // S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:本体生产透视。
+    // 单一数据源 = ado_s8_order_flow_manufacturing_{process,loss_factor,operator} 三表。
+    // BASELINE_PPT 读 (order_id IS NULL) baseline 行;CURRENT_FILTERED 读订单级行(order_id IS NOT NULL),
+    //   按 IMPORT/AGG > SEED 优先级去重后,按业务口径聚合:
+    //     process actual_days:AVG(多订单按行平均)
+    //     process plan_qty:SUM(多订单累计计划台次)
+    //     process achievement_rate:AVG(多订单平均达成率),TOTAL 行特殊处理见 BuildManufacturingProcessAggregated。
+    //     process cycle_status / achievement_status:聚合后按阈值重判(与 baseline 同口径,运行期不修改 seed 行)。
+    //     loss factor count:SUM;ratio_pct / loss_hours:AVG。
+    //     operator avg_hours:AVG;status:取首单的 status(baseline 每操作员固定,AVG 后语义不变)。
+    //   orderCodes 为空时返回空骨架(不静默 fallback baseline,避免 baseline 泄漏到单订单态)。
+    // status 阈值与 seed 同步:cycle_status (≤pi green / ≤pi*1.2 yellow / 否则 red),
+    //   achievement_status (≥0.95 green / ≥0.80 yellow / 否则 red)。
+    // ──────────────────────────────────────────────────────────────────────
+
+    private const string ManufacturingProcessTotalCode = "TOTAL";
+
+    // S8-...-FIX-1R:order-level TOTAL.achievement_rate / achievement_status 锚定 fixture,
+    // 与 baseline TOTAL(0.90 / yellow)保持一致,不再用 plan_qty 加权计算(避免 65% red 与 90% yellow 冲突)。
+    // SEED 过渡口径;真实 IMPORT/AGG 接入后由真实生产达成数据替换。
+    private const decimal ManufacturingTotalAchievementRate = 0.9000m;
+    private const string ManufacturingTotalAchievementStatus = "yellow";
+
+    public async Task<AdoS8OrderFlowManufacturingPivotDto> GetManufacturingPivotAsync(
+        AdoS8OrderFlowManufacturingPivotQueryDto query)
+    {
+        var tenantId = query.TenantId ?? 1;
+        var factoryId = query.FactoryId ?? 1;
+        var scope = string.IsNullOrWhiteSpace(query.Scope) ? ScopeBaselinePpt : query.Scope;
+
+        if (string.Equals(scope, ScopeBaselinePpt, StringComparison.OrdinalIgnoreCase))
+        {
+            var processRows = await _mfgProcessRep.AsQueryable()
+                .Where(p => p.TenantId == tenantId && p.FactoryId == factoryId && !p.IsDeleted)
+                .Where(p => p.OrderId == null)
+                .ToListAsync();
+            var lossRows = await _mfgLossRep.AsQueryable()
+                .Where(p => p.TenantId == tenantId && p.FactoryId == factoryId && !p.IsDeleted)
+                .Where(p => p.OrderId == null)
+                .ToListAsync();
+            var operatorRows = await _mfgOperatorRep.AsQueryable()
+                .Where(p => p.TenantId == tenantId && p.FactoryId == factoryId && !p.IsDeleted)
+                .Where(p => p.OrderId == null)
+                .ToListAsync();
+
+            return BuildManufacturingPivotFromBaseline(scope, processRows, lossRows, operatorRows);
+        }
+
+        if (string.Equals(scope, ScopeCurrentFiltered, StringComparison.OrdinalIgnoreCase))
+        {
+            var orderCodes = ParseOrderCodesCsv(query.OrderCodes);
+            if (orderCodes.Count == 0)
+                return new AdoS8OrderFlowManufacturingPivotDto { Scope = scope };
+
+            var processRows = await _mfgProcessRep.AsQueryable()
+                .Where(p => p.TenantId == tenantId && p.FactoryId == factoryId && !p.IsDeleted)
+                .Where(p => p.OrderId != null && p.OrderCode != null)
+                .Where(p => orderCodes.Contains(p.OrderCode!))
+                .ToListAsync();
+            var lossRows = await _mfgLossRep.AsQueryable()
+                .Where(p => p.TenantId == tenantId && p.FactoryId == factoryId && !p.IsDeleted)
+                .Where(p => p.OrderId != null && p.OrderCode != null)
+                .Where(p => orderCodes.Contains(p.OrderCode!))
+                .ToListAsync();
+            var operatorRows = await _mfgOperatorRep.AsQueryable()
+                .Where(p => p.TenantId == tenantId && p.FactoryId == factoryId && !p.IsDeleted)
+                .Where(p => p.OrderId != null && p.OrderCode != null)
+                .Where(p => orderCodes.Contains(p.OrderCode!))
+                .ToListAsync();
+
+            if (processRows.Count == 0 && lossRows.Count == 0 && operatorRows.Count == 0)
+                return new AdoS8OrderFlowManufacturingPivotDto { Scope = scope };
+
+            // IMPORT/AGG > SEED 去重:同 (order_code, process_code/factor_code/operator_code) 上 IMPORT/AGG 优先。
+            var preferredProcess = SelectPreferredMfgProcess(processRows);
+            var preferredLoss = SelectPreferredMfgLossFactor(lossRows);
+            var preferredOperator = SelectPreferredMfgOperator(operatorRows);
+
+            return new AdoS8OrderFlowManufacturingPivotDto
+            {
+                Scope = scope,
+                Processes = BuildManufacturingProcessAggregated(preferredProcess),
+                LossFactors = BuildManufacturingLossFactorAggregated(preferredLoss),
+                Operators = BuildManufacturingOperatorAggregated(preferredOperator),
+            };
+        }
+
+        return new AdoS8OrderFlowManufacturingPivotDto { Scope = scope };
+    }
+
+    private static AdoS8OrderFlowManufacturingPivotDto BuildManufacturingPivotFromBaseline(
+        string scope,
+        List<AdoS8OrderFlowManufacturingProcess> processRows,
+        List<AdoS8OrderFlowManufacturingLossFactor> lossRows,
+        List<AdoS8OrderFlowManufacturingOperator> operatorRows)
+    {
+        var processes = processRows
+            .OrderBy(r => r.SortNo)
+            .Select(r => new AdoS8OrderFlowManufacturingProcessDto
+            {
+                ProcessCode = r.ProcessCode,
+                ProcessName = r.ProcessName,
+                PiDays = r.PiDays,
+                ActualDays = r.ActualDays,
+                CycleStatus = r.CycleStatus,
+                PlanQty = r.PlanQty,
+                AchievementRate = r.AchievementRate,
+                AchievementStatus = r.AchievementStatus,
+                SortNo = r.SortNo,
+            })
+            .ToList();
+
+        var losses = lossRows
+            .OrderBy(r => r.SortNo)
+            .Select(r => new AdoS8OrderFlowManufacturingLossFactorDto
+            {
+                FactorCode = r.FactorCode,
+                FactorName = r.FactorName,
+                CountValue = r.CountValue,
+                RatioPct = r.RatioPct,
+                LossHours = r.LossHours,
+                SortNo = r.SortNo,
+            })
+            .ToList();
+
+        var operators = operatorRows
+            .OrderBy(r => r.SortNo)
+            .Select(r => new AdoS8OrderFlowManufacturingOperatorDto
+            {
+                OperatorCode = r.OperatorCode,
+                OperatorName = r.OperatorName,
+                AvgHours = r.AvgHours,
+                Status = r.Status,
+                SortNo = r.SortNo,
+            })
+            .ToList();
+
+        return new AdoS8OrderFlowManufacturingPivotDto
+        {
+            Scope = scope,
+            Processes = processes,
+            LossFactors = losses,
+            Operators = operators,
+        };
+    }
+
+    private static List<AdoS8OrderFlowManufacturingProcess> SelectPreferredMfgProcess(
+        List<AdoS8OrderFlowManufacturingProcess> rows)
+    {
+        var grouped = rows.GroupBy(r => (r.OrderCode, r.ProcessCode));
+        var result = new List<AdoS8OrderFlowManufacturingProcess>(rows.Count);
+        foreach (var g in grouped)
+        {
+            var preferred = g.FirstOrDefault(r =>
+                string.Equals(r.DataSource, "IMPORT", StringComparison.OrdinalIgnoreCase) ||
+                string.Equals(r.DataSource, "AGG", StringComparison.OrdinalIgnoreCase));
+            result.Add(preferred ?? g.First());
+        }
+        return result;
+    }
+
+    private static List<AdoS8OrderFlowManufacturingLossFactor> SelectPreferredMfgLossFactor(
+        List<AdoS8OrderFlowManufacturingLossFactor> rows)
+    {
+        var grouped = rows.GroupBy(r => (r.OrderCode, r.FactorCode));
+        var result = new List<AdoS8OrderFlowManufacturingLossFactor>(rows.Count);
+        foreach (var g in grouped)
+        {
+            var preferred = g.FirstOrDefault(r =>
+                string.Equals(r.DataSource, "IMPORT", StringComparison.OrdinalIgnoreCase) ||
+                string.Equals(r.DataSource, "AGG", StringComparison.OrdinalIgnoreCase));
+            result.Add(preferred ?? g.First());
+        }
+        return result;
+    }
+
+    private static List<AdoS8OrderFlowManufacturingOperator> SelectPreferredMfgOperator(
+        List<AdoS8OrderFlowManufacturingOperator> rows)
+    {
+        var grouped = rows.GroupBy(r => (r.OrderCode, r.OperatorCode));
+        var result = new List<AdoS8OrderFlowManufacturingOperator>(rows.Count);
+        foreach (var g in grouped)
+        {
+            var preferred = g.FirstOrDefault(r =>
+                string.Equals(r.DataSource, "IMPORT", StringComparison.OrdinalIgnoreCase) ||
+                string.Equals(r.DataSource, "AGG", StringComparison.OrdinalIgnoreCase));
+            result.Add(preferred ?? g.First());
+        }
+        return result;
+    }
+
+    /// <summary>
+    /// 多订单工序聚合:
+    ///   非 TOTAL 行:actual_days = AVG;plan_qty = SUM;achievement_rate = AVG(保留 4 位小数);
+    ///                cycle_status 按聚合 actual vs pi 重判;achievement_status 按聚合 rate 重判。
+    ///   TOTAL 行:pi=6(取 baseline 常量);actual = AVG(与 4 工序 AVG 之和守恒,差异为 rounding 容差);
+    ///             plan_qty = NULL;
+    ///             S8-...-FIX-1R:achievement_rate / achievement_status 锚定 fixture(0.90 / yellow),
+    ///             不再做 plan_qty 加权计算(避免与 baseline TOTAL 视觉冲突);
+    ///             cycle_status 按聚合 actual vs pi 重判。
+    /// </summary>
+    private static List<AdoS8OrderFlowManufacturingProcessDto> BuildManufacturingProcessAggregated(
+        List<AdoS8OrderFlowManufacturingProcess> rows)
+    {
+        var grouped = rows
+            .GroupBy(r => r.ProcessCode)
+            .ToDictionary(g => g.Key, g => g.ToList());
+
+        // S8-...-FIX-1R:TOTAL 行 rate / status 锚定 fixture,不再做 4 工序 plan_qty 加权计算,
+        // 不需要维护中间 aggregatedRates 字典。
+        var processDtos = new List<AdoS8OrderFlowManufacturingProcessDto>();
+
+        foreach (var kv in grouped.OrderBy(g => g.Value.First().SortNo))
+        {
+            var code = kv.Key;
+            var list = kv.Value;
+            var sample = list[0];
+            var isTotal = string.Equals(code, ManufacturingProcessTotalCode, StringComparison.OrdinalIgnoreCase);
+
+            var actualAvg = decimal.Round(list.Average(r => r.ActualDays), 3);
+            var pi = sample.PiDays;
+
+            decimal? aggregatedRate;
+            int? planQtySum;
+            string achStatus;
+            if (isTotal)
+            {
+                // S8-...-FIX-1R:TOTAL 行 rate / status 锚定 fixture(0.90 / yellow),
+                // 不再做 plan_qty 加权计算;非 TOTAL 行的 plan_qty 仍保留供 UI 显示,但不参与 TOTAL.rate。
+                planQtySum = null;
+                aggregatedRate = ManufacturingTotalAchievementRate;
+                achStatus = ManufacturingTotalAchievementStatus;
+            }
+            else
+            {
+                planQtySum = list.Where(r => r.PlanQty.HasValue).Sum(r => r.PlanQty!.Value);
+                var rateRows = list.Where(r => r.AchievementRate.HasValue).ToList();
+                aggregatedRate = rateRows.Count == 0
+                    ? null
+                    : decimal.Round(rateRows.Average(r => r.AchievementRate!.Value), 4);
+                achStatus = aggregatedRate.HasValue
+                    ? ClassifyMfgAchievementStatus(aggregatedRate.Value)
+                    : string.Empty;
+            }
+
+            var cycleStatus = ClassifyMfgCycleStatus(actualAvg, pi);
+
+            processDtos.Add(new AdoS8OrderFlowManufacturingProcessDto
+            {
+                ProcessCode = sample.ProcessCode,
+                ProcessName = sample.ProcessName,
+                PiDays = pi,
+                ActualDays = actualAvg,
+                CycleStatus = cycleStatus,
+                PlanQty = planQtySum,
+                AchievementRate = aggregatedRate,
+                AchievementStatus = achStatus,
+                SortNo = sample.SortNo,
+            });
+        }
+
+        return processDtos;
+    }
+
+    private static List<AdoS8OrderFlowManufacturingLossFactorDto> BuildManufacturingLossFactorAggregated(
+        List<AdoS8OrderFlowManufacturingLossFactor> rows)
+    {
+        return rows
+            .GroupBy(r => r.FactorCode)
+            .OrderBy(g => g.First().SortNo)
+            .Select(g =>
+            {
+                var sample = g.First();
+                var countList = g.Where(r => r.CountValue.HasValue).ToList();
+                var ratioList = g.Where(r => r.RatioPct.HasValue).ToList();
+                var hoursList = g.Where(r => r.LossHours.HasValue).ToList();
+                return new AdoS8OrderFlowManufacturingLossFactorDto
+                {
+                    FactorCode = sample.FactorCode,
+                    FactorName = sample.FactorName,
+                    CountValue = countList.Count == 0 ? null : countList.Sum(r => r.CountValue!.Value),
+                    RatioPct = ratioList.Count == 0
+                        ? null
+                        : decimal.Round(ratioList.Average(r => r.RatioPct!.Value), 2),
+                    LossHours = hoursList.Count == 0
+                        ? null
+                        : decimal.Round(hoursList.Average(r => r.LossHours!.Value), 2),
+                    SortNo = sample.SortNo,
+                };
+            })
+            .ToList();
+    }
+
+    private static List<AdoS8OrderFlowManufacturingOperatorDto> BuildManufacturingOperatorAggregated(
+        List<AdoS8OrderFlowManufacturingOperator> rows)
+    {
+        return rows
+            .GroupBy(r => r.OperatorCode)
+            .OrderBy(g => g.First().SortNo)
+            .Select(g =>
+            {
+                var sample = g.First();
+                return new AdoS8OrderFlowManufacturingOperatorDto
+                {
+                    OperatorCode = sample.OperatorCode,
+                    OperatorName = sample.OperatorName,
+                    AvgHours = decimal.Round(g.Average(r => r.AvgHours), 2),
+                    // 每操作员 baseline status 固化,多订单聚合时各订单值一致;取首单不引入歧义。
+                    Status = sample.Status,
+                    SortNo = sample.SortNo,
+                };
+            })
+            .ToList();
+    }
+
+    private static string ClassifyMfgCycleStatus(decimal actual, decimal pi)
+    {
+        if (actual <= pi) return "green";
+        if (actual <= pi * 1.2m) return "yellow";
+        return "red";
+    }
+
+    private static string ClassifyMfgAchievementStatus(decimal rate)
+    {
+        if (rate >= 0.95m) return "green";
+        if (rate >= 0.80m) return "yellow";
+        return "red";
+    }
 }