Files
xk-admin/apps/web-antd/src/components/canvas-spreadsheet/composables/useSelection.ts
李琦 a38da5ce92
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
1. Excel交互组件封装优化
2026-06-26 12:52:26 +08:00

269 lines
6.7 KiB
TypeScript

import { ref } from 'vue';
import type { CellRange } from '../types';
import {
normalizeRange,
rangesContainCell,
} from '../commands/FillRangeCommand';
export interface SelectionModifiers {
shift?: boolean;
ctrl?: boolean;
}
function fullRowRange(row: number, maxCol: number): CellRange {
return normalizeRange({
startRow: row,
endRow: row,
startCol: 0,
endCol: maxCol,
});
}
function fullColRange(col: number, maxRow: number): CellRange {
return normalizeRange({
startRow: 0,
endRow: maxRow,
startCol: col,
endCol: col,
});
}
function rowRange(r0: number, r1: number, maxCol: number): CellRange {
return normalizeRange({
startRow: r0,
endRow: r1,
startCol: 0,
endCol: maxCol,
});
}
function colRange(c0: number, c1: number, maxRow: number): CellRange {
return normalizeRange({
startRow: 0,
endRow: maxRow,
startCol: c0,
endCol: c1,
});
}
function isFullRowRange(range: CellRange, maxCol: number): boolean {
const r = normalizeRange(range);
return r.startCol === 0 && r.endCol === maxCol;
}
function isFullColRange(range: CellRange, maxRow: number): boolean {
const r = normalizeRange(range);
return r.startRow === 0 && r.endRow === maxRow;
}
function rangeContainsRow(range: CellRange, row: number, maxCol: number): boolean {
const r = normalizeRange(range);
return isFullRowRange(r, maxCol) && row >= r.startRow && row <= r.endRow;
}
function rangeContainsCol(range: CellRange, col: number, maxRow: number): boolean {
const r = normalizeRange(range);
return isFullColRange(r, maxRow) && col >= r.startCol && col <= r.endCol;
}
export function useSelection() {
const ranges = ref<CellRange[]>([]);
const anchor = ref<{ row: number; col: number } | null>(null);
const activeCell = ref<{ row: number; col: number } | null>(null);
const isFillDragging = ref(false);
/** @deprecated use ranges */
const selection = ranges;
function selectCell(row: number, col: number) {
activeCell.value = { row, col };
anchor.value = { row, col };
ranges.value = [
{ startRow: row, startCol: col, endRow: row, endCol: col },
];
}
function extendSelection(row: number, col: number) {
if (!anchor.value) {
selectCell(row, col);
return;
}
ranges.value = [
{
startRow: anchor.value.row,
startCol: anchor.value.col,
endRow: row,
endCol: col,
},
];
activeCell.value = { row, col };
}
function selectRange(range: CellRange) {
const normalized = normalizeRange(range);
ranges.value = [normalized];
activeCell.value = {
row: normalized.startRow,
col: normalized.startCol,
};
anchor.value = { ...activeCell.value };
}
function getSelectionRanges(): CellRange[] {
return ranges.value.map((r) => normalizeRange(r));
}
function getNormalizedSelection(): CellRange | null {
const primary = getPrimaryRange();
return primary;
}
function getPrimaryRange(): CellRange | null {
if (!ranges.value.length) return null;
if (!activeCell.value) return normalizeRange(ranges.value[0]!);
const { row, col } = activeCell.value;
for (const range of ranges.value) {
const r = normalizeRange(range);
if (
row >= r.startRow &&
row <= r.endRow &&
col >= r.startCol &&
col <= r.endCol
) {
return r;
}
}
return normalizeRange(ranges.value[ranges.value.length - 1]!);
}
function containsCell(row: number, col: number): boolean {
return rangesContainCell(ranges.value, row, col);
}
function selectAll(maxRow: number, maxCol: number) {
const range = normalizeRange({
startRow: 0,
endRow: maxRow,
startCol: 0,
endCol: maxCol,
});
ranges.value = [range];
activeCell.value = { row: 0, col: 0 };
anchor.value = { row: 0, col: 0 };
}
function selectEntireRow(
row: number,
maxCol: number,
opts: SelectionModifiers = {},
) {
const { shift, ctrl } = opts;
if (ctrl) {
const next = [...ranges.value];
const idx = next.findIndex((r) => rangeContainsRow(r, row, maxCol));
if (idx >= 0) {
next.splice(idx, 1);
} else {
next.push(fullRowRange(row, maxCol));
}
ranges.value = next.length ? next : [];
if (ranges.value.length) {
activeCell.value = { row, col: 0 };
if (!shift) anchor.value = { row, col: 0 };
} else {
activeCell.value = null;
}
return;
}
if (shift && anchor.value) {
const range = rowRange(anchor.value.row, row, maxCol);
ranges.value = [range];
activeCell.value = { row, col: 0 };
return;
}
ranges.value = [fullRowRange(row, maxCol)];
activeCell.value = { row, col: 0 };
anchor.value = { row, col: 0 };
}
function selectEntireColumn(
col: number,
maxRow: number,
opts: SelectionModifiers = {},
) {
const { shift, ctrl } = opts;
if (ctrl) {
const next = [...ranges.value];
const idx = next.findIndex((r) => rangeContainsCol(r, col, maxRow));
if (idx >= 0) {
next.splice(idx, 1);
} else {
next.push(fullColRange(col, maxRow));
}
ranges.value = next.length ? next : [];
if (ranges.value.length) {
activeCell.value = { row: 0, col };
if (!shift) anchor.value = { row: 0, col };
} else {
activeCell.value = null;
}
return;
}
if (shift && anchor.value) {
const range = colRange(anchor.value.col, col, maxRow);
ranges.value = [range];
activeCell.value = { row: 0, col };
return;
}
ranges.value = [fullColRange(col, maxRow)];
activeCell.value = { row: 0, col };
anchor.value = { row: 0, col };
}
function extendRowSelection(row: number, maxCol: number) {
if (!anchor.value) {
selectEntireRow(row, maxCol);
return;
}
ranges.value = [rowRange(anchor.value.row, row, maxCol)];
activeCell.value = { row, col: 0 };
}
function extendColumnSelection(col: number, maxRow: number) {
if (!anchor.value) {
selectEntireColumn(col, maxRow);
return;
}
ranges.value = [colRange(anchor.value.col, col, maxRow)];
activeCell.value = { row: 0, col };
}
function clearSelection() {
ranges.value = [];
anchor.value = null;
activeCell.value = null;
}
return {
ranges,
selection,
anchor,
activeCell,
isFillDragging,
selectCell,
extendSelection,
selectRange,
selectAll,
selectEntireRow,
selectEntireColumn,
extendRowSelection,
extendColumnSelection,
getSelectionRanges,
getNormalizedSelection,
getPrimaryRange,
containsCell,
clearSelection,
};
}