diff --git a/frontend/src/components/scan/ProductCard.tsx b/frontend/src/components/scan/ProductCard.tsx
index a391e74..9f794f7 100644
--- a/frontend/src/components/scan/ProductCard.tsx
+++ b/frontend/src/components/scan/ProductCard.tsx
@@ -1,7 +1,7 @@
/** 产品信息卡片 */
import { Package } from "lucide-react";
import type { ProductScanResponse } from "../../types/api";
-import { statusColor, statusLabel } from "../../constants/task";
+import { lifecycleBadge, statusColor, statusLabel } from "../../constants/task";
interface ProductCardProps {
product: ProductScanResponse;
@@ -10,6 +10,8 @@ interface ProductCardProps {
export default function ProductCard({ product }: ProductCardProps) {
// 优先显示宏观状态(整体流转),回退到产品状态字段
const displayStatus = product.overall_status || product.status;
+ // 🔧 发货测试 / 售后维修 — 仅「测试 / 维修」工序下显示
+ const lifeBadge = lifecycleBadge(product.overall_status, product.lifecycle_phase);
return (
@@ -18,6 +20,11 @@ export default function ProductCard({ product }: ProductCardProps) {
{statusLabel(displayStatus)}
+ {lifeBadge && (
+
+ {lifeBadge.label}
+
+ )}
diff --git a/frontend/src/pages/MatrixBoard.tsx b/frontend/src/pages/MatrixBoard.tsx
index 6e6549a..0ec8454 100644
--- a/frontend/src/pages/MatrixBoard.tsx
+++ b/frontend/src/pages/MatrixBoard.tsx
@@ -8,6 +8,7 @@ import { Loader2 } from "lucide-react";
import dayjs, { type Dayjs } from "dayjs";
import { fetchWipMatrix, fetchWipMatrixDetail, type WipMatrixRow, type WipMatrixDetailRow } from "../services/dashboardApi";
import { fetchDeviceRecords, type DeviceRecord } from "../services/analyticsApi";
+import { lifecycleBadge } from "../constants/task";
const { RangePicker } = DatePicker;
@@ -285,8 +286,21 @@ export default function MatrixBoard() {
{
title: "产品名称",
dataIndex: "material_name",
- width: 160,
- render: (v) => {v || "—"},
+ width: 200,
+ render: (v: string, record: WipMatrixDetailRow) => {
+ // 🔧 发货测试 / 售后维修 — 工序取当前下钻的列名(点产品名时为全部工序,不显示)
+ const lb = lifecycleBadge(drill?.process, record.lifecycle_phase);
+ return (
+
+ {v || "—"}
+ {lb && (
+
+ {lb.label}
+
+ )}
+
+ );
+ },
},
{
title: "身份证号",
diff --git a/frontend/src/pages/ScanPage.tsx b/frontend/src/pages/ScanPage.tsx
index 1f36a6c..90058f5 100644
--- a/frontend/src/pages/ScanPage.tsx
+++ b/frontend/src/pages/ScanPage.tsx
@@ -6,6 +6,7 @@ import { scanProduct } from "../services/productApi";
import type { ProductScanResponse } from "../types/api";
import ManualInput from "../components/scan/ManualInput";
import QueryResult from "../components/scan/QueryResult";
+import { lifecycleBadge } from "../constants/task";
// 🚀 CameraScanner → QrScanner → html5-qrcode (~200KB),仅在首次点开摄像头时加载
const CameraScanner = lazy(() => import("../components/scan/CameraScanner"));
@@ -74,6 +75,11 @@ export default function ScanPage() {
{product.overall_status || "未设定"}
+ {/* 🔧 售后回流标识:处于发货测试/售后维修环节时红底白字提示 */}
+ {(() => {
+ const lb = lifecycleBadge(product.overall_status, product.lifecycle_phase);
+ return lb ? {lb.label} : null;
+ })()}
)}
@@ -126,6 +132,11 @@ export default function ScanPage() {
{product.overall_status || "未设定"}
+ {/* 🔧 售后回流标识:处于发货测试/售后维修环节时红底白字提示 */}
+ {(() => {
+ const lb = lifecycleBadge(product.overall_status, product.lifecycle_phase);
+ return lb ?
{lb.label} : null;
+ })()}
)}
diff --git a/frontend/src/pages/admin/AdminProductsPage.tsx b/frontend/src/pages/admin/AdminProductsPage.tsx
index 0c8e39a..1880248 100644
--- a/frontend/src/pages/admin/AdminProductsPage.tsx
+++ b/frontend/src/pages/admin/AdminProductsPage.tsx
@@ -13,7 +13,7 @@ import {
} from "../../services/printApi";
import { useToast } from "../../components/ui/Toast";
import { useAuth } from "../../contexts/AuthContext";
-import { getStatusConfig } from "../../constants/task";
+import { getStatusConfig, lifecycleBadge } from "../../constants/task";
const QR_BASE = "/api/v1/products/qrcode";
@@ -275,12 +275,21 @@ export default function AdminProductsPage() {
{p.serial_number}
- {(() => {
- const cfg = getStatusConfig(p.macro_status || p.status);
- return cfg.label ? (
-
{cfg.label}
- ) : null;
- })()}
+
+ {(() => {
+ const cfg = getStatusConfig(p.macro_status || p.status);
+ return cfg.label ? (
+ {cfg.label}
+ ) : null;
+ })()}
+ {/* 🔧 发货测试 / 售后维修 — 仅「测试 / 维修」工序下显示 */}
+ {(() => {
+ const lb = lifecycleBadge(p.overall_status, p.lifecycle_phase);
+ return lb ? (
+ {lb.label}
+ ) : null;
+ })()}
+
diff --git a/frontend/src/pages/admin/AdminTasksPage.tsx b/frontend/src/pages/admin/AdminTasksPage.tsx
index 4a68dc5..19340d8 100644
--- a/frontend/src/pages/admin/AdminTasksPage.tsx
+++ b/frontend/src/pages/admin/AdminTasksPage.tsx
@@ -17,7 +17,7 @@ import { Modal, ReceiveConfirmModal, RejectModal, TransferModal } from "../../co
import type { ProductResponse } from "../../types/admin";
import type { ProductScanResponse } from "../../types/api";
import { useToast } from "../../components/ui/Toast";
-import { getStatusConfig } from "../../constants/task";
+import { getStatusConfig, lifecycleBadge, ALL_OVERALL_OPTIONS } from "../../constants/task";
import { useAuth } from "../../contexts/AuthContext";
const STATUS_TABS = [
@@ -107,8 +107,21 @@ export default function AdminTasksPage() {
{
key: "overall_status", label: "当前工序", colSpan: 1,
filterType: "enum", getFilterValue: (p) => p.overall_status || "—",
- enumOptions: ["备货", "生产", "测试", "维修", "待仓库收货", "已入库", "已出库"].map((v) => ({ value: v, label: v })),
- render: (p) => {p.overall_status || "—"},
+ // 🔧 筛选用两阶段并集:售后设备的「发货测试 / 售后维修」也要能被筛出来
+ enumOptions: ALL_OVERALL_OPTIONS.map((v) => ({ value: v, label: v })),
+ render: (p) => {
+ const lb = lifecycleBadge(p.overall_status, p.lifecycle_phase);
+ return (
+
+ {p.overall_status || "—"}
+ {lb && (
+
+ {lb.label}
+
+ )}
+
+ );
+ },
},
{
key: "status", label: "产品状态", colSpan: 1,