refactor(intake): extract finished sample shipment workspace
This commit is contained in:
parent
921c55c97f
commit
9961f8a1b9
@ -0,0 +1,262 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { InlineSelect } from "./components/InlineControls";
|
||||
import {
|
||||
SkuColumnResizableFrame,
|
||||
SkuRowField,
|
||||
} from "./components/SkuTableFields";
|
||||
import {
|
||||
FINISHED_SAMPLE_SHIPMENT_COLUMN_DEFAULT_WIDTHS,
|
||||
FINISHED_SAMPLE_SHIPMENT_SHIPPED_OPTIONS,
|
||||
type FinishedSampleShipmentColumnWidthKey,
|
||||
type FinishedSampleShipmentEditableKey,
|
||||
} from "./skuFieldConfig";
|
||||
import {
|
||||
isFinishedSampleShipmentRowComplete,
|
||||
type ProductFinishedSampleShipmentDisplayRow,
|
||||
} from "./sampleWorkflowHelpers";
|
||||
|
||||
type FinishedSampleShipmentWorkspaceProps = {
|
||||
allRows: ProductFinishedSampleShipmentDisplayRow[];
|
||||
displayedRows: ProductFinishedSampleShipmentDisplayRow[];
|
||||
inheritedSkuBatchTabs: ReactNode;
|
||||
columnWidths: Record<FinishedSampleShipmentColumnWidthKey, number>;
|
||||
canEditQuantity: boolean;
|
||||
canEditDecision: boolean;
|
||||
canEditTrackingNumber: boolean;
|
||||
onColumnResize: (
|
||||
column: FinishedSampleShipmentColumnWidthKey,
|
||||
width: number,
|
||||
) => void;
|
||||
onUpdateRow: (
|
||||
skuId: string,
|
||||
key: FinishedSampleShipmentEditableKey,
|
||||
value: string,
|
||||
) => void;
|
||||
onPreviewImage: (src: string, alt: string) => void;
|
||||
};
|
||||
|
||||
export function FinishedSampleShipmentWorkspace({
|
||||
allRows,
|
||||
displayedRows,
|
||||
inheritedSkuBatchTabs,
|
||||
columnWidths,
|
||||
canEditQuantity,
|
||||
canEditDecision,
|
||||
canEditTrackingNumber,
|
||||
onColumnResize,
|
||||
onUpdateRow,
|
||||
onPreviewImage,
|
||||
}: FinishedSampleShipmentWorkspaceProps) {
|
||||
const renderReadOnlyCell = (
|
||||
value: string,
|
||||
column: FinishedSampleShipmentColumnWidthKey,
|
||||
) => (
|
||||
<SkuRowField
|
||||
value={value || "-"}
|
||||
readOnly
|
||||
mode="singleLineResizable"
|
||||
columnWidth={columnWidths[column]}
|
||||
onColumnResize={(width) => onColumnResize(column, width)}
|
||||
onChange={() => undefined}
|
||||
/>
|
||||
);
|
||||
const renderImageCell = (
|
||||
row: ProductFinishedSampleShipmentDisplayRow,
|
||||
index: number,
|
||||
) => {
|
||||
if (!row.image) {
|
||||
return (
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded border border-dashed border-apple-separator bg-apple-bg-secondary text-[11px] text-apple-label-tertiary">
|
||||
无图
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const alt = row.model || `成品寄样图片${index + 1}`;
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="block h-12 w-12 overflow-hidden rounded border border-apple-separator bg-apple-bg-secondary"
|
||||
onClick={() => onPreviewImage(row.image, alt)}
|
||||
>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={row.image} alt={alt} className="h-full w-full object-cover" />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
const renderShipmentInput = (
|
||||
row: ProductFinishedSampleShipmentDisplayRow,
|
||||
key: Extract<
|
||||
FinishedSampleShipmentEditableKey,
|
||||
"sampleQuantity" | "trackingNumber"
|
||||
>,
|
||||
placeholder: string,
|
||||
readOnly: boolean,
|
||||
column: Extract<
|
||||
FinishedSampleShipmentColumnWidthKey,
|
||||
"sampleQuantity" | "trackingNumber"
|
||||
>,
|
||||
) => (
|
||||
<SkuRowField
|
||||
value={row[key]}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
mode="singleLineResizable"
|
||||
tone="manual"
|
||||
columnWidth={columnWidths[column]}
|
||||
onColumnResize={(width) => onColumnResize(column, width)}
|
||||
testId={`finished-sample-shipment-${key}-${row.skuId}`}
|
||||
onChange={(value) => onUpdateRow(row.skuId, key, value)}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="finished-sample-shipment-workspace"
|
||||
className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-apple-xl border border-apple-separator bg-apple-bg-primary"
|
||||
>
|
||||
<div className="border-b border-apple-separator px-3 py-2">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
{inheritedSkuBatchTabs}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-h-0 min-w-0 flex-1 overflow-hidden p-3">
|
||||
{allRows.length === 0 ? (
|
||||
<div className="flex min-h-[260px] items-center justify-center rounded-apple-xl border border-dashed border-apple-separator text-sm text-apple-label-secondary">
|
||||
当前还没有 SKU 信息,先维护 SKU 后再进行成品寄样。
|
||||
</div>
|
||||
) : displayedRows.length === 0 ? (
|
||||
<div className="flex min-h-[260px] items-center justify-center rounded-apple-xl border border-dashed border-apple-separator text-sm text-apple-label-secondary">
|
||||
当前批次还没有 SKU 信息。
|
||||
</div>
|
||||
) : (
|
||||
<div className="non-integrated-table-scroll non-integrated-workspace-table-scroll h-full max-w-full rounded-apple-lg border border-apple-separator">
|
||||
<table className="min-w-[1760px] w-full border-collapse text-xs">
|
||||
<thead className="bg-apple-bg-secondary/40 text-apple-label-secondary">
|
||||
<tr>
|
||||
{[
|
||||
"寄样",
|
||||
"序号",
|
||||
"图片",
|
||||
"型号",
|
||||
"货号",
|
||||
"套件量",
|
||||
"供应商名称",
|
||||
"条码",
|
||||
"条码规格名称",
|
||||
"安装方式",
|
||||
"寄样数量",
|
||||
"是否寄出",
|
||||
"快递单号",
|
||||
].map((label) => (
|
||||
<th
|
||||
key={label}
|
||||
className="whitespace-nowrap border-b border-apple-separator px-2 py-2 text-left font-apple-medium"
|
||||
>
|
||||
{label}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{displayedRows.map((row, index) => (
|
||||
<tr
|
||||
key={row.skuId}
|
||||
className="border-b border-apple-separator last:border-b-0"
|
||||
>
|
||||
<td className="px-2 py-2">
|
||||
<span
|
||||
className={`inline-flex whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] ${
|
||||
isFinishedSampleShipmentRowComplete(row)
|
||||
? "bg-[#dff7e8] text-[#137a38]"
|
||||
: "bg-[#fff3df] text-[#9b6511]"
|
||||
}`}
|
||||
>
|
||||
{isFinishedSampleShipmentRowComplete(row)
|
||||
? "已完成"
|
||||
: "请寄样"}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-2 py-2 text-apple-label-secondary">
|
||||
{index + 1}
|
||||
</td>
|
||||
<td className="px-2 py-2">{renderImageCell(row, index)}</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.model, "model")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.skuCode, "skuCode")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.setCount, "setCount")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.supplierName, "supplierName")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.barcode, "barcode")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.specName, "specName")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.installMethod, "installMethod")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderShipmentInput(
|
||||
row,
|
||||
"sampleQuantity",
|
||||
"请输入数量",
|
||||
!canEditQuantity,
|
||||
"sampleQuantity",
|
||||
)}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
<SkuColumnResizableFrame
|
||||
columnWidth={columnWidths.shipped}
|
||||
minWidth={
|
||||
FINISHED_SAMPLE_SHIPMENT_COLUMN_DEFAULT_WIDTHS.shipped
|
||||
}
|
||||
onColumnResize={(width) =>
|
||||
onColumnResize("shipped", width)
|
||||
}
|
||||
>
|
||||
<InlineSelect
|
||||
ariaLabel="成品寄样是否寄出"
|
||||
dataTestId={`finished-sample-shipment-shipped-${row.skuId}`}
|
||||
value={row.shipped}
|
||||
options={FINISHED_SAMPLE_SHIPMENT_SHIPPED_OPTIONS}
|
||||
placeholder="请选择"
|
||||
includeEmptyOption={false}
|
||||
readOnly={!canEditDecision}
|
||||
showIndicatorWhenReadOnly
|
||||
onChange={(value) =>
|
||||
onUpdateRow(row.skuId, "shipped", value)
|
||||
}
|
||||
buttonClassName="h-8 w-full min-w-0 rounded border border-apple-separator bg-apple-bg-secondary px-2 text-xs text-apple-label-primary outline-none disabled:cursor-not-allowed disabled:bg-apple-bg-primary disabled:text-apple-label-secondary"
|
||||
/>
|
||||
</SkuColumnResizableFrame>
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderShipmentInput(
|
||||
row,
|
||||
"trackingNumber",
|
||||
"请输入快递单号",
|
||||
!canEditTrackingNumber,
|
||||
"trackingNumber",
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -27,6 +27,7 @@ import {
|
||||
InlineSelect,
|
||||
InlineSuggestionInput,
|
||||
} from "./components/InlineControls";
|
||||
import { FinishedSampleShipmentWorkspace } from "./FinishedSampleShipmentWorkspace";
|
||||
import {
|
||||
FactoryLeadTimeField,
|
||||
FactoryWarehouseField,
|
||||
@ -604,7 +605,6 @@ import {
|
||||
normalizeFinishedSampleShipmentRowsForPayload,
|
||||
normalizeFinishedSampleShipmentShipped,
|
||||
normalizeSampleMeasurementRowsForPayload,
|
||||
type ProductFinishedSampleShipmentDisplayRow,
|
||||
} from "./sampleWorkflowHelpers";
|
||||
import {
|
||||
buildFirstQualityRows,
|
||||
@ -731,7 +731,6 @@ import {
|
||||
FINISHED_SAMPLE_SHIPMENT_COLUMN_DEFAULT_WIDTHS,
|
||||
FINISHED_SAMPLE_SHIPMENT_EXISTING_SAMPLE_TRACKING,
|
||||
FINISHED_SAMPLE_SHIPMENT_NOT_REQUIRED_TRACKING,
|
||||
FINISHED_SAMPLE_SHIPMENT_SHIPPED_OPTIONS,
|
||||
INSTALL_METHOD_OPTIONS,
|
||||
COMPONENT_SKU_CATEGORY_LABEL_BY_KEY,
|
||||
COMPONENT_SKU_CATEGORY_OPTIONS,
|
||||
@ -18403,236 +18402,25 @@ export default function NonIntegratedDetailClient({
|
||||
}
|
||||
|
||||
function renderFinishedSampleShipmentWorkspace() {
|
||||
const renderReadOnlyCell = (
|
||||
value: string,
|
||||
column: FinishedSampleShipmentColumnWidthKey,
|
||||
) => (
|
||||
<SkuRowField
|
||||
value={value || "-"}
|
||||
readOnly
|
||||
mode="singleLineResizable"
|
||||
columnWidth={finishedSampleShipmentColumnWidths[column]}
|
||||
onColumnResize={(width) =>
|
||||
handleFinishedSampleShipmentColumnResize(column, width)
|
||||
}
|
||||
onChange={() => undefined}
|
||||
/>
|
||||
);
|
||||
const renderImageCell = (
|
||||
row: ProductFinishedSampleShipmentDisplayRow,
|
||||
index: number,
|
||||
) => {
|
||||
if (!row.image) {
|
||||
return (
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded border border-dashed border-apple-separator bg-apple-bg-secondary text-[11px] text-apple-label-tertiary">
|
||||
无图
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="block h-12 w-12 overflow-hidden rounded border border-apple-separator bg-apple-bg-secondary"
|
||||
onClick={() =>
|
||||
setSkuImagePreview({
|
||||
kind: "image",
|
||||
src: row.image,
|
||||
alt: row.model || `成品寄样图片${index + 1}`,
|
||||
})
|
||||
}
|
||||
>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={row.image}
|
||||
alt={row.model || `成品寄样图片${index + 1}`}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
const renderShipmentInput = (
|
||||
row: ProductFinishedSampleShipmentDisplayRow,
|
||||
key: Extract<
|
||||
FinishedSampleShipmentEditableKey,
|
||||
"sampleQuantity" | "trackingNumber"
|
||||
>,
|
||||
placeholder: string,
|
||||
readOnly: boolean,
|
||||
column: Extract<
|
||||
FinishedSampleShipmentColumnWidthKey,
|
||||
"sampleQuantity" | "trackingNumber"
|
||||
>,
|
||||
) => (
|
||||
<SkuRowField
|
||||
value={row[key]}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
mode="singleLineResizable"
|
||||
tone="manual"
|
||||
columnWidth={finishedSampleShipmentColumnWidths[column]}
|
||||
onColumnResize={(width) =>
|
||||
handleFinishedSampleShipmentColumnResize(column, width)
|
||||
}
|
||||
testId={`finished-sample-shipment-${key}-${row.skuId}`}
|
||||
onChange={(value) =>
|
||||
updateFinishedSampleShipmentRow(row.skuId, key, value)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="finished-sample-shipment-workspace"
|
||||
className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-apple-xl border border-apple-separator bg-apple-bg-primary"
|
||||
>
|
||||
<div className="border-b border-apple-separator px-3 py-2">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
{renderInheritedSkuBatchTabs()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-h-0 min-w-0 flex-1 overflow-hidden p-3">
|
||||
{productFinishedSampleShipmentRows.length === 0 ? (
|
||||
<div className="flex min-h-[260px] items-center justify-center rounded-apple-xl border border-dashed border-apple-separator text-sm text-apple-label-secondary">
|
||||
当前还没有 SKU 信息,先维护 SKU 后再进行成品寄样。
|
||||
</div>
|
||||
) : displayedFinishedSampleShipmentRows.length === 0 ? (
|
||||
<div className="flex min-h-[260px] items-center justify-center rounded-apple-xl border border-dashed border-apple-separator text-sm text-apple-label-secondary">
|
||||
当前批次还没有 SKU 信息。
|
||||
</div>
|
||||
) : (
|
||||
<div className="non-integrated-table-scroll non-integrated-workspace-table-scroll h-full max-w-full rounded-apple-lg border border-apple-separator">
|
||||
<table className="min-w-[1760px] w-full border-collapse text-xs">
|
||||
<thead className="bg-apple-bg-secondary/40 text-apple-label-secondary">
|
||||
<tr>
|
||||
{[
|
||||
"寄样",
|
||||
"序号",
|
||||
"图片",
|
||||
"型号",
|
||||
"货号",
|
||||
"套件量",
|
||||
"供应商名称",
|
||||
"条码",
|
||||
"条码规格名称",
|
||||
"安装方式",
|
||||
"寄样数量",
|
||||
"是否寄出",
|
||||
"快递单号",
|
||||
].map((label) => (
|
||||
<th
|
||||
key={label}
|
||||
className="whitespace-nowrap border-b border-apple-separator px-2 py-2 text-left font-apple-medium"
|
||||
>
|
||||
{label}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{displayedFinishedSampleShipmentRows.map((row, index) => (
|
||||
<tr
|
||||
key={row.skuId}
|
||||
className="border-b border-apple-separator last:border-b-0"
|
||||
>
|
||||
<td className="px-2 py-2">
|
||||
<span
|
||||
className={`inline-flex whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] ${
|
||||
isFinishedSampleShipmentRowComplete(row)
|
||||
? "bg-[#dff7e8] text-[#137a38]"
|
||||
: "bg-[#fff3df] text-[#9b6511]"
|
||||
}`}
|
||||
>
|
||||
{isFinishedSampleShipmentRowComplete(row)
|
||||
? "已完成"
|
||||
: "请寄样"}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-2 py-2 text-apple-label-secondary">
|
||||
{index + 1}
|
||||
</td>
|
||||
<td className="px-2 py-2">{renderImageCell(row, index)}</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.model, "model")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.skuCode, "skuCode")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.setCount, "setCount")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.supplierName, "supplierName")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.barcode, "barcode")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.specName, "specName")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderReadOnlyCell(row.installMethod, "installMethod")}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderShipmentInput(
|
||||
row,
|
||||
"sampleQuantity",
|
||||
"请输入数量",
|
||||
!canEditFinishedSampleShipmentQuantity,
|
||||
"sampleQuantity",
|
||||
)}
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
<SkuColumnResizableFrame
|
||||
columnWidth={finishedSampleShipmentColumnWidths.shipped}
|
||||
minWidth={
|
||||
FINISHED_SAMPLE_SHIPMENT_COLUMN_DEFAULT_WIDTHS.shipped
|
||||
}
|
||||
onColumnResize={(width) =>
|
||||
handleFinishedSampleShipmentColumnResize(
|
||||
"shipped",
|
||||
width,
|
||||
)
|
||||
}
|
||||
>
|
||||
<InlineSelect
|
||||
ariaLabel="成品寄样是否寄出"
|
||||
dataTestId={`finished-sample-shipment-shipped-${row.skuId}`}
|
||||
value={row.shipped}
|
||||
options={FINISHED_SAMPLE_SHIPMENT_SHIPPED_OPTIONS}
|
||||
placeholder="请选择"
|
||||
includeEmptyOption={false}
|
||||
readOnly={!canEditFinishedSampleShipmentDecision}
|
||||
showIndicatorWhenReadOnly
|
||||
onChange={(value) =>
|
||||
updateFinishedSampleShipmentRow(
|
||||
row.skuId,
|
||||
"shipped",
|
||||
value,
|
||||
)
|
||||
}
|
||||
buttonClassName="h-8 w-full min-w-0 rounded border border-apple-separator bg-apple-bg-secondary px-2 text-xs text-apple-label-primary outline-none disabled:cursor-not-allowed disabled:bg-apple-bg-primary disabled:text-apple-label-secondary"
|
||||
/>
|
||||
</SkuColumnResizableFrame>
|
||||
</td>
|
||||
<td className="px-2 py-2">
|
||||
{renderShipmentInput(
|
||||
row,
|
||||
"trackingNumber",
|
||||
"请输入快递单号",
|
||||
!canEditFinishedSampleShipmentTrackingNumber,
|
||||
"trackingNumber",
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<FinishedSampleShipmentWorkspace
|
||||
allRows={productFinishedSampleShipmentRows}
|
||||
displayedRows={displayedFinishedSampleShipmentRows}
|
||||
inheritedSkuBatchTabs={renderInheritedSkuBatchTabs()}
|
||||
columnWidths={finishedSampleShipmentColumnWidths}
|
||||
canEditQuantity={canEditFinishedSampleShipmentQuantity}
|
||||
canEditDecision={canEditFinishedSampleShipmentDecision}
|
||||
canEditTrackingNumber={canEditFinishedSampleShipmentTrackingNumber}
|
||||
onColumnResize={handleFinishedSampleShipmentColumnResize}
|
||||
onUpdateRow={updateFinishedSampleShipmentRow}
|
||||
onPreviewImage={(src, alt) =>
|
||||
setSkuImagePreview({
|
||||
kind: "image",
|
||||
src,
|
||||
alt,
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user