fix:sample/plate 之前的开发

This commit is contained in:
彭帅
2026-05-28 11:56:17 +08:00
parent fc36bc83e3
commit 8b65de36b8
367 changed files with 57752 additions and 947 deletions

View File

@@ -0,0 +1,187 @@
"use client";
import { useCallback, useMemo, useState } from "react";
import { GitFork } from "lucide-react";
import { BrapiEntityPage, type BrapiFormField } from "@/components/brapi/BrapiEntityPage";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
CROSS_TYPE_OPTIONS,
PLANNED_CROSS_STATUS_OPTIONS,
crossTypeLabel,
plannedStatusLabel,
} from "../constants";
import {
createCrossRow,
createPlannedCrossRow,
normalizeCrossForm,
normalizePlannedCrossForm,
updateCrossRow,
updatePlannedCrossRow,
} from "../api";
import { useCrossPedigree } from "../CrossPedigreeContext";
import { NONE_SELECT_VALUE } from "../types";
export function CrossEntityTab() {
const { snapshot, refresh } = useCrossPedigree();
const [subTab, setSubTab] = useState("planned");
const crossingProjectOptions = snapshot?.crossingProjectOptions ?? [];
const plannedCrossOptions = snapshot?.plannedCrossOptions ?? [];
const loadPlannedRows = useCallback(async () => {
const data = await refresh(false);
return data.plannedCrosses as unknown as Record<string, unknown>[];
}, [refresh]);
const loadActualRows = useCallback(async () => {
const data = await refresh(false);
return data.actualCrosses as unknown as Record<string, unknown>[];
}, [refresh]);
const fetchPlannedRecord = useCallback(async (id: string) => {
const data = await refresh(false);
const row = data.plannedCrosses.find((item) => item.id === id);
if (!row) throw new Error("计划杂交不存在");
return normalizePlannedCrossForm(row);
}, [refresh]);
const fetchActualRecord = useCallback(async (id: string) => {
const data = await refresh(false);
const row = data.actualCrosses.find((item) => item.id === id);
if (!row) throw new Error("实际杂交不存在");
return normalizeCrossForm(row);
}, [refresh]);
const plannedFields = useMemo<BrapiFormField[]>(() => [
{
key: "name",
label: "计划杂交名称",
type: "text",
required: true,
placeholder: "如 B73 x Mo17 / Cross-2026-001",
},
{
key: "crossing_project_id",
label: "杂交项目",
type: "select",
required: true,
options: [{ value: NONE_SELECT_VALUE, label: "请选择杂交项目" }, ...crossingProjectOptions],
},
{
key: "cross_type",
label: "杂交类型",
type: "select",
options: [{ value: NONE_SELECT_VALUE, label: "不指定类型" }, ...CROSS_TYPE_OPTIONS],
},
{
key: "status",
label: "状态",
type: "select",
options: PLANNED_CROSS_STATUS_OPTIONS,
},
], [crossingProjectOptions]);
const actualFields = useMemo<BrapiFormField[]>(() => [
{
key: "name",
label: "实际杂交名称",
type: "text",
required: true,
placeholder: "如 B73 x Mo17 实际杂交",
},
{
key: "crossing_project_id",
label: "杂交项目",
type: "select",
required: true,
options: [{ value: NONE_SELECT_VALUE, label: "请选择杂交项目" }, ...crossingProjectOptions],
},
{
key: "cross_type",
label: "杂交类型",
type: "select",
options: [{ value: NONE_SELECT_VALUE, label: "不指定类型" }, ...CROSS_TYPE_OPTIONS],
},
{
key: "planned_cross_id",
label: "来源计划杂交",
type: "select",
options: [{ value: NONE_SELECT_VALUE, label: "不关联计划杂交" }, ...plannedCrossOptions],
},
], [crossingProjectOptions, plannedCrossOptions]);
return (
<Tabs value={subTab} onValueChange={setSubTab} className="flex min-h-full flex-col gap-4">
<TabsList className="w-full justify-start overflow-x-auto rounded-lg border bg-white p-1 dark:border-slate-800 dark:bg-slate-950 sm:w-fit">
<TabsTrigger value="planned"> (planned=true)</TabsTrigger>
<TabsTrigger value="actual"> (planned=false)</TabsTrigger>
</TabsList>
{subTab === "planned" ? (
<TabsContent value="planned" className="mt-0 min-h-0 flex-1">
<BrapiEntityPage
icon={GitFork}
iconBg="bg-gradient-to-br from-emerald-500 to-green-600"
title="计划杂交"
description="cross_entity(planned=true)录入杂交计划亲本请在「杂交亲本」Tab 维护"
addLabel="新增计划杂交"
useEnhancedDialog
columns={[
{ key: "plannedCrossDbId", label: "Cross ID" },
{ key: "name", label: "名称" },
{ key: "crossing_project_name", label: "杂交项目" },
{ key: "cross_type", label: "类型", render: crossTypeLabel },
{ key: "status", label: "状态", render: plannedStatusLabel },
]}
fields={plannedFields}
data={[]}
stats={[
{
label: "/brapi/v2/plannedcrosses",
value: "BrAPI",
className: "bg-emerald-50 text-emerald-700 dark:bg-emerald-400/10 dark:text-emerald-200",
},
]}
loadData={loadPlannedRows}
fetchRecord={fetchPlannedRecord}
createRecord={(payload) => createPlannedCrossRow(payload) as unknown as Promise<Record<string, unknown>>}
updateRecord={(id, payload) => updatePlannedCrossRow(id, payload) as unknown as Promise<Record<string, unknown>>}
/>
</TabsContent>
) : null}
{subTab === "actual" ? (
<TabsContent value="actual" className="mt-0 min-h-0 flex-1">
<BrapiEntityPage
icon={GitFork}
iconBg="bg-gradient-to-br from-green-600 to-emerald-700"
title="实际杂交"
description="cross_entity(planned=false)完成实际杂交后可关联来源计划杂交亲本请在「杂交亲本」Tab 维护"
addLabel="新增实际杂交"
useEnhancedDialog
columns={[
{ key: "crossDbId", label: "Cross ID" },
{ key: "name", label: "名称" },
{ key: "crossing_project_name", label: "杂交项目" },
{ key: "plannedCrossName", label: "来源计划杂交" },
{ key: "cross_type", label: "类型", render: crossTypeLabel },
]}
fields={actualFields}
data={[]}
stats={[
{
label: "/brapi/v2/crosses",
value: "BrAPI",
className: "bg-green-50 text-green-700 dark:bg-green-400/10 dark:text-green-200",
},
]}
loadData={loadActualRows}
fetchRecord={fetchActualRecord}
createRecord={(payload) => createCrossRow(payload) as unknown as Promise<Record<string, unknown>>}
updateRecord={(id, payload) => updateCrossRow(id, payload) as unknown as Promise<Record<string, unknown>>}
/>
</TabsContent>
) : null}
</Tabs>
);
}