merge: 解决冲突,保留使用 SharedAssetFamilyDTO 的类型修复
This commit is contained in:
commit
e7d2c8626c
@ -18,8 +18,7 @@ interface VariantDTO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface AssemblyWorkspaceSnapshot {
|
interface AssemblyWorkspaceSnapshot {
|
||||||
assetSeriesId?: string
|
assetSeriesId?: string | null
|
||||||
[key: string]: unknown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type InspectorTabKey = 'assembly' | 'ai'
|
type InspectorTabKey = 'assembly' | 'ai'
|
||||||
@ -86,7 +85,7 @@ export default function AssistedAssemblyMobileView({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 系列列表(未选择时显示) */}
|
{/* 系列列表(未选择时显示) */}
|
||||||
{!selectedSeriesId && assetSeries.length > 0 && (
|
{!selectedAssetSeriesId && assetSeries.length > 0 && (
|
||||||
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
|
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
|
||||||
<div className="space-y-2 px-4 py-2">
|
<div className="space-y-2 px-4 py-2">
|
||||||
{assetSeries.map((series) => (
|
{assetSeries.map((series) => (
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import {
|
|||||||
NON_INTEGRATED_DOCUMENT_WORKSPACE_CATEGORIES,
|
NON_INTEGRATED_DOCUMENT_WORKSPACE_CATEGORIES,
|
||||||
replaceNonIntegratedProducts,
|
replaceNonIntegratedProducts,
|
||||||
saveNonIntegratedProduct,
|
saveNonIntegratedProduct,
|
||||||
|
type NonIntegratedFactoryRow,
|
||||||
type NonIntegratedSkuItem,
|
type NonIntegratedSkuItem,
|
||||||
type NonIntegratedProductRecord,
|
type NonIntegratedProductRecord,
|
||||||
} from "./nonIntegratedStorage";
|
} from "./nonIntegratedStorage";
|
||||||
@ -454,6 +455,38 @@ function createSkuItem(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createFactoryRow(
|
||||||
|
overrides: Partial<NonIntegratedFactoryRow> = {},
|
||||||
|
): 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(
|
function createMaterialFinish(
|
||||||
overrides: Partial<MaterialDTO> & Pick<MaterialDTO, "id" | "name">,
|
overrides: Partial<MaterialDTO> & Pick<MaterialDTO, "id" | "name">,
|
||||||
): MaterialDTO {
|
): 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();
|
const actor = userEvent.setup();
|
||||||
|
|
||||||
saveNonIntegratedProduct(
|
saveNonIntegratedProduct(
|
||||||
@ -4573,12 +4606,12 @@ describe("NonIntegratedDetailClient", () => {
|
|||||||
expect(savedProduct?.factoryRows.map((row) => row.warehouse)).toEqual([
|
expect(savedProduct?.factoryRows.map((row) => row.warehouse)).toEqual([
|
||||||
"郑州仓",
|
"郑州仓",
|
||||||
"郑州仓",
|
"郑州仓",
|
||||||
"",
|
"郑州仓",
|
||||||
]);
|
]);
|
||||||
expect(savedProduct?.factoryRows.map((row) => row.shippingMethod)).toEqual([
|
expect(savedProduct?.factoryRows.map((row) => row.shippingMethod)).toEqual([
|
||||||
"代发",
|
"代发",
|
||||||
"代发",
|
"代发",
|
||||||
"",
|
"代发",
|
||||||
]);
|
]);
|
||||||
expect(
|
expect(
|
||||||
savedProduct?.factoryRows.map((row) => row.minimumOrderQuantity),
|
savedProduct?.factoryRows.map((row) => row.minimumOrderQuantity),
|
||||||
@ -4586,7 +4619,7 @@ describe("NonIntegratedDetailClient", () => {
|
|||||||
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
|
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
|
||||||
"OEM",
|
"OEM",
|
||||||
"OEM",
|
"OEM",
|
||||||
"",
|
"OEM",
|
||||||
]);
|
]);
|
||||||
expect(
|
expect(
|
||||||
savedProduct?.factoryRows.map((row) => row.installationService),
|
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.supplierCategory)).toEqual([
|
||||||
"主力供应商",
|
"主力供应商",
|
||||||
"主力供应商",
|
"主力供应商",
|
||||||
"",
|
"主力供应商",
|
||||||
]);
|
]);
|
||||||
expect(
|
expect(
|
||||||
savedProduct?.factoryRows.map((row) => row.purchaseOrderMethod),
|
savedProduct?.factoryRows.map((row) => row.purchaseOrderMethod),
|
||||||
).toEqual(["订单式", "订单式", ""]);
|
).toEqual(["订单式", "订单式", "订单式"]);
|
||||||
expect(savedProduct?.skuItems.map((item) => item.manufacturer)).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.warehouse)).toEqual([
|
||||||
"杭州仓",
|
"杭州仓",
|
||||||
"杭州仓",
|
"杭州仓",
|
||||||
"",
|
"杭州仓",
|
||||||
]);
|
]);
|
||||||
expect(savedProduct?.factoryRows.map((row) => row.shippingMethod)).toEqual([
|
expect(savedProduct?.factoryRows.map((row) => row.shippingMethod)).toEqual([
|
||||||
"入仓",
|
"入仓",
|
||||||
"入仓",
|
"入仓",
|
||||||
"",
|
"入仓",
|
||||||
]);
|
]);
|
||||||
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
|
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
|
||||||
"ODM",
|
"ODM",
|
||||||
"ODM",
|
"ODM",
|
||||||
"",
|
"ODM",
|
||||||
]);
|
]);
|
||||||
expect(savedProduct?.skuItems.map((item) => item.manufacturer)).toEqual([
|
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.shippingMethod)).toEqual([
|
||||||
"入仓",
|
"入仓",
|
||||||
"入仓",
|
"入仓",
|
||||||
"",
|
"入仓",
|
||||||
]);
|
]);
|
||||||
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
|
expect(savedProduct?.factoryRows.map((row) => row.productionType)).toEqual([
|
||||||
"ODM",
|
"ODM",
|
||||||
"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(
|
||||||
|
<NonIntegratedDetailClient mode="edit" productId={productId} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
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 () => {
|
it("persists the SKU national standard compliance selection", async () => {
|
||||||
const actor = userEvent.setup();
|
const actor = userEvent.setup();
|
||||||
|
|
||||||
@ -6447,8 +6546,16 @@ describe("NonIntegratedDetailClient", () => {
|
|||||||
weightKg: "18.5",
|
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(() => {
|
await waitFor(() => {
|
||||||
const savedProduct = getNonIntegratedProductById(
|
const savedProduct = getNonIntegratedProductById(
|
||||||
"SZ0230-sample-measurement",
|
"SZ0230-sample-measurement",
|
||||||
@ -6458,6 +6565,7 @@ describe("NonIntegratedDetailClient", () => {
|
|||||||
expect.any(String),
|
expect.any(String),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
expect(confirmButton).toHaveTextContent("已确认");
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.getByTestId("sample-measurement-lengthCm-sku-sample-1"),
|
screen.getByTestId("sample-measurement-lengthCm-sku-sample-1"),
|
||||||
|
|||||||
@ -1370,7 +1370,9 @@ export default function NonIntegratedDetailClient({
|
|||||||
isReadOnly || isSeriesSkuComponentAggregateMode;
|
isReadOnly || isSeriesSkuComponentAggregateMode;
|
||||||
const {
|
const {
|
||||||
allFinishedSampleShipmentRowsComplete,
|
allFinishedSampleShipmentRowsComplete,
|
||||||
|
allProductFactoryRowsConfirmed,
|
||||||
allProductFactoryRowsComplete,
|
allProductFactoryRowsComplete,
|
||||||
|
allSampleMeasurementRowsConfirmedByPricing,
|
||||||
allSampleMeasurementRowsComplete,
|
allSampleMeasurementRowsComplete,
|
||||||
confirmedProductFactoryRowCount,
|
confirmedProductFactoryRowCount,
|
||||||
displayedFinishedSampleShipmentRowsComplete,
|
displayedFinishedSampleShipmentRowsComplete,
|
||||||
@ -1383,6 +1385,7 @@ export default function NonIntegratedDetailClient({
|
|||||||
displayedProductPricingRowsAllSystemEntered,
|
displayedProductPricingRowsAllSystemEntered,
|
||||||
displayedProductPricingRowsComplete,
|
displayedProductPricingRowsComplete,
|
||||||
displayedProductPricingRowsReadyForPush,
|
displayedProductPricingRowsReadyForPush,
|
||||||
|
displayedSampleMeasurementRowsConfirmedByPricing,
|
||||||
displayedSampleMeasurementRowsComplete,
|
displayedSampleMeasurementRowsComplete,
|
||||||
isSampleMeasurementSkuLocked,
|
isSampleMeasurementSkuLocked,
|
||||||
planningLayoutHasContent,
|
planningLayoutHasContent,
|
||||||
@ -1460,6 +1463,9 @@ export default function NonIntegratedDetailClient({
|
|||||||
const activeDocumentWorkspaceHasContent =
|
const activeDocumentWorkspaceHasContent =
|
||||||
(documentWorkspaceCountByCategory[activeDocumentWorkspaceCategory] ?? 0) >
|
(documentWorkspaceCountByCategory[activeDocumentWorkspaceCategory] ?? 0) >
|
||||||
0;
|
0;
|
||||||
|
const displayedSampleMeasurementHasPendingRows =
|
||||||
|
displayedProductSampleMeasurementRows.length > 0 &&
|
||||||
|
!displayedSampleMeasurementRowsComplete;
|
||||||
const {
|
const {
|
||||||
basicInfoDisplayCount,
|
basicInfoDisplayCount,
|
||||||
basicInfoIsApproved,
|
basicInfoIsApproved,
|
||||||
@ -1476,19 +1482,19 @@ export default function NonIntegratedDetailClient({
|
|||||||
isWorkflowNodeConfirmed,
|
isWorkflowNodeConfirmed,
|
||||||
} = useNonIntegratedWorkflowConfirmationState({
|
} = useNonIntegratedWorkflowConfirmationState({
|
||||||
allFinishedSampleShipmentRowsComplete,
|
allFinishedSampleShipmentRowsComplete,
|
||||||
allProductFactoryRowsComplete,
|
allProductFactoryRowsConfirmed,
|
||||||
allSampleMeasurementRowsComplete,
|
allSampleMeasurementRowsConfirmedByPricing,
|
||||||
basicInfoHasContent,
|
basicInfoHasContent,
|
||||||
displayedFinishedSampleShipmentRowsComplete,
|
displayedFinishedSampleShipmentRowsComplete,
|
||||||
displayedFirstQualityRowsComplete,
|
displayedFirstQualityRowsComplete,
|
||||||
displayedProductFactoryIsConfirmed,
|
displayedProductFactoryIsConfirmed,
|
||||||
displayedProductLimitRowsComplete,
|
displayedProductLimitRowsComplete,
|
||||||
displayedProductSampleMeasurementRows,
|
displayedProductSampleMeasurementRows,
|
||||||
|
displayedSampleMeasurementRowsConfirmedByPricing,
|
||||||
displayedSampleMeasurementRowsComplete,
|
displayedSampleMeasurementRowsComplete,
|
||||||
documentWorkspaceApprovedAt,
|
documentWorkspaceApprovedAt,
|
||||||
documentWorkspaceConfirmations,
|
documentWorkspaceConfirmations,
|
||||||
documentWorkspaceRevisionSignatures,
|
documentWorkspaceRevisionSignatures,
|
||||||
isSampleMeasurementSkuLocked,
|
|
||||||
previousDocumentWorkspaceRevisionSignatures:
|
previousDocumentWorkspaceRevisionSignatures:
|
||||||
documentWorkspaceRevisionSignatureRef.current,
|
documentWorkspaceRevisionSignatureRef.current,
|
||||||
productPricingCanBeConfirmed,
|
productPricingCanBeConfirmed,
|
||||||
@ -1498,20 +1504,13 @@ export default function NonIntegratedDetailClient({
|
|||||||
});
|
});
|
||||||
useNonIntegratedWorkflowAutoConfirmationEffects({
|
useNonIntegratedWorkflowAutoConfirmationEffects({
|
||||||
allFinishedSampleShipmentRowsComplete,
|
allFinishedSampleShipmentRowsComplete,
|
||||||
allProductFactoryRowsComplete,
|
|
||||||
allSampleMeasurementRowsComplete,
|
|
||||||
existingProductCreatedAt,
|
existingProductCreatedAt,
|
||||||
factoryRows,
|
|
||||||
finishedSampleShipmentRows,
|
finishedSampleShipmentRows,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
mode,
|
mode,
|
||||||
productFactoryRows,
|
|
||||||
productId,
|
productId,
|
||||||
sampleMeasurementRows,
|
|
||||||
setDocumentWorkspaceApprovedAt,
|
setDocumentWorkspaceApprovedAt,
|
||||||
setDocumentWorkspaceConfirmations,
|
setDocumentWorkspaceConfirmations,
|
||||||
setFactoryRows,
|
|
||||||
supplierCodeByName,
|
|
||||||
});
|
});
|
||||||
useNonIntegratedWorkflowRevisionResetEffect({
|
useNonIntegratedWorkflowRevisionResetEffect({
|
||||||
documentWorkspaceRevisionSignatureRef,
|
documentWorkspaceRevisionSignatureRef,
|
||||||
@ -1803,6 +1802,7 @@ export default function NonIntegratedDetailClient({
|
|||||||
documentWorkspaceConfirmations;
|
documentWorkspaceConfirmations;
|
||||||
const nextDocumentWorkspaceApprovedAt =
|
const nextDocumentWorkspaceApprovedAt =
|
||||||
overrides?.documentWorkspaceApprovedAt ?? documentWorkspaceApprovedAt;
|
overrides?.documentWorkspaceApprovedAt ?? documentWorkspaceApprovedAt;
|
||||||
|
const nextFactoryRows = overrides?.factoryRows ?? productFactoryRows;
|
||||||
const nextReviewRounds = overrides?.reviewRounds ?? reviewRounds;
|
const nextReviewRounds = overrides?.reviewRounds ?? reviewRounds;
|
||||||
const nextFinishedSampleShipmentRows =
|
const nextFinishedSampleShipmentRows =
|
||||||
overrides?.finishedSampleShipmentRows ?? productFinishedSampleShipmentRows;
|
overrides?.finishedSampleShipmentRows ?? productFinishedSampleShipmentRows;
|
||||||
@ -1810,6 +1810,8 @@ export default function NonIntegratedDetailClient({
|
|||||||
overrides?.openingReference ?? openingReferenceRef.current;
|
overrides?.openingReference ?? openingReferenceRef.current;
|
||||||
const nextSkuItems = overrides?.skuItems ?? skuItems;
|
const nextSkuItems = overrides?.skuItems ?? skuItems;
|
||||||
const nextPricingRows = overrides?.pricingRows ?? productPricingRows;
|
const nextPricingRows = overrides?.pricingRows ?? productPricingRows;
|
||||||
|
const nextSampleMeasurementRows =
|
||||||
|
overrides?.sampleMeasurementRows ?? productSampleMeasurementRows;
|
||||||
const nextSkuBatchCount = overrides?.skuBatchCount ?? skuBatchCount;
|
const nextSkuBatchCount = overrides?.skuBatchCount ?? skuBatchCount;
|
||||||
const nextSkuBatchConfirmedAt =
|
const nextSkuBatchConfirmedAt =
|
||||||
overrides?.skuBatchConfirmedAt ?? skuBatchConfirmedAt;
|
overrides?.skuBatchConfirmedAt ?? skuBatchConfirmedAt;
|
||||||
@ -1874,11 +1876,11 @@ export default function NonIntegratedDetailClient({
|
|||||||
bomDetails,
|
bomDetails,
|
||||||
nextReviewRounds,
|
nextReviewRounds,
|
||||||
qualityInspectionSheet,
|
qualityInspectionSheet,
|
||||||
productFactoryRows,
|
nextFactoryRows,
|
||||||
nextPricingRows,
|
nextPricingRows,
|
||||||
nextPlanningLayoutRows,
|
nextPlanningLayoutRows,
|
||||||
productLimitRows,
|
productLimitRows,
|
||||||
productSampleMeasurementRows,
|
nextSampleMeasurementRows,
|
||||||
nextFinishedSampleShipmentRows,
|
nextFinishedSampleShipmentRows,
|
||||||
productFirstQualityRows,
|
productFirstQualityRows,
|
||||||
uploadFiles,
|
uploadFiles,
|
||||||
@ -2585,13 +2587,16 @@ export default function NonIntegratedDetailClient({
|
|||||||
derivedSkuItems,
|
derivedSkuItems,
|
||||||
displayedProductFactoryHasPendingRows,
|
displayedProductFactoryHasPendingRows,
|
||||||
displayedProductFactoryHasSystemEnteredPricingRows,
|
displayedProductFactoryHasSystemEnteredPricingRows,
|
||||||
|
displayedProductFactoryIsConfirmed,
|
||||||
displayedProductFactoryRows,
|
displayedProductFactoryRows,
|
||||||
displayedProductFactoryRowsComplete,
|
displayedProductFactoryRowsComplete,
|
||||||
documentWorkspaceApprovedAt,
|
documentWorkspaceApprovedAt,
|
||||||
documentWorkspaceConfirmations,
|
documentWorkspaceConfirmations,
|
||||||
|
documentWorkspaceRevisionSignatureRef,
|
||||||
isCurrentUserAdmin,
|
isCurrentUserAdmin,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
isSkuItemFactoryConfirmed,
|
isSkuItemFactoryConfirmed,
|
||||||
|
persistEditedProduct,
|
||||||
productFactoryModelAutofillRef,
|
productFactoryModelAutofillRef,
|
||||||
productFactoryReopenField,
|
productFactoryReopenField,
|
||||||
productFactoryRows,
|
productFactoryRows,
|
||||||
@ -2631,7 +2636,7 @@ export default function NonIntegratedDetailClient({
|
|||||||
documentWorkspaceApprovedAt,
|
documentWorkspaceApprovedAt,
|
||||||
documentWorkspaceConfirmations,
|
documentWorkspaceConfirmations,
|
||||||
documentWorkspaceRevisionSignatureRef,
|
documentWorkspaceRevisionSignatureRef,
|
||||||
isProductFactorySkuComplete,
|
isProductFactorySkuConfirmed: isSkuItemFactoryConfirmed,
|
||||||
isProductLimitNodeLocked,
|
isProductLimitNodeLocked,
|
||||||
isProductPricingNodeLocked,
|
isProductPricingNodeLocked,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
@ -2643,6 +2648,8 @@ export default function NonIntegratedDetailClient({
|
|||||||
planningLayoutRowsRef,
|
planningLayoutRowsRef,
|
||||||
pricingRows,
|
pricingRows,
|
||||||
productId,
|
productId,
|
||||||
|
productSampleMeasurementRows,
|
||||||
|
sampleMeasurementRows,
|
||||||
scheduleAutoSave,
|
scheduleAutoSave,
|
||||||
setDocumentWorkspaceApprovedAt,
|
setDocumentWorkspaceApprovedAt,
|
||||||
setDocumentWorkspaceConfirmations,
|
setDocumentWorkspaceConfirmations,
|
||||||
@ -2879,11 +2886,20 @@ export default function NonIntegratedDetailClient({
|
|||||||
handleFinishedSampleShipmentStatusClick,
|
handleFinishedSampleShipmentStatusClick,
|
||||||
handleSampleMeasurementStatusClick,
|
handleSampleMeasurementStatusClick,
|
||||||
} = useSampleWorkflowStatusController({
|
} = useSampleWorkflowStatusController({
|
||||||
|
documentWorkspaceApprovedAt,
|
||||||
|
documentWorkspaceConfirmations,
|
||||||
|
documentWorkspaceRevisionSignatureRef,
|
||||||
displayedFinishedSampleShipmentRows,
|
displayedFinishedSampleShipmentRows,
|
||||||
displayedFinishedSampleShipmentRowsComplete,
|
displayedFinishedSampleShipmentRowsComplete,
|
||||||
displayedProductFactoryIsConfirmed,
|
displayedProductFactoryIsConfirmed,
|
||||||
displayedProductSampleMeasurementRows,
|
displayedProductSampleMeasurementRows,
|
||||||
|
displayedSampleMeasurementIsConfirmed,
|
||||||
displayedSampleMeasurementRowsComplete,
|
displayedSampleMeasurementRowsComplete,
|
||||||
|
isReadOnly,
|
||||||
|
persistEditedProduct,
|
||||||
|
productSampleMeasurementRows,
|
||||||
|
setDocumentWorkspaceApprovedAt,
|
||||||
|
setDocumentWorkspaceConfirmations,
|
||||||
setSaveMessage,
|
setSaveMessage,
|
||||||
setSaveMessageType,
|
setSaveMessageType,
|
||||||
});
|
});
|
||||||
@ -3820,7 +3836,7 @@ export default function NonIntegratedDetailClient({
|
|||||||
allRows: productSampleMeasurementRows,
|
allRows: productSampleMeasurementRows,
|
||||||
displayedRows: displayedProductSampleMeasurementRows,
|
displayedRows: displayedProductSampleMeasurementRows,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
isProductFactorySkuComplete,
|
isProductFactorySkuConfirmed: isSkuItemFactoryConfirmed,
|
||||||
isSampleMeasurementSkuLocked,
|
isSampleMeasurementSkuLocked,
|
||||||
onUpdateRow: updateSampleMeasurementRow,
|
onUpdateRow: updateSampleMeasurementRow,
|
||||||
},
|
},
|
||||||
@ -4320,9 +4336,12 @@ export default function NonIntegratedDetailClient({
|
|||||||
documentWorkspaceCountByCategory
|
documentWorkspaceCountByCategory
|
||||||
}
|
}
|
||||||
documentWorkspaceView={documentWorkspaceView}
|
documentWorkspaceView={documentWorkspaceView}
|
||||||
isProductFactoryRowComplete={isProductFactoryRowComplete}
|
isSampleMeasurementConfirmed={
|
||||||
|
displayedSampleMeasurementIsConfirmed
|
||||||
|
}
|
||||||
isWorkflowNodeConfirmed={isWorkflowNodeConfirmed}
|
isWorkflowNodeConfirmed={isWorkflowNodeConfirmed}
|
||||||
productFactoryRows={productFactoryRows}
|
productFactoryRows={productFactoryRows}
|
||||||
|
sampleMeasurementRows={productSampleMeasurementRows}
|
||||||
visibleGroupedUploadFiles={visibleGroupedUploadFiles}
|
visibleGroupedUploadFiles={visibleGroupedUploadFiles}
|
||||||
onOpenBasicInfo={() => setDocumentWorkspaceView("detail")}
|
onOpenBasicInfo={() => setDocumentWorkspaceView("detail")}
|
||||||
onOpenDocumentWorkspace={handleOpenDocumentWorkspace}
|
onOpenDocumentWorkspace={handleOpenDocumentWorkspace}
|
||||||
@ -4781,6 +4800,7 @@ export default function NonIntegratedDetailClient({
|
|||||||
displayedProductPricingRowsReadyForPush,
|
displayedProductPricingRowsReadyForPush,
|
||||||
displayedProductSampleMeasurementRowCount:
|
displayedProductSampleMeasurementRowCount:
|
||||||
displayedProductSampleMeasurementRows.length,
|
displayedProductSampleMeasurementRows.length,
|
||||||
|
displayedSampleMeasurementHasPendingRows,
|
||||||
displayedSampleMeasurementIsConfirmed,
|
displayedSampleMeasurementIsConfirmed,
|
||||||
documentWorkspaceConfirmationAction:
|
documentWorkspaceConfirmationAction:
|
||||||
renderDocumentWorkspaceConfirmationAction(),
|
renderDocumentWorkspaceConfirmationAction(),
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { MaterialDTO } from "@/server/services";
|
|||||||
import type {
|
import type {
|
||||||
NonIntegratedDocumentWorkspaceApprovalMap,
|
NonIntegratedDocumentWorkspaceApprovalMap,
|
||||||
NonIntegratedDocumentWorkspaceConfirmationMap,
|
NonIntegratedDocumentWorkspaceConfirmationMap,
|
||||||
|
NonIntegratedFactoryRow,
|
||||||
NonIntegratedFinishedSampleShipmentRow,
|
NonIntegratedFinishedSampleShipmentRow,
|
||||||
NonIntegratedOpeningReference,
|
NonIntegratedOpeningReference,
|
||||||
NonIntegratedProductRecord,
|
NonIntegratedProductRecord,
|
||||||
@ -11,6 +12,7 @@ import type {
|
|||||||
NonIntegratedReviewIssue,
|
NonIntegratedReviewIssue,
|
||||||
NonIntegratedReviewRound,
|
NonIntegratedReviewRound,
|
||||||
NonIntegratedReviewSheet,
|
NonIntegratedReviewSheet,
|
||||||
|
NonIntegratedSampleMeasurementRow,
|
||||||
NonIntegratedSkuItem,
|
NonIntegratedSkuItem,
|
||||||
} from "./core/nonIntegratedStorage";
|
} from "./core/nonIntegratedStorage";
|
||||||
import type {
|
import type {
|
||||||
@ -58,6 +60,8 @@ export type AutoSaveNoticeType = "saving" | "success" | "error";
|
|||||||
export type PersistEditedProductOverrides = {
|
export type PersistEditedProductOverrides = {
|
||||||
documentWorkspaceConfirmations?: NonIntegratedDocumentWorkspaceConfirmationMap;
|
documentWorkspaceConfirmations?: NonIntegratedDocumentWorkspaceConfirmationMap;
|
||||||
documentWorkspaceApprovedAt?: NonIntegratedDocumentWorkspaceApprovalMap;
|
documentWorkspaceApprovedAt?: NonIntegratedDocumentWorkspaceApprovalMap;
|
||||||
|
factoryRows?: NonIntegratedFactoryRow[];
|
||||||
|
sampleMeasurementRows?: NonIntegratedSampleMeasurementRow[];
|
||||||
reviewRounds?: NonIntegratedReviewRound[];
|
reviewRounds?: NonIntegratedReviewRound[];
|
||||||
finishedSampleShipmentRows?: NonIntegratedFinishedSampleShipmentRow[];
|
finishedSampleShipmentRows?: NonIntegratedFinishedSampleShipmentRow[];
|
||||||
openingReference?: NonIntegratedOpeningReference;
|
openingReference?: NonIntegratedOpeningReference;
|
||||||
|
|||||||
@ -1,89 +1,41 @@
|
|||||||
import { useEffect, type Dispatch, type SetStateAction } from "react";
|
import { useEffect, type Dispatch, type SetStateAction } from "react";
|
||||||
import {
|
import {
|
||||||
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
||||||
PRODUCT_FACTORY_WORKSPACE_CATEGORY,
|
|
||||||
SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY,
|
|
||||||
} from "./workspaces/documents/documentWorkspaceConfig";
|
} from "./workspaces/documents/documentWorkspaceConfig";
|
||||||
import type { DocumentWorkspaceCategory } from "./workspaces/documents/documentWorkspaceHelpers";
|
import type { DocumentWorkspaceCategory } from "./workspaces/documents/documentWorkspaceHelpers";
|
||||||
import {
|
|
||||||
isProductFactoryRowComplete,
|
|
||||||
normalizeFactoryRowsForPayload,
|
|
||||||
} from "./workspaces/basic-info/productFactoryHelpers";
|
|
||||||
import type {
|
import type {
|
||||||
NonIntegratedDocumentWorkspaceApprovalMap,
|
NonIntegratedDocumentWorkspaceApprovalMap,
|
||||||
NonIntegratedDocumentWorkspaceConfirmationMap,
|
NonIntegratedDocumentWorkspaceConfirmationMap,
|
||||||
NonIntegratedFactoryRow,
|
|
||||||
NonIntegratedFinishedSampleShipmentRow,
|
NonIntegratedFinishedSampleShipmentRow,
|
||||||
NonIntegratedSampleMeasurementRow,
|
|
||||||
} from "./core/nonIntegratedStorage";
|
} from "./core/nonIntegratedStorage";
|
||||||
|
|
||||||
type DetailMode = "create" | "edit" | "view";
|
type DetailMode = "create" | "edit" | "view";
|
||||||
|
|
||||||
type UseNonIntegratedWorkflowAutoConfirmationEffectsParams = {
|
type UseNonIntegratedWorkflowAutoConfirmationEffectsParams = {
|
||||||
allFinishedSampleShipmentRowsComplete: boolean;
|
allFinishedSampleShipmentRowsComplete: boolean;
|
||||||
allProductFactoryRowsComplete: boolean;
|
|
||||||
allSampleMeasurementRowsComplete: boolean;
|
|
||||||
existingProductCreatedAt: string;
|
existingProductCreatedAt: string;
|
||||||
factoryRows: NonIntegratedFactoryRow[];
|
|
||||||
finishedSampleShipmentRows: NonIntegratedFinishedSampleShipmentRow[];
|
finishedSampleShipmentRows: NonIntegratedFinishedSampleShipmentRow[];
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
mode: DetailMode;
|
mode: DetailMode;
|
||||||
productFactoryRows: NonIntegratedFactoryRow[];
|
|
||||||
productId?: string;
|
productId?: string;
|
||||||
sampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
|
|
||||||
setDocumentWorkspaceApprovedAt: Dispatch<
|
setDocumentWorkspaceApprovedAt: Dispatch<
|
||||||
SetStateAction<NonIntegratedDocumentWorkspaceApprovalMap>
|
SetStateAction<NonIntegratedDocumentWorkspaceApprovalMap>
|
||||||
>;
|
>;
|
||||||
setDocumentWorkspaceConfirmations: Dispatch<
|
setDocumentWorkspaceConfirmations: Dispatch<
|
||||||
SetStateAction<NonIntegratedDocumentWorkspaceConfirmationMap>
|
SetStateAction<NonIntegratedDocumentWorkspaceConfirmationMap>
|
||||||
>;
|
>;
|
||||||
setFactoryRows: Dispatch<SetStateAction<NonIntegratedFactoryRow[]>>;
|
|
||||||
supplierCodeByName: Map<string, string>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useNonIntegratedWorkflowAutoConfirmationEffects({
|
export function useNonIntegratedWorkflowAutoConfirmationEffects({
|
||||||
allFinishedSampleShipmentRowsComplete,
|
allFinishedSampleShipmentRowsComplete,
|
||||||
allProductFactoryRowsComplete,
|
|
||||||
allSampleMeasurementRowsComplete,
|
|
||||||
existingProductCreatedAt,
|
existingProductCreatedAt,
|
||||||
factoryRows,
|
|
||||||
finishedSampleShipmentRows,
|
finishedSampleShipmentRows,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
mode,
|
mode,
|
||||||
productFactoryRows,
|
|
||||||
productId,
|
productId,
|
||||||
sampleMeasurementRows,
|
|
||||||
setDocumentWorkspaceApprovedAt,
|
setDocumentWorkspaceApprovedAt,
|
||||||
setDocumentWorkspaceConfirmations,
|
setDocumentWorkspaceConfirmations,
|
||||||
setFactoryRows,
|
|
||||||
supplierCodeByName,
|
|
||||||
}: UseNonIntegratedWorkflowAutoConfirmationEffectsParams) {
|
}: 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(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
mode !== "edit" ||
|
mode !== "edit" ||
|
||||||
@ -99,17 +51,6 @@ export function useNonIntegratedWorkflowAutoConfirmationEffects({
|
|||||||
touched: boolean;
|
touched: boolean;
|
||||||
complete: 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,
|
category: FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
||||||
touched: finishedSampleShipmentRows.length > 0,
|
touched: finishedSampleShipmentRows.length > 0,
|
||||||
@ -149,15 +90,11 @@ export function useNonIntegratedWorkflowAutoConfirmationEffects({
|
|||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
allFinishedSampleShipmentRowsComplete,
|
allFinishedSampleShipmentRowsComplete,
|
||||||
allProductFactoryRowsComplete,
|
|
||||||
allSampleMeasurementRowsComplete,
|
|
||||||
existingProductCreatedAt,
|
existingProductCreatedAt,
|
||||||
factoryRows.length,
|
|
||||||
finishedSampleShipmentRows.length,
|
finishedSampleShipmentRows.length,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
mode,
|
mode,
|
||||||
productId,
|
productId,
|
||||||
sampleMeasurementRows.length,
|
|
||||||
setDocumentWorkspaceApprovedAt,
|
setDocumentWorkspaceApprovedAt,
|
||||||
setDocumentWorkspaceConfirmations,
|
setDocumentWorkspaceConfirmations,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -56,7 +56,7 @@ export function useNonIntegratedWorkflowCompletion({
|
|||||||
productSampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
|
productSampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
|
||||||
}) {
|
}) {
|
||||||
const confirmedProductFactoryRowCount = useMemo(
|
const confirmedProductFactoryRowCount = useMemo(
|
||||||
() => productFactoryRows.filter(isProductFactoryRowComplete).length,
|
() => productFactoryRows.filter((row) => row.confirmed).length,
|
||||||
[productFactoryRows],
|
[productFactoryRows],
|
||||||
);
|
);
|
||||||
const populatedProductPricingRowCount = useMemo(
|
const populatedProductPricingRowCount = useMemo(
|
||||||
@ -109,7 +109,10 @@ export function useNonIntegratedWorkflowCompletion({
|
|||||||
displayedProductFactoryRows.some((row) => !isProductFactoryRowComplete(row));
|
displayedProductFactoryRows.some((row) => !isProductFactoryRowComplete(row));
|
||||||
const displayedProductFactoryIsConfirmed =
|
const displayedProductFactoryIsConfirmed =
|
||||||
displayedProductFactoryRows.length > 0 &&
|
displayedProductFactoryRows.length > 0 &&
|
||||||
!displayedProductFactoryHasPendingRows;
|
displayedProductFactoryRows.every((row) => row.confirmed);
|
||||||
|
const allProductFactoryRowsConfirmed =
|
||||||
|
productFactoryRows.length > 0 &&
|
||||||
|
productFactoryRows.every((row) => row.confirmed);
|
||||||
const displayedProductFactoryRowsComplete =
|
const displayedProductFactoryRowsComplete =
|
||||||
displayedProductFactoryRows.length > 0 &&
|
displayedProductFactoryRows.length > 0 &&
|
||||||
displayedProductFactoryRows.every(isProductFactoryRowComplete);
|
displayedProductFactoryRows.every(isProductFactoryRowComplete);
|
||||||
@ -162,6 +165,16 @@ export function useNonIntegratedWorkflowCompletion({
|
|||||||
),
|
),
|
||||||
[productPricingRows],
|
[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 =
|
const displayedProductFactoryHasSystemEnteredPricingRows =
|
||||||
displayedProductFactoryRows.some((row) =>
|
displayedProductFactoryRows.some((row) =>
|
||||||
productPricingSystemEnteredSkuIdSet.has(row.skuId),
|
productPricingSystemEnteredSkuIdSet.has(row.skuId),
|
||||||
@ -179,7 +192,10 @@ export function useNonIntegratedWorkflowCompletion({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
allFinishedSampleShipmentRowsComplete,
|
allFinishedSampleShipmentRowsComplete,
|
||||||
|
allProductFactoryRowsConfirmed,
|
||||||
allProductFactoryRowsComplete,
|
allProductFactoryRowsComplete,
|
||||||
|
allProductPricingRowsSystemEntered,
|
||||||
|
allSampleMeasurementRowsConfirmedByPricing,
|
||||||
allSampleMeasurementRowsComplete,
|
allSampleMeasurementRowsComplete,
|
||||||
confirmedProductFactoryRowCount,
|
confirmedProductFactoryRowCount,
|
||||||
displayedFinishedSampleShipmentRowsComplete,
|
displayedFinishedSampleShipmentRowsComplete,
|
||||||
@ -192,6 +208,7 @@ export function useNonIntegratedWorkflowCompletion({
|
|||||||
displayedProductPricingRowsAllSystemEntered,
|
displayedProductPricingRowsAllSystemEntered,
|
||||||
displayedProductPricingRowsComplete,
|
displayedProductPricingRowsComplete,
|
||||||
displayedProductPricingRowsReadyForPush,
|
displayedProductPricingRowsReadyForPush,
|
||||||
|
displayedSampleMeasurementRowsConfirmedByPricing,
|
||||||
displayedSampleMeasurementRowsComplete,
|
displayedSampleMeasurementRowsComplete,
|
||||||
isSampleMeasurementSkuLocked,
|
isSampleMeasurementSkuLocked,
|
||||||
planningLayoutHasContent,
|
planningLayoutHasContent,
|
||||||
|
|||||||
@ -25,19 +25,19 @@ import {
|
|||||||
|
|
||||||
type UseNonIntegratedWorkflowConfirmationStateParams = {
|
type UseNonIntegratedWorkflowConfirmationStateParams = {
|
||||||
allFinishedSampleShipmentRowsComplete: boolean;
|
allFinishedSampleShipmentRowsComplete: boolean;
|
||||||
allProductFactoryRowsComplete: boolean;
|
allProductFactoryRowsConfirmed: boolean;
|
||||||
allSampleMeasurementRowsComplete: boolean;
|
allSampleMeasurementRowsConfirmedByPricing: boolean;
|
||||||
basicInfoHasContent: boolean;
|
basicInfoHasContent: boolean;
|
||||||
displayedFinishedSampleShipmentRowsComplete: boolean;
|
displayedFinishedSampleShipmentRowsComplete: boolean;
|
||||||
displayedFirstQualityRowsComplete: boolean;
|
displayedFirstQualityRowsComplete: boolean;
|
||||||
displayedProductFactoryIsConfirmed: boolean;
|
displayedProductFactoryIsConfirmed: boolean;
|
||||||
displayedProductLimitRowsComplete: boolean;
|
displayedProductLimitRowsComplete: boolean;
|
||||||
displayedProductSampleMeasurementRows: Array<{ skuId: string }>;
|
displayedProductSampleMeasurementRows: Array<{ skuId: string }>;
|
||||||
|
displayedSampleMeasurementRowsConfirmedByPricing: boolean;
|
||||||
displayedSampleMeasurementRowsComplete: boolean;
|
displayedSampleMeasurementRowsComplete: boolean;
|
||||||
documentWorkspaceApprovedAt: NonIntegratedDocumentWorkspaceApprovalMap;
|
documentWorkspaceApprovedAt: NonIntegratedDocumentWorkspaceApprovalMap;
|
||||||
documentWorkspaceConfirmations: NonIntegratedDocumentWorkspaceConfirmationMap;
|
documentWorkspaceConfirmations: NonIntegratedDocumentWorkspaceConfirmationMap;
|
||||||
documentWorkspaceRevisionSignatures: Record<WorkflowNodeCategory, string>;
|
documentWorkspaceRevisionSignatures: Record<WorkflowNodeCategory, string>;
|
||||||
isSampleMeasurementSkuLocked: (skuId: string) => boolean;
|
|
||||||
previousDocumentWorkspaceRevisionSignatures:
|
previousDocumentWorkspaceRevisionSignatures:
|
||||||
| Record<WorkflowNodeCategory, string>
|
| Record<WorkflowNodeCategory, string>
|
||||||
| null
|
| null
|
||||||
@ -54,19 +54,19 @@ type UseNonIntegratedWorkflowConfirmationStateParams = {
|
|||||||
|
|
||||||
export function useNonIntegratedWorkflowConfirmationState({
|
export function useNonIntegratedWorkflowConfirmationState({
|
||||||
allFinishedSampleShipmentRowsComplete,
|
allFinishedSampleShipmentRowsComplete,
|
||||||
allProductFactoryRowsComplete,
|
allProductFactoryRowsConfirmed,
|
||||||
allSampleMeasurementRowsComplete,
|
allSampleMeasurementRowsConfirmedByPricing,
|
||||||
basicInfoHasContent,
|
basicInfoHasContent,
|
||||||
displayedFinishedSampleShipmentRowsComplete,
|
displayedFinishedSampleShipmentRowsComplete,
|
||||||
displayedFirstQualityRowsComplete,
|
displayedFirstQualityRowsComplete,
|
||||||
displayedProductFactoryIsConfirmed,
|
displayedProductFactoryIsConfirmed,
|
||||||
displayedProductLimitRowsComplete,
|
displayedProductLimitRowsComplete,
|
||||||
displayedProductSampleMeasurementRows,
|
displayedProductSampleMeasurementRows,
|
||||||
|
displayedSampleMeasurementRowsConfirmedByPricing,
|
||||||
displayedSampleMeasurementRowsComplete,
|
displayedSampleMeasurementRowsComplete,
|
||||||
documentWorkspaceApprovedAt,
|
documentWorkspaceApprovedAt,
|
||||||
documentWorkspaceConfirmations,
|
documentWorkspaceConfirmations,
|
||||||
documentWorkspaceRevisionSignatures,
|
documentWorkspaceRevisionSignatures,
|
||||||
isSampleMeasurementSkuLocked,
|
|
||||||
previousDocumentWorkspaceRevisionSignatures,
|
previousDocumentWorkspaceRevisionSignatures,
|
||||||
productPricingCanBeConfirmed,
|
productPricingCanBeConfirmed,
|
||||||
projectStatus,
|
projectStatus,
|
||||||
@ -92,13 +92,15 @@ export function useNonIntegratedWorkflowConfirmationState({
|
|||||||
const isWorkflowNodeConfirmed = useCallback(
|
const isWorkflowNodeConfirmed = useCallback(
|
||||||
(category: WorkflowNodeCategory, hasContent: boolean) => {
|
(category: WorkflowNodeCategory, hasContent: boolean) => {
|
||||||
if (category === PRODUCT_FACTORY_WORKSPACE_CATEGORY) {
|
if (category === PRODUCT_FACTORY_WORKSPACE_CATEGORY) {
|
||||||
return hasContent && allProductFactoryRowsComplete;
|
return hasContent && allProductFactoryRowsConfirmed;
|
||||||
}
|
}
|
||||||
if (category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY) {
|
if (category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY) {
|
||||||
|
if (!hasContent || !allProductFactoryRowsConfirmed) return false;
|
||||||
|
if (allSampleMeasurementRowsConfirmedByPricing) return true;
|
||||||
return (
|
return (
|
||||||
hasContent &&
|
documentWorkspaceConfirmations[category] === true &&
|
||||||
allProductFactoryRowsComplete &&
|
Boolean(documentWorkspaceApprovedAt[category]) &&
|
||||||
allSampleMeasurementRowsComplete
|
!dirtyWorkflowNodeCategories.has(category)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (category === FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY) {
|
if (category === FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY) {
|
||||||
@ -110,12 +112,6 @@ export function useNonIntegratedWorkflowConfirmationState({
|
|||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY &&
|
|
||||||
!displayedProductFactoryIsConfirmed
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
!shouldRequireWorkflowConfirmation(category) ||
|
!shouldRequireWorkflowConfirmation(category) ||
|
||||||
@ -127,10 +123,9 @@ export function useNonIntegratedWorkflowConfirmationState({
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
allFinishedSampleShipmentRowsComplete,
|
allFinishedSampleShipmentRowsComplete,
|
||||||
allProductFactoryRowsComplete,
|
allProductFactoryRowsConfirmed,
|
||||||
allSampleMeasurementRowsComplete,
|
allSampleMeasurementRowsConfirmedByPricing,
|
||||||
dirtyWorkflowNodeCategories,
|
dirtyWorkflowNodeCategories,
|
||||||
displayedProductFactoryIsConfirmed,
|
|
||||||
documentWorkspaceApprovedAt,
|
documentWorkspaceApprovedAt,
|
||||||
documentWorkspaceConfirmations,
|
documentWorkspaceConfirmations,
|
||||||
productPricingCanBeConfirmed,
|
productPricingCanBeConfirmed,
|
||||||
@ -142,11 +137,6 @@ export function useNonIntegratedWorkflowConfirmationState({
|
|||||||
Boolean(documentWorkspaceApprovedAt[category]),
|
Boolean(documentWorkspaceApprovedAt[category]),
|
||||||
[documentWorkspaceApprovedAt, documentWorkspaceConfirmations],
|
[documentWorkspaceApprovedAt, documentWorkspaceConfirmations],
|
||||||
);
|
);
|
||||||
const isSampleMeasurementNodeLocked =
|
|
||||||
displayedProductSampleMeasurementRows.length > 0 &&
|
|
||||||
displayedProductSampleMeasurementRows.every((row) =>
|
|
||||||
isSampleMeasurementSkuLocked(row.skuId),
|
|
||||||
);
|
|
||||||
const isFinishedSampleShipmentNodeLocked = isDocumentWorkspaceNodeLocked(
|
const isFinishedSampleShipmentNodeLocked = isDocumentWorkspaceNodeLocked(
|
||||||
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
||||||
);
|
);
|
||||||
@ -156,12 +146,20 @@ export function useNonIntegratedWorkflowConfirmationState({
|
|||||||
const isProductLimitNodeLocked = isDocumentWorkspaceNodeLocked(
|
const isProductLimitNodeLocked = isDocumentWorkspaceNodeLocked(
|
||||||
PRODUCT_LIMIT_WORKSPACE_CATEGORY,
|
PRODUCT_LIMIT_WORKSPACE_CATEGORY,
|
||||||
);
|
);
|
||||||
const displayedSampleMeasurementIsConfirmed = isWorkflowNodeConfirmed(
|
const displayedSampleMeasurementHasContent =
|
||||||
SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY,
|
displayedProductSampleMeasurementRows.length > 0;
|
||||||
displayedSampleMeasurementRowsComplete,
|
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 =
|
const isSampleMeasurementNodeApproved =
|
||||||
isSampleMeasurementNodeLocked &&
|
displayedSampleMeasurementIsConfirmed &&
|
||||||
!dirtyWorkflowNodeCategories.has(SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY);
|
!dirtyWorkflowNodeCategories.has(SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY);
|
||||||
const displayedFinishedSampleShipmentIsConfirmed = isWorkflowNodeConfirmed(
|
const displayedFinishedSampleShipmentIsConfirmed = isWorkflowNodeConfirmed(
|
||||||
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
||||||
|
|||||||
@ -128,7 +128,7 @@ export function useNonIntegratedWorkflowRows({
|
|||||||
() =>
|
() =>
|
||||||
new Set(
|
new Set(
|
||||||
productFactoryRows
|
productFactoryRows
|
||||||
.filter((row) => row.confirmed || isProductFactoryRowComplete(row))
|
.filter((row) => row.confirmed)
|
||||||
.map((row) => row.skuId),
|
.map((row) => row.skuId),
|
||||||
),
|
),
|
||||||
[productFactoryRows],
|
[productFactoryRows],
|
||||||
|
|||||||
@ -15,7 +15,7 @@ type SampleMeasurementWorkspaceProps = {
|
|||||||
displayedRows: ProductSampleMeasurementDisplayRow[];
|
displayedRows: ProductSampleMeasurementDisplayRow[];
|
||||||
inheritedSkuBatchTabs: ReactNode;
|
inheritedSkuBatchTabs: ReactNode;
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
isProductFactorySkuComplete: (skuId: string) => boolean;
|
isProductFactorySkuConfirmed: (skuId: string) => boolean;
|
||||||
isSampleMeasurementSkuLocked: (skuId: string) => boolean;
|
isSampleMeasurementSkuLocked: (skuId: string) => boolean;
|
||||||
onUpdateRow: (
|
onUpdateRow: (
|
||||||
skuId: string,
|
skuId: string,
|
||||||
@ -50,7 +50,7 @@ export function SampleMeasurementWorkspace({
|
|||||||
displayedRows,
|
displayedRows,
|
||||||
inheritedSkuBatchTabs,
|
inheritedSkuBatchTabs,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
isProductFactorySkuComplete,
|
isProductFactorySkuConfirmed,
|
||||||
isSampleMeasurementSkuLocked,
|
isSampleMeasurementSkuLocked,
|
||||||
onUpdateRow,
|
onUpdateRow,
|
||||||
}: SampleMeasurementWorkspaceProps) {
|
}: SampleMeasurementWorkspaceProps) {
|
||||||
@ -64,7 +64,7 @@ export function SampleMeasurementWorkspace({
|
|||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
readOnly={
|
readOnly={
|
||||||
isReadOnly ||
|
isReadOnly ||
|
||||||
!isProductFactorySkuComplete(row.skuId) ||
|
!isProductFactorySkuConfirmed(row.skuId) ||
|
||||||
isSampleMeasurementSkuLocked(row.skuId)
|
isSampleMeasurementSkuLocked(row.skuId)
|
||||||
}
|
}
|
||||||
mode="singleLineResizable"
|
mode="singleLineResizable"
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import {
|
|||||||
MODEL_SHARED_PRODUCT_FACTORY_KEYS,
|
MODEL_SHARED_PRODUCT_FACTORY_KEYS,
|
||||||
PACKAGE_SHARED_PRODUCT_FACTORY_PURCHASING_KEYS,
|
PACKAGE_SHARED_PRODUCT_FACTORY_PURCHASING_KEYS,
|
||||||
PRODUCT_FACTORY_REQUIRED_FIELDS,
|
PRODUCT_FACTORY_REQUIRED_FIELDS,
|
||||||
|
SPU_SHARED_PRODUCT_FACTORY_KEYS,
|
||||||
} from "./skuFieldConfig";
|
} from "./skuFieldConfig";
|
||||||
import { buildAutoBarcode, shouldKeepCustomBarcode } from "./skuAutoHelpers";
|
import { buildAutoBarcode, shouldKeepCustomBarcode } from "./skuAutoHelpers";
|
||||||
import { SUPPLIER_CODE_BY_NAME } from "./supplierDirectory";
|
import { SUPPLIER_CODE_BY_NAME } from "./supplierDirectory";
|
||||||
@ -84,6 +85,8 @@ export function normalizeModelSharedProductFactoryRows(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return rows.map((row) => {
|
return rows.map((row) => {
|
||||||
|
if (row.confirmed) return row;
|
||||||
|
|
||||||
const modelKey = getSkuFactoryModelKey(row);
|
const modelKey = getSkuFactoryModelKey(row);
|
||||||
if (!modelKey) return row;
|
if (!modelKey) return row;
|
||||||
|
|
||||||
@ -101,6 +104,40 @@ export function normalizeModelSharedProductFactoryRows(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function normalizeSpuSharedProductFactoryRows(
|
||||||
|
rows: NonIntegratedFactoryRow[],
|
||||||
|
) {
|
||||||
|
const sharedValueByKey = new Map<string, string>();
|
||||||
|
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(
|
export function getProductFactoryMissingFieldLabels(
|
||||||
row: NonIntegratedFactoryRow,
|
row: NonIntegratedFactoryRow,
|
||||||
) {
|
) {
|
||||||
@ -123,7 +160,7 @@ export function getProductFactoryStatusMessage({
|
|||||||
if (rows.length === 0) return null;
|
if (rows.length === 0) return null;
|
||||||
if (isRowsComplete) {
|
if (isRowsComplete) {
|
||||||
return {
|
return {
|
||||||
message: "产品定厂已完成",
|
message: "资料已填完核对无误请确认。",
|
||||||
type: "success" as const,
|
type: "success" as const,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -249,7 +286,7 @@ export function buildProductFactoryRows(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return normalizeModelSharedProductFactoryRows(rows);
|
return normalizeSharedProductFactoryRows(rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeFactoryRowsForPayload(
|
export function normalizeFactoryRowsForPayload(
|
||||||
@ -294,5 +331,5 @@ export function normalizeFactoryRowsForPayload(
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return normalizeModelSharedProductFactoryRows(normalizedRows);
|
return normalizeSharedProductFactoryRows(normalizedRows);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -161,10 +161,13 @@ export const PACKAGE_SHARED_PRODUCT_FACTORY_PURCHASING_KEYS =
|
|||||||
"assemblyMode",
|
"assemblyMode",
|
||||||
]);
|
]);
|
||||||
export const MODEL_SHARED_PRODUCT_FACTORY_KEYS = new Set<ProductFactoryEditableKey>([
|
export const MODEL_SHARED_PRODUCT_FACTORY_KEYS = new Set<ProductFactoryEditableKey>([
|
||||||
|
"installationService",
|
||||||
|
]);
|
||||||
|
export const SPU_SHARED_PRODUCT_FACTORY_KEYS = new Set<ProductFactoryEditableKey>([
|
||||||
"warehouse",
|
"warehouse",
|
||||||
"shippingMethod",
|
"shippingMethod",
|
||||||
|
"installMethod",
|
||||||
"productionType",
|
"productionType",
|
||||||
"installationService",
|
|
||||||
"supplierCategory",
|
"supplierCategory",
|
||||||
"purchaseOrderMethod",
|
"purchaseOrderMethod",
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -28,8 +28,6 @@ export const PRODUCT_LIMIT_WORKSPACE_CATEGORY: DocumentWorkspaceCategory =
|
|||||||
export const PLANNING_LAYOUT_WORKSPACE_CATEGORY: DocumentWorkspaceCategory =
|
export const PLANNING_LAYOUT_WORKSPACE_CATEGORY: DocumentWorkspaceCategory =
|
||||||
NON_INTEGRATED_PLANNING_LAYOUT_WORKSPACE_CATEGORY;
|
NON_INTEGRATED_PLANNING_LAYOUT_WORKSPACE_CATEGORY;
|
||||||
export const AUTO_COMPLETED_WORKFLOW_CATEGORIES = new Set<WorkflowNodeCategory>([
|
export const AUTO_COMPLETED_WORKFLOW_CATEGORIES = new Set<WorkflowNodeCategory>([
|
||||||
PRODUCT_FACTORY_WORKSPACE_CATEGORY,
|
|
||||||
SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY,
|
|
||||||
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
FINISHED_SAMPLE_SHIPMENT_WORKSPACE_CATEGORY,
|
||||||
]);
|
]);
|
||||||
export const FACTORY_QUALITY_WORKSPACE_CATEGORY: DocumentWorkspaceCategory =
|
export const FACTORY_QUALITY_WORKSPACE_CATEGORY: DocumentWorkspaceCategory =
|
||||||
|
|||||||
@ -10,6 +10,7 @@ type ProductFactoryHeaderActionsProps = {
|
|||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
rowCount: number;
|
rowCount: number;
|
||||||
hasPendingRows: boolean;
|
hasPendingRows: boolean;
|
||||||
|
isConfirmed: boolean;
|
||||||
hasSystemEnteredPricingRows: boolean;
|
hasSystemEnteredPricingRows: boolean;
|
||||||
isReopenPickerOpen: boolean;
|
isReopenPickerOpen: boolean;
|
||||||
reopenField: ProductFactoryEditableKey;
|
reopenField: ProductFactoryEditableKey;
|
||||||
@ -26,6 +27,7 @@ export function ProductFactoryHeaderActions({
|
|||||||
isReadOnly,
|
isReadOnly,
|
||||||
rowCount,
|
rowCount,
|
||||||
hasPendingRows,
|
hasPendingRows,
|
||||||
|
isConfirmed,
|
||||||
hasSystemEnteredPricingRows,
|
hasSystemEnteredPricingRows,
|
||||||
isReopenPickerOpen,
|
isReopenPickerOpen,
|
||||||
reopenField,
|
reopenField,
|
||||||
@ -98,10 +100,15 @@ export function ProductFactoryHeaderActions({
|
|||||||
) : null}
|
) : null}
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
|
data-testid="product-factory-confirm"
|
||||||
onClick={onStatusClick}
|
onClick={onStatusClick}
|
||||||
disabled={rowCount === 0}
|
disabled={rowCount === 0}
|
||||||
>
|
>
|
||||||
{hasPendingRows ? "当前资料未填完" : "已完成"}
|
{hasPendingRows
|
||||||
|
? "当前资料未填完"
|
||||||
|
: isConfirmed
|
||||||
|
? "已确认"
|
||||||
|
: "资料已填完核对无误请确认。"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -141,14 +141,18 @@ export function ProductFactoryInfoTable({
|
|||||||
<td className="px-2 py-2">
|
<td className="px-2 py-2">
|
||||||
<span
|
<span
|
||||||
className={`inline-flex whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] ${
|
className={`inline-flex whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] ${
|
||||||
isProductFactoryRowComplete(row)
|
row.confirmed
|
||||||
? "bg-[#dff7e8] text-[#137a38]"
|
? "bg-[#dff7e8] text-[#137a38]"
|
||||||
: "bg-[#fff3df] text-[#9b6511]"
|
: isProductFactoryRowComplete(row)
|
||||||
|
? "bg-[#e7f1ff] text-[#1764ad]"
|
||||||
|
: "bg-[#fff3df] text-[#9b6511]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isProductFactoryRowComplete(row)
|
{row.confirmed
|
||||||
? "已完成"
|
? "已确认"
|
||||||
: "当前资料未填完"}
|
: isProductFactoryRowComplete(row)
|
||||||
|
? "资料已填完"
|
||||||
|
: "当前资料未填完"}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-2 py-2 text-apple-label-secondary">
|
<td className="px-2 py-2 text-apple-label-secondary">
|
||||||
|
|||||||
@ -40,14 +40,18 @@ export function ProductFactorySkuInfoTable({
|
|||||||
<td className="px-3 py-2">
|
<td className="px-3 py-2">
|
||||||
<span
|
<span
|
||||||
className={`inline-flex rounded-full px-2 py-0.5 text-[11px] ${
|
className={`inline-flex rounded-full px-2 py-0.5 text-[11px] ${
|
||||||
isProductFactoryRowComplete(row)
|
row.confirmed
|
||||||
? "bg-[#dff7e8] text-[#137a38]"
|
? "bg-[#dff7e8] text-[#137a38]"
|
||||||
: "bg-[#fff3df] text-[#9b6511]"
|
: isProductFactoryRowComplete(row)
|
||||||
|
? "bg-[#e7f1ff] text-[#1764ad]"
|
||||||
|
: "bg-[#fff3df] text-[#9b6511]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isProductFactoryRowComplete(row)
|
{row.confirmed
|
||||||
? "已完成"
|
? "已确认"
|
||||||
: "当前资料未填完"}
|
: isProductFactoryRowComplete(row)
|
||||||
|
? "资料已填完"
|
||||||
|
: "当前资料未填完"}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-3 py-2">{row.model || "-"}</td>
|
<td className="px-3 py-2">{row.model || "-"}</td>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
MODEL_AUTOFILL_PRODUCT_FACTORY_KEYS,
|
MODEL_AUTOFILL_PRODUCT_FACTORY_KEYS,
|
||||||
MODEL_SHARED_PRODUCT_FACTORY_KEYS,
|
MODEL_SHARED_PRODUCT_FACTORY_KEYS,
|
||||||
PACKAGE_SHARED_PRODUCT_FACTORY_KEYS,
|
PACKAGE_SHARED_PRODUCT_FACTORY_KEYS,
|
||||||
|
SPU_SHARED_PRODUCT_FACTORY_KEYS,
|
||||||
type ProductFactoryEditableKey,
|
type ProductFactoryEditableKey,
|
||||||
type ProductFactoryModelAutofillEntry,
|
type ProductFactoryModelAutofillEntry,
|
||||||
} from "../basic-info/skuFieldConfig";
|
} from "../basic-info/skuFieldConfig";
|
||||||
@ -48,6 +49,10 @@ export function getProductFactoryTargetSkuIds(
|
|||||||
const targetItem = items.find((item) => item.id === targetId);
|
const targetItem = items.find((item) => item.id === targetId);
|
||||||
if (!targetItem) return new Set([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)) {
|
if (MODEL_SHARED_PRODUCT_FACTORY_KEYS.has(key)) {
|
||||||
const targetModelKey = getSkuFactoryModelKey(targetItem);
|
const targetModelKey = getSkuFactoryModelKey(targetItem);
|
||||||
if (!targetModelKey) return new Set([targetId]);
|
if (!targetModelKey) return new Set([targetId]);
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import type {
|
|||||||
SetStateAction,
|
SetStateAction,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
|
import type { PersistEditedProductOverrides } from "../../nonIntegratedDetailTypes";
|
||||||
import type {
|
import type {
|
||||||
NonIntegratedDocumentWorkspaceApprovalMap,
|
NonIntegratedDocumentWorkspaceApprovalMap,
|
||||||
NonIntegratedDocumentWorkspaceConfirmationMap,
|
NonIntegratedDocumentWorkspaceConfirmationMap,
|
||||||
@ -16,10 +17,15 @@ import {
|
|||||||
type ProductFactoryEditableKey,
|
type ProductFactoryEditableKey,
|
||||||
type ProductFactoryModelAutofillEntry,
|
type ProductFactoryModelAutofillEntry,
|
||||||
} from "../basic-info/skuFieldConfig";
|
} 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 { buildSkuItemsAfterSetCountCommit } from "../basic-info/skuSetCountCommitHelpers";
|
||||||
import { getStyleKeyFromModel } from "../style-assets/styleFileHelpers";
|
import { getStyleKeyFromModel } from "../style-assets/styleFileHelpers";
|
||||||
import { PRODUCT_FACTORY_WORKSPACE_CATEGORY } from "../documents/documentWorkspaceConfig";
|
import { PRODUCT_FACTORY_WORKSPACE_CATEGORY } from "../documents/documentWorkspaceConfig";
|
||||||
|
import type { WorkflowNodeCategory } from "../documents/documentWorkspaceHelpers";
|
||||||
import {
|
import {
|
||||||
confirmProductFactorySupplierRowsForSku,
|
confirmProductFactorySupplierRowsForSku,
|
||||||
reopenProductFactoryRows,
|
reopenProductFactoryRows,
|
||||||
@ -35,18 +41,30 @@ type ApplySkuSupplierName = (
|
|||||||
value: string,
|
value: string,
|
||||||
) => NonIntegratedSkuItem;
|
) => NonIntegratedSkuItem;
|
||||||
|
|
||||||
|
type PersistEditedProduct = (params: {
|
||||||
|
successMessage: string;
|
||||||
|
errorFallbackMessage: string;
|
||||||
|
overrides?: PersistEditedProductOverrides;
|
||||||
|
suppressSuccessMessage?: boolean;
|
||||||
|
}) => Promise<boolean>;
|
||||||
|
|
||||||
type UseProductFactoryRowControllerParams = {
|
type UseProductFactoryRowControllerParams = {
|
||||||
applySkuSupplierName: ApplySkuSupplierName;
|
applySkuSupplierName: ApplySkuSupplierName;
|
||||||
derivedSkuItems: NonIntegratedSkuItem[];
|
derivedSkuItems: NonIntegratedSkuItem[];
|
||||||
displayedProductFactoryHasPendingRows: boolean;
|
displayedProductFactoryHasPendingRows: boolean;
|
||||||
displayedProductFactoryHasSystemEnteredPricingRows: boolean;
|
displayedProductFactoryHasSystemEnteredPricingRows: boolean;
|
||||||
|
displayedProductFactoryIsConfirmed: boolean;
|
||||||
displayedProductFactoryRows: NonIntegratedFactoryRow[];
|
displayedProductFactoryRows: NonIntegratedFactoryRow[];
|
||||||
displayedProductFactoryRowsComplete: boolean;
|
displayedProductFactoryRowsComplete: boolean;
|
||||||
documentWorkspaceApprovedAt: NonIntegratedDocumentWorkspaceApprovalMap;
|
documentWorkspaceApprovedAt: NonIntegratedDocumentWorkspaceApprovalMap;
|
||||||
documentWorkspaceConfirmations: NonIntegratedDocumentWorkspaceConfirmationMap;
|
documentWorkspaceConfirmations: NonIntegratedDocumentWorkspaceConfirmationMap;
|
||||||
|
documentWorkspaceRevisionSignatureRef: MutableRefObject<
|
||||||
|
Record<WorkflowNodeCategory, string> | null
|
||||||
|
>;
|
||||||
isCurrentUserAdmin: boolean;
|
isCurrentUserAdmin: boolean;
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
isSkuItemFactoryConfirmed: (item: NonIntegratedSkuItem) => boolean;
|
isSkuItemFactoryConfirmed: (item: NonIntegratedSkuItem) => boolean;
|
||||||
|
persistEditedProduct: PersistEditedProduct;
|
||||||
productFactoryModelAutofillRef: MutableRefObject<
|
productFactoryModelAutofillRef: MutableRefObject<
|
||||||
Map<string, ProductFactoryModelAutofillEntry>
|
Map<string, ProductFactoryModelAutofillEntry>
|
||||||
>;
|
>;
|
||||||
@ -73,13 +91,16 @@ export function useProductFactoryRowController({
|
|||||||
derivedSkuItems,
|
derivedSkuItems,
|
||||||
displayedProductFactoryHasPendingRows,
|
displayedProductFactoryHasPendingRows,
|
||||||
displayedProductFactoryHasSystemEnteredPricingRows,
|
displayedProductFactoryHasSystemEnteredPricingRows,
|
||||||
|
displayedProductFactoryIsConfirmed,
|
||||||
displayedProductFactoryRows,
|
displayedProductFactoryRows,
|
||||||
displayedProductFactoryRowsComplete,
|
displayedProductFactoryRowsComplete,
|
||||||
documentWorkspaceApprovedAt,
|
documentWorkspaceApprovedAt,
|
||||||
documentWorkspaceConfirmations,
|
documentWorkspaceConfirmations,
|
||||||
|
documentWorkspaceRevisionSignatureRef,
|
||||||
isCurrentUserAdmin,
|
isCurrentUserAdmin,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
isSkuItemFactoryConfirmed,
|
isSkuItemFactoryConfirmed,
|
||||||
|
persistEditedProduct,
|
||||||
productFactoryModelAutofillRef,
|
productFactoryModelAutofillRef,
|
||||||
productFactoryReopenField,
|
productFactoryReopenField,
|
||||||
productFactoryRows,
|
productFactoryRows,
|
||||||
@ -156,32 +177,32 @@ export function useProductFactoryRowController({
|
|||||||
|
|
||||||
if (key === "installMethod") {
|
if (key === "installMethod") {
|
||||||
setSkuItems((current) => {
|
setSkuItems((current) => {
|
||||||
const targetItem = workflowSkuItems.find((item) => item.id === skuId);
|
const targetSkuIds = getProductFactoryTargetSkuIds(
|
||||||
if (!targetItem) return current;
|
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 (targetStyleKeys.size > 0) {
|
||||||
if (targetStyleKey) {
|
setStyleDetails((currentDetails) => {
|
||||||
const targetSkuIds = new Set(
|
let nextDetails = currentDetails;
|
||||||
workflowSkuItems
|
targetStyleKeys.forEach((styleKey) => {
|
||||||
.filter((item) => getStyleKeyFromModel(item.model) === targetStyleKey)
|
nextDetails = updateStyleDetailEntry(nextDetails, styleKey, {
|
||||||
.map((item) => item.id),
|
installMethod: value,
|
||||||
);
|
});
|
||||||
|
});
|
||||||
setStyleDetails((currentDetails) =>
|
return nextDetails;
|
||||||
updateStyleDetailEntry(currentDetails, targetStyleKey, {
|
});
|
||||||
installMethod: value,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return current.map((item) =>
|
|
||||||
targetSkuIds.has(item.id)
|
|
||||||
? { ...item, installMethod: value }
|
|
||||||
: item,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return current.map((item) =>
|
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");
|
setSaveMessageType("success");
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleProductFactoryStatusClick() {
|
async function handleProductFactoryStatusClick() {
|
||||||
const statusMessage = getProductFactoryStatusMessage({
|
const statusMessage = getProductFactoryStatusMessage({
|
||||||
isRowsComplete: displayedProductFactoryRowsComplete,
|
isRowsComplete: displayedProductFactoryRowsComplete,
|
||||||
rows: displayedProductFactoryRows,
|
rows: displayedProductFactoryRows,
|
||||||
});
|
});
|
||||||
if (!statusMessage) return;
|
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);
|
setSaveMessage(statusMessage.message);
|
||||||
setSaveMessageType(statusMessage.type);
|
setSaveMessageType(statusMessage.type);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,10 @@ import type {
|
|||||||
NonIntegratedSkuItem,
|
NonIntegratedSkuItem,
|
||||||
} from "../../nonIntegratedStorage";
|
} from "../../nonIntegratedStorage";
|
||||||
import type { FinishedSampleShipmentEditableKey } from "../basic-info/skuFieldConfig";
|
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 type { WorkflowNodeCategory } from "../documents/documentWorkspaceHelpers";
|
||||||
import {
|
import {
|
||||||
updateFirstQualityRowsForSku,
|
updateFirstQualityRowsForSku,
|
||||||
@ -77,7 +80,7 @@ type UseProductWorkflowRowControllerParams = {
|
|||||||
documentWorkspaceRevisionSignatureRef: MutableRefObject<
|
documentWorkspaceRevisionSignatureRef: MutableRefObject<
|
||||||
Record<WorkflowNodeCategory, string> | null
|
Record<WorkflowNodeCategory, string> | null
|
||||||
>;
|
>;
|
||||||
isProductFactorySkuComplete: (skuId: string) => boolean;
|
isProductFactorySkuConfirmed: (skuId: string) => boolean;
|
||||||
isProductLimitNodeLocked: boolean;
|
isProductLimitNodeLocked: boolean;
|
||||||
isProductPricingNodeLocked: boolean;
|
isProductPricingNodeLocked: boolean;
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
@ -89,6 +92,8 @@ type UseProductWorkflowRowControllerParams = {
|
|||||||
planningLayoutRowsRef: MutableRefObject<NonIntegratedPlanningLayoutRow[]>;
|
planningLayoutRowsRef: MutableRefObject<NonIntegratedPlanningLayoutRow[]>;
|
||||||
pricingRows: NonIntegratedPricingRow[];
|
pricingRows: NonIntegratedPricingRow[];
|
||||||
productId?: string;
|
productId?: string;
|
||||||
|
productSampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
|
||||||
|
sampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
|
||||||
scheduleAutoSave: (overrides?: PersistEditedProductOverrides) => void;
|
scheduleAutoSave: (overrides?: PersistEditedProductOverrides) => void;
|
||||||
setDocumentWorkspaceApprovedAt: Dispatch<
|
setDocumentWorkspaceApprovedAt: Dispatch<
|
||||||
SetStateAction<NonIntegratedDocumentWorkspaceApprovalMap>
|
SetStateAction<NonIntegratedDocumentWorkspaceApprovalMap>
|
||||||
@ -128,7 +133,7 @@ export function useProductWorkflowRowController({
|
|||||||
documentWorkspaceApprovedAt,
|
documentWorkspaceApprovedAt,
|
||||||
documentWorkspaceConfirmations,
|
documentWorkspaceConfirmations,
|
||||||
documentWorkspaceRevisionSignatureRef,
|
documentWorkspaceRevisionSignatureRef,
|
||||||
isProductFactorySkuComplete,
|
isProductFactorySkuConfirmed,
|
||||||
isProductLimitNodeLocked,
|
isProductLimitNodeLocked,
|
||||||
isProductPricingNodeLocked,
|
isProductPricingNodeLocked,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
@ -140,6 +145,8 @@ export function useProductWorkflowRowController({
|
|||||||
planningLayoutRowsRef,
|
planningLayoutRowsRef,
|
||||||
pricingRows,
|
pricingRows,
|
||||||
productId,
|
productId,
|
||||||
|
productSampleMeasurementRows,
|
||||||
|
sampleMeasurementRows,
|
||||||
scheduleAutoSave,
|
scheduleAutoSave,
|
||||||
setDocumentWorkspaceApprovedAt,
|
setDocumentWorkspaceApprovedAt,
|
||||||
setDocumentWorkspaceConfirmations,
|
setDocumentWorkspaceConfirmations,
|
||||||
@ -233,16 +240,25 @@ export function useProductWorkflowRowController({
|
|||||||
});
|
});
|
||||||
const nextProductPricingCanBeConfirmed =
|
const nextProductPricingCanBeConfirmed =
|
||||||
canConfirmProductPricingRows(nextPricingRows);
|
canConfirmProductPricingRows(nextPricingRows);
|
||||||
|
const nextSampleMeasurementCanBeConfirmedByPricing =
|
||||||
|
nextProductPricingCanBeConfirmed &&
|
||||||
|
productSampleMeasurementRows.length > 0;
|
||||||
const nextApprovedAt = nextProductPricingCanBeConfirmed
|
const nextApprovedAt = nextProductPricingCanBeConfirmed
|
||||||
? {
|
? {
|
||||||
...documentWorkspaceApprovedAt,
|
...documentWorkspaceApprovedAt,
|
||||||
[PRODUCT_PRICING_WORKSPACE_CATEGORY]: pushedAt,
|
[PRODUCT_PRICING_WORKSPACE_CATEGORY]: pushedAt,
|
||||||
|
...(nextSampleMeasurementCanBeConfirmedByPricing
|
||||||
|
? { [SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]: pushedAt }
|
||||||
|
: {}),
|
||||||
}
|
}
|
||||||
: documentWorkspaceApprovedAt;
|
: documentWorkspaceApprovedAt;
|
||||||
const nextConfirmations = nextProductPricingCanBeConfirmed
|
const nextConfirmations = nextProductPricingCanBeConfirmed
|
||||||
? {
|
? {
|
||||||
...documentWorkspaceConfirmations,
|
...documentWorkspaceConfirmations,
|
||||||
[PRODUCT_PRICING_WORKSPACE_CATEGORY]: true,
|
[PRODUCT_PRICING_WORKSPACE_CATEGORY]: true,
|
||||||
|
...(nextSampleMeasurementCanBeConfirmedByPricing
|
||||||
|
? { [SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]: true }
|
||||||
|
: {}),
|
||||||
}
|
}
|
||||||
: documentWorkspaceConfirmations;
|
: documentWorkspaceConfirmations;
|
||||||
const pushSuccessMessage =
|
const pushSuccessMessage =
|
||||||
@ -257,6 +273,12 @@ export function useProductWorkflowRowController({
|
|||||||
...documentWorkspaceRevisionSignatureRef.current,
|
...documentWorkspaceRevisionSignatureRef.current,
|
||||||
[PRODUCT_PRICING_WORKSPACE_CATEGORY]:
|
[PRODUCT_PRICING_WORKSPACE_CATEGORY]:
|
||||||
JSON.stringify(nextPricingRows),
|
JSON.stringify(nextPricingRows),
|
||||||
|
...(nextSampleMeasurementCanBeConfirmedByPricing
|
||||||
|
? {
|
||||||
|
[SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY]:
|
||||||
|
JSON.stringify(sampleMeasurementRows),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,7 +478,7 @@ export function useProductWorkflowRowController({
|
|||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
isReadOnly ||
|
isReadOnly ||
|
||||||
!isProductFactorySkuComplete(skuId) ||
|
!isProductFactorySkuConfirmed(skuId) ||
|
||||||
isSampleMeasurementSkuLocked(skuId)
|
isSampleMeasurementSkuLocked(skuId)
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ type SampleMeasurementHeaderActionsProps = {
|
|||||||
actionGroupClassName: string;
|
actionGroupClassName: string;
|
||||||
rowCount: number;
|
rowCount: number;
|
||||||
isProductFactoryConfirmed: boolean;
|
isProductFactoryConfirmed: boolean;
|
||||||
|
hasPendingRows: boolean;
|
||||||
isSampleMeasurementConfirmed: boolean;
|
isSampleMeasurementConfirmed: boolean;
|
||||||
onStatusClick: () => void;
|
onStatusClick: () => void;
|
||||||
};
|
};
|
||||||
@ -12,6 +13,7 @@ export function SampleMeasurementHeaderActions({
|
|||||||
actionGroupClassName,
|
actionGroupClassName,
|
||||||
rowCount,
|
rowCount,
|
||||||
isProductFactoryConfirmed,
|
isProductFactoryConfirmed,
|
||||||
|
hasPendingRows,
|
||||||
isSampleMeasurementConfirmed,
|
isSampleMeasurementConfirmed,
|
||||||
onStatusClick,
|
onStatusClick,
|
||||||
}: SampleMeasurementHeaderActionsProps) {
|
}: SampleMeasurementHeaderActionsProps) {
|
||||||
@ -19,6 +21,7 @@ export function SampleMeasurementHeaderActions({
|
|||||||
<div className={actionGroupClassName}>
|
<div className={actionGroupClassName}>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
|
data-testid="sample-measurement-confirm"
|
||||||
onClick={onStatusClick}
|
onClick={onStatusClick}
|
||||||
disabled={rowCount === 0}
|
disabled={rowCount === 0}
|
||||||
title={
|
title={
|
||||||
@ -28,8 +31,10 @@ export function SampleMeasurementHeaderActions({
|
|||||||
{!isProductFactoryConfirmed
|
{!isProductFactoryConfirmed
|
||||||
? "定厂未完成"
|
? "定厂未完成"
|
||||||
: isSampleMeasurementConfirmed
|
: isSampleMeasurementConfirmed
|
||||||
? "已完成"
|
? "已确认"
|
||||||
: "当前资料未填完"}
|
: hasPendingRows
|
||||||
|
? "当前资料未填完"
|
||||||
|
: "资料已填完核对无误请确认。"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -153,7 +153,7 @@ export function getSampleMeasurementStatusMessage({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: "样包测量已完成",
|
message: "资料已填完核对无误请确认。",
|
||||||
type: "success" as const,
|
type: "success" as const,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,37 +1,77 @@
|
|||||||
import type {
|
import type {
|
||||||
Dispatch,
|
Dispatch,
|
||||||
|
MutableRefObject,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
} from "react";
|
} 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 {
|
import {
|
||||||
getFinishedSampleShipmentStatusMessage,
|
getFinishedSampleShipmentStatusMessage,
|
||||||
getSampleMeasurementStatusMessage,
|
getSampleMeasurementStatusMessage,
|
||||||
|
normalizeSampleMeasurementRowsForPayload,
|
||||||
type ProductFinishedSampleShipmentDisplayRow,
|
type ProductFinishedSampleShipmentDisplayRow,
|
||||||
type ProductSampleMeasurementDisplayRow,
|
type ProductSampleMeasurementDisplayRow,
|
||||||
} from "./sampleWorkflowHelpers";
|
} from "./sampleWorkflowHelpers";
|
||||||
|
|
||||||
type SaveMessageType = "success" | "error";
|
type SaveMessageType = "success" | "error";
|
||||||
|
|
||||||
|
type PersistEditedProduct = (params: {
|
||||||
|
successMessage: string;
|
||||||
|
errorFallbackMessage: string;
|
||||||
|
overrides?: PersistEditedProductOverrides;
|
||||||
|
suppressSuccessMessage?: boolean;
|
||||||
|
}) => Promise<boolean>;
|
||||||
|
|
||||||
type UseSampleWorkflowStatusControllerParams = {
|
type UseSampleWorkflowStatusControllerParams = {
|
||||||
|
documentWorkspaceApprovedAt: NonIntegratedDocumentWorkspaceApprovalMap;
|
||||||
|
documentWorkspaceConfirmations: NonIntegratedDocumentWorkspaceConfirmationMap;
|
||||||
displayedFinishedSampleShipmentRows: ProductFinishedSampleShipmentDisplayRow[];
|
displayedFinishedSampleShipmentRows: ProductFinishedSampleShipmentDisplayRow[];
|
||||||
displayedFinishedSampleShipmentRowsComplete: boolean;
|
displayedFinishedSampleShipmentRowsComplete: boolean;
|
||||||
displayedProductFactoryIsConfirmed: boolean;
|
displayedProductFactoryIsConfirmed: boolean;
|
||||||
displayedProductSampleMeasurementRows: ProductSampleMeasurementDisplayRow[];
|
displayedProductSampleMeasurementRows: ProductSampleMeasurementDisplayRow[];
|
||||||
|
displayedSampleMeasurementIsConfirmed: boolean;
|
||||||
displayedSampleMeasurementRowsComplete: boolean;
|
displayedSampleMeasurementRowsComplete: boolean;
|
||||||
|
documentWorkspaceRevisionSignatureRef: MutableRefObject<
|
||||||
|
Record<WorkflowNodeCategory, string> | null
|
||||||
|
>;
|
||||||
|
isReadOnly: boolean;
|
||||||
|
persistEditedProduct: PersistEditedProduct;
|
||||||
|
productSampleMeasurementRows: ProductSampleMeasurementDisplayRow[];
|
||||||
|
setDocumentWorkspaceApprovedAt: Dispatch<
|
||||||
|
SetStateAction<NonIntegratedDocumentWorkspaceApprovalMap>
|
||||||
|
>;
|
||||||
|
setDocumentWorkspaceConfirmations: Dispatch<
|
||||||
|
SetStateAction<NonIntegratedDocumentWorkspaceConfirmationMap>
|
||||||
|
>;
|
||||||
setSaveMessage: Dispatch<SetStateAction<string>>;
|
setSaveMessage: Dispatch<SetStateAction<string>>;
|
||||||
setSaveMessageType: Dispatch<SetStateAction<SaveMessageType>>;
|
setSaveMessageType: Dispatch<SetStateAction<SaveMessageType>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useSampleWorkflowStatusController({
|
export function useSampleWorkflowStatusController({
|
||||||
|
documentWorkspaceApprovedAt,
|
||||||
|
documentWorkspaceConfirmations,
|
||||||
displayedFinishedSampleShipmentRows,
|
displayedFinishedSampleShipmentRows,
|
||||||
displayedFinishedSampleShipmentRowsComplete,
|
displayedFinishedSampleShipmentRowsComplete,
|
||||||
displayedProductFactoryIsConfirmed,
|
displayedProductFactoryIsConfirmed,
|
||||||
displayedProductSampleMeasurementRows,
|
displayedProductSampleMeasurementRows,
|
||||||
|
displayedSampleMeasurementIsConfirmed,
|
||||||
displayedSampleMeasurementRowsComplete,
|
displayedSampleMeasurementRowsComplete,
|
||||||
|
documentWorkspaceRevisionSignatureRef,
|
||||||
|
isReadOnly,
|
||||||
|
persistEditedProduct,
|
||||||
|
productSampleMeasurementRows,
|
||||||
|
setDocumentWorkspaceApprovedAt,
|
||||||
|
setDocumentWorkspaceConfirmations,
|
||||||
setSaveMessage,
|
setSaveMessage,
|
||||||
setSaveMessageType,
|
setSaveMessageType,
|
||||||
}: UseSampleWorkflowStatusControllerParams) {
|
}: UseSampleWorkflowStatusControllerParams) {
|
||||||
function handleSampleMeasurementStatusClick() {
|
async function handleSampleMeasurementStatusClick() {
|
||||||
const statusMessage = getSampleMeasurementStatusMessage({
|
const statusMessage = getSampleMeasurementStatusMessage({
|
||||||
isFactoryConfirmed: displayedProductFactoryIsConfirmed,
|
isFactoryConfirmed: displayedProductFactoryIsConfirmed,
|
||||||
isRowsComplete: displayedSampleMeasurementRowsComplete,
|
isRowsComplete: displayedSampleMeasurementRowsComplete,
|
||||||
@ -39,6 +79,47 @@ export function useSampleWorkflowStatusController({
|
|||||||
});
|
});
|
||||||
if (!statusMessage) return;
|
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);
|
setSaveMessage(statusMessage.message);
|
||||||
setSaveMessageType(statusMessage.type);
|
setSaveMessageType(statusMessage.type);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,6 +54,7 @@ export function DocumentWorkspaceHeaderActionsSlot({
|
|||||||
displayedProductPricingRowsComplete,
|
displayedProductPricingRowsComplete,
|
||||||
displayedProductPricingRowsReadyForPush,
|
displayedProductPricingRowsReadyForPush,
|
||||||
displayedProductSampleMeasurementRowCount,
|
displayedProductSampleMeasurementRowCount,
|
||||||
|
displayedSampleMeasurementHasPendingRows,
|
||||||
displayedSampleMeasurementIsConfirmed,
|
displayedSampleMeasurementIsConfirmed,
|
||||||
documentWorkspaceConfirmationAction,
|
documentWorkspaceConfirmationAction,
|
||||||
documentWorkspaceUploadInputRef,
|
documentWorkspaceUploadInputRef,
|
||||||
@ -157,6 +158,7 @@ export function DocumentWorkspaceHeaderActionsSlot({
|
|||||||
displayedProductPricingRowsComplete: boolean;
|
displayedProductPricingRowsComplete: boolean;
|
||||||
displayedProductPricingRowsReadyForPush: boolean;
|
displayedProductPricingRowsReadyForPush: boolean;
|
||||||
displayedProductSampleMeasurementRowCount: number;
|
displayedProductSampleMeasurementRowCount: number;
|
||||||
|
displayedSampleMeasurementHasPendingRows: boolean;
|
||||||
displayedSampleMeasurementIsConfirmed: boolean;
|
displayedSampleMeasurementIsConfirmed: boolean;
|
||||||
documentWorkspaceConfirmationAction: ReactNode;
|
documentWorkspaceConfirmationAction: ReactNode;
|
||||||
documentWorkspaceUploadInputRef: RefObject<HTMLInputElement | null>;
|
documentWorkspaceUploadInputRef: RefObject<HTMLInputElement | null>;
|
||||||
@ -262,6 +264,7 @@ export function DocumentWorkspaceHeaderActionsSlot({
|
|||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
rowCount={displayedProductFactoryRowCount}
|
rowCount={displayedProductFactoryRowCount}
|
||||||
hasPendingRows={displayedProductFactoryHasPendingRows}
|
hasPendingRows={displayedProductFactoryHasPendingRows}
|
||||||
|
isConfirmed={displayedProductFactoryIsConfirmed}
|
||||||
hasSystemEnteredPricingRows={
|
hasSystemEnteredPricingRows={
|
||||||
displayedProductFactoryHasSystemEnteredPricingRows
|
displayedProductFactoryHasSystemEnteredPricingRows
|
||||||
}
|
}
|
||||||
@ -282,6 +285,7 @@ export function DocumentWorkspaceHeaderActionsSlot({
|
|||||||
actionGroupClassName={actionGroupClassName}
|
actionGroupClassName={actionGroupClassName}
|
||||||
rowCount={displayedProductSampleMeasurementRowCount}
|
rowCount={displayedProductSampleMeasurementRowCount}
|
||||||
isProductFactoryConfirmed={displayedProductFactoryIsConfirmed}
|
isProductFactoryConfirmed={displayedProductFactoryIsConfirmed}
|
||||||
|
hasPendingRows={displayedSampleMeasurementHasPendingRows}
|
||||||
isSampleMeasurementConfirmed={displayedSampleMeasurementIsConfirmed}
|
isSampleMeasurementConfirmed={displayedSampleMeasurementIsConfirmed}
|
||||||
onStatusClick={onSampleMeasurementStatusClick}
|
onStatusClick={onSampleMeasurementStatusClick}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -10,8 +10,10 @@ import {
|
|||||||
import { DocumentWorkspaceSidebarStatusIcon } from "../../components/DocumentWorkspaceControls";
|
import { DocumentWorkspaceSidebarStatusIcon } from "../../components/DocumentWorkspaceControls";
|
||||||
import type {
|
import type {
|
||||||
NonIntegratedFactoryRow,
|
NonIntegratedFactoryRow,
|
||||||
|
NonIntegratedSampleMeasurementRow,
|
||||||
NonIntegratedUploadFile,
|
NonIntegratedUploadFile,
|
||||||
} from "../../nonIntegratedStorage";
|
} from "../../nonIntegratedStorage";
|
||||||
|
import { SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY } from "../documents/documentWorkspaceConfig";
|
||||||
|
|
||||||
type DocumentWorkspaceView = "detail" | "document";
|
type DocumentWorkspaceView = "detail" | "document";
|
||||||
|
|
||||||
@ -27,9 +29,10 @@ export function DocumentWorkspaceSidebar({
|
|||||||
basicInfoNeedsConfirmation,
|
basicInfoNeedsConfirmation,
|
||||||
documentWorkspaceCountByCategory,
|
documentWorkspaceCountByCategory,
|
||||||
documentWorkspaceView,
|
documentWorkspaceView,
|
||||||
isProductFactoryRowComplete,
|
|
||||||
isWorkflowNodeConfirmed,
|
isWorkflowNodeConfirmed,
|
||||||
productFactoryRows,
|
productFactoryRows,
|
||||||
|
sampleMeasurementRows,
|
||||||
|
isSampleMeasurementConfirmed,
|
||||||
visibleGroupedUploadFiles,
|
visibleGroupedUploadFiles,
|
||||||
onOpenBasicInfo,
|
onOpenBasicInfo,
|
||||||
onOpenDocumentWorkspace,
|
onOpenDocumentWorkspace,
|
||||||
@ -42,12 +45,13 @@ export function DocumentWorkspaceSidebar({
|
|||||||
Record<DocumentWorkspaceCategory, number>
|
Record<DocumentWorkspaceCategory, number>
|
||||||
>;
|
>;
|
||||||
documentWorkspaceView: DocumentWorkspaceView;
|
documentWorkspaceView: DocumentWorkspaceView;
|
||||||
isProductFactoryRowComplete: (row: NonIntegratedFactoryRow) => boolean;
|
|
||||||
isWorkflowNodeConfirmed: (
|
isWorkflowNodeConfirmed: (
|
||||||
category: DocumentWorkspaceCategory,
|
category: DocumentWorkspaceCategory,
|
||||||
hasContent: boolean,
|
hasContent: boolean,
|
||||||
) => boolean;
|
) => boolean;
|
||||||
productFactoryRows: NonIntegratedFactoryRow[];
|
productFactoryRows: NonIntegratedFactoryRow[];
|
||||||
|
sampleMeasurementRows: NonIntegratedSampleMeasurementRow[];
|
||||||
|
isSampleMeasurementConfirmed: boolean;
|
||||||
visibleGroupedUploadFiles: GroupedWorkspaceFiles[];
|
visibleGroupedUploadFiles: GroupedWorkspaceFiles[];
|
||||||
onOpenBasicInfo: () => void;
|
onOpenBasicInfo: () => void;
|
||||||
onOpenDocumentWorkspace: (category: DocumentWorkspaceCategory) => void;
|
onOpenDocumentWorkspace: (category: DocumentWorkspaceCategory) => void;
|
||||||
@ -74,13 +78,14 @@ export function DocumentWorkspaceSidebar({
|
|||||||
const categoryHasContent =
|
const categoryHasContent =
|
||||||
category === PRODUCT_FACTORY_WORKSPACE_CATEGORY
|
category === PRODUCT_FACTORY_WORKSPACE_CATEGORY
|
||||||
? productFactoryRows.length > 0
|
? productFactoryRows.length > 0
|
||||||
|
: category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY
|
||||||
|
? sampleMeasurementRows.length > 0
|
||||||
: hasFiles;
|
: hasFiles;
|
||||||
const categoryNeedsConfirmation =
|
const categoryNeedsConfirmation =
|
||||||
category === PRODUCT_FACTORY_WORKSPACE_CATEGORY
|
category === PRODUCT_FACTORY_WORKSPACE_CATEGORY
|
||||||
? !(
|
? !productFactoryRows.every((row) => row.confirmed)
|
||||||
productFactoryRows.length > 0 &&
|
: category === SAMPLE_MEASUREMENT_WORKSPACE_CATEGORY
|
||||||
productFactoryRows.every(isProductFactoryRowComplete)
|
? !isSampleMeasurementConfirmed
|
||||||
)
|
|
||||||
: needsConfirmation;
|
: needsConfirmation;
|
||||||
const shouldInsertBasicInfoTrigger = index === basicInfoInsertIndex;
|
const shouldInsertBasicInfoTrigger = index === basicInfoInsertIndex;
|
||||||
const basicInfoIsActive = documentWorkspaceView === "detail";
|
const basicInfoIsActive = documentWorkspaceView === "detail";
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import Input, { Textarea } from '@/components/ui/Input'
|
|||||||
import Modal from '@/components/ui/Modal'
|
import Modal from '@/components/ui/Modal'
|
||||||
import Button from '@/components/ui/Button'
|
import Button from '@/components/ui/Button'
|
||||||
import Select from '@/components/ui/Select'
|
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 { ProductWithSkus } from '../home/home-client.types'
|
||||||
import type { LucideIcon } from 'lucide-react'
|
import type { LucideIcon } from 'lucide-react'
|
||||||
|
|
||||||
@ -63,12 +63,12 @@ export interface HomeMobileViewProps {
|
|||||||
|
|
||||||
/* 删除产品 */
|
/* 删除产品 */
|
||||||
deletingProduct: ProductWithSkus | null
|
deletingProduct: ProductWithSkus | null
|
||||||
onDeleteProduct: () => void
|
onDeleteProduct: () => void | Promise<void>
|
||||||
onCloseDeleteProduct: () => void
|
onCloseDeleteProduct: () => void
|
||||||
|
|
||||||
/* 删除 SKU */
|
/* 删除 SKU */
|
||||||
deletingSku: { product: ProductWithSkus; sku: { skuCode: string } } | null
|
deletingSku: { product: ProductWithSkus; sku: { skuCode: string } } | null
|
||||||
onDeleteSKU: () => void
|
onDeleteSKU: () => void | Promise<void>
|
||||||
onCloseDeleteSKU: () => void
|
onCloseDeleteSKU: () => void
|
||||||
|
|
||||||
/* 添加 SKU */
|
/* 添加 SKU */
|
||||||
@ -81,7 +81,7 @@ export interface HomeMobileViewProps {
|
|||||||
onMarkHomeReturn: () => void
|
onMarkHomeReturn: () => void
|
||||||
|
|
||||||
/* Toast */
|
/* Toast */
|
||||||
toasts: Array<{ id: string; message: string; type?: string }>
|
toasts: ToastData[]
|
||||||
onRemoveToast: (id: string) => void
|
onRemoveToast: (id: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +406,9 @@ export default function HomeMobileView({
|
|||||||
<DeleteConfirmDialog
|
<DeleteConfirmDialog
|
||||||
isOpen={!!deletingProduct}
|
isOpen={!!deletingProduct}
|
||||||
onClose={onCloseDeleteProduct}
|
onClose={onCloseDeleteProduct}
|
||||||
onConfirm={onDeleteProduct}
|
onConfirm={async () => {
|
||||||
|
await onDeleteProduct()
|
||||||
|
}}
|
||||||
title="删除产品"
|
title="删除产品"
|
||||||
description={
|
description={
|
||||||
deletingProduct
|
deletingProduct
|
||||||
@ -428,7 +430,9 @@ export default function HomeMobileView({
|
|||||||
<DeleteConfirmDialog
|
<DeleteConfirmDialog
|
||||||
isOpen={!!deletingSku}
|
isOpen={!!deletingSku}
|
||||||
onClose={onCloseDeleteSKU}
|
onClose={onCloseDeleteSKU}
|
||||||
onConfirm={onDeleteSKU}
|
onConfirm={async () => {
|
||||||
|
await onDeleteSKU()
|
||||||
|
}}
|
||||||
title="删除 SKU"
|
title="删除 SKU"
|
||||||
description={
|
description={
|
||||||
deletingSku
|
deletingSku
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user