feat: localmpr viewer

This commit is contained in:
mozzie 2024-09-09 21:58:49 +08:00
parent 3077c78c76
commit 6df7442b9b
6 changed files with 210 additions and 184 deletions

View File

@ -8,4 +8,9 @@
- 换版本重新测量
pnpm config set virtual-store-dir-max-length 70
pnpm config set virtual-store-dir-max-length 70
## 待解决
- dicom导入后本地appData建立一个拷贝区域复制dicom原片满足二次导出防止原片的路径修改、移动硬盘被拔电源

View File

@ -72,6 +72,10 @@ function createWindow() {
python_process = spawn(path.join(process.env.VITE_PUBLIC!, "main.exe"));
}
} else {
if (platform !== "macos") {
python_process = spawn(path.join(process.env.VITE_PUBLIC!, "main.exe"));
}
win.loadFile(path.join(RENDERER_DIST, "index.html")).then(() => {
if (process.argv.length >= 2) {
const folderPath = process.argv[2];

View File

@ -7,6 +7,7 @@ import { useEffect } from "react";
import { Models } from "./pages/Models";
import { Tools } from "./pages/Tools";
import { Datasource } from "./pages/Datasource";
import { Viewer } from "./pages/Viewer";
function App() {
const theme = document.querySelector("html")!.getAttribute("theme") as
@ -33,6 +34,7 @@ function App() {
<Route path="datasource" element={<Datasource />} />
<Route path="tools" element={<Tools />} />
<Route path="setting" element={<Setting />} />
<Route path="viewer" element={<Viewer />} />
</Route>
</Routes>
</Router>

View File

@ -90,7 +90,7 @@ export const MenuBar = () => {
toast({
variant: "default",
title: "完成",
description: `本次操作共导入${structDicom.length}组序列数据,耗时:${(
description: `导入${structDicom.length}组序列数据,耗时:${(
scanDuration / 1000
).toFixed(2)} s`,
action: (

View File

@ -71,185 +71,6 @@ const columnsAlias: { [K in keyof Partial<Series> as string]: string } = {
AcquisitionDate: "采集日期",
};
export const columns: ColumnDef<Series>[] = [
{
id: "select",
header: ({ table }) => (
<Checkbox
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
),
enableSorting: false,
enableHiding: false,
},
{
id: "PatientName",
accessorKey: "PatientName",
header: columnsAlias["PatientName"],
cell: ({ row }) => (
<div className="capitalize">{row.getValue("PatientName")}</div>
),
},
{
id: "PatientAge",
accessorKey: "PatientAge",
header: columnsAlias["PatientAge"],
cell: ({ row }) => (
<div className="capitalize">{row.getValue("PatientAge")}</div>
),
},
{
id: "PatientSex",
accessorKey: "PatientSex",
header: columnsAlias["PatientSex"],
cell: ({ row }) => (
<div className="capitalize">{row.getValue("PatientSex")}</div>
),
},
{
id: "SeriesInstanceUID",
accessorKey: "SeriesInstanceUID",
header: columnsAlias["SeriesInstanceUID"],
cell: ({ row }) => (
<div className="capitalize">{row.getValue("SeriesInstanceUID")}</div>
),
},
{
id: "filePaths",
accessorKey: "filePaths",
header: columnsAlias["filePaths"],
cell: ({ row }) => (
<div className="capitalize">
{(row.getValue("filePaths") as string[]).length}
</div>
),
},
{
id: "AcquisitionDate",
accessorKey: "AcquisitionDate",
header: ({ column }) => {
return (
<div className="flex items-center">
{columnsAlias["AcquisitionDate"]}
<Button
variant="ghost"
className="h-7 w-7 ml-2"
size="icon"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
<ArrowUpDown className="h-3.5 w-3.5" />
</Button>
</div>
);
},
cell: ({ row }) =>
row.getValue("AcquisitionDate") && (
<div className="capitalize">
<span>{row.getValue("AcquisitionDate")}</span>
</div>
),
},
{
id: "createTime",
accessorKey: "createTime",
header: ({ column }) => {
return (
<div className="flex items-center">
{columnsAlias["createTime"]}
<Button
variant="ghost"
className="h-7 w-7 ml-2"
size="icon"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
<ArrowUpDown className="h-3.5 w-3.5" />
</Button>
</div>
);
},
cell: ({ row }) =>
row.getValue("createTime") && (
<div className="capitalize">
<span>{dayjs(row.getValue("createTime")).format("YYYYMMDD")}</span>
<Badge className="ml-2 text-xs font-normal">
{timeAgo(row.getValue("createTime"))}
</Badge>
</div>
),
},
{
id: "updateTime",
accessorKey: "updateTime",
header: ({ column }) => {
return (
<div className="flex items-center">
{columnsAlias["updateTime"]}
<Button
variant="ghost"
className="h-7 w-7 ml-2"
size="icon"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
<ArrowUpDown className="h-3.5 w-3.5" />
</Button>
</div>
);
},
cell: ({ row }) =>
row.getValue("updateTime") && (
<div className="capitalize">
<span>{dayjs(row.getValue("updateTime")).format("YYYYMMDD")}</span>
<Badge className="ml-2 text-xs font-normal">
{timeAgo(row.getValue("updateTime"))}
</Badge>
</div>
),
},
{
id: "actions",
header: "操作",
enableHiding: false,
cell: ({ row }) => {
const payment = row.original;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem
onClick={() => navigator.clipboard.writeText(payment.id)}
>
Copy payment ID
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>View customer</DropdownMenuItem>
<DropdownMenuItem>View payment details</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
},
];
interface SeriesTableProps {
data: Series[];
}
@ -265,6 +86,183 @@ export function SeriesTable(props: SeriesTableProps) {
const [rowSelection, setRowSelection] = useState({});
const navigate = useNavigate();
const columns: ColumnDef<Series>[] = [
{
id: "select",
header: ({ table }) => (
<Checkbox
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
),
enableSorting: false,
enableHiding: false,
},
{
id: "PatientName",
accessorKey: "PatientName",
header: columnsAlias["PatientName"],
cell: ({ row }) => (
<div className="capitalize">{row.getValue("PatientName")}</div>
),
},
{
id: "PatientAge",
accessorKey: "PatientAge",
header: columnsAlias["PatientAge"],
cell: ({ row }) => (
<div className="capitalize">{row.getValue("PatientAge")}</div>
),
},
{
id: "PatientSex",
accessorKey: "PatientSex",
header: columnsAlias["PatientSex"],
cell: ({ row }) => (
<div className="capitalize">{row.getValue("PatientSex")}</div>
),
},
{
id: "SeriesInstanceUID",
accessorKey: "SeriesInstanceUID",
header: columnsAlias["SeriesInstanceUID"],
cell: ({ row }) => (
<div className="capitalize">{row.getValue("SeriesInstanceUID")}</div>
),
},
{
id: "filePaths",
accessorKey: "filePaths",
header: columnsAlias["filePaths"],
cell: ({ row }) => (
<div className="capitalize">
{(row.getValue("filePaths") as string[]).length}
</div>
),
},
{
id: "AcquisitionDate",
accessorKey: "AcquisitionDate",
header: ({ column }) => {
return (
<div className="flex items-center">
{columnsAlias["AcquisitionDate"]}
<Button
variant="ghost"
className="h-7 w-7 ml-2"
size="icon"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
<ArrowUpDown className="h-3.5 w-3.5" />
</Button>
</div>
);
},
cell: ({ row }) =>
row.getValue("AcquisitionDate") && (
<div className="capitalize">
<span>{row.getValue("AcquisitionDate")}</span>
</div>
),
},
{
id: "createTime",
accessorKey: "createTime",
header: ({ column }) => {
return (
<div className="flex items-center">
{columnsAlias["createTime"]}
<Button
variant="ghost"
className="h-7 w-7 ml-2"
size="icon"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
<ArrowUpDown className="h-3.5 w-3.5" />
</Button>
</div>
);
},
cell: ({ row }) =>
row.getValue("createTime") && (
<div className="capitalize">
<span>{dayjs(row.getValue("createTime")).format("YYYYMMDD")}</span>
<Badge className="ml-2 text-xs font-normal">
{timeAgo(row.getValue("createTime"))}
</Badge>
</div>
),
},
{
id: "updateTime",
accessorKey: "updateTime",
header: ({ column }) => {
return (
<div className="flex items-center">
{columnsAlias["updateTime"]}
<Button
variant="ghost"
className="h-7 w-7 ml-2"
size="icon"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
<ArrowUpDown className="h-3.5 w-3.5" />
</Button>
</div>
);
},
cell: ({ row }) =>
row.getValue("updateTime") && (
<div className="capitalize">
<span>{dayjs(row.getValue("updateTime")).format("YYYYMMDD")}</span>
<Badge className="ml-2 text-xs font-normal">
{timeAgo(row.getValue("updateTime"))}
</Badge>
</div>
),
},
{
id: "actions",
header: "操作",
enableHiding: false,
cell: ({ row }) => {
const dicom = row.original;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel></DropdownMenuLabel>
<DropdownMenuItem
onClick={() => handle2Viewer(dicom)}
></DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem></DropdownMenuItem>
<DropdownMenuItem></DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
},
];
const table = useReactTable({
data: props.data,
columns,
@ -295,6 +293,11 @@ export function SeriesTable(props: SeriesTableProps) {
navigate("/", { state: { selectDicoms } });
};
const handle2Viewer = (dicom) => {
const { SeriesInstanceUID } = dicom
navigate(`/viewer?SeriesInstanceUID=${SeriesInstanceUID}`)
}
return (
<div className="w-full h-full flex flex-col">
<div className="flex-shrink-0 flex items-center p-4">
@ -387,9 +390,9 @@ export function SeriesTable(props: SeriesTableProps) {
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}

View File

@ -0,0 +1,12 @@
import { useLocation } from "react-router-dom"
export const Viewer = () => {
const location = useLocation()
const queryParams = new URLSearchParams(location.search);
const SeriesInstanceUID = queryParams.get('SeriesInstanceUID'); // 获取URL参数
return <div>
{SeriesInstanceUID}
<p>dicom的mpr方案</p>
</div>
}