Merge pull request #252 from Abeautifulsnow/feat/grid-export-selected-rows
feat(grid): add export selected rows and batch restore
This commit is contained in:
commit
a4ad5cd08b
|
|
@ -938,6 +938,7 @@ const {
|
|||
requestDeleteRow,
|
||||
confirmDeleteRow,
|
||||
restoreRow,
|
||||
restoreRows,
|
||||
pendingDeleteRowIds,
|
||||
requestDeleteRows,
|
||||
cloneRows,
|
||||
|
|
@ -1122,6 +1123,22 @@ function affectedRowIds(): number[] {
|
|||
return [];
|
||||
}
|
||||
|
||||
function exportSelectedRowsCsv() {
|
||||
return exportCsv(affectedRowIds());
|
||||
}
|
||||
|
||||
function exportSelectedRowsXlsx() {
|
||||
return exportXlsx(affectedRowIds());
|
||||
}
|
||||
|
||||
function exportSelectedRowsJson() {
|
||||
return exportJson(affectedRowIds());
|
||||
}
|
||||
|
||||
function exportSelectedRowsMarkdown() {
|
||||
return exportMarkdown(affectedRowIds());
|
||||
}
|
||||
|
||||
function isRowActive(index: number): boolean {
|
||||
const item = displayItems.value[index];
|
||||
if (item && isRowSelected(item.id)) return true;
|
||||
|
|
@ -2632,8 +2649,12 @@ defineExpose({
|
|||
<CopyPlus class="w-3.5 h-3.5 mr-2" />
|
||||
{{ isMultiRow ? t("grid.cloneRows", { count: multiRowCount }) : t("grid.cloneRow") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem v-if="contextRowItem.isDeleted" @click="restoreRow(contextRowItem.id)">
|
||||
<Undo2 class="w-3.5 h-3.5 mr-2" /> {{ t("grid.restoreRow") }}
|
||||
<ContextMenuItem
|
||||
v-if="contextRowItem.isDeleted"
|
||||
@click="isMultiRow ? restoreRows(affectedRowIds()) : restoreRow(contextRowItem.id)"
|
||||
>
|
||||
<Undo2 class="w-3.5 h-3.5 mr-2" />
|
||||
{{ isMultiRow ? t("grid.restoreRows", { count: multiRowCount }) : t("grid.restoreRow") }}
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem
|
||||
v-else
|
||||
|
|
@ -2652,6 +2673,15 @@ defineExpose({
|
|||
<ContextMenuItem @click="exportXlsx">{{ t("grid.exportXlsx") }}</ContextMenuItem>
|
||||
<ContextMenuItem @click="exportJson">{{ t("grid.exportJson") }}</ContextMenuItem>
|
||||
<ContextMenuItem @click="exportMarkdown">{{ t("grid.exportMarkdown") }}</ContextMenuItem>
|
||||
<template v-if="isMultiRow">
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem @click="exportSelectedRowsCsv">{{ t("grid.exportSelectedRowsCsv") }}</ContextMenuItem>
|
||||
<ContextMenuItem @click="exportSelectedRowsXlsx">{{ t("grid.exportSelectedRowsXlsx") }}</ContextMenuItem>
|
||||
<ContextMenuItem @click="exportSelectedRowsJson">{{ t("grid.exportSelectedRowsJson") }}</ContextMenuItem>
|
||||
<ContextMenuItem @click="exportSelectedRowsMarkdown">{{
|
||||
t("grid.exportSelectedRowsMarkdown")
|
||||
}}</ContextMenuItem>
|
||||
</template>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
</ContextMenuContent>
|
||||
|
|
@ -2676,7 +2706,7 @@ defineExpose({
|
|||
<span v-if="result.truncated" class="text-amber-500 text-xs ml-1">(truncated)</span>
|
||||
<span v-if="!hasData">{{ t("grid.rowsAffected", { count: result.affected_rows }) }}</span>
|
||||
<span>{{ result.execution_time_ms }}ms</span>
|
||||
<span v-if="hasCellSelection" class="text-foreground">{{ selectionSummary }}</span>
|
||||
<span v-if="selectedRowCount > 0 || hasCellSelection" class="text-foreground">{{ selectionSummary }}</span>
|
||||
|
||||
<template v-if="editable && (tableMeta || customSave) && !useTransaction">
|
||||
<span v-if="hasPendingChanges" class="ml-2 text-foreground">
|
||||
|
|
@ -2730,6 +2760,15 @@ defineExpose({
|
|||
<DropdownMenuItem @click="exportXlsx">{{ t("grid.exportXlsx") }}</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="exportJson">{{ t("grid.exportJson") }}</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="exportMarkdown">{{ t("grid.exportMarkdown") }}</DropdownMenuItem>
|
||||
<template v-if="isMultiRow">
|
||||
<ContextMenuSeparator />
|
||||
<DropdownMenuItem @click="exportSelectedRowsCsv">{{ t("grid.exportSelectedRowsCsv") }}</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="exportSelectedRowsXlsx">{{ t("grid.exportSelectedRowsXlsx") }}</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="exportSelectedRowsJson">{{ t("grid.exportSelectedRowsJson") }}</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="exportSelectedRowsMarkdown">{{
|
||||
t("grid.exportSelectedRowsMarkdown")
|
||||
}}</DropdownMenuItem>
|
||||
</template>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
|
|
|
|||
|
|
@ -448,6 +448,12 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
|||
}
|
||||
}
|
||||
|
||||
function restoreRows(rowIds: number[]) {
|
||||
for (const rowId of rowIds) {
|
||||
restoreRow(rowId);
|
||||
}
|
||||
}
|
||||
|
||||
function deleteSelectedRow(contextCell: Ref<{ rowId: number; rowIndex: number; col: number } | null>) {
|
||||
if (!contextCell.value) return;
|
||||
requestDeleteRow(contextCell.value.rowId);
|
||||
|
|
@ -679,6 +685,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
|||
requestDeleteRows,
|
||||
confirmDeleteRow,
|
||||
restoreRow,
|
||||
restoreRows,
|
||||
deleteSelectedRow,
|
||||
saveChanges,
|
||||
discardChanges,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,12 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
|||
toast(t("grid.copied"));
|
||||
}
|
||||
|
||||
function rowsToExport(rowIds?: number[]): RowItem[] {
|
||||
if (!rowIds?.length) return displayItems.value;
|
||||
const rowIdSet = new Set(rowIds);
|
||||
return displayItems.value.filter((item) => rowIdSet.has(item.id));
|
||||
}
|
||||
|
||||
// --- Selection copy functions ---
|
||||
function copySelectionTsv() {
|
||||
if (!hasCellSelection.value) return;
|
||||
|
|
@ -233,9 +239,9 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
|||
}
|
||||
|
||||
// --- Export functions ---
|
||||
async function exportCsv() {
|
||||
async function exportCsv(rowIds?: number[]) {
|
||||
try {
|
||||
const rows = displayItems.value.map((item) => item.data.map((c) => displayCellValue(c)));
|
||||
const rows = rowsToExport(rowIds).map((item) => item.data.map((c) => displayCellValue(c)));
|
||||
if (await saveFileContent(formatCsv(columns.value, rows), "export.csv", "CSV", "csv")) {
|
||||
toast(t("grid.exported"));
|
||||
}
|
||||
|
|
@ -244,9 +250,9 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
|||
}
|
||||
}
|
||||
|
||||
async function exportJson() {
|
||||
async function exportJson(rowIds?: number[]) {
|
||||
try {
|
||||
const rows = displayItems.value.map((item) => item.data);
|
||||
const rows = rowsToExport(rowIds).map((item) => item.data);
|
||||
if (await saveFileContent(formatJson(columns.value, rows), "export.json", "JSON", "json")) {
|
||||
toast(t("grid.exported"));
|
||||
}
|
||||
|
|
@ -255,10 +261,10 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
|||
}
|
||||
}
|
||||
|
||||
async function exportMarkdown() {
|
||||
async function exportMarkdown(rowIds?: number[]) {
|
||||
try {
|
||||
const cols = columns.value;
|
||||
const visibleRows = displayItems.value.map((item) => item.data);
|
||||
const visibleRows = rowsToExport(rowIds).map((item) => item.data);
|
||||
const { formatMarkdownTable } = await import("@/lib/markdownTable");
|
||||
const md = formatMarkdownTable({ columns: cols, rows: visibleRows });
|
||||
if (await saveFileContent(md, "export.md", "Markdown", "md")) {
|
||||
|
|
@ -269,13 +275,13 @@ export function useDataGridExport(options: UseDataGridExportOptions) {
|
|||
}
|
||||
}
|
||||
|
||||
async function exportXlsx() {
|
||||
async function exportXlsx(rowIds?: number[]) {
|
||||
try {
|
||||
const { buildXlsxWorkbook } = await import("@/lib/xlsxExport");
|
||||
const workbook = buildXlsxWorkbook({
|
||||
sheetName: tableMeta.value?.tableName || "Export",
|
||||
columns: columns.value,
|
||||
rows: displayItems.value.map((item) => item.data),
|
||||
rows: rowsToExport(rowIds).map((item) => item.data),
|
||||
});
|
||||
if (await saveBinaryFileContent(workbook, "export.xlsx", "Excel", "xlsx")) {
|
||||
toast(t("grid.exported"));
|
||||
|
|
|
|||
|
|
@ -246,6 +246,10 @@ export default {
|
|||
exportXlsx: "Export XLSX",
|
||||
exportJson: "Export JSON",
|
||||
exportMarkdown: "Export Markdown",
|
||||
exportSelectedRowsCsv: "Export Selected Rows as CSV",
|
||||
exportSelectedRowsXlsx: "Export Selected Rows as XLSX",
|
||||
exportSelectedRowsJson: "Export Selected Rows as JSON",
|
||||
exportSelectedRowsMarkdown: "Export Selected Rows as Markdown",
|
||||
exported: "Exported",
|
||||
exportFailed: "Export failed: {message}",
|
||||
filter: "Filter",
|
||||
|
|
@ -288,6 +292,7 @@ export default {
|
|||
deleteRow: "Delete Row",
|
||||
deleteRows: "Delete {count} Rows",
|
||||
cloneRows: "Clone {count} Rows",
|
||||
restoreRows: "Restore {count} Rows",
|
||||
copyRows: "Copy {count} Rows (JSON)",
|
||||
copyRowsInsert: "Copy {count} Rows as INSERT",
|
||||
selectedRows: "{count} rows selected",
|
||||
|
|
|
|||
|
|
@ -247,6 +247,10 @@ export default {
|
|||
exportXlsx: "Exportar XLSX",
|
||||
exportJson: "Exportar JSON",
|
||||
exportMarkdown: "Exportar Markdown",
|
||||
exportSelectedRowsCsv: "Exportar filas seleccionadas como CSV",
|
||||
exportSelectedRowsXlsx: "Exportar filas seleccionadas como XLSX",
|
||||
exportSelectedRowsJson: "Exportar filas seleccionadas como JSON",
|
||||
exportSelectedRowsMarkdown: "Exportar filas seleccionadas como Markdown",
|
||||
exported: "Exportado",
|
||||
exportFailed: "Error al exportar: {message}",
|
||||
filter: "Filtrar",
|
||||
|
|
@ -289,6 +293,7 @@ export default {
|
|||
deleteRow: "Eliminar fila",
|
||||
deleteRows: "Eliminar {count} filas",
|
||||
cloneRows: "Clonar {count} filas",
|
||||
restoreRows: "Restaurar {count} filas",
|
||||
copyRows: "Copiar {count} filas (JSON)",
|
||||
copyRowsInsert: "Copiar {count} filas como INSERT",
|
||||
selectedRows: "{count} filas seleccionadas",
|
||||
|
|
|
|||
|
|
@ -245,6 +245,10 @@ export default {
|
|||
exportXlsx: "导出 XLSX",
|
||||
exportJson: "导出 JSON",
|
||||
exportMarkdown: "导出 Markdown",
|
||||
exportSelectedRowsCsv: "导出选中行为 CSV",
|
||||
exportSelectedRowsXlsx: "导出选中行为 XLSX",
|
||||
exportSelectedRowsJson: "导出选中行为 JSON",
|
||||
exportSelectedRowsMarkdown: "导出选中行为 Markdown",
|
||||
exported: "导出完成",
|
||||
exportFailed: "导出失败:{message}",
|
||||
filter: "筛选",
|
||||
|
|
@ -287,6 +291,7 @@ export default {
|
|||
deleteRow: "删除行",
|
||||
deleteRows: "删除 {count} 行",
|
||||
cloneRows: "克隆 {count} 行",
|
||||
restoreRows: "恢复 {count} 行",
|
||||
copyRows: "复制 {count} 行 (JSON)",
|
||||
copyRowsInsert: "复制 {count} 行为 INSERT",
|
||||
selectedRows: "已选 {count} 行",
|
||||
|
|
|
|||
Loading…
Reference in New Issue