refactor(ui): 统一复选框组件使用 defineModel 和 model-value 语法

- 在 BenchmarkTable.vue 中使用 defineModel 替代 props 和 emit 管理选中状态
- 统一所有复选框组件使用 model-value 属性替代 checked 属性
- 移除不必要的 class 样式和事件修饰符,简化代码逻辑
- 优化表格头部固定样式,提升滚动体验
This commit is contained in:
2026-03-19 00:54:33 +08:00
parent 7987cf35f9
commit 292ddc989d
4 changed files with 34 additions and 38 deletions

View File

@@ -3,7 +3,6 @@ import { computed, ref } from 'vue'
import { formatTime } from '../utils/benchmarkUtils'
import GradientButton from '@/components/GradientButton.vue'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
import { Card, CardContent } from '@/components/ui/card'
import {
Table,
@@ -14,18 +13,20 @@ import {
TableRow,
} from '@/components/ui/table'
import { Spinner } from '@/components/ui/spinner'
import { Badge } from '@/components/ui/badge'
import { Checkbox } from '@/components/ui/checkbox'
// 使用 defineModel 正确定义 v-model
const selectedRowKeys = defineModel('selectedRowKeys', { type: Array, default: () => [] })
const props = defineProps({
data: { type: Array, required: true },
selectedRowKeys: { type: Array, required: true },
loading: { type: Boolean, default: false },
loadingMore: { type: Boolean, default: false },
hasMore: { type: Boolean, default: false },
})
const emit = defineEmits(['update:selectedRowKeys', 'export', 'loadMore', 'createAsyncTask'])
const emit = defineEmits(['export', 'loadMore', 'createAsyncTask'])
// 列定义
const columns = [
@@ -45,13 +46,13 @@ const sortOrder = ref('desc')
// 全选状态
const isAllSelected = computed(() => {
return props.data.length > 0 && props.selectedRowKeys.length === props.data.length
return props.data.length > 0 && selectedRowKeys.value.length === props.data.length
})
// 半选状态(部分选中)
// 半选状态
const isIndeterminate = computed(() => {
const selectedLen = props.selectedRowKeys.length
return selectedLen > 0 && selectedLen < props.data.length
const len = selectedRowKeys.value.length
return len > 0 && len < props.data.length
})
// 切换排序
@@ -62,28 +63,25 @@ function handleSort(key) {
sortKey.value = key
sortOrder.value = 'desc'
}
emit('update:selectedRowKeys', [])
selectedRowKeys.value = []
}
// 选切换
// 选切换
function handleSelectAll(checked) {
if (checked) {
emit('update:selectedRowKeys', props.data.map(item => String(item.id)))
} else {
emit('update:selectedRowKeys', [])
}
selectedRowKeys.value = checked ? props.data.map(item => String(item.id)) : []
}
// 单行选择
function handleSelect(id) {
const key = String(id)
const newKeys = [...props.selectedRowKeys]
const index = newKeys.indexOf(key)
const keys = [...selectedRowKeys.value]
const index = keys.indexOf(key)
if (index > -1) {
newKeys.splice(index, 1)
keys.splice(index, 1)
} else {
newKeys.push(key)
keys.push(key)
}
emit('update:selectedRowKeys', newKeys)
selectedRowKeys.value = keys
}
// 排序后的数据
@@ -130,21 +128,20 @@ function formatNumber(value) {
</div>
<!-- 表格 -->
<div class="overflow-x-auto max-h-[calc(100vh-400px)] overflow-y-auto
<div class="overflow-x-auto max-h-[calc(100vh-400px)] overflow-y-auto relative
[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5
[&::-webkit-scrollbar-track]:bg-transparent
[&::-webkit-scrollbar-thumb]:bg-muted-foreground/30 [&::-webkit-scrollbar-thumb]:rounded"
>
<Table>
<TableHeader>
<TableRow>
<TableRow class="sticky top-0 z-10 bg-card/95 backdrop-blur-sm">
<TableHead class="w-[60px]">
<div class="flex items-center gap-2">
<Checkbox
:checked="isAllSelected"
:model-value="isAllSelected"
:indeterminate="isIndeterminate"
@update:checked="handleSelectAll"
class="scale-110"
@update:model-value="handleSelectAll"
/>
<span class="text-xs text-muted-foreground">全选</span>
</div>
@@ -186,9 +183,8 @@ function formatNumber(value) {
>
<TableCell class="w-[60px]">
<Checkbox
:checked="selectedRowKeys.includes(String(record.id))"
@update:checked="handleSelect(record.id)"
class="scale-110"
:model-value="selectedRowKeys.includes(String(record.id))"
@update:model-value="handleSelect(record.id)"
/>
</TableCell>
<TableCell>

View File

@@ -261,9 +261,9 @@
<div class="flex items-center justify-between px-6 py-3 border-t border-border">
<div class="flex items-center gap-4">
<Checkbox
:checked="selectedFileIds.length === fileList.length && fileList.length > 0"
:model-value="selectedFileIds.length === fileList.length && fileList.length > 0"
:indeterminate="selectedFileIds.length > 0 && selectedFileIds.length < fileList.length"
@update:checked="handleSelectAll"
@update:model-value="handleSelectAll"
>
全选
</Checkbox>

View File

@@ -89,8 +89,8 @@
<TableRow>
<TableHead class="w-[50px]">
<Checkbox
:checked="isAllSelected"
@update:checked="handleSelectAll"
:model-value="isAllSelected"
@update:model-value="handleSelectAll"
/>
</TableHead>
<TableHead class="w-[80px]">ID</TableHead>
@@ -105,8 +105,8 @@
<TableRow v-for="record in list" :key="record.id">
<TableCell>
<Checkbox
:checked="selectedRowKeys.includes(record.id)"
@update:checked="handleSelectRow(record.id)"
:model-value="selectedRowKeys.includes(record.id)"
@update:model-value="handleSelectRow(record.id)"
/>
</TableCell>
<TableCell>{{ record.id }}</TableCell>

View File

@@ -99,8 +99,8 @@
<TableRow>
<TableHead class="w-[50px]">
<Checkbox
:checked="isAllSelected"
@update:checked="handleSelectAll"
:model-value="isAllSelected"
@update:model-value="handleSelectAll"
/>
</TableHead>
<TableHead class="w-[70px]">ID</TableHead>
@@ -120,8 +120,8 @@
>
<TableCell>
<Checkbox
:checked="selectedRowKeys.includes(record.id)"
@update:checked.stop="handleSelectRow(record.id)"
:model-value="selectedRowKeys.includes(record.id)"
@update:model-value.stop="handleSelectRow(record.id)"
/>
</TableCell>
<TableCell>{{ record.id }}</TableCell>