refactor(intake): split primary intake domains
This commit is contained in:
parent
64cd9d67a5
commit
aa2ce7910b
@ -1,7 +1,7 @@
|
||||
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import AccessoryLibraryPanel from '@/app/intake/AccessoryLibraryPanel'
|
||||
import PackagingMaterialLibraryPanel from '@/app/intake/PackagingMaterialLibraryPanel'
|
||||
import AccessoryLibraryPanel from '@/app/intake/bom-library/AccessoryLibraryPanel'
|
||||
import PackagingMaterialLibraryPanel from '@/app/intake/bom-library/PackagingMaterialLibraryPanel'
|
||||
|
||||
const LEGACY_PACKAGING_MATERIAL_LIBRARY_STORAGE_KEY =
|
||||
'formal-intake-packaging-material-library-items'
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import EdgeBandingLibraryPanel from '@/app/intake/EdgeBandingLibraryPanel'
|
||||
import EdgeBandingLibraryPanel from '@/app/intake/bom-library/EdgeBandingLibraryPanel'
|
||||
import { createEdgeBandingLibraryItem } from '@/lib/edge-banding-library'
|
||||
|
||||
const LEGACY_EDGE_BANDING_LIBRARY_STORAGE_KEY =
|
||||
|
||||
@ -820,6 +820,7 @@ describe('IntakeClient', () => {
|
||||
'true',
|
||||
)
|
||||
} finally {
|
||||
jest.runOnlyPendingTimers()
|
||||
jest.useRealTimers()
|
||||
}
|
||||
})
|
||||
@ -1961,10 +1962,25 @@ describe('IntakeClient', () => {
|
||||
new File(['reference-image'], 'cabinet.png', { type: 'image/png' }),
|
||||
)
|
||||
|
||||
await waitFor(
|
||||
() =>
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'/api/intake/reference-image-estimate',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
}),
|
||||
),
|
||||
{ timeout: 5000 },
|
||||
)
|
||||
|
||||
expect(screen.getByRole('heading', { name: '样包模板明细' })).toBeInTheDocument()
|
||||
expect(screen.getByText('分类')).toBeInTheDocument()
|
||||
expect(screen.getByText('封边米数')).toBeInTheDocument()
|
||||
expect(await screen.findByText('图片识别:柜体侧板')).toBeInTheDocument()
|
||||
expect(
|
||||
await screen.findByText('图片识别:柜体侧板', undefined, {
|
||||
timeout: 5000,
|
||||
}),
|
||||
).toBeInTheDocument()
|
||||
expect(screen.getByText('图片识别:层板/顶底板')).toBeInTheDocument()
|
||||
expect(screen.getByText('图片识别:前后拉板')).toBeInTheDocument()
|
||||
expect(screen.getByText('图片识别:三合板背板')).toBeInTheDocument()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,202 @@
|
||||
import { Layers3, Package, Palette } from "lucide-react";
|
||||
import MaterialLibraryClient from "@/app/asset-center/material-library/MaterialLibraryClient";
|
||||
import AccessoryLibraryPanel from "./AccessoryLibraryPanel";
|
||||
import EdgeBandingLibraryPanel from "./EdgeBandingLibraryPanel";
|
||||
import PackagingMaterialLibraryPanel from "./PackagingMaterialLibraryPanel";
|
||||
import SteelFrameLibraryPanel from "./SteelFrameLibraryPanel";
|
||||
import { isIntakeNonIntegratedDesignDepartmentUser } from "@/lib/non-integrated-permissions";
|
||||
import type { MaterialCategoryDTO, MaterialDTO, SubstrateDictionaryBundleDTO, SubstrateDTO } from "@/server/services";
|
||||
|
||||
type IntakeDomainUser = {
|
||||
role: string;
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
businessRoles?: string[];
|
||||
avatar: string | null;
|
||||
department: { id: string; name: string; fullPath?: string } | null;
|
||||
departmentPaths?: string[];
|
||||
};
|
||||
|
||||
export type BomLibraryKey =
|
||||
| "materialLibrary"
|
||||
| "finishLibrary"
|
||||
| "edgeBandingLibrary"
|
||||
| "steelFrameLibrary"
|
||||
| "packagingLibrary"
|
||||
| "packagingMaterialLibrary";
|
||||
|
||||
export const BOM_LIBRARY_OPTIONS: {
|
||||
key: BomLibraryKey;
|
||||
label: string;
|
||||
description: string;
|
||||
helper: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "materialLibrary",
|
||||
label: "板材资料库",
|
||||
description:
|
||||
"只展示板材基材,方便在产品资料 BOM 下维护板材本体资料。",
|
||||
helper:
|
||||
"数据仍复用资产中心基础资料库,系列和饰面花色入口在这里不显示。",
|
||||
},
|
||||
{
|
||||
key: "finishLibrary",
|
||||
label: "花色资料库",
|
||||
description:
|
||||
"只展示饰面花色,方便在产品资料 BOM 下维护花色、贴图和参数。",
|
||||
helper:
|
||||
"数据仍复用资产中心基础资料库,板材基材入口在这里不显示。",
|
||||
},
|
||||
{
|
||||
key: "edgeBandingLibrary",
|
||||
label: "封边资料库",
|
||||
description:
|
||||
"按板材厚度维护封边条,细节资料里的封边自动项会按对应厚度筛选并带出单价。",
|
||||
helper:
|
||||
"维护规格名称、规格、单位、单价和适配板材厚度;封边行仍可在细节资料里手动改单价。",
|
||||
},
|
||||
{
|
||||
key: "steelFrameLibrary",
|
||||
label: "钢架资料库",
|
||||
description:
|
||||
"不再预置系统钢架规格,只保留每吨钢价与人工新建规格,系统会自动重算重量、支数和每米单价。",
|
||||
helper:
|
||||
"当前按名称、长、宽、壁厚录入,保存后的规格会直接参与钢架 BOM 匹配,并随每吨钢价联动刷新。",
|
||||
},
|
||||
{
|
||||
key: "packagingLibrary",
|
||||
label: "配件资料库",
|
||||
description:
|
||||
"产品资料下独立维护的配件资料区,按新的业务口径重新配置,不复用原包材资料逻辑。",
|
||||
helper: "适合维护配件名称、配件编码、分类规则和后续要补充的独立资料。",
|
||||
},
|
||||
{
|
||||
key: "packagingMaterialLibrary",
|
||||
label: "包材资料库",
|
||||
description:
|
||||
"产品资料下独立维护的包材资料区,沿用和配件资料库相同的字母分组逻辑,但单独保存数据。",
|
||||
helper:
|
||||
"适合维护纸箱、泡沫、护角等包材名称、编码、图片和价格,不会和配件资料串在一起。",
|
||||
},
|
||||
];
|
||||
|
||||
export function getBomLibraryLabel(library: BomLibraryKey) {
|
||||
return (
|
||||
BOM_LIBRARY_OPTIONS.find((option) => option.key === library)?.label ??
|
||||
"BOM资料库"
|
||||
);
|
||||
}
|
||||
|
||||
export function BomDetail({
|
||||
user,
|
||||
canEditLibraries,
|
||||
activeBomLibrary,
|
||||
materialLibrarySubstrates,
|
||||
materialLibraryFinishes,
|
||||
materialLibraryCategories,
|
||||
materialLibraryDictionaries,
|
||||
onMaterialLibraryFinishesChange,
|
||||
}: {
|
||||
user: IntakeDomainUser;
|
||||
canEditLibraries?: boolean;
|
||||
activeBomLibrary: BomLibraryKey;
|
||||
materialLibrarySubstrates: SubstrateDTO[];
|
||||
materialLibraryFinishes: MaterialDTO[];
|
||||
materialLibraryCategories: MaterialCategoryDTO[];
|
||||
materialLibraryDictionaries: SubstrateDictionaryBundleDTO;
|
||||
onMaterialLibraryFinishesChange?: (finishes: MaterialDTO[]) => void;
|
||||
}) {
|
||||
const canEditBomLibraries =
|
||||
canEditLibraries ??
|
||||
(user.role === "SUPER_ADMIN" ||
|
||||
user.role === "ADMIN" ||
|
||||
isIntakeNonIntegratedDesignDepartmentUser(user));
|
||||
|
||||
if (activeBomLibrary === "materialLibrary" || activeBomLibrary === "finishLibrary") {
|
||||
const visibleTab = activeBomLibrary === "materialLibrary" ? "substrate" : "finish";
|
||||
return (
|
||||
<div className="flex h-full min-h-0 flex-col overflow-hidden rounded-apple-xl border border-apple-separator bg-apple-bg-primary shadow-apple-xs">
|
||||
<MaterialLibraryClient
|
||||
key={activeBomLibrary}
|
||||
embedded
|
||||
canEditOverride={canEditBomLibraries}
|
||||
initialActiveTab={visibleTab}
|
||||
visibleTabs={[visibleTab]}
|
||||
initialSubstrates={materialLibrarySubstrates}
|
||||
initialFinishes={materialLibraryFinishes}
|
||||
initialCategories={materialLibraryCategories}
|
||||
initialDictionaries={materialLibraryDictionaries}
|
||||
onFinishesChange={onMaterialLibraryFinishesChange}
|
||||
user={user}
|
||||
metrics={[
|
||||
...(visibleTab === "substrate"
|
||||
? [
|
||||
{
|
||||
label: "板材基材",
|
||||
value: materialLibrarySubstrates.length,
|
||||
icon: <Package className="h-4 w-4" />,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
label: "饰面花色",
|
||||
value: materialLibraryFinishes.length,
|
||||
icon: <Palette className="h-4 w-4" />,
|
||||
},
|
||||
{
|
||||
label: "花色分类",
|
||||
value: materialLibraryCategories.length,
|
||||
icon: <Layers3 className="h-4 w-4" />,
|
||||
},
|
||||
]),
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (activeBomLibrary === "steelFrameLibrary") {
|
||||
return (
|
||||
<div className="flex h-full flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary p-4 shadow-apple-xs">
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<SteelFrameLibraryPanel canEditItems={canEditBomLibraries} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (activeBomLibrary === "edgeBandingLibrary") {
|
||||
return (
|
||||
<div className="flex h-full flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary p-4 shadow-apple-xs">
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<EdgeBandingLibraryPanel canEditItems={canEditBomLibraries} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (activeBomLibrary === "packagingMaterialLibrary") {
|
||||
return (
|
||||
<div className="flex h-full flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary p-4 shadow-apple-xs">
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<PackagingMaterialLibraryPanel canEditItems={canEditBomLibraries} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary p-4 shadow-apple-xs">
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<AccessoryLibraryPanel
|
||||
canEditItems={canEditBomLibraries}
|
||||
canDeleteItems={
|
||||
canEditBomLibraries &&
|
||||
(user.role === "SUPER_ADMIN" || user.role === "ADMIN")
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
export function SpuLabel() {
|
||||
return (
|
||||
<span translate="no" className="notranslate">
|
||||
SPU
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -46,7 +46,7 @@ import type { MaterialDTO } from "@/server/services";
|
||||
import {
|
||||
clearSpuRuleLibraryRuntimeCache,
|
||||
writeSpuRuleLibraryRules,
|
||||
} from "../spuRuleLibraryLogic";
|
||||
} from "../product-development/spuRuleLibraryLogic";
|
||||
import { parseZipFile } from "@/lib/zip-parser";
|
||||
import { extractPreviewModelFromZip } from "../../../lib/model-preview-zip";
|
||||
import {
|
||||
|
||||
@ -245,12 +245,12 @@ import type {
|
||||
AssetVariantDTO,
|
||||
MaterialDTO,
|
||||
} from "@/server/services";
|
||||
import RawMaterialLibraryPanel from "@/app/intake/RawMaterialLibraryPanel";
|
||||
import RawMaterialLibraryPanel from "@/app/intake/raw-material-library/RawMaterialLibraryPanel";
|
||||
import {
|
||||
SPU_RULE_LIBRARY_UPDATED_EVENT,
|
||||
getEstimatedSpuAssignment,
|
||||
syncSpuRuleLibraryRulesFromServer,
|
||||
} from "../spuRuleLibraryLogic";
|
||||
} from "../product-development/spuRuleLibraryLogic";
|
||||
import {
|
||||
readPreSkuPackageComponentDetails,
|
||||
type SeriesDraftSkuFields,
|
||||
@ -9078,7 +9078,7 @@ export default function NonIntegratedDetailClient({
|
||||
}
|
||||
|
||||
let isMounted = true;
|
||||
void import("@/app/intake/IntakeClient").then((module) => {
|
||||
void import("@/app/intake/product-patent/ProductPatentDomain").then((module) => {
|
||||
if (!isMounted) return;
|
||||
setLinkEntryProductPatentDashboard(
|
||||
() => module.ProductPatentDashboard,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,46 @@
|
||||
import RawMaterialLibraryPanel, { type RawMaterialLibraryKey } from "./RawMaterialLibraryPanel";
|
||||
|
||||
export type { RawMaterialLibraryKey };
|
||||
|
||||
export const RAW_MATERIAL_LIBRARY_OPTIONS: {
|
||||
key: RawMaterialLibraryKey;
|
||||
label: string;
|
||||
description: string;
|
||||
}[] = [
|
||||
{
|
||||
key: "processConfig",
|
||||
label: "材质工艺配置",
|
||||
description: "表格类信息和工艺规则占位",
|
||||
},
|
||||
{
|
||||
key: "detailArchive",
|
||||
label: "材质详情档案",
|
||||
description: "材质百科式详情页占位",
|
||||
},
|
||||
];
|
||||
|
||||
export function getRawMaterialLibraryLabel(library: RawMaterialLibraryKey) {
|
||||
return (
|
||||
RAW_MATERIAL_LIBRARY_OPTIONS.find((option) => option.key === library)
|
||||
?.label ?? "原材料资料库"
|
||||
);
|
||||
}
|
||||
|
||||
export function RawMaterialLibraryDetail({
|
||||
activeRawMaterialLibrary,
|
||||
selectedMaterialName,
|
||||
}: {
|
||||
activeRawMaterialLibrary: RawMaterialLibraryKey;
|
||||
selectedMaterialName?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex h-full flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary p-4 shadow-apple-xs">
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<RawMaterialLibraryPanel
|
||||
activeLibrary={activeRawMaterialLibrary}
|
||||
selectedMaterialName={selectedMaterialName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
import { ReferenceImageCostEstimator } from "../raw-material-library/RawMaterialLibraryPanel";
|
||||
import type { SubstrateDTO } from "@/server/services";
|
||||
|
||||
|
||||
export function ReferenceEstimatorDetail({
|
||||
materialLibrarySubstrates,
|
||||
}: {
|
||||
materialLibrarySubstrates: SubstrateDTO[];
|
||||
}) {
|
||||
return (
|
||||
<div className="flex h-full flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary p-4 shadow-apple-xs">
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<ReferenceImageCostEstimator
|
||||
materialLibrarySubstrates={materialLibrarySubstrates}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -8,7 +8,7 @@ import type {
|
||||
NonIntegratedSampleMeasurementRow,
|
||||
NonIntegratedSkuItem,
|
||||
} from '@/app/intake/non-integrated/nonIntegratedStorage'
|
||||
import { SPU_RULE_LIBRARY_SEED_RULES } from '@/app/intake/spuRuleLibrarySeed'
|
||||
import { SPU_RULE_LIBRARY_SEED_RULES } from '@/app/intake/product-development/spuRuleLibrarySeed'
|
||||
|
||||
type JushuitanCredentials = {
|
||||
appKey: string
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user