20260811165111
This commit is contained in:
1 parent
5adbf59425
commit
ce78653207
34 files changed
+3793
-366
No files matched your search
@@ -1,24 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, ref, shallowRef } from "vue";
|
||||
import { toast } from "vue-sonner";
|
||||
import {
|
||||
CheckCircle2,
|
||||
Copy,
|
||||
Database,
|
||||
Pencil,
|
||||
Plus,
|
||||
RefreshCw,
|
||||
Rows3,
|
||||
Search,
|
||||
Trash2,
|
||||
X,
|
||||
} from "@lucide/vue";
|
||||
import FmsAutoComplete from "@/components/FmsAutoComplete.vue";
|
||||
import FmsSelect from "@/components/FmsSelect.vue";
|
||||
import { Copy, Pencil, Plus, RefreshCw, Search, Trash2, X } from "@lucide/vue";
|
||||
import FmsTable from "@/components/fms-table/FmsTable.vue";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
@@ -39,7 +24,8 @@ type DemoRow = {
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
const ROW_COUNT = 15;
|
||||
const ROW_COUNT = 5000;
|
||||
const DEMO_NAMES = ["客户资料", "订单状态", "库存预警", "合同归档", "发票登记"];
|
||||
const OWNER_OPTIONS = [
|
||||
{ label: "林晓", value: "lin-xiao" },
|
||||
{ label: "陈默", value: "chen-mo" },
|
||||
@@ -55,7 +41,7 @@ function buildRows(): DemoRow[] {
|
||||
return Array.from({ length: ROW_COUNT }, (_, index) => ({
|
||||
id: `R${String(index + 1).padStart(4, "0")}`,
|
||||
code: `FMS-${String(index + 1).padStart(4, "0")}`,
|
||||
name: ["客户资料", "订单状态", "库存预警", "合同归档", "发票登记"][index % 5] + ` ${index + 1}`,
|
||||
name: `${DEMO_NAMES[index % DEMO_NAMES.length]} ${index + 1}`,
|
||||
owner: OWNER_OPTIONS[index % OWNER_OPTIONS.length]!.value,
|
||||
status: index % 7 === 0 ? 0 : 1,
|
||||
enabled: index % 11 === 0 ? 0 : 1,
|
||||
@@ -141,7 +127,6 @@ const rowSelection = computed(() => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const enabledCount = computed(() => dataSource.value.filter((row) => row.enabled === 1).length);
|
||||
const selectedCount = computed(() => selectedRowKeys.value.length);
|
||||
|
||||
function syncRows() {
|
||||
@@ -235,204 +220,74 @@ function clearSelection() {
|
||||
selectedRowKeys.value = [];
|
||||
tableRef.value?.clearSelectedArea();
|
||||
}
|
||||
|
||||
// 远程控件 demo
|
||||
const localeCode = ref("");
|
||||
const localeLabel = ref("");
|
||||
const localeRecord = ref<Record<string, unknown> | null>(null);
|
||||
const autoValue = ref("");
|
||||
const autoRecord = ref<Record<string, unknown> | null>(null);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="flex min-h-full flex-col gap-5 pb-2">
|
||||
<header class="flex flex-wrap items-end justify-between gap-4 border-b pb-4">
|
||||
<div class="min-w-0">
|
||||
<div
|
||||
class="mb-1 flex items-center gap-2 text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground"
|
||||
>
|
||||
<Database class="size-3.5" />
|
||||
FmsTable Playground
|
||||
</div>
|
||||
<h1 class="text-2xl font-semibold tracking-tight">数据表格工作台</h1>
|
||||
<p class="mt-1 max-w-2xl text-sm text-muted-foreground">
|
||||
在真实数据场景下验证虚拟滚动、行选择、单元格编辑和行拖拽。
|
||||
</p>
|
||||
</div>
|
||||
<main class="flex h-full min-h-[460px] flex-col gap-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<Button variant="outline" size="sm" @click="clearSelection">
|
||||
<X data-icon="inline-start" />
|
||||
清空选择
|
||||
<Button size="sm" @click="addRow">
|
||||
<Plus data-icon="inline-start" />
|
||||
新增行
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" @click="regenerate">
|
||||
<RefreshCw data-icon="inline-start" />
|
||||
重新生成
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" :disabled="!selectedCount" @click="editFirstSelected">
|
||||
<Pencil data-icon="inline-start" />
|
||||
编辑选中
|
||||
</Button>
|
||||
<Button size="sm" @click="regenerate">
|
||||
<RefreshCw data-icon="inline-start" />
|
||||
重新生成
|
||||
<Button variant="ghost" size="sm" :disabled="!selectedCount" @click="clearSelection">
|
||||
<X data-icon="inline-start" />
|
||||
清空选择
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="grid grid-cols-2 gap-3 sm:grid-cols-4" aria-label="表格统计">
|
||||
<Card class="gap-2 py-3">
|
||||
<CardHeader class="flex items-center justify-between px-4 pb-0 pt-0"
|
||||
><CardTitle class="text-xs font-medium text-muted-foreground">总记录</CardTitle
|
||||
><Rows3 class="size-4 text-muted-foreground"
|
||||
/></CardHeader>
|
||||
<CardContent class="px-4"
|
||||
><div class="text-xl font-semibold tabular-nums">
|
||||
{{ dataSource.length.toLocaleString() }}
|
||||
</div></CardContent
|
||||
>
|
||||
</Card>
|
||||
<Card class="gap-2 py-3">
|
||||
<CardHeader class="flex items-center justify-between px-4 pb-0 pt-0"
|
||||
><CardTitle class="text-xs font-medium text-muted-foreground">当前显示</CardTitle
|
||||
><Search class="size-4 text-muted-foreground"
|
||||
/></CardHeader>
|
||||
<CardContent class="px-4"
|
||||
><div class="text-xl font-semibold tabular-nums">
|
||||
{{ filteredRows.length.toLocaleString() }}
|
||||
</div></CardContent
|
||||
>
|
||||
</Card>
|
||||
<Card class="gap-2 py-3">
|
||||
<CardHeader class="flex items-center justify-between px-4 pb-0 pt-0"
|
||||
><CardTitle class="text-xs font-medium text-muted-foreground">已启用</CardTitle
|
||||
><CheckCircle2 class="size-4 text-muted-foreground"
|
||||
/></CardHeader>
|
||||
<CardContent class="px-4"
|
||||
><div class="text-xl font-semibold tabular-nums">
|
||||
{{ enabledCount.toLocaleString() }}
|
||||
</div></CardContent
|
||||
>
|
||||
</Card>
|
||||
<Card class="gap-2 py-3">
|
||||
<CardHeader class="flex items-center justify-between px-4 pb-0 pt-0"
|
||||
><CardTitle class="text-xs font-medium text-muted-foreground">已选择</CardTitle
|
||||
><Badge variant="secondary">{{ selectedCount }}</Badge></CardHeader
|
||||
>
|
||||
<CardContent class="px-4"
|
||||
><div class="text-xl font-semibold tabular-nums">{{ selectedCount }}</div></CardContent
|
||||
>
|
||||
</Card>
|
||||
</section>
|
||||
|
||||
<section class="flex min-h-0 flex-1 flex-col gap-3 rounded-lg border bg-card p-3 sm:p-4">
|
||||
<div class="flex flex-wrap items-end justify-between gap-3">
|
||||
<div>
|
||||
<h2 class="text-base font-semibold">记录清单</h2>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
点击文本或下拉单元格开始编辑,复选框可直接切换。
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-end gap-2">
|
||||
<Button size="sm" @click="addRow">
|
||||
<Plus data-icon="inline-start" />
|
||||
新增行
|
||||
</Button>
|
||||
<label class="grid gap-1 text-xs text-muted-foreground">
|
||||
<span>搜索</span>
|
||||
<Input
|
||||
v-model="searchQuery"
|
||||
class="h-8 w-44 text-xs"
|
||||
placeholder="编号、名称或负责人"
|
||||
/>
|
||||
</label>
|
||||
<label class="grid gap-1 text-xs text-muted-foreground">
|
||||
<span>状态</span>
|
||||
<Select v-model="statusFilter">
|
||||
<SelectTrigger size="sm" class="h-8 w-28"
|
||||
><SelectValue placeholder="全部状态"
|
||||
/></SelectTrigger>
|
||||
<SelectContent
|
||||
><SelectGroup
|
||||
><SelectItem value="all">全部状态</SelectItem
|
||||
><SelectItem value="1">启用</SelectItem
|
||||
><SelectItem value="0">禁用</SelectItem></SelectGroup
|
||||
></SelectContent
|
||||
>
|
||||
</Select>
|
||||
</label>
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="text-xs tabular-nums text-muted-foreground">
|
||||
{{ filteredRows.length.toLocaleString() }} / {{ dataSource.length.toLocaleString() }} 条
|
||||
</span>
|
||||
<div class="relative">
|
||||
<Search
|
||||
class="pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<Input
|
||||
v-model="searchQuery"
|
||||
class="h-8 w-56 pl-8 text-xs"
|
||||
aria-label="搜索编号、名称或负责人"
|
||||
/>
|
||||
</div>
|
||||
<Select v-model="statusFilter">
|
||||
<SelectTrigger size="sm" class="h-8 w-28" aria-label="筛选状态">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="all">全部状态</SelectItem>
|
||||
<SelectItem value="1">启用</SelectItem>
|
||||
<SelectItem value="0">禁用</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="min-h-[460px] flex-1">
|
||||
<FmsTable
|
||||
ref="tableRef"
|
||||
v-model:columns="columns"
|
||||
:data-source="filteredRows"
|
||||
:row-selection="rowSelection"
|
||||
:active-row-key="activeRowKey"
|
||||
row-key="id"
|
||||
row-draggable
|
||||
show-overflow
|
||||
@change="onTableChange"
|
||||
@row-order-change="onRowOrderChange"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid gap-3 lg:grid-cols-2">
|
||||
<Card class="gap-4 py-4">
|
||||
<CardHeader class="px-4 pb-0 pt-0"
|
||||
><CardTitle class="text-sm">FmsSelect 远程选择</CardTitle></CardHeader
|
||||
>
|
||||
<CardContent class="px-4">
|
||||
<div class="grid gap-3 sm:grid-cols-[240px_1fr] sm:items-center">
|
||||
<FmsSelect
|
||||
v-model="localeCode"
|
||||
v-model:label="localeLabel"
|
||||
view-name="b_i18n_type"
|
||||
label-key="b_name"
|
||||
value-key="b_code"
|
||||
order-by="b_code ASC"
|
||||
:page-size="10"
|
||||
allow-clear
|
||||
placeholder="选择语言类型..."
|
||||
@change="localeRecord = $event"
|
||||
/>
|
||||
<div class="grid gap-1 text-xs text-muted-foreground">
|
||||
<span
|
||||
>值:<code class="text-foreground">{{ localeCode || "-" }}</code></span
|
||||
><span
|
||||
>记录:<code class="text-foreground">{{
|
||||
localeRecord ? JSON.stringify(localeRecord) : "-"
|
||||
}}</code></span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card class="gap-4 py-4">
|
||||
<CardHeader class="px-4 pb-0 pt-0"
|
||||
><CardTitle class="text-sm">FmsAutoComplete 搜索</CardTitle></CardHeader
|
||||
>
|
||||
<CardContent class="px-4">
|
||||
<div class="grid gap-3 sm:grid-cols-[240px_1fr] sm:items-center">
|
||||
<FmsAutoComplete
|
||||
v-model="autoValue"
|
||||
view-name="b_i18n_type"
|
||||
label-key="b_name"
|
||||
value-key="b_code"
|
||||
order-by="b_code ASC"
|
||||
placeholder="输入语言关键字..."
|
||||
@change="autoRecord = $event"
|
||||
/>
|
||||
<div class="grid gap-1 text-xs text-muted-foreground">
|
||||
<span
|
||||
>输入:<code class="text-foreground">{{ autoValue || "-" }}</code></span
|
||||
><span
|
||||
>记录:<code class="text-foreground">{{
|
||||
autoRecord ? JSON.stringify(autoRecord) : "-"
|
||||
}}</code></span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</section>
|
||||
<div class="min-h-0 flex-1">
|
||||
<FmsTable
|
||||
ref="tableRef"
|
||||
v-model:columns="columns"
|
||||
:data-source="filteredRows"
|
||||
:row-selection="rowSelection"
|
||||
:active-row-key="activeRowKey"
|
||||
row-key="id"
|
||||
row-draggable
|
||||
scroll-row-by-row="scrollbar"
|
||||
show-overflow
|
||||
@change="onTableChange"
|
||||
@row-order-change="onRowOrderChange"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
Reference in new issue
Block a user