diff --git a/furniture-3d-system/src/app/assisted-assembly/mobile/AssistedAssemblyMobileView.tsx b/furniture-3d-system/src/app/assisted-assembly/mobile/AssistedAssemblyMobileView.tsx
index 68d45e5e..7bbf75b2 100644
--- a/furniture-3d-system/src/app/assisted-assembly/mobile/AssistedAssemblyMobileView.tsx
+++ b/furniture-3d-system/src/app/assisted-assembly/mobile/AssistedAssemblyMobileView.tsx
@@ -18,8 +18,7 @@ interface VariantDTO {
}
interface AssemblyWorkspaceSnapshot {
- assetSeriesId?: string
- [key: string]: unknown
+ assetSeriesId?: string | null
}
type InspectorTabKey = 'assembly' | 'ai'
@@ -86,7 +85,7 @@ export default function AssistedAssemblyMobileView({
{/* 系列列表(未选择时显示) */}
- {!selectedSeriesId && assetSeries.length > 0 && (
+ {!selectedAssetSeriesId && assetSeries.length > 0 && (
{assetSeries.map((series) => (
diff --git a/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.test.tsx b/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.test.tsx
index 1109f218..718d866c 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.test.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.test.tsx
@@ -34,6 +34,7 @@ import {
NON_INTEGRATED_DOCUMENT_WORKSPACE_CATEGORIES,
replaceNonIntegratedProducts,
saveNonIntegratedProduct,
+ type NonIntegratedFactoryRow,
type NonIntegratedSkuItem,
type NonIntegratedProductRecord,
} from "./nonIntegratedStorage";
@@ -454,6 +455,38 @@ function createSkuItem(
};
}
+function createFactoryRow(
+ overrides: Partial
= {},
+): NonIntegratedFactoryRow {
+ return {
+ skuId: "sku-test-1",
+ confirmed: false,
+ model: "SZ0230K01",
+ skuCode: "SZ023001",
+ setCount: "1",
+ barcode: "SZ023001N1280V01",
+ specName: "款式一 140/60/75",
+ size: "140/60/75",
+ color: "胡桃色",
+ material: "橡胶木",
+ installMethod: "拆装",
+ supplierName: "兰考华兰家具",
+ supplierCode: "N1280",
+ warehouse: "郑州仓",
+ shippingMethod: "入仓",
+ minimumOrderQuantity: "50",
+ taxIncludedUnitPrice: "",
+ leadTime: "30天",
+ assemblyMode: "",
+ productionType: "OEM",
+ installationService: "送货",
+ supplierCategory: "主力供应商",
+ purchaseOrderMethod: "订单式",
+ executeStandard: "GB/T 3324",
+ ...overrides,
+ };
+}
+
function createMaterialFinish(
overrides: Partial & Pick,
): MaterialDTO {
@@ -4446,7 +4479,7 @@ describe("NonIntegratedDetailClient", () => {
});
});
- it("shares product factory selection fields by model without changing SKU content", async () => {
+ it("shares product factory selection fields by SPU without changing SKU content", async () => {
const actor = userEvent.setup();
saveNonIntegratedProduct(
@@ -4573,12 +4606,12 @@ describe("NonIntegratedDetailClient", () => {
expect(savedProduct?.factoryRows.map((row) => row.warehouse)).toEqual([
"郑州仓",
"郑州仓",
- "",
+ "郑州仓",
]);
expect(savedProduct?.factoryRows.map((row) => row.shippingMethod)).toEqual([
"代发",
"代发",
- "",
+ "代发",
]);
expect(
savedProduct?.factoryRows.map((row) => row.minimumOrderQuantity),
@@ -4586,7 +4619,7 @@ describe("NonIntegratedDetailClient", () => {
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
"OEM",
"OEM",
- "",
+ "OEM",
]);
expect(
savedProduct?.factoryRows.map((row) => row.installationService),
@@ -4594,11 +4627,11 @@ describe("NonIntegratedDetailClient", () => {
expect(savedProduct?.factoryRows.map((row) => row.supplierCategory)).toEqual([
"主力供应商",
"主力供应商",
- "",
+ "主力供应商",
]);
expect(
savedProduct?.factoryRows.map((row) => row.purchaseOrderMethod),
- ).toEqual(["订单式", "订单式", ""]);
+ ).toEqual(["订单式", "订单式", "订单式"]);
expect(savedProduct?.skuItems.map((item) => item.manufacturer)).toEqual([
"曹县嘉欢",
"曹县嘉欢",
@@ -4640,17 +4673,17 @@ describe("NonIntegratedDetailClient", () => {
expect(savedProduct?.factoryRows.map((row) => row.warehouse)).toEqual([
"杭州仓",
"杭州仓",
- "",
+ "杭州仓",
]);
expect(savedProduct?.factoryRows.map((row) => row.shippingMethod)).toEqual([
"入仓",
"入仓",
- "",
+ "入仓",
]);
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
"ODM",
"ODM",
- "",
+ "ODM",
]);
expect(savedProduct?.skuItems.map((item) => item.manufacturer)).toEqual([
"曹县嘉欢",
@@ -4679,16 +4712,82 @@ describe("NonIntegratedDetailClient", () => {
expect(savedProduct?.factoryRows.map((row) => row.shippingMethod)).toEqual([
"入仓",
"入仓",
- "",
+ "入仓",
]);
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
"ODM",
"ODM",
- "",
+ "ODM",
]);
});
});
+ it("requires product factory rows to be manually confirmed after all fields are filled", async () => {
+ const actor = userEvent.setup();
+ const productId = "SZ0230-product-factory-manual-confirm";
+
+ saveNonIntegratedProduct(
+ createProductRecord({
+ id: productId,
+ spu: "SZ0230",
+ skuBatchConfirmedAt: CONFIRMED_SKU_BATCH_AT,
+ skuItems: [
+ createSkuItem({
+ id: "sku-factory-confirm-1",
+ model: "SZ0230K01",
+ skuCode: "SZ023001",
+ barcode: "SZ023001N1280V01",
+ manufacturer: "兰考华兰家具",
+ manufacturerCode: "N1280",
+ installMethod: "拆装",
+ executeStandard: "GB/T 3324",
+ }),
+ ],
+ factoryRows: [
+ createFactoryRow({
+ skuId: "sku-factory-confirm-1",
+ confirmed: false,
+ model: "SZ0230K01",
+ skuCode: "SZ023001",
+ barcode: "SZ023001N1280V01",
+ }),
+ ],
+ documentWorkspaceConfirmations:
+ createDefaultDocumentWorkspaceConfirmations(false),
+ }),
+ );
+
+ render(
+ ,
+ );
+
+ await actor.click(screen.getByTestId("document-workspace-trigger-产品定厂"));
+
+ const confirmButton = screen.getByTestId("product-factory-confirm");
+ expect(confirmButton).toHaveTextContent("资料已填完核对无误请确认。");
+
+ await waitFor(() => {
+ const savedProduct = getNonIntegratedProductById(productId);
+ expect(savedProduct?.factoryRows?.[0]?.confirmed).toBe(false);
+ expect(savedProduct?.documentWorkspaceConfirmations?.产品定厂).not.toBe(
+ true,
+ );
+ expect(savedProduct?.documentWorkspaceApprovedAt?.产品定厂).toBeUndefined();
+ });
+
+ await actor.click(confirmButton);
+
+ await waitFor(() => {
+ const savedProduct = getNonIntegratedProductById(productId);
+ expect(savedProduct?.factoryRows?.[0]?.confirmed).toBe(true);
+ expect(savedProduct?.documentWorkspaceConfirmations?.产品定厂).toBe(true);
+ expect(savedProduct?.documentWorkspaceApprovedAt?.产品定厂).toEqual(
+ expect.any(String),
+ );
+ });
+ expect(confirmButton).toHaveTextContent("已确认");
+ });
+
it("persists the SKU national standard compliance selection", async () => {
const actor = userEvent.setup();
@@ -6447,8 +6546,16 @@ describe("NonIntegratedDetailClient", () => {
weightKg: "18.5",
},
]);
+ expect(savedProduct?.documentWorkspaceConfirmations?.样包测量).not.toBe(
+ true,
+ );
+ expect(savedProduct?.documentWorkspaceApprovedAt?.样包测量).toBeUndefined();
});
+ const confirmButton = screen.getByTestId("sample-measurement-confirm");
+ expect(confirmButton).toHaveTextContent("资料已填完核对无误请确认。");
+ await actor.click(confirmButton);
+
await waitFor(() => {
const savedProduct = getNonIntegratedProductById(
"SZ0230-sample-measurement",
@@ -6458,6 +6565,7 @@ describe("NonIntegratedDetailClient", () => {
expect.any(String),
);
});
+ expect(confirmButton).toHaveTextContent("已确认");
expect(
screen.getByTestId("sample-measurement-lengthCm-sku-sample-1"),
diff --git a/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.tsx b/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.tsx
index e5c185ef..bebf75b2 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.tsx
@@ -1370,7 +1370,9 @@ export default function NonIntegratedDetailClient({
isReadOnly || isSeriesSkuComponentAggregateMode;
const {
allFinishedSampleShipmentRowsComplete,
+ allProductFactoryRowsConfirmed,
allProductFactoryRowsComplete,
+ allSampleMeasurementRowsConfirmedByPricing,
allSampleMeasurementRowsComplete,
confirmedProductFactoryRowCount,
displayedFinishedSampleShipmentRowsComplete,
@@ -1383,6 +1385,7 @@ export default function NonIntegratedDetailClient({
displayedProductPricingRowsAllSystemEntered,
displayedProductPricingRowsComplete,
displayedProductPricingRowsReadyForPush,
+ displayedSampleMeasurementRowsConfirmedByPricing,
displayedSampleMeasurementRowsComplete,
isSampleMeasurementSkuLocked,
planningLayoutHasContent,
@@ -1460,6 +1463,9 @@ export default function NonIntegratedDetailClient({
const activeDocumentWorkspaceHasContent =
(documentWorkspaceCountByCategory[activeDocumentWorkspaceCategory] ?? 0) >
0;
+ const displayedSampleMeasurementHasPendingRows =
+ displayedProductSampleMeasurementRows.length > 0 &&
+ !displayedSampleMeasurementRowsComplete;
const {
basicInfoDisplayCount,
basicInfoIsApproved,
@@ -1476,19 +1482,19 @@ export default function NonIntegratedDetailClient({
isWorkflowNodeConfirmed,
} = useNonIntegratedWorkflowConfirmationState({
allFinishedSampleShipmentRowsComplete,
- allProductFactoryRowsComplete,
- allSampleMeasurementRowsComplete,
+ allProductFactoryRowsConfirmed,
+ allSampleMeasurementRowsConfirmedByPricing,
basicInfoHasContent,
displayedFinishedSampleShipmentRowsComplete,
displayedFirstQualityRowsComplete,
displayedProductFactoryIsConfirmed,
displayedProductLimitRowsComplete,
displayedProductSampleMeasurementRows,
+ displayedSampleMeasurementRowsConfirmedByPricing,
displayedSampleMeasurementRowsComplete,
documentWorkspaceApprovedAt,
documentWorkspaceConfirmations,
documentWorkspaceRevisionSignatures,
- isSampleMeasurementSkuLocked,
previousDocumentWorkspaceRevisionSignatures:
documentWorkspaceRevisionSignatureRef.current,
productPricingCanBeConfirmed,
@@ -1498,20 +1504,13 @@ export default function NonIntegratedDetailClient({
});
useNonIntegratedWorkflowAutoConfirmationEffects({
allFinishedSampleShipmentRowsComplete,
- allProductFactoryRowsComplete,
- allSampleMeasurementRowsComplete,
existingProductCreatedAt,
- factoryRows,
finishedSampleShipmentRows,
isReadOnly,
mode,
- productFactoryRows,
productId,
- sampleMeasurementRows,
setDocumentWorkspaceApprovedAt,
setDocumentWorkspaceConfirmations,
- setFactoryRows,
- supplierCodeByName,
});
useNonIntegratedWorkflowRevisionResetEffect({
documentWorkspaceRevisionSignatureRef,
@@ -1803,6 +1802,7 @@ export default function NonIntegratedDetailClient({
documentWorkspaceConfirmations;
const nextDocumentWorkspaceApprovedAt =
overrides?.documentWorkspaceApprovedAt ?? documentWorkspaceApprovedAt;
+ const nextFactoryRows = overrides?.factoryRows ?? productFactoryRows;
const nextReviewRounds = overrides?.reviewRounds ?? reviewRounds;
const nextFinishedSampleShipmentRows =
overrides?.finishedSampleShipmentRows ?? productFinishedSampleShipmentRows;
@@ -1810,6 +1810,8 @@ export default function NonIntegratedDetailClient({
overrides?.openingReference ?? openingReferenceRef.current;
const nextSkuItems = overrides?.skuItems ?? skuItems;
const nextPricingRows = overrides?.pricingRows ?? productPricingRows;
+ const nextSampleMeasurementRows =
+ overrides?.sampleMeasurementRows ?? productSampleMeasurementRows;
const nextSkuBatchCount = overrides?.skuBatchCount ?? skuBatchCount;
const nextSkuBatchConfirmedAt =
overrides?.skuBatchConfirmedAt ?? skuBatchConfirmedAt;
@@ -1874,11 +1876,11 @@ export default function NonIntegratedDetailClient({
bomDetails,
nextReviewRounds,
qualityInspectionSheet,
- productFactoryRows,
+ nextFactoryRows,
nextPricingRows,
nextPlanningLayoutRows,
productLimitRows,
- productSampleMeasurementRows,
+ nextSampleMeasurementRows,
nextFinishedSampleShipmentRows,
productFirstQualityRows,
uploadFiles,
@@ -2585,13 +2587,16 @@ export default function NonIntegratedDetailClient({
derivedSkuItems,
displayedProductFactoryHasPendingRows,
displayedProductFactoryHasSystemEnteredPricingRows,
+ displayedProductFactoryIsConfirmed,
displayedProductFactoryRows,
displayedProductFactoryRowsComplete,
documentWorkspaceApprovedAt,
documentWorkspaceConfirmations,
+ documentWorkspaceRevisionSignatureRef,
isCurrentUserAdmin,
isReadOnly,
isSkuItemFactoryConfirmed,
+ persistEditedProduct,
productFactoryModelAutofillRef,
productFactoryReopenField,
productFactoryRows,
@@ -2631,7 +2636,7 @@ export default function NonIntegratedDetailClient({
documentWorkspaceApprovedAt,
documentWorkspaceConfirmations,
documentWorkspaceRevisionSignatureRef,
- isProductFactorySkuComplete,
+ isProductFactorySkuConfirmed: isSkuItemFactoryConfirmed,
isProductLimitNodeLocked,
isProductPricingNodeLocked,
isReadOnly,
@@ -2643,6 +2648,8 @@ export default function NonIntegratedDetailClient({
planningLayoutRowsRef,
pricingRows,
productId,
+ productSampleMeasurementRows,
+ sampleMeasurementRows,
scheduleAutoSave,
setDocumentWorkspaceApprovedAt,
setDocumentWorkspaceConfirmations,
@@ -2879,11 +2886,20 @@ export default function NonIntegratedDetailClient({
handleFinishedSampleShipmentStatusClick,
handleSampleMeasurementStatusClick,
} = useSampleWorkflowStatusController({
+ documentWorkspaceApprovedAt,
+ documentWorkspaceConfirmations,
+ documentWorkspaceRevisionSignatureRef,
displayedFinishedSampleShipmentRows,
displayedFinishedSampleShipmentRowsComplete,
displayedProductFactoryIsConfirmed,
displayedProductSampleMeasurementRows,
+ displayedSampleMeasurementIsConfirmed,
displayedSampleMeasurementRowsComplete,
+ isReadOnly,
+ persistEditedProduct,
+ productSampleMeasurementRows,
+ setDocumentWorkspaceApprovedAt,
+ setDocumentWorkspaceConfirmations,
setSaveMessage,
setSaveMessageType,
});
@@ -3820,7 +3836,7 @@ export default function NonIntegratedDetailClient({
allRows: productSampleMeasurementRows,
displayedRows: displayedProductSampleMeasurementRows,
isReadOnly,
- isProductFactorySkuComplete,
+ isProductFactorySkuConfirmed: isSkuItemFactoryConfirmed,
isSampleMeasurementSkuLocked,
onUpdateRow: updateSampleMeasurementRow,
},
@@ -4320,9 +4336,12 @@ export default function NonIntegratedDetailClient({
documentWorkspaceCountByCategory
}
documentWorkspaceView={documentWorkspaceView}
- isProductFactoryRowComplete={isProductFactoryRowComplete}
+ isSampleMeasurementConfirmed={
+ displayedSampleMeasurementIsConfirmed
+ }
isWorkflowNodeConfirmed={isWorkflowNodeConfirmed}
productFactoryRows={productFactoryRows}
+ sampleMeasurementRows={productSampleMeasurementRows}
visibleGroupedUploadFiles={visibleGroupedUploadFiles}
onOpenBasicInfo={() => setDocumentWorkspaceView("detail")}
onOpenDocumentWorkspace={handleOpenDocumentWorkspace}
@@ -4781,6 +4800,7 @@ export default function NonIntegratedDetailClient({
displayedProductPricingRowsReadyForPush,
displayedProductSampleMeasurementRowCount:
displayedProductSampleMeasurementRows.length,
+ displayedSampleMeasurementHasPendingRows,
displayedSampleMeasurementIsConfirmed,
documentWorkspaceConfirmationAction:
renderDocumentWorkspaceConfirmationAction(),
diff --git a/furniture-3d-system/src/app/intake/non-integrated/nonIntegratedDetailTypes.ts b/furniture-3d-system/src/app/intake/non-integrated/nonIntegratedDetailTypes.ts
index 0f58be86..f66c6dc1 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/nonIntegratedDetailTypes.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/nonIntegratedDetailTypes.ts
@@ -2,6 +2,7 @@ import type { MaterialDTO } from "@/server/services";
import type {
NonIntegratedDocumentWorkspaceApprovalMap,
NonIntegratedDocumentWorkspaceConfirmationMap,
+ NonIntegratedFactoryRow,
NonIntegratedFinishedSampleShipmentRow,
NonIntegratedOpeningReference,
NonIntegratedProductRecord,
@@ -11,6 +12,7 @@ import type {
NonIntegratedReviewIssue,
NonIntegratedReviewRound,
NonIntegratedReviewSheet,
+ NonIntegratedSampleMeasurementRow,
NonIntegratedSkuItem,
} from "./core/nonIntegratedStorage";
import type {
@@ -58,6 +60,8 @@ export type AutoSaveNoticeType = "saving" | "success" | "error";
export type PersistEditedProductOverrides = {
documentWorkspaceConfirmations?: NonIntegratedDocumentWorkspaceConfirmationMap;
documentWorkspaceApprovedAt?: NonIntegratedDocumentWorkspaceApprovalMap;
+ factoryRows?: NonIntegratedFactoryRow[];
+ sampleMeasurementRows?: NonIntegratedSampleMeasurementRow[];
reviewRounds?: NonIntegratedReviewRound[];
finishedSampleShipmentRows?: NonIntegratedFinishedSampleShipmentRow[];
openingReference?: NonIntegratedOpeningReference;
diff --git a/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowAutoConfirmationEffects.ts b/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowAutoConfirmationEffects.ts
index 30fea2b2..819c4ce6 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowAutoConfirmationEffects.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowAutoConfirmationEffects.ts
@@ -1,89 +1,41 @@
import { useEffect, type Dispatch, type SetStateAction } from "react";
import {
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
- PRODUCT_FACTORY_WORKSPACE_CATEGORY,
- SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY,
} from "./workspaces/documents/documentWorkspaceConfig";
import type { DocumentWorkspaceCategory } from "./workspaces/documents/documentWorkspaceHelpers";
-import {
- isProductFactoryRowComplete,
- normalizeFactoryRowsForPayload,
-} from "./workspaces/basic-info/productFactoryHelpers";
import type {
NonIntegratedDocumentWorkspaceApprovalMap,
NonIntegratedDocumentWorkspaceConfirmationMap,
- NonIntegratedFactoryRow,
NonIntegratedFinishedSampleShipmentRow,
- NonIntegratedSampleMeasurementRow,
} from "./core/nonIntegratedStorage";
type DetailMode = "create" | "edit" | "view";
type UseNonIntegratedWorkflowAutoConfirmationEffectsParams = {
allFinishedSampleShipmentRowsComplete: boolean;
- allProductFactoryRowsComplete: boolean;
- allSampleMeasurementRowsComplete: boolean;
existingProductCreatedAt: string;
- factoryRows: NonIntegratedFactoryRow[];
finishedSampleShipmentRows: NonIntegratedFinishedSampleShipmentRow[];
isReadOnly: boolean;
mode: DetailMode;
- productFactoryRows: NonIntegratedFactoryRow[];
productId?: string;
- sampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
setDocumentWorkspaceApprovedAt: Dispatch<
SetStateAction
>;
setDocumentWorkspaceConfirmations: Dispatch<
SetStateAction
>;
- setFactoryRows: Dispatch>;
- supplierCodeByName: Map;
};
export function useNonIntegratedWorkflowAutoConfirmationEffects({
allFinishedSampleShipmentRowsComplete,
- allProductFactoryRowsComplete,
- allSampleMeasurementRowsComplete,
existingProductCreatedAt,
- factoryRows,
finishedSampleShipmentRows,
isReadOnly,
mode,
- productFactoryRows,
productId,
- sampleMeasurementRows,
setDocumentWorkspaceApprovedAt,
setDocumentWorkspaceConfirmations,
- setFactoryRows,
- supplierCodeByName,
}: UseNonIntegratedWorkflowAutoConfirmationEffectsParams) {
- useEffect(() => {
- if (isReadOnly || factoryRows.length === 0) return;
-
- const normalizedRows = normalizeFactoryRowsForPayload(
- productFactoryRows,
- supplierCodeByName,
- );
- const hasConfirmationChange = normalizedRows.some(
- (row) => row.confirmed !== isProductFactoryRowComplete(row),
- );
- if (!hasConfirmationChange) return;
-
- setFactoryRows(
- normalizedRows.map((row) => ({
- ...row,
- confirmed: isProductFactoryRowComplete(row),
- })),
- );
- }, [
- factoryRows.length,
- isReadOnly,
- productFactoryRows,
- setFactoryRows,
- supplierCodeByName,
- ]);
-
useEffect(() => {
if (
mode !== "edit" ||
@@ -99,17 +51,6 @@ export function useNonIntegratedWorkflowAutoConfirmationEffects({
touched: boolean;
complete: boolean;
}> = [
- {
- category: PRODUCT_FACTORY_WORKSPACE_CATEGORY,
- touched: factoryRows.length > 0,
- complete: allProductFactoryRowsComplete,
- },
- {
- category: SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY,
- touched: sampleMeasurementRows.length > 0,
- complete:
- allProductFactoryRowsComplete && allSampleMeasurementRowsComplete,
- },
{
category: FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
touched: finishedSampleShipmentRows.length > 0,
@@ -149,15 +90,11 @@ export function useNonIntegratedWorkflowAutoConfirmationEffects({
});
}, [
allFinishedSampleShipmentRowsComplete,
- allProductFactoryRowsComplete,
- allSampleMeasurementRowsComplete,
existingProductCreatedAt,
- factoryRows.length,
finishedSampleShipmentRows.length,
isReadOnly,
mode,
productId,
- sampleMeasurementRows.length,
setDocumentWorkspaceApprovedAt,
setDocumentWorkspaceConfirmations,
]);
diff --git a/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowCompletion.ts b/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowCompletion.ts
index 2827725a..d582c6f3 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowCompletion.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowCompletion.ts
@@ -56,7 +56,7 @@ export function useNonIntegratedWorkflowCompletion({
productSampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
}) {
const confirmedProductFactoryRowCount = useMemo(
- () => productFactoryRows.filter(isProductFactoryRowComplete).length,
+ () => productFactoryRows.filter((row) => row.confirmed).length,
[productFactoryRows],
);
const populatedProductPricingRowCount = useMemo(
@@ -109,7 +109,10 @@ export function useNonIntegratedWorkflowCompletion({
displayedProductFactoryRows.some((row) => !isProductFactoryRowComplete(row));
const displayedProductFactoryIsConfirmed =
displayedProductFactoryRows.length > 0 &&
- !displayedProductFactoryHasPendingRows;
+ displayedProductFactoryRows.every((row) => row.confirmed);
+ const allProductFactoryRowsConfirmed =
+ productFactoryRows.length > 0 &&
+ productFactoryRows.every((row) => row.confirmed);
const displayedProductFactoryRowsComplete =
displayedProductFactoryRows.length > 0 &&
displayedProductFactoryRows.every(isProductFactoryRowComplete);
@@ -162,6 +165,16 @@ export function useNonIntegratedWorkflowCompletion({
),
[productPricingRows],
);
+ const allSampleMeasurementRowsConfirmedByPricing =
+ productSampleMeasurementRows.length > 0 &&
+ productSampleMeasurementRows.every((row) =>
+ productPricingSystemEnteredSkuIdSet.has(row.skuId),
+ );
+ const displayedSampleMeasurementRowsConfirmedByPricing =
+ displayedProductSampleMeasurementRows.length > 0 &&
+ displayedProductSampleMeasurementRows.every((row) =>
+ productPricingSystemEnteredSkuIdSet.has(row.skuId),
+ );
const displayedProductFactoryHasSystemEnteredPricingRows =
displayedProductFactoryRows.some((row) =>
productPricingSystemEnteredSkuIdSet.has(row.skuId),
@@ -179,7 +192,10 @@ export function useNonIntegratedWorkflowCompletion({
return {
allFinishedSampleShipmentRowsComplete,
+ allProductFactoryRowsConfirmed,
allProductFactoryRowsComplete,
+ allProductPricingRowsSystemEntered,
+ allSampleMeasurementRowsConfirmedByPricing,
allSampleMeasurementRowsComplete,
confirmedProductFactoryRowCount,
displayedFinishedSampleShipmentRowsComplete,
@@ -192,6 +208,7 @@ export function useNonIntegratedWorkflowCompletion({
displayedProductPricingRowsAllSystemEntered,
displayedProductPricingRowsComplete,
displayedProductPricingRowsReadyForPush,
+ displayedSampleMeasurementRowsConfirmedByPricing,
displayedSampleMeasurementRowsComplete,
isSampleMeasurementSkuLocked,
planningLayoutHasContent,
diff --git a/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowConfirmationState.ts b/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowConfirmationState.ts
index db84f226..5b48d2f9 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowConfirmationState.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowConfirmationState.ts
@@ -25,19 +25,19 @@ import {
type UseNonIntegratedWorkflowConfirmationStateParams = {
allFinishedSampleShipmentRowsComplete: boolean;
- allProductFactoryRowsComplete: boolean;
- allSampleMeasurementRowsComplete: boolean;
+ allProductFactoryRowsConfirmed: boolean;
+ allSampleMeasurementRowsConfirmedByPricing: boolean;
basicInfoHasContent: boolean;
displayedFinishedSampleShipmentRowsComplete: boolean;
displayedFirstQualityRowsComplete: boolean;
displayedProductFactoryIsConfirmed: boolean;
displayedProductLimitRowsComplete: boolean;
displayedProductSampleMeasurementRows: Array<{ skuId: string }>;
+ displayedSampleMeasurementRowsConfirmedByPricing: boolean;
displayedSampleMeasurementRowsComplete: boolean;
documentWorkspaceApprovedAt: NonIntegratedDocumentWorkspaceApprovalMap;
documentWorkspaceConfirmations: NonIntegratedDocumentWorkspaceConfirmationMap;
documentWorkspaceRevisionSignatures: Record;
- isSampleMeasurementSkuLocked: (skuId: string) => boolean;
previousDocumentWorkspaceRevisionSignatures:
| Record
| null
@@ -54,19 +54,19 @@ type UseNonIntegratedWorkflowConfirmationStateParams = {
export function useNonIntegratedWorkflowConfirmationState({
allFinishedSampleShipmentRowsComplete,
- allProductFactoryRowsComplete,
- allSampleMeasurementRowsComplete,
+ allProductFactoryRowsConfirmed,
+ allSampleMeasurementRowsConfirmedByPricing,
basicInfoHasContent,
displayedFinishedSampleShipmentRowsComplete,
displayedFirstQualityRowsComplete,
displayedProductFactoryIsConfirmed,
displayedProductLimitRowsComplete,
displayedProductSampleMeasurementRows,
+ displayedSampleMeasurementRowsConfirmedByPricing,
displayedSampleMeasurementRowsComplete,
documentWorkspaceApprovedAt,
documentWorkspaceConfirmations,
documentWorkspaceRevisionSignatures,
- isSampleMeasurementSkuLocked,
previousDocumentWorkspaceRevisionSignatures,
productPricingCanBeConfirmed,
projectStatus,
@@ -92,13 +92,15 @@ export function useNonIntegratedWorkflowConfirmationState({
const isWorkflowNodeConfirmed = useCallback(
(category: WorkflowNodeCategory, hasContent: boolean) => {
if (category === PRODUCT_FACTORY_WORKSPACE_CATEGORY) {
- return hasContent && allProductFactoryRowsComplete;
+ return hasContent && allProductFactoryRowsConfirmed;
}
if (category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY) {
+ if (!hasContent || !allProductFactoryRowsConfirmed) return false;
+ if (allSampleMeasurementRowsConfirmedByPricing) return true;
return (
- hasContent &&
- allProductFactoryRowsComplete &&
- allSampleMeasurementRowsComplete
+ documentWorkspaceConfirmations[category] === true &&
+ Boolean(documentWorkspaceApprovedAt[category]) &&
+ !dirtyWorkflowNodeCategories.has(category)
);
}
if (category === FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY) {
@@ -110,12 +112,6 @@ export function useNonIntegratedWorkflowConfirmationState({
) {
return false;
}
- if (
- category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY &&
- !displayedProductFactoryIsConfirmed
- ) {
- return false;
- }
return (
!shouldRequireWorkflowConfirmation(category) ||
@@ -127,10 +123,9 @@ export function useNonIntegratedWorkflowConfirmationState({
},
[
allFinishedSampleShipmentRowsComplete,
- allProductFactoryRowsComplete,
- allSampleMeasurementRowsComplete,
+ allProductFactoryRowsConfirmed,
+ allSampleMeasurementRowsConfirmedByPricing,
dirtyWorkflowNodeCategories,
- displayedProductFactoryIsConfirmed,
documentWorkspaceApprovedAt,
documentWorkspaceConfirmations,
productPricingCanBeConfirmed,
@@ -142,11 +137,6 @@ export function useNonIntegratedWorkflowConfirmationState({
Boolean(documentWorkspaceApprovedAt[category]),
[documentWorkspaceApprovedAt, documentWorkspaceConfirmations],
);
- const isSampleMeasurementNodeLocked =
- displayedProductSampleMeasurementRows.length > 0 &&
- displayedProductSampleMeasurementRows.every((row) =>
- isSampleMeasurementSkuLocked(row.skuId),
- );
const isFinishedSampleShipmentNodeLocked = isDocumentWorkspaceNodeLocked(
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
);
@@ -156,12 +146,20 @@ export function useNonIntegratedWorkflowConfirmationState({
const isProductLimitNodeLocked = isDocumentWorkspaceNodeLocked(
PRODUCT_LIMIT_WORKSPACE_CATEGORY,
);
- const displayedSampleMeasurementIsConfirmed = isWorkflowNodeConfirmed(
- SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY,
- displayedSampleMeasurementRowsComplete,
- );
+ const displayedSampleMeasurementHasContent =
+ displayedProductSampleMeasurementRows.length > 0;
+ const displayedSampleMeasurementStoredConfirmed =
+ documentWorkspaceConfirmations[SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY] ===
+ true &&
+ Boolean(documentWorkspaceApprovedAt[SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]) &&
+ !dirtyWorkflowNodeCategories.has(SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY);
+ const displayedSampleMeasurementIsConfirmed =
+ displayedSampleMeasurementHasContent &&
+ displayedProductFactoryIsConfirmed &&
+ (displayedSampleMeasurementRowsConfirmedByPricing ||
+ displayedSampleMeasurementStoredConfirmed);
const isSampleMeasurementNodeApproved =
- isSampleMeasurementNodeLocked &&
+ displayedSampleMeasurementIsConfirmed &&
!dirtyWorkflowNodeCategories.has(SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY);
const displayedFinishedSampleShipmentIsConfirmed = isWorkflowNodeConfirmed(
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
diff --git a/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowRows.ts b/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowRows.ts
index d7ca3e06..752e7091 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowRows.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/useNonIntegratedWorkflowRows.ts
@@ -128,7 +128,7 @@ export function useNonIntegratedWorkflowRows({
() =>
new Set(
productFactoryRows
- .filter((row) => row.confirmed || isProductFactoryRowComplete(row))
+ .filter((row) => row.confirmed)
.map((row) => row.skuId),
),
[productFactoryRows],
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/SampleMeasurementWorkspace.tsx b/furniture-3d-system/src/app/intake/non-integrated/workspaces/SampleMeasurementWorkspace.tsx
index 7fe185e4..3dd7821e 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/SampleMeasurementWorkspace.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/SampleMeasurementWorkspace.tsx
@@ -15,7 +15,7 @@ type SampleMeasurementWorkspaceProps = {
displayedRows: ProductSampleMeasurementDisplayRow[];
inheritedSkuBatchTabs: ReactNode;
isReadOnly: boolean;
- isProductFactorySkuComplete: (skuId: string) => boolean;
+ isProductFactorySkuConfirmed: (skuId: string) => boolean;
isSampleMeasurementSkuLocked: (skuId: string) => boolean;
onUpdateRow: (
skuId: string,
@@ -50,7 +50,7 @@ export function SampleMeasurementWorkspace({
displayedRows,
inheritedSkuBatchTabs,
isReadOnly,
- isProductFactorySkuComplete,
+ isProductFactorySkuConfirmed,
isSampleMeasurementSkuLocked,
onUpdateRow,
}: SampleMeasurementWorkspaceProps) {
@@ -64,7 +64,7 @@ export function SampleMeasurementWorkspace({
placeholder={placeholder}
readOnly={
isReadOnly ||
- !isProductFactorySkuComplete(row.skuId) ||
+ !isProductFactorySkuConfirmed(row.skuId) ||
isSampleMeasurementSkuLocked(row.skuId)
}
mode="singleLineResizable"
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/productFactoryHelpers.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/productFactoryHelpers.ts
index f02d173d..4b09b66a 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/productFactoryHelpers.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/productFactoryHelpers.ts
@@ -11,6 +11,7 @@ import {
MODEL_SHARED_PRODUCT_FACTORY_KEYS,
PACKAGE_SHARED_PRODUCT_FACTORY_PURCHASING_KEYS,
PRODUCT_FACTORY_REQUIRED_FIELDS,
+ SPU_SHARED_PRODUCT_FACTORY_KEYS,
} from "./skuFieldConfig";
import { buildAutoBarcode, shouldKeepCustomBarcode } from "./skuAutoHelpers";
import { SUPPLIER_CODE_BY_NAME } from "./supplierDirectory";
@@ -84,6 +85,8 @@ export function normalizeModelSharedProductFactoryRows(
});
return rows.map((row) => {
+ if (row.confirmed) return row;
+
const modelKey = getSkuFactoryModelKey(row);
if (!modelKey) return row;
@@ -101,6 +104,40 @@ export function normalizeModelSharedProductFactoryRows(
});
}
+export function normalizeSpuSharedProductFactoryRows(
+ rows: NonIntegratedFactoryRow[],
+) {
+ const sharedValueByKey = new Map();
+ SPU_SHARED_PRODUCT_FACTORY_KEYS.forEach((key) => {
+ const sharedValue = rows.find((row) => row[key].trim())?.[key].trim() ?? "";
+ sharedValueByKey.set(key, sharedValue);
+ });
+
+ return rows.map((row) => {
+ if (row.confirmed) return row;
+
+ let nextRow = row;
+ SPU_SHARED_PRODUCT_FACTORY_KEYS.forEach((key) => {
+ const sharedValue = sharedValueByKey.get(key);
+ if (sharedValue === undefined || nextRow[key] === sharedValue) return;
+ nextRow = {
+ ...nextRow,
+ [key]: sharedValue,
+ };
+ });
+
+ return nextRow;
+ });
+}
+
+export function normalizeSharedProductFactoryRows(
+ rows: NonIntegratedFactoryRow[],
+) {
+ return normalizeSpuSharedProductFactoryRows(
+ normalizeModelSharedProductFactoryRows(rows),
+ );
+}
+
export function getProductFactoryMissingFieldLabels(
row: NonIntegratedFactoryRow,
) {
@@ -123,7 +160,7 @@ export function getProductFactoryStatusMessage({
if (rows.length === 0) return null;
if (isRowsComplete) {
return {
- message: "产品定厂已完成",
+ message: "资料已填完核对无误请确认。",
type: "success" as const,
};
}
@@ -249,7 +286,7 @@ export function buildProductFactoryRows(
);
});
- return normalizeModelSharedProductFactoryRows(rows);
+ return normalizeSharedProductFactoryRows(rows);
}
export function normalizeFactoryRowsForPayload(
@@ -294,5 +331,5 @@ export function normalizeFactoryRowsForPayload(
};
});
- return normalizeModelSharedProductFactoryRows(normalizedRows);
+ return normalizeSharedProductFactoryRows(normalizedRows);
}
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuFieldConfig.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuFieldConfig.ts
index 68c9272f..8685cdec 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuFieldConfig.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuFieldConfig.ts
@@ -161,10 +161,13 @@ export const PACKAGE_SHARED_PRODUCT_FACTORY_PURCHASING_KEYS =
"assemblyMode",
]);
export const MODEL_SHARED_PRODUCT_FACTORY_KEYS = new Set([
+ "installationService",
+]);
+export const SPU_SHARED_PRODUCT_FACTORY_KEYS = new Set([
"warehouse",
"shippingMethod",
+ "installMethod",
"productionType",
- "installationService",
"supplierCategory",
"purchaseOrderMethod",
]);
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/documents/documentWorkspaceConfig.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/documents/documentWorkspaceConfig.ts
index f681d181..55ecb30f 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/documents/documentWorkspaceConfig.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/documents/documentWorkspaceConfig.ts
@@ -28,8 +28,6 @@ export const PRODUCT_LIMIT_WORKSPACE_CATEGORY: DocumentWorkspaceCategory =
export const PLANNING_LAYOUT_WORKSPACE_CATEGORY: DocumentWorkspaceCategory =
NON_INTEGRATED_PLANNING_LAYOUT_WORKSPACE_CATEGORY;
export const AUTO_COMPLETED_WORKFLOW_CATEGORIES = new Set([
- PRODUCT_FACTORY_WORKSPACE_CATEGORY,
- SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY,
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
]);
export const FACTORY_QUALITY_WORKSPACE_CATEGORY: DocumentWorkspaceCategory =
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactoryHeaderActions.tsx b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactoryHeaderActions.tsx
index 8c559917..1cc9132f 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactoryHeaderActions.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactoryHeaderActions.tsx
@@ -10,6 +10,7 @@ type ProductFactoryHeaderActionsProps = {
isReadOnly: boolean;
rowCount: number;
hasPendingRows: boolean;
+ isConfirmed: boolean;
hasSystemEnteredPricingRows: boolean;
isReopenPickerOpen: boolean;
reopenField: ProductFactoryEditableKey;
@@ -26,6 +27,7 @@ export function ProductFactoryHeaderActions({
isReadOnly,
rowCount,
hasPendingRows,
+ isConfirmed,
hasSystemEnteredPricingRows,
isReopenPickerOpen,
reopenField,
@@ -98,10 +100,15 @@ export function ProductFactoryHeaderActions({
) : null}
);
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactoryInfoTable.tsx b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactoryInfoTable.tsx
index d3ad91f2..04cea71a 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactoryInfoTable.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactoryInfoTable.tsx
@@ -141,14 +141,18 @@ export function ProductFactoryInfoTable({
- {isProductFactoryRowComplete(row)
- ? "已完成"
- : "当前资料未填完"}
+ {row.confirmed
+ ? "已确认"
+ : isProductFactoryRowComplete(row)
+ ? "资料已填完"
+ : "当前资料未填完"}
|
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactorySkuInfoTable.tsx b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactorySkuInfoTable.tsx
index 5c3371c4..f47aa5f4 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactorySkuInfoTable.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/ProductFactorySkuInfoTable.tsx
@@ -40,14 +40,18 @@ export function ProductFactorySkuInfoTable({
|
- {isProductFactoryRowComplete(row)
- ? "已完成"
- : "当前资料未填完"}
+ {row.confirmed
+ ? "已确认"
+ : isProductFactoryRowComplete(row)
+ ? "资料已填完"
+ : "当前资料未填完"}
|
{row.model || "-"} |
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/productFactoryTargetSkuHelpers.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/productFactoryTargetSkuHelpers.ts
index bfb2d1cc..43037ec2 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/productFactoryTargetSkuHelpers.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/productFactoryTargetSkuHelpers.ts
@@ -6,6 +6,7 @@ import {
MODEL_AUTOFILL_PRODUCT_FACTORY_KEYS,
MODEL_SHARED_PRODUCT_FACTORY_KEYS,
PACKAGE_SHARED_PRODUCT_FACTORY_KEYS,
+ SPU_SHARED_PRODUCT_FACTORY_KEYS,
type ProductFactoryEditableKey,
type ProductFactoryModelAutofillEntry,
} from "../basic-info/skuFieldConfig";
@@ -48,6 +49,10 @@ export function getProductFactoryTargetSkuIds(
const targetItem = items.find((item) => item.id === targetId);
if (!targetItem) return new Set([targetId]);
+ if (SPU_SHARED_PRODUCT_FACTORY_KEYS.has(key)) {
+ return new Set(items.map((item) => item.id));
+ }
+
if (MODEL_SHARED_PRODUCT_FACTORY_KEYS.has(key)) {
const targetModelKey = getSkuFactoryModelKey(targetItem);
if (!targetModelKey) return new Set([targetId]);
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/useProductFactoryRowController.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/useProductFactoryRowController.ts
index 2bc298c1..b7bb17c0 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/useProductFactoryRowController.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-factory/useProductFactoryRowController.ts
@@ -4,6 +4,7 @@ import type {
SetStateAction,
} from "react";
+import type { PersistEditedProductOverrides } from "../../nonIntegratedDetailTypes";
import type {
NonIntegratedDocumentWorkspaceApprovalMap,
NonIntegratedDocumentWorkspaceConfirmationMap,
@@ -16,10 +17,15 @@ import {
type ProductFactoryEditableKey,
type ProductFactoryModelAutofillEntry,
} from "../basic-info/skuFieldConfig";
-import { normalizeFactorySupplier, getProductFactoryStatusMessage } from "../basic-info/productFactoryHelpers";
+import {
+ getProductFactoryStatusMessage,
+ normalizeFactoryRowsForPayload,
+ normalizeFactorySupplier,
+} from "../basic-info/productFactoryHelpers";
import { buildSkuItemsAfterSetCountCommit } from "../basic-info/skuSetCountCommitHelpers";
import { getStyleKeyFromModel } from "../style-assets/styleFileHelpers";
import { PRODUCT_FACTORY_WORKSPACE_CATEGORY } from "../documents/documentWorkspaceConfig";
+import type { WorkflowNodeCategory } from "../documents/documentWorkspaceHelpers";
import {
confirmProductFactorySupplierRowsForSku,
reopenProductFactoryRows,
@@ -35,18 +41,30 @@ type ApplySkuSupplierName = (
value: string,
) => NonIntegratedSkuItem;
+type PersistEditedProduct = (params: {
+ successMessage: string;
+ errorFallbackMessage: string;
+ overrides?: PersistEditedProductOverrides;
+ suppressSuccessMessage?: boolean;
+}) => Promise
;
+
type UseProductFactoryRowControllerParams = {
applySkuSupplierName: ApplySkuSupplierName;
derivedSkuItems: NonIntegratedSkuItem[];
displayedProductFactoryHasPendingRows: boolean;
displayedProductFactoryHasSystemEnteredPricingRows: boolean;
+ displayedProductFactoryIsConfirmed: boolean;
displayedProductFactoryRows: NonIntegratedFactoryRow[];
displayedProductFactoryRowsComplete: boolean;
documentWorkspaceApprovedAt: NonIntegratedDocumentWorkspaceApprovalMap;
documentWorkspaceConfirmations: NonIntegratedDocumentWorkspaceConfirmationMap;
+ documentWorkspaceRevisionSignatureRef: MutableRefObject<
+ Record | null
+ >;
isCurrentUserAdmin: boolean;
isReadOnly: boolean;
isSkuItemFactoryConfirmed: (item: NonIntegratedSkuItem) => boolean;
+ persistEditedProduct: PersistEditedProduct;
productFactoryModelAutofillRef: MutableRefObject<
Map
>;
@@ -73,13 +91,16 @@ export function useProductFactoryRowController({
derivedSkuItems,
displayedProductFactoryHasPendingRows,
displayedProductFactoryHasSystemEnteredPricingRows,
+ displayedProductFactoryIsConfirmed,
displayedProductFactoryRows,
displayedProductFactoryRowsComplete,
documentWorkspaceApprovedAt,
documentWorkspaceConfirmations,
+ documentWorkspaceRevisionSignatureRef,
isCurrentUserAdmin,
isReadOnly,
isSkuItemFactoryConfirmed,
+ persistEditedProduct,
productFactoryModelAutofillRef,
productFactoryReopenField,
productFactoryRows,
@@ -156,32 +177,32 @@ export function useProductFactoryRowController({
if (key === "installMethod") {
setSkuItems((current) => {
- const targetItem = workflowSkuItems.find((item) => item.id === skuId);
- if (!targetItem) return current;
+ const targetSkuIds = getProductFactoryTargetSkuIds(
+ workflowSkuItems,
+ skuId,
+ key,
+ );
+ const targetStyleKeys = new Set(
+ workflowSkuItems
+ .filter((item) => targetSkuIds.has(item.id))
+ .map((item) => getStyleKeyFromModel(item.model))
+ .filter(Boolean),
+ );
- const targetStyleKey = getStyleKeyFromModel(targetItem.model);
- if (targetStyleKey) {
- const targetSkuIds = new Set(
- workflowSkuItems
- .filter((item) => getStyleKeyFromModel(item.model) === targetStyleKey)
- .map((item) => item.id),
- );
-
- setStyleDetails((currentDetails) =>
- updateStyleDetailEntry(currentDetails, targetStyleKey, {
- installMethod: value,
- }),
- );
-
- return current.map((item) =>
- targetSkuIds.has(item.id)
- ? { ...item, installMethod: value }
- : item,
- );
+ if (targetStyleKeys.size > 0) {
+ setStyleDetails((currentDetails) => {
+ let nextDetails = currentDetails;
+ targetStyleKeys.forEach((styleKey) => {
+ nextDetails = updateStyleDetailEntry(nextDetails, styleKey, {
+ installMethod: value,
+ });
+ });
+ return nextDetails;
+ });
}
return current.map((item) =>
- item.id === skuId ? { ...item, installMethod: value } : item,
+ targetSkuIds.has(item.id) ? { ...item, installMethod: value } : item,
);
});
}
@@ -235,13 +256,65 @@ export function useProductFactoryRowController({
setSaveMessageType("success");
}
- function handleProductFactoryStatusClick() {
+ async function handleProductFactoryStatusClick() {
const statusMessage = getProductFactoryStatusMessage({
isRowsComplete: displayedProductFactoryRowsComplete,
rows: displayedProductFactoryRows,
});
if (!statusMessage) return;
+ if (
+ !isReadOnly &&
+ displayedProductFactoryRowsComplete &&
+ !displayedProductFactoryIsConfirmed
+ ) {
+ const targetSkuIds = new Set(
+ displayedProductFactoryRows.map((row) => row.skuId),
+ );
+ const normalizedRows = normalizeFactoryRowsForPayload(
+ productFactoryRows,
+ supplierCodeByName,
+ );
+ const nextRows = normalizedRows.map((row) =>
+ targetSkuIds.has(row.skuId) ? { ...row, confirmed: true } : row,
+ );
+ const allRowsConfirmed =
+ nextRows.length > 0 && nextRows.every((row) => row.confirmed);
+ const approvedAt = new Date().toISOString();
+ const nextConfirmations = {
+ ...documentWorkspaceConfirmations,
+ [PRODUCT_FACTORY_WORKSPACE_CATEGORY]: allRowsConfirmed,
+ };
+ const nextApprovedAt = { ...documentWorkspaceApprovedAt };
+ if (allRowsConfirmed) {
+ nextApprovedAt[PRODUCT_FACTORY_WORKSPACE_CATEGORY] = approvedAt;
+ } else {
+ delete nextApprovedAt[PRODUCT_FACTORY_WORKSPACE_CATEGORY];
+ }
+
+ setFactoryRows(nextRows);
+ setDocumentWorkspaceConfirmations(nextConfirmations);
+ setDocumentWorkspaceApprovedAt(nextApprovedAt);
+ if (documentWorkspaceRevisionSignatureRef.current) {
+ documentWorkspaceRevisionSignatureRef.current = {
+ ...documentWorkspaceRevisionSignatureRef.current,
+ [PRODUCT_FACTORY_WORKSPACE_CATEGORY]: JSON.stringify(nextRows),
+ };
+ }
+ await persistEditedProduct({
+ successMessage: allRowsConfirmed
+ ? "产品定厂已确认"
+ : "当前批次产品定厂已确认",
+ errorFallbackMessage: "产品定厂确认保存失败",
+ overrides: {
+ factoryRows: nextRows,
+ documentWorkspaceConfirmations: nextConfirmations,
+ documentWorkspaceApprovedAt: nextApprovedAt,
+ },
+ });
+ return;
+ }
+
setSaveMessage(statusMessage.message);
setSaveMessageType(statusMessage.type);
}
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-workflow/useProductWorkflowRowController.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-workflow/useProductWorkflowRowController.ts
index 760071d5..44f90cb7 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-workflow/useProductWorkflowRowController.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/product-workflow/useProductWorkflowRowController.ts
@@ -20,7 +20,10 @@ import type {
NonIntegratedSkuItem,
} from "../../nonIntegratedStorage";
import type { FinishedSampleShipmentEditableKey } from "../basic-info/skuFieldConfig";
-import { PRODUCT_PRICING_WORKSPACE_CATEGORY } from "../documents/documentWorkspaceConfig";
+import {
+ PRODUCT_PRICING_WORKSPACE_CATEGORY,
+ SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY,
+} from "../documents/documentWorkspaceConfig";
import type { WorkflowNodeCategory } from "../documents/documentWorkspaceHelpers";
import {
updateFirstQualityRowsForSku,
@@ -77,7 +80,7 @@ type UseProductWorkflowRowControllerParams = {
documentWorkspaceRevisionSignatureRef: MutableRefObject<
Record | null
>;
- isProductFactorySkuComplete: (skuId: string) => boolean;
+ isProductFactorySkuConfirmed: (skuId: string) => boolean;
isProductLimitNodeLocked: boolean;
isProductPricingNodeLocked: boolean;
isReadOnly: boolean;
@@ -89,6 +92,8 @@ type UseProductWorkflowRowControllerParams = {
planningLayoutRowsRef: MutableRefObject;
pricingRows: NonIntegratedPricingRow[];
productId?: string;
+ productSampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
+ sampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
scheduleAutoSave: (overrides?: PersistEditedProductOverrides) => void;
setDocumentWorkspaceApprovedAt: Dispatch<
SetStateAction
@@ -128,7 +133,7 @@ export function useProductWorkflowRowController({
documentWorkspaceApprovedAt,
documentWorkspaceConfirmations,
documentWorkspaceRevisionSignatureRef,
- isProductFactorySkuComplete,
+ isProductFactorySkuConfirmed,
isProductLimitNodeLocked,
isProductPricingNodeLocked,
isReadOnly,
@@ -140,6 +145,8 @@ export function useProductWorkflowRowController({
planningLayoutRowsRef,
pricingRows,
productId,
+ productSampleMeasurementRows,
+ sampleMeasurementRows,
scheduleAutoSave,
setDocumentWorkspaceApprovedAt,
setDocumentWorkspaceConfirmations,
@@ -233,16 +240,25 @@ export function useProductWorkflowRowController({
});
const nextProductPricingCanBeConfirmed =
canConfirmProductPricingRows(nextPricingRows);
+ const nextSampleMeasurementCanBeConfirmedByPricing =
+ nextProductPricingCanBeConfirmed &&
+ productSampleMeasurementRows.length > 0;
const nextApprovedAt = nextProductPricingCanBeConfirmed
? {
...documentWorkspaceApprovedAt,
[PRODUCT_PRICING_WORKSPACE_CATEGORY]: pushedAt,
+ ...(nextSampleMeasurementCanBeConfirmedByPricing
+ ? { [SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]: pushedAt }
+ : {}),
}
: documentWorkspaceApprovedAt;
const nextConfirmations = nextProductPricingCanBeConfirmed
? {
...documentWorkspaceConfirmations,
[PRODUCT_PRICING_WORKSPACE_CATEGORY]: true,
+ ...(nextSampleMeasurementCanBeConfirmedByPricing
+ ? { [SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]: true }
+ : {}),
}
: documentWorkspaceConfirmations;
const pushSuccessMessage =
@@ -257,6 +273,12 @@ export function useProductWorkflowRowController({
...documentWorkspaceRevisionSignatureRef.current,
[PRODUCT_PRICING_WORKSPACE_CATEGORY]:
JSON.stringify(nextPricingRows),
+ ...(nextSampleMeasurementCanBeConfirmedByPricing
+ ? {
+ [SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]:
+ JSON.stringify(sampleMeasurementRows),
+ }
+ : {}),
};
}
}
@@ -456,7 +478,7 @@ export function useProductWorkflowRowController({
) {
if (
isReadOnly ||
- !isProductFactorySkuComplete(skuId) ||
+ !isProductFactorySkuConfirmed(skuId) ||
isSampleMeasurementSkuLocked(skuId)
)
return;
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/SampleMeasurementHeaderActions.tsx b/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/SampleMeasurementHeaderActions.tsx
index 039f526e..689eddf0 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/SampleMeasurementHeaderActions.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/SampleMeasurementHeaderActions.tsx
@@ -4,6 +4,7 @@ type SampleMeasurementHeaderActionsProps = {
actionGroupClassName: string;
rowCount: number;
isProductFactoryConfirmed: boolean;
+ hasPendingRows: boolean;
isSampleMeasurementConfirmed: boolean;
onStatusClick: () => void;
};
@@ -12,6 +13,7 @@ export function SampleMeasurementHeaderActions({
actionGroupClassName,
rowCount,
isProductFactoryConfirmed,
+ hasPendingRows,
isSampleMeasurementConfirmed,
onStatusClick,
}: SampleMeasurementHeaderActionsProps) {
@@ -19,6 +21,7 @@ export function SampleMeasurementHeaderActions({
);
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/sampleWorkflowHelpers.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/sampleWorkflowHelpers.ts
index 64e384a3..9a635cda 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/sampleWorkflowHelpers.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/sampleWorkflowHelpers.ts
@@ -153,7 +153,7 @@ export function getSampleMeasurementStatusMessage({
}
return {
- message: "样包测量已完成",
+ message: "资料已填完核对无误请确认。",
type: "success" as const,
};
}
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/useSampleWorkflowStatusController.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/useSampleWorkflowStatusController.ts
index f77eb1de..4a2cb5b1 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/useSampleWorkflowStatusController.ts
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/sample-workflow/useSampleWorkflowStatusController.ts
@@ -1,37 +1,77 @@
import type {
Dispatch,
+ MutableRefObject,
SetStateAction,
} from "react";
+import type { PersistEditedProductOverrides } from "../../nonIntegratedDetailTypes";
+import type {
+ NonIntegratedDocumentWorkspaceApprovalMap,
+ NonIntegratedDocumentWorkspaceConfirmationMap,
+} from "../../nonIntegratedStorage";
+import { SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY } from "../documents/documentWorkspaceConfig";
+import type { WorkflowNodeCategory } from "../documents/documentWorkspaceHelpers";
import {
getFinishedSampleShipmentStatusMessage,
getSampleMeasurementStatusMessage,
+ normalizeSampleMeasurementRowsForPayload,
type ProductFinishedSampleShipmentDisplayRow,
type ProductSampleMeasurementDisplayRow,
} from "./sampleWorkflowHelpers";
type SaveMessageType = "success" | "error";
+type PersistEditedProduct = (params: {
+ successMessage: string;
+ errorFallbackMessage: string;
+ overrides?: PersistEditedProductOverrides;
+ suppressSuccessMessage?: boolean;
+}) => Promise;
+
type UseSampleWorkflowStatusControllerParams = {
+ documentWorkspaceApprovedAt: NonIntegratedDocumentWorkspaceApprovalMap;
+ documentWorkspaceConfirmations: NonIntegratedDocumentWorkspaceConfirmationMap;
displayedFinishedSampleShipmentRows: ProductFinishedSampleShipmentDisplayRow[];
displayedFinishedSampleShipmentRowsComplete: boolean;
displayedProductFactoryIsConfirmed: boolean;
displayedProductSampleMeasurementRows: ProductSampleMeasurementDisplayRow[];
+ displayedSampleMeasurementIsConfirmed: boolean;
displayedSampleMeasurementRowsComplete: boolean;
+ documentWorkspaceRevisionSignatureRef: MutableRefObject<
+ Record | null
+ >;
+ isReadOnly: boolean;
+ persistEditedProduct: PersistEditedProduct;
+ productSampleMeasurementRows: ProductSampleMeasurementDisplayRow[];
+ setDocumentWorkspaceApprovedAt: Dispatch<
+ SetStateAction
+ >;
+ setDocumentWorkspaceConfirmations: Dispatch<
+ SetStateAction
+ >;
setSaveMessage: Dispatch>;
setSaveMessageType: Dispatch>;
};
export function useSampleWorkflowStatusController({
+ documentWorkspaceApprovedAt,
+ documentWorkspaceConfirmations,
displayedFinishedSampleShipmentRows,
displayedFinishedSampleShipmentRowsComplete,
displayedProductFactoryIsConfirmed,
displayedProductSampleMeasurementRows,
+ displayedSampleMeasurementIsConfirmed,
displayedSampleMeasurementRowsComplete,
+ documentWorkspaceRevisionSignatureRef,
+ isReadOnly,
+ persistEditedProduct,
+ productSampleMeasurementRows,
+ setDocumentWorkspaceApprovedAt,
+ setDocumentWorkspaceConfirmations,
setSaveMessage,
setSaveMessageType,
}: UseSampleWorkflowStatusControllerParams) {
- function handleSampleMeasurementStatusClick() {
+ async function handleSampleMeasurementStatusClick() {
const statusMessage = getSampleMeasurementStatusMessage({
isFactoryConfirmed: displayedProductFactoryIsConfirmed,
isRowsComplete: displayedSampleMeasurementRowsComplete,
@@ -39,6 +79,47 @@ export function useSampleWorkflowStatusController({
});
if (!statusMessage) return;
+ if (
+ !isReadOnly &&
+ displayedProductFactoryIsConfirmed &&
+ displayedSampleMeasurementRowsComplete &&
+ !displayedSampleMeasurementIsConfirmed
+ ) {
+ const approvedAt = new Date().toISOString();
+ const nextConfirmations = {
+ ...documentWorkspaceConfirmations,
+ [SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]: true,
+ };
+ const nextApprovedAt = {
+ ...documentWorkspaceApprovedAt,
+ [SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]: approvedAt,
+ };
+ const nextSampleMeasurementRows = normalizeSampleMeasurementRowsForPayload(
+ productSampleMeasurementRows,
+ );
+
+ setDocumentWorkspaceConfirmations(nextConfirmations);
+ setDocumentWorkspaceApprovedAt(nextApprovedAt);
+ if (documentWorkspaceRevisionSignatureRef.current) {
+ documentWorkspaceRevisionSignatureRef.current = {
+ ...documentWorkspaceRevisionSignatureRef.current,
+ [SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]: JSON.stringify(
+ nextSampleMeasurementRows,
+ ),
+ };
+ }
+ await persistEditedProduct({
+ successMessage: "样包测量已确认",
+ errorFallbackMessage: "样包测量确认保存失败",
+ overrides: {
+ sampleMeasurementRows: nextSampleMeasurementRows,
+ documentWorkspaceConfirmations: nextConfirmations,
+ documentWorkspaceApprovedAt: nextApprovedAt,
+ },
+ });
+ return;
+ }
+
setSaveMessage(statusMessage.message);
setSaveMessageType(statusMessage.type);
}
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/shared/DocumentWorkspaceHeaderActionsSlot.tsx b/furniture-3d-system/src/app/intake/non-integrated/workspaces/shared/DocumentWorkspaceHeaderActionsSlot.tsx
index 7ee99435..f9e1e4ac 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/shared/DocumentWorkspaceHeaderActionsSlot.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/shared/DocumentWorkspaceHeaderActionsSlot.tsx
@@ -54,6 +54,7 @@ export function DocumentWorkspaceHeaderActionsSlot({
displayedProductPricingRowsComplete,
displayedProductPricingRowsReadyForPush,
displayedProductSampleMeasurementRowCount,
+ displayedSampleMeasurementHasPendingRows,
displayedSampleMeasurementIsConfirmed,
documentWorkspaceConfirmationAction,
documentWorkspaceUploadInputRef,
@@ -157,6 +158,7 @@ export function DocumentWorkspaceHeaderActionsSlot({
displayedProductPricingRowsComplete: boolean;
displayedProductPricingRowsReadyForPush: boolean;
displayedProductSampleMeasurementRowCount: number;
+ displayedSampleMeasurementHasPendingRows: boolean;
displayedSampleMeasurementIsConfirmed: boolean;
documentWorkspaceConfirmationAction: ReactNode;
documentWorkspaceUploadInputRef: RefObject;
@@ -262,6 +264,7 @@ export function DocumentWorkspaceHeaderActionsSlot({
isReadOnly={isReadOnly}
rowCount={displayedProductFactoryRowCount}
hasPendingRows={displayedProductFactoryHasPendingRows}
+ isConfirmed={displayedProductFactoryIsConfirmed}
hasSystemEnteredPricingRows={
displayedProductFactoryHasSystemEnteredPricingRows
}
@@ -282,6 +285,7 @@ export function DocumentWorkspaceHeaderActionsSlot({
actionGroupClassName={actionGroupClassName}
rowCount={displayedProductSampleMeasurementRowCount}
isProductFactoryConfirmed={displayedProductFactoryIsConfirmed}
+ hasPendingRows={displayedSampleMeasurementHasPendingRows}
isSampleMeasurementConfirmed={displayedSampleMeasurementIsConfirmed}
onStatusClick={onSampleMeasurementStatusClick}
/>
diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/shared/DocumentWorkspaceSidebar.tsx b/furniture-3d-system/src/app/intake/non-integrated/workspaces/shared/DocumentWorkspaceSidebar.tsx
index e953b106..ce93db11 100644
--- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/shared/DocumentWorkspaceSidebar.tsx
+++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/shared/DocumentWorkspaceSidebar.tsx
@@ -10,8 +10,10 @@ import {
import { DocumentWorkspaceSidebarStatusIcon } from "../../components/DocumentWorkspaceControls";
import type {
NonIntegratedFactoryRow,
+ NonIntegratedSampleMeasurementRow,
NonIntegratedUploadFile,
} from "../../nonIntegratedStorage";
+import { SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY } from "../documents/documentWorkspaceConfig";
type DocumentWorkspaceView = "detail" | "document";
@@ -27,9 +29,10 @@ export function DocumentWorkspaceSidebar({
basicInfoNeedsConfirmation,
documentWorkspaceCountByCategory,
documentWorkspaceView,
- isProductFactoryRowComplete,
isWorkflowNodeConfirmed,
productFactoryRows,
+ sampleMeasurementRows,
+ isSampleMeasurementConfirmed,
visibleGroupedUploadFiles,
onOpenBasicInfo,
onOpenDocumentWorkspace,
@@ -42,12 +45,13 @@ export function DocumentWorkspaceSidebar({
Record
>;
documentWorkspaceView: DocumentWorkspaceView;
- isProductFactoryRowComplete: (row: NonIntegratedFactoryRow) => boolean;
isWorkflowNodeConfirmed: (
category: DocumentWorkspaceCategory,
hasContent: boolean,
) => boolean;
productFactoryRows: NonIntegratedFactoryRow[];
+ sampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
+ isSampleMeasurementConfirmed: boolean;
visibleGroupedUploadFiles: GroupedWorkspaceFiles[];
onOpenBasicInfo: () => void;
onOpenDocumentWorkspace: (category: DocumentWorkspaceCategory) => void;
@@ -74,13 +78,14 @@ export function DocumentWorkspaceSidebar({
const categoryHasContent =
category === PRODUCT_FACTORY_WORKSPACE_CATEGORY
? productFactoryRows.length > 0
+ : category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY
+ ? sampleMeasurementRows.length > 0
: hasFiles;
const categoryNeedsConfirmation =
category === PRODUCT_FACTORY_WORKSPACE_CATEGORY
- ? !(
- productFactoryRows.length > 0 &&
- productFactoryRows.every(isProductFactoryRowComplete)
- )
+ ? !productFactoryRows.every((row) => row.confirmed)
+ : category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY
+ ? !isSampleMeasurementConfirmed
: needsConfirmation;
const shouldInsertBasicInfoTrigger = index === basicInfoInsertIndex;
const basicInfoIsActive = documentWorkspaceView === "detail";
diff --git a/furniture-3d-system/src/app/mobile/HomeMobileView.tsx b/furniture-3d-system/src/app/mobile/HomeMobileView.tsx
index 19ced019..7d85a424 100644
--- a/furniture-3d-system/src/app/mobile/HomeMobileView.tsx
+++ b/furniture-3d-system/src/app/mobile/HomeMobileView.tsx
@@ -8,7 +8,7 @@ import Input, { Textarea } from '@/components/ui/Input'
import Modal from '@/components/ui/Modal'
import Button from '@/components/ui/Button'
import Select from '@/components/ui/Select'
-import { ToastContainer } from '@/components/ui/Toast'
+import { ToastContainer, type ToastData } from '@/components/ui/Toast'
import type { ProductWithSkus } from '../home/home-client.types'
import type { LucideIcon } from 'lucide-react'
@@ -63,12 +63,12 @@ export interface HomeMobileViewProps {
/* 删除产品 */
deletingProduct: ProductWithSkus | null
- onDeleteProduct: () => void
+ onDeleteProduct: () => void | Promise
onCloseDeleteProduct: () => void
/* 删除 SKU */
deletingSku: { product: ProductWithSkus; sku: { skuCode: string } } | null
- onDeleteSKU: () => void
+ onDeleteSKU: () => void | Promise
onCloseDeleteSKU: () => void
/* 添加 SKU */
@@ -81,7 +81,7 @@ export interface HomeMobileViewProps {
onMarkHomeReturn: () => void
/* Toast */
- toasts: Array<{ id: string; message: string; type?: string }>
+ toasts: ToastData[]
onRemoveToast: (id: string) => void
}
@@ -406,7 +406,9 @@ export default function HomeMobileView({
{
+ await onDeleteProduct()
+ }}
title="删除产品"
description={
deletingProduct
@@ -428,7 +430,9 @@ export default function HomeMobileView({
{
+ await onDeleteSKU()
+ }}
title="删除 SKU"
description={
deletingSku