feat: add marquee selection box overlay during drag-to-select

Show a semi-transparent blue rectangle overlay while dragging to
select rows, matching the project's primary color theme with dark
mode support. The box spans the full table width from drag start
to current mouse position.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
erio
2026-03-08 01:45:22 +08:00
parent be75fc3474
commit 2475d4a205
4 changed files with 243 additions and 0 deletions

View File

@@ -132,6 +132,7 @@
</template>
<template #table>
<AccountBulkActionsBar :selected-ids="selIds" @delete="handleBulkDelete" @edit="showBulkEdit = true" @clear="selIds = []" @select-page="selectPage" @toggle-schedulable="handleBulkToggleSchedulable" />
<div ref="accountTableRef">
<DataTable
:columns="cols"
:data="accounts"
@@ -252,6 +253,7 @@
</div>
</template>
</DataTable>
</div>
</template>
<template #pagination><Pagination v-if="pagination.total > 0" :page="pagination.page" :total="pagination.total" :page-size="pagination.page_size" @update:page="handlePageChange" @update:pageSize="handlePageSizeChange" /></template>
</TablePageLayout>
@@ -285,6 +287,7 @@ import { useAppStore } from '@/stores/app'
import { useAuthStore } from '@/stores/auth'
import { adminAPI } from '@/api/admin'
import { useTableLoader } from '@/composables/useTableLoader'
import { useSwipeSelect } from '@/composables/useSwipeSelect'
import AppLayout from '@/components/layout/AppLayout.vue'
import TablePageLayout from '@/components/layout/TablePageLayout.vue'
import DataTable from '@/components/common/DataTable.vue'
@@ -319,6 +322,12 @@ const authStore = useAuthStore()
const proxies = ref<Proxy[]>([])
const groups = ref<AdminGroup[]>([])
const selIds = ref<number[]>([])
const accountTableRef = ref<HTMLElement | null>(null)
useSwipeSelect(accountTableRef, {
isSelected: (id) => selIds.value.includes(id),
select: (id) => { if (!selIds.value.includes(id)) selIds.value.push(id) },
deselect: (id) => { selIds.value = selIds.value.filter(x => x !== id) }
})
const selPlatforms = computed<AccountPlatform[]>(() => {
const platforms = new Set(
accounts.value

View File

@@ -88,6 +88,7 @@
</template>
<template #table>
<div ref="proxyTableRef">
<DataTable :columns="columns" :data="proxies" :loading="loading">
<template #header-select>
<input
@@ -325,6 +326,7 @@
/>
</template>
</DataTable>
</div>
</template>
<template #pagination>
@@ -880,6 +882,7 @@ import Select from '@/components/common/Select.vue'
import Icon from '@/components/icons/Icon.vue'
import PlatformTypeBadge from '@/components/common/PlatformTypeBadge.vue'
import { useClipboard } from '@/composables/useClipboard'
import { useSwipeSelect } from '@/composables/useSwipeSelect'
const { t } = useI18n()
const appStore = useAppStore()
@@ -959,6 +962,12 @@ const qualityCheckingProxyIds = ref<Set<number>>(new Set())
const batchTesting = ref(false)
const batchQualityChecking = ref(false)
const selectedProxyIds = ref<Set<number>>(new Set())
const proxyTableRef = ref<HTMLElement | null>(null)
useSwipeSelect(proxyTableRef, {
isSelected: (id) => selectedProxyIds.value.has(id),
select: (id) => { const next = new Set(selectedProxyIds.value); next.add(id); selectedProxyIds.value = next },
deselect: (id) => { const next = new Set(selectedProxyIds.value); next.delete(id); selectedProxyIds.value = next }
})
const accountsProxy = ref<Proxy | null>(null)
const proxyAccounts = ref<ProxyAccountSummary[]>([])
const accountsLoading = ref(false)