diff --git a/frontend/src/pages/admin/AdminProductsPage.tsx b/frontend/src/pages/admin/AdminProductsPage.tsx index eae6ce1..6fcf5b8 100644 --- a/frontend/src/pages/admin/AdminProductsPage.tsx +++ b/frontend/src/pages/admin/AdminProductsPage.tsx @@ -250,7 +250,8 @@ export default function AdminProductsPage() { return {formatDuration(h)}; })()} - + +
diff --git a/frontend/src/pages/admin/AnalyticsDashboard.tsx b/frontend/src/pages/admin/AnalyticsDashboard.tsx index 989873a..08f8c39 100644 --- a/frontend/src/pages/admin/AnalyticsDashboard.tsx +++ b/frontend/src/pages/admin/AnalyticsDashboard.tsx @@ -2,8 +2,8 @@ * 个人能力图谱:X 轴 = 设备身份证,单机耗时对比,支持点击柱子下钻备注弹窗(含照片)。 */ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useSearchParams } from "react-router-dom"; -import { DatePicker, Tabs, Select, Button, Empty, Modal, Timeline, Image } from "antd"; -import { Users, GitBranch, RefreshCw, Loader2, AlertCircle } from "lucide-react"; +import { DatePicker, Tabs, Select, Button, Empty, Modal, Timeline, Image, Radio } from "antd"; +import { Users, GitBranch, RefreshCw, Loader2, AlertCircle, CalendarDays } from "lucide-react"; import dayjs, { type Dayjs } from "dayjs"; import type { EChartsCoreOption } from "echarts/core"; import "dayjs/locale/zh-cn"; @@ -88,6 +88,8 @@ export default function AnalyticsDashboard() { const [capabilityLoading, setCapabilityLoading] = useState(false); const [flow, setFlow] = useState(null); const [flowLoading, setFlowLoading] = useState(false); + // 📅 设备生产总天数口径:自然天 / 工作日 + const [totalDaysMode, setTotalDaysMode] = useState<"natural" | "workdays">("natural"); const [error, setError] = useState(null); // ─── 弹窗下钻:设备备注(all=true 表示流转图点击,展示全部) ── @@ -673,10 +675,57 @@ export default function AnalyticsDashboard() {
)} + {/* 📅 设备生产总天数(自然天 / 工作日切换) */} +
+
+

+ 📅 设备生产总天数 +

+ setTotalDaysMode(e.target.value)} + size="small" + optionType="button" + buttonStyle="solid" + > + 自然天 + 工作日 + +
+ {flowLoading && !flow ? ( +
+ +
+ ) : !flow || flow.devices.length === 0 ? ( +
暂无设备数据,请选择筛选条件后查询
+ ) : ( +
+
+

设备数

+

{flow.devices.length}

+
+
+

{totalDaysMode === "natural" ? "平均生产总天数(自然天)" : "平均生产总天数(工作日)"}

+

+ {Math.round(flow.devices.reduce((s, d) => s + (totalDaysMode === "natural" ? d.total_days : d.total_workdays), 0) / flow.devices.length)} + +

+
+
+

最长生产周期({totalDaysMode === "natural" ? "自然天" : "工作日"})

+

+ {Math.max(...flow.devices.map(d => totalDaysMode === "natural" ? d.total_days : d.total_workdays))} + +

+
+
+ )} +
+ {/* 主体:两个可视化区块 */} setActiveTab(k as "capability" | "flow")} items={[ { key: "capability", diff --git a/frontend/src/services/analyticsApi.ts b/frontend/src/services/analyticsApi.ts index 3938eab..ff0a30b 100644 --- a/frontend/src/services/analyticsApi.ts +++ b/frontend/src/services/analyticsApi.ts @@ -41,6 +41,8 @@ export interface FlowDevice { spec_model: string; lead_time: number; // 设备生命周期总时长(小时) started_at: string; // 设备最早介入时间(T0),MM-DD HH:mm + total_days: number; // 设备生产总天数(自然天) + total_workdays: number; // 设备生产总天数(工作日) } // 时间区间:deviceIndex, startOffset, endOffset, taskName, duration, isMain diff --git a/frontend/src/types/admin.ts b/frontend/src/types/admin.ts index b41028f..223a269 100644 --- a/frontend/src/types/admin.ts +++ b/frontend/src/types/admin.ts @@ -24,6 +24,8 @@ export interface ProductResponse { latest_record_assignee_id: string | null; latest_record_assignee_name: string | null; active_duration_hours: number | null; + production_days: number; + production_days_workdays: number; } /** MOM 物料选项 */