refactor(intake): extract product data workspace
This commit is contained in:
parent
778d03c903
commit
ffd53ec713
@ -46,6 +46,7 @@ import {
|
||||
type BasicFieldType,
|
||||
} from "./basicInfoConfig";
|
||||
import { ProjectReviewWorkspace } from "./ProjectReviewWorkspace";
|
||||
import { ProductDataWorkspace } from "./ProductDataWorkspace";
|
||||
import {
|
||||
BomBoardMaterialField,
|
||||
BomEdgeBandingField,
|
||||
@ -20288,71 +20289,6 @@ function renderFactoryQualityWorkspace() {
|
||||
);
|
||||
}
|
||||
|
||||
function renderProductDataPreviewContent() {
|
||||
if (!effectiveSelectedWorkspaceFile) {
|
||||
return (
|
||||
<WorkspacePreviewEmptyState
|
||||
title={workspacePreviewTitle}
|
||||
description={workspacePreviewDescription}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
effectiveSelectedWorkspacePreviewType === "image" ||
|
||||
effectiveSelectedWorkspacePreviewType === "pdf"
|
||||
) {
|
||||
return renderDocumentWorkspacePreviewContent();
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="product-data-detail-preview"
|
||||
className="flex h-full w-full flex-col gap-3 rounded-apple-xl border border-dashed border-apple-separator bg-white p-4"
|
||||
>
|
||||
<div>
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
资料明细
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-apple-label-secondary">
|
||||
当前分类只对 PDF
|
||||
和图片做在线预览,其它文件保留明细展开,模型师按明细查看和下载即可。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
<div className="rounded-apple-lg border border-apple-separator bg-apple-bg-secondary/20 px-3 py-2.5">
|
||||
<p className="text-[11px] text-apple-label-secondary">资料分类</p>
|
||||
<p className="mt-1 text-sm font-apple-medium text-apple-label-primary">
|
||||
{activeProductDataGroupEntry?.label ?? "产品资料"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-apple-lg border border-apple-separator bg-apple-bg-secondary/20 px-3 py-2.5">
|
||||
<p className="text-[11px] text-apple-label-secondary">文件类型</p>
|
||||
<p className="mt-1 text-sm font-apple-medium text-apple-label-primary">
|
||||
{getUploadFileTypeLabel(effectiveSelectedWorkspaceFile)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-apple-lg border border-apple-separator bg-apple-bg-secondary/20 px-3 py-2.5 md:col-span-2">
|
||||
<p className="text-[11px] text-apple-label-secondary">文件名称</p>
|
||||
<p className="mt-1 break-all text-sm font-apple-medium text-apple-label-primary">
|
||||
{effectiveSelectedWorkspaceFile.name}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-apple-lg border border-apple-separator bg-[#f8fafc] px-4 py-3">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
当前文件不做在线预览
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-apple-label-secondary">
|
||||
DWG、Excel、PPT、压缩包等资料会保留在中间明细栏,右侧只展示关键信息。需要查看完整内容时,直接点击上方“下载”即可。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function renderOpeningReferenceWorkspace() {
|
||||
const topFields: {
|
||||
key: OpeningReferenceFieldKey;
|
||||
@ -21188,140 +21124,21 @@ function renderFactoryQualityWorkspace() {
|
||||
}
|
||||
function renderProductDataWorkspace() {
|
||||
return (
|
||||
<div
|
||||
data-testid="product-data-workspace"
|
||||
className="grid min-h-0 flex-1 gap-3 xl:grid-cols-[260px_320px_minmax(0,1fr)]"
|
||||
>
|
||||
<div className="flex min-h-0 flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary">
|
||||
<div className="border-b border-apple-separator px-3 py-3">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
资料分类
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-apple-label-secondary">
|
||||
左侧按资料类型分栏;上传时会自动落到当前分类。
|
||||
</p>
|
||||
</div>
|
||||
<div className="min-h-0 flex-1 space-y-2 overflow-y-auto p-3 pr-2">
|
||||
{productDataGroupEntries.map((group) => {
|
||||
const isActive = activeProductDataGroup === group.key;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={group.key}
|
||||
type="button"
|
||||
data-testid={`product-data-group-${group.key}`}
|
||||
onClick={() => setActiveProductDataGroup(group.key)}
|
||||
className={`w-full rounded-apple-xl border px-3 py-3 text-left transition ${
|
||||
isActive
|
||||
? "border-apple-blue bg-apple-blue/10"
|
||||
: "border-apple-separator bg-apple-bg-secondary/20 hover:bg-apple-bg-secondary/40"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
{group.label}
|
||||
</p>
|
||||
<span
|
||||
className={`rounded-full px-2 py-0.5 text-[11px] ${
|
||||
isActive
|
||||
? "bg-apple-blue text-white"
|
||||
: "bg-apple-bg-primary text-apple-label-secondary"
|
||||
}`}
|
||||
>
|
||||
{group.files.length} 份
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-2 text-xs leading-5 text-apple-label-secondary">
|
||||
{group.description}
|
||||
</p>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-0 min-w-0 flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary">
|
||||
<div className="border-b border-apple-separator px-3 py-3">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
资料明细
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-apple-label-secondary">
|
||||
当前分类:{activeProductDataGroupEntry?.label ?? "产品资料"} · 共{" "}
|
||||
{activeProductDataGroupFiles.length} 份
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{activeProductDataGroupFiles.length === 0 ? (
|
||||
<div className="flex min-h-[240px] flex-1 flex-col items-center justify-center px-5 text-center">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
当前还没有{activeProductDataGroupEntry?.label ?? "产品资料"}
|
||||
</p>
|
||||
<p className="mt-2 text-xs leading-5 text-apple-label-secondary">
|
||||
点击上方“批量上传”后,这里会显示当前分类下的文件明细。
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="min-h-0 flex-1 space-y-2 overflow-y-auto p-3 pr-2">
|
||||
{activeProductDataGroupFiles.map((file) => {
|
||||
const isActive = effectiveSelectedWorkspaceFile?.id === file.id;
|
||||
const previewType = getUploadFilePreviewType(file);
|
||||
const supportsInlinePreview =
|
||||
previewType === "image" || previewType === "pdf";
|
||||
|
||||
return (
|
||||
<button
|
||||
key={file.id}
|
||||
type="button"
|
||||
data-testid={`product-data-file-${file.id}`}
|
||||
onClick={() => handleSelectWorkspaceFile(file.id)}
|
||||
className={`w-full rounded-apple-lg border px-3 py-3 text-left transition ${
|
||||
isActive
|
||||
? "border-apple-blue bg-apple-blue/10"
|
||||
: "border-apple-separator bg-apple-bg-secondary/20 hover:bg-apple-bg-secondary/40"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-sm font-apple-medium text-apple-label-primary">
|
||||
{file.name}
|
||||
</p>
|
||||
<p className="mt-1 text-[11px] text-apple-label-secondary">
|
||||
{supportsInlinePreview
|
||||
? "右侧可直接预览 PDF / 图片"
|
||||
: "右侧展开资料明细,可直接下载"}
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
className={`rounded-full px-2 py-0.5 text-[11px] ${
|
||||
isActive
|
||||
? "bg-apple-blue text-white"
|
||||
: "bg-apple-bg-primary text-apple-label-secondary"
|
||||
}`}
|
||||
>
|
||||
{getUploadFileTypeLabel(file)}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-0 min-w-0 flex-1 flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-secondary/20">
|
||||
<div className="border-b border-apple-separator px-4 py-2.5">
|
||||
<p className="truncate text-sm font-apple-medium text-apple-label-primary">
|
||||
{workspacePreviewTitle}
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-apple-label-secondary">
|
||||
{workspacePreviewDescription}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex min-h-0 flex-1 items-center justify-center p-3">
|
||||
{renderProductDataPreviewContent()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ProductDataWorkspace
|
||||
productDataGroupEntries={productDataGroupEntries}
|
||||
activeProductDataGroup={activeProductDataGroup}
|
||||
activeProductDataGroupLabel={
|
||||
activeProductDataGroupEntry?.label ?? "产品资料"
|
||||
}
|
||||
activeProductDataGroupFiles={activeProductDataGroupFiles}
|
||||
selectedWorkspaceFile={effectiveSelectedWorkspaceFile}
|
||||
selectedWorkspacePreviewType={effectiveSelectedWorkspacePreviewType}
|
||||
workspacePreviewTitle={workspacePreviewTitle}
|
||||
workspacePreviewDescription={workspacePreviewDescription}
|
||||
onActiveProductDataGroupChange={setActiveProductDataGroup}
|
||||
onSelectWorkspaceFile={handleSelectWorkspaceFile}
|
||||
renderDocumentPreviewContent={renderDocumentWorkspacePreviewContent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,269 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import type { ProductDataGroup } from "./documentWorkspaceHelpers";
|
||||
import type { NonIntegratedUploadFile } from "./nonIntegratedStorage";
|
||||
import {
|
||||
getUploadFilePreviewType,
|
||||
getUploadFileTypeLabel,
|
||||
type UploadFilePreviewType,
|
||||
} from "./uploadFilePreview";
|
||||
import { WorkspacePreviewEmptyState } from "./components/WorkspaceShell";
|
||||
|
||||
type ProductDataGroupEntry = {
|
||||
key: ProductDataGroup;
|
||||
label: string;
|
||||
description: string;
|
||||
files: NonIntegratedUploadFile[];
|
||||
};
|
||||
|
||||
type ProductDataWorkspaceProps = {
|
||||
productDataGroupEntries: ProductDataGroupEntry[];
|
||||
activeProductDataGroup: ProductDataGroup;
|
||||
activeProductDataGroupLabel: string;
|
||||
activeProductDataGroupFiles: NonIntegratedUploadFile[];
|
||||
selectedWorkspaceFile: NonIntegratedUploadFile | null;
|
||||
selectedWorkspacePreviewType: UploadFilePreviewType;
|
||||
workspacePreviewTitle: string;
|
||||
workspacePreviewDescription: string;
|
||||
onActiveProductDataGroupChange: (group: ProductDataGroup) => void;
|
||||
onSelectWorkspaceFile: (fileId: string) => void;
|
||||
renderDocumentPreviewContent: () => ReactNode;
|
||||
};
|
||||
|
||||
export function ProductDataWorkspace({
|
||||
productDataGroupEntries,
|
||||
activeProductDataGroup,
|
||||
activeProductDataGroupLabel,
|
||||
activeProductDataGroupFiles,
|
||||
selectedWorkspaceFile,
|
||||
selectedWorkspacePreviewType,
|
||||
workspacePreviewTitle,
|
||||
workspacePreviewDescription,
|
||||
onActiveProductDataGroupChange,
|
||||
onSelectWorkspaceFile,
|
||||
renderDocumentPreviewContent,
|
||||
}: ProductDataWorkspaceProps) {
|
||||
return (
|
||||
<div
|
||||
data-testid="product-data-workspace"
|
||||
className="grid min-h-0 flex-1 gap-3 xl:grid-cols-[260px_320px_minmax(0,1fr)]"
|
||||
>
|
||||
<div className="flex min-h-0 flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary">
|
||||
<div className="border-b border-apple-separator px-3 py-3">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
资料分类
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-apple-label-secondary">
|
||||
左侧按资料类型分栏;上传时会自动落到当前分类。
|
||||
</p>
|
||||
</div>
|
||||
<div className="min-h-0 flex-1 space-y-2 overflow-y-auto p-3 pr-2">
|
||||
{productDataGroupEntries.map((group) => {
|
||||
const isActive = activeProductDataGroup === group.key;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={group.key}
|
||||
type="button"
|
||||
data-testid={`product-data-group-${group.key}`}
|
||||
onClick={() => onActiveProductDataGroupChange(group.key)}
|
||||
className={`w-full rounded-apple-xl border px-3 py-3 text-left transition ${
|
||||
isActive
|
||||
? "border-apple-blue bg-apple-blue/10"
|
||||
: "border-apple-separator bg-apple-bg-secondary/20 hover:bg-apple-bg-secondary/40"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
{group.label}
|
||||
</p>
|
||||
<span
|
||||
className={`rounded-full px-2 py-0.5 text-[11px] ${
|
||||
isActive
|
||||
? "bg-apple-blue text-white"
|
||||
: "bg-apple-bg-primary text-apple-label-secondary"
|
||||
}`}
|
||||
>
|
||||
{group.files.length} 份
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-2 text-xs leading-5 text-apple-label-secondary">
|
||||
{group.description}
|
||||
</p>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-0 min-w-0 flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-primary">
|
||||
<div className="border-b border-apple-separator px-3 py-3">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
资料明细
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-apple-label-secondary">
|
||||
当前分类:{activeProductDataGroupLabel} · 共{" "}
|
||||
{activeProductDataGroupFiles.length} 份
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{activeProductDataGroupFiles.length === 0 ? (
|
||||
<div className="flex min-h-[240px] flex-1 flex-col items-center justify-center px-5 text-center">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
当前还没有{activeProductDataGroupLabel}
|
||||
</p>
|
||||
<p className="mt-2 text-xs leading-5 text-apple-label-secondary">
|
||||
点击上方“批量上传”后,这里会显示当前分类下的文件明细。
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="min-h-0 flex-1 space-y-2 overflow-y-auto p-3 pr-2">
|
||||
{activeProductDataGroupFiles.map((file) => {
|
||||
const isActive = selectedWorkspaceFile?.id === file.id;
|
||||
const previewType = getUploadFilePreviewType(file);
|
||||
const supportsInlinePreview =
|
||||
previewType === "image" || previewType === "pdf";
|
||||
|
||||
return (
|
||||
<button
|
||||
key={file.id}
|
||||
type="button"
|
||||
data-testid={`product-data-file-${file.id}`}
|
||||
onClick={() => onSelectWorkspaceFile(file.id)}
|
||||
className={`w-full rounded-apple-lg border px-3 py-3 text-left transition ${
|
||||
isActive
|
||||
? "border-apple-blue bg-apple-blue/10"
|
||||
: "border-apple-separator bg-apple-bg-secondary/20 hover:bg-apple-bg-secondary/40"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-sm font-apple-medium text-apple-label-primary">
|
||||
{file.name}
|
||||
</p>
|
||||
<p className="mt-1 text-[11px] text-apple-label-secondary">
|
||||
{supportsInlinePreview
|
||||
? "右侧可直接预览 PDF / 图片"
|
||||
: "右侧展开资料明细,可直接下载"}
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
className={`rounded-full px-2 py-0.5 text-[11px] ${
|
||||
isActive
|
||||
? "bg-apple-blue text-white"
|
||||
: "bg-apple-bg-primary text-apple-label-secondary"
|
||||
}`}
|
||||
>
|
||||
{getUploadFileTypeLabel(file)}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-0 min-w-0 flex-1 flex-col rounded-apple-xl border border-apple-separator bg-apple-bg-secondary/20">
|
||||
<div className="border-b border-apple-separator px-4 py-2.5">
|
||||
<p className="truncate text-sm font-apple-medium text-apple-label-primary">
|
||||
{workspacePreviewTitle}
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-apple-label-secondary">
|
||||
{workspacePreviewDescription}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex min-h-0 flex-1 items-center justify-center p-3">
|
||||
<ProductDataPreviewContent
|
||||
selectedWorkspaceFile={selectedWorkspaceFile}
|
||||
selectedWorkspacePreviewType={selectedWorkspacePreviewType}
|
||||
workspacePreviewTitle={workspacePreviewTitle}
|
||||
workspacePreviewDescription={workspacePreviewDescription}
|
||||
activeProductDataGroupLabel={activeProductDataGroupLabel}
|
||||
renderDocumentPreviewContent={renderDocumentPreviewContent}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ProductDataPreviewContent({
|
||||
selectedWorkspaceFile,
|
||||
selectedWorkspacePreviewType,
|
||||
workspacePreviewTitle,
|
||||
workspacePreviewDescription,
|
||||
activeProductDataGroupLabel,
|
||||
renderDocumentPreviewContent,
|
||||
}: {
|
||||
selectedWorkspaceFile: NonIntegratedUploadFile | null;
|
||||
selectedWorkspacePreviewType: UploadFilePreviewType;
|
||||
workspacePreviewTitle: string;
|
||||
workspacePreviewDescription: string;
|
||||
activeProductDataGroupLabel: string;
|
||||
renderDocumentPreviewContent: () => ReactNode;
|
||||
}) {
|
||||
if (!selectedWorkspaceFile) {
|
||||
return (
|
||||
<WorkspacePreviewEmptyState
|
||||
title={workspacePreviewTitle}
|
||||
description={workspacePreviewDescription}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
selectedWorkspacePreviewType === "image" ||
|
||||
selectedWorkspacePreviewType === "pdf"
|
||||
) {
|
||||
return <>{renderDocumentPreviewContent()}</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="product-data-detail-preview"
|
||||
className="flex h-full w-full flex-col gap-3 rounded-apple-xl border border-dashed border-apple-separator bg-white p-4"
|
||||
>
|
||||
<div>
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
资料明细
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-apple-label-secondary">
|
||||
当前分类只对 PDF
|
||||
和图片做在线预览,其它文件保留明细展开,模型师按明细查看和下载即可。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
<div className="rounded-apple-lg border border-apple-separator bg-apple-bg-secondary/20 px-3 py-2.5">
|
||||
<p className="text-[11px] text-apple-label-secondary">资料分类</p>
|
||||
<p className="mt-1 text-sm font-apple-medium text-apple-label-primary">
|
||||
{activeProductDataGroupLabel}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-apple-lg border border-apple-separator bg-apple-bg-secondary/20 px-3 py-2.5">
|
||||
<p className="text-[11px] text-apple-label-secondary">文件类型</p>
|
||||
<p className="mt-1 text-sm font-apple-medium text-apple-label-primary">
|
||||
{getUploadFileTypeLabel(selectedWorkspaceFile)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-apple-lg border border-apple-separator bg-apple-bg-secondary/20 px-3 py-2.5 md:col-span-2">
|
||||
<p className="text-[11px] text-apple-label-secondary">文件名称</p>
|
||||
<p className="mt-1 break-all text-sm font-apple-medium text-apple-label-primary">
|
||||
{selectedWorkspaceFile.name}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-apple-lg border border-apple-separator bg-[#f8fafc] px-4 py-3">
|
||||
<p className="text-sm font-apple-medium text-apple-label-primary">
|
||||
当前文件不做在线预览
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-5 text-apple-label-secondary">
|
||||
DWG、Excel、PPT、压缩包等资料会保留在中间明细栏,右侧只展示关键信息。需要查看完整内容时,直接点击上方“下载”即可。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user