import type { ColumnDef, ColumnFiltersState, ExpandedState, SortingState, VisibilityState, } from "@tanstack/vue-table"; import { getCoreRowModel, getExpandedRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useVueTable, } from "@tanstack/vue-table"; import { h, ref, computed, version } from "vue"; import { createInjectionState } from "@vueuse/core"; import type { BoardData } from "../../utils/BoardManager"; import { useBoardManager } from "../../utils/BoardManager"; import { useDialogStore } from "@/stores/dialog"; const [useProvideBoardTableManager, useBoardTableManager] = createInjectionState(() => { // 从BoardManager获取数据和方法 const boardManager = useBoardManager()!; const dialog = useDialogStore(); // 编辑状态 const isEditMode = ref(false); // 表格状态管理 const sorting = ref([]); const columnFilters = ref([]); const columnVisibility = ref({ // 默认隐藏端口、ID、状态列和板卡名称列 port: false, id: false, status: false, version: false, }); const rowSelection = ref({}); const expanded = ref({}); // 表格列定义 const columns: ColumnDef[] = [ { id: "select", header: ({ table }) => h("input", { type: "checkbox", class: "checkbox", checked: table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() ? "indeterminate" : false), onChange: (event: Event) => table.toggleAllPageRowsSelected( !!(event.target as HTMLInputElement).checked, ), }), cell: ({ row }) => h("input", { type: "checkbox", class: "checkbox", checked: row.getIsSelected(), onChange: (event: Event) => row.toggleSelected(!!(event.target as HTMLInputElement).checked), }), enableSorting: false, enableHiding: false, }, { accessorKey: "boardName", header: "板卡名称", cell: ({ row }) => { const device = row.original; return isEditMode.value ? h("input", { type: "text", class: "input input-sm w-full", value: device.boardName, onInput: (e: Event) => { device.boardName = (e.target as HTMLInputElement).value; }, }) : h("span", { class: "font-medium" }, device.boardName); }, enableHiding: true, }, { accessorKey: "devAddr", header: "IP 地址", cell: ({ row }) => { const device = row.original; return isEditMode.value ? h("input", { type: "text", class: "input input-sm w-full", value: device.ipAddr, onInput: (e: Event) => { device.ipAddr = (e.target as HTMLInputElement).value; }, }) : h("span", { class: "font-medium" }, device.ipAddr); }, }, { accessorKey: "port", header: "端口", cell: ({ row }) => { const device = row.original; return isEditMode.value ? h("input", { type: "number", class: "input input-sm w-full", value: device.port, onInput: (e: Event) => { device.port = parseInt((e.target as HTMLInputElement).value); }, }) : h("span", { class: "font-mono" }, device.port.toString()); }, enableHiding: true, }, { accessorKey: "id", header: "设备ID", cell: ({ row }) => h("span", { class: "font-mono text-xs" }, row.original.id), enableHiding: true, }, { accessorKey: "status", header: "状态", cell: ({ row }) => { const device = row.original; const statusText = device.status === 0 ? "忙碌" : "可用"; const statusClass = device.status === 0 ? "badge-warning" : "badge-success"; return h( "span", { class: `badge ${statusClass} min-w-15`, }, statusText, ); }, enableHiding: true, }, { accessorKey: "version", header: "版本号", cell: ({ row }) => h("span", { class: "font-mono" }, row.original.firmVersion), }, { accessorKey: "defaultBitstream", header: "默认启动位流", cell: ({ row }) => { const device = row.original; return h( "select", { class: "select select-bordered select-sm w-full", value: device.defaultBitstream, onChange: (e: Event) => { device.defaultBitstream = (e.target as HTMLSelectElement).value; }, }, [ h("option", { value: "黄金位流" }, "黄金位流"), h("option", { value: "应用位流1" }, "应用位流1"), h("option", { value: "应用位流2" }, "应用位流2"), h("option", { value: "应用位流3" }, "应用位流3"), ], ); }, }, { id: "goldBitstream", header: "黄金位流", cell: ({ row }) => { const device = row.original; return h("input", { type: "file", class: "file-input file-input-primary file-input-sm", onChange: (e: Event) => boardManager.handleFileChange(e, device, "goldBitstreamFile"), }); }, }, { id: "appBitstream1", header: "应用位流1", cell: ({ row }) => { const device = row.original; return h("input", { type: "file", class: "file-input file-input-secondary file-input-sm", onChange: (e: Event) => boardManager.handleFileChange(e, device, "appBitstream1File"), }); }, }, { id: "appBitstream2", header: "应用位流2", cell: ({ row }) => { const device = row.original; return h("input", { type: "file", class: "file-input file-input-accent file-input-sm", onChange: (e: Event) => boardManager.handleFileChange(e, device, "appBitstream2File"), }); }, }, { id: "appBitstream3", header: "应用位流3", cell: ({ row }) => { const device = row.original; return h("input", { type: "file", class: "file-input file-input-info file-input-sm", onChange: (e: Event) => boardManager.handleFileChange(e, device, "appBitstream3File"), }); }, }, { id: "actions", header: "操作", cell: ({ row }) => { const device = row.original; // 根据编辑模式显示不同的按钮 if (isEditMode.value) { return h( "div", { class: ["flex gap-2", { "min-w-30": !isEditMode.value }], }, [ h( "button", { class: "btn btn-error btn-sm", onClick: async () => { const confirmed = confirm( `确定要删除设备 ${device.ipAddr} 吗?`, ); if (confirmed) { await deleteBoard(device.id); } }, }, "删除", ), ], ); } else { return h("div", { class: "flex gap-2 min-w-30" }, [ h( "button", { class: "btn btn-warning btn-sm", onClick: () => uploadAndDownloadBitstreams( device, device.goldBitstreamFile, device.appBitstream1File, device.appBitstream2File, device.appBitstream3File, ), }, "固化", ), h( "button", { class: "btn btn-success btn-sm", onClick: () => hotresetBitstream( device, boardManager.getSelectedBitstreamNum( device.defaultBitstream, ), ), }, "热启动", ), ]); } }, enableHiding: false, }, ]; // 创建表格实例 const table = useVueTable({ get data() { return boardManager.boards.value; }, get columns() { return columns; }, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), getExpandedRowModel: getExpandedRowModel(), onSortingChange: (updaterOrValue) => { if (typeof updaterOrValue === "function") { sorting.value = updaterOrValue(sorting.value); } else { sorting.value = updaterOrValue; } }, onColumnFiltersChange: (updaterOrValue) => { if (typeof updaterOrValue === "function") { columnFilters.value = updaterOrValue(columnFilters.value); } else { columnFilters.value = updaterOrValue; } }, onColumnVisibilityChange: (updaterOrValue) => { if (typeof updaterOrValue === "function") { columnVisibility.value = updaterOrValue(columnVisibility.value); } else { columnVisibility.value = updaterOrValue; } }, onRowSelectionChange: (updaterOrValue) => { if (typeof updaterOrValue === "function") { rowSelection.value = updaterOrValue(rowSelection.value); } else { rowSelection.value = updaterOrValue; } }, onExpandedChange: (updaterOrValue) => { if (typeof updaterOrValue === "function") { expanded.value = updaterOrValue(expanded.value); } else { expanded.value = updaterOrValue; } }, state: { get sorting() { return sorting.value; }, get columnFilters() { return columnFilters.value; }, get columnVisibility() { return columnVisibility.value; }, get rowSelection() { return rowSelection.value; }, get expanded() { return expanded.value; }, }, }); // UI层的API封装方法 - 添加dialog提示 // 获取所有板卡信息 async function getAllBoards(): Promise { const result = await boardManager.getAllBoards(); if (result.success) { dialog?.info("获取板卡信息成功"); } else { dialog?.error(result.error || "获取板卡信息失败"); } return result.success; } // 新增板卡 async function addBoard(name: string, ipAddr: string, port: number): Promise { const result = await boardManager.addBoard(name, ipAddr, port); if (result.success) { dialog?.info("新增板卡成功"); } else { dialog?.error(result.error || "新增板卡失败"); } return result.success; } // 删除板卡 async function deleteBoard(boardId: string): Promise { const result = await boardManager.deleteBoard(boardId); if (result.success) { dialog?.info("删除板卡成功"); } else { dialog?.error(result.error || "删除板卡失败"); } return result.success; } // 上传并固化位流 async function uploadAndDownloadBitstreams( board: BoardData, goldBitstream?: File, appBitstream1?: File, appBitstream2?: File, appBitstream3?: File, ): Promise { const result = await boardManager.uploadAndDownloadBitstreams( board, goldBitstream, appBitstream1, appBitstream2, appBitstream3, ); if (result.success) { dialog?.info("固化比特流成功"); } else { dialog?.error(result.error || "固化比特流失败"); } return result.success; } // 热启动位流 async function hotresetBitstream(board: BoardData, bitstreamNum: number): Promise { const result = await boardManager.hotresetBitstream(board, bitstreamNum); if (result.success) { dialog?.info("切换比特流成功"); } else { dialog?.error(result.error || "切换比特流失败"); } return result.success; } // 表格操作方法 const getSelectedRows = () => table.getFilteredSelectedRowModel().rows; const getAllRows = () => table.getFilteredRowModel().rows; const getColumnByKey = (key: string) => table.getColumn(key); const getAllHideableColumns = () => table.getAllColumns().filter((column) => column.getCanHide()); const getHeaderGroups = () => table.getHeaderGroups(); const getRowModel = () => table.getRowModel(); const canPreviousPage = () => table.getCanPreviousPage(); const canNextPage = () => table.getCanNextPage(); const previousPage = () => table.previousPage(); const nextPage = () => table.nextPage(); // 编辑模式控制 const toggleEditMode = () => { isEditMode.value = !isEditMode.value; }; // 删除选中的实验板 const deleteSelectedBoards = async () => { const selectedRows = getSelectedRows(); if (selectedRows.length === 0) { dialog?.warn("请先选择要删除的实验板"); return false; } const boardNames = selectedRows .map((row) => row.original.boardName || row.original.ipAddr) .join("、"); const confirmed = confirm( `确定要删除以下 ${selectedRows.length} 个实验板吗?\n${boardNames}`, ); if (!confirmed) { return false; } let successCount = 0; let failCount = 0; // 批量删除 for (const row of selectedRows) { const board = row.original; const result = await boardManager.deleteBoard(board.id); if (result.success) { successCount++; } else { failCount++; } } // 清空选择状态 rowSelection.value = {}; // 显示结果提示 if (failCount === 0) { dialog?.info(`成功删除 ${successCount} 个实验板`); } else if (successCount === 0) { dialog?.error( `删除失败,共 ${failCount} 个实验板删除失败`, ); } else { dialog?.warn( `部分删除成功:成功 ${successCount} 个,失败 ${failCount} 个`, ); } return successCount > 0; }; return { // 表格实例 table, // 列定义 columns, // 表格操作方法 getSelectedRows, getAllRows, getColumnByKey, getAllHideableColumns, getHeaderGroups, getRowModel, canPreviousPage, canNextPage, previousPage, nextPage, deleteSelectedBoards, // 状态 sorting, columnFilters, columnVisibility, rowSelection, expanded, // 编辑模式 isEditMode, toggleEditMode, // UI层封装的API方法 getAllBoards, addBoard, deleteBoard, uploadAndDownloadBitstreams, hotresetBitstream, // BoardManager 的引用 boardManager, }; }); export { useProvideBoardTableManager, useBoardTableManager };