feat: 添加虚拟表格示例 (#1007)

* feat: 添加虚拟表格示例
This commit is contained in:
xiaoming
2024-03-20 15:00:47 +08:00
committed by GitHub
parent f0a80c680e
commit 2367eedc5d
78 changed files with 16678 additions and 14 deletions

View File

@@ -0,0 +1,105 @@
import type {
LoadingConfig,
AdaptiveConfig,
PaginationProps
} from "@pureadmin/table";
import { tableData } from "../data";
import { ref, onMounted, reactive } from "vue";
import { clone, delay } from "@pureadmin/utils";
export function useColumns() {
const dataList = ref([]);
const loading = ref(true);
const columns: TableColumnList = [
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
];
/** 分页配置 */
const pagination = reactive<PaginationProps>({
pageSize: 20,
currentPage: 1,
pageSizes: [20, 40, 60],
total: 0,
align: "right",
background: true,
small: false
});
/** 加载动画配置 */
const loadingConfig = reactive<LoadingConfig>({
text: "正在加载第一页...",
viewBox: "-10, -10, 50, 50",
spinner: `
<path class="path" d="
M 30 15
L 28 17
M 25.61 25.61
A 15 15, 0, 0, 1, 15 30
A 15 15, 0, 1, 1, 27.99 7.5
L 15 15
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
`
// svg: "",
// background: rgba()
});
/** 撑满内容区自适应高度相关配置 */
const adaptiveConfig: AdaptiveConfig = {
/** 表格距离页面底部的偏移量,默认值为 `96` */
offsetBottom: 110
/** 是否固定表头,默认值为 `true`如果不想固定表头fixHeader设置为false并且表格要设置table-layout="auto" */
// fixHeader: true
/** 页面 `resize` 时的防抖时间,默认值为 `60` ms */
// timeout: 60
/** 表头的 `z-index`,默认值为 `100` */
// zIndex: 100
};
function onSizeChange(val) {
console.log("onSizeChange", val);
}
function onCurrentChange(val) {
loadingConfig.text = `正在加载第${val}页...`;
loading.value = true;
delay(600).then(() => {
loading.value = false;
});
}
onMounted(() => {
delay(600).then(() => {
const newList = [];
Array.from({ length: 6 }).forEach(() => {
newList.push(clone(tableData, true));
});
newList.flat(Infinity).forEach((item, index) => {
dataList.value.push({ id: index, ...item });
});
pagination.total = dataList.value.length;
loading.value = false;
});
});
return {
loading,
columns,
dataList,
pagination,
loadingConfig,
adaptiveConfig,
onSizeChange,
onCurrentChange
};
}

View File

@@ -0,0 +1,41 @@
<script setup lang="ts">
import { ref } from "vue";
import { useColumns } from "./columns";
const tableRef = ref();
const {
loading,
columns,
dataList,
pagination,
loadingConfig,
adaptiveConfig,
onSizeChange,
onCurrentChange
} = useColumns();
</script>
<template>
<pure-table
ref="tableRef"
border
adaptive
:adaptiveConfig="adaptiveConfig"
row-key="id"
alignWhole="center"
showOverflowTooltip
:loading="loading"
:loading-config="loadingConfig"
:data="
dataList.slice(
(pagination.currentPage - 1) * pagination.pageSize,
pagination.currentPage * pagination.pageSize
)
"
:columns="columns"
:pagination="pagination"
@page-size-change="onSizeChange"
@page-current-change="onCurrentChange"
/>
</template>

View File

@@ -0,0 +1,73 @@
import { ref } from "vue";
import { tableDataDrag } from "../data";
import { clone } from "@pureadmin/utils";
import { message } from "@/utils/message";
import { CustomMouseMenu } from "@howdyjs/mouse-menu";
export function useColumns() {
const dataList = ref(clone(tableDataDrag, true));
const columns: TableColumnList = [
{
label: "ID",
prop: "id"
},
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
}
];
// 配置参考https://kongfandong.cn/howdy/mouse-menu/readme
const menuOptions = {
menuList: [
{
label: ({ id }) => `ID为${id}`,
disabled: true
},
{
label: "修改",
tips: "Edit",
fn: row =>
message(
`您修改了第 ${
dataList.value.findIndex(v => v.id === row.id) + 1
} 行,数据为:${JSON.stringify(row)}`,
{
type: "success"
}
)
}
]
};
function showMouseMenu(row, column, event) {
event.preventDefault();
const { x, y } = event;
const ctx = CustomMouseMenu({
el: event.currentTarget,
params: row,
// 菜单容器的CSS设置
menuWrapperCss: {
background: "var(--el-bg-color)"
},
menuItemCss: {
labelColor: "var(--el-text-color)",
hoverLabelColor: "var(--el-color-primary)",
hoverTipsColor: "var(--el-color-primary)"
},
...menuOptions
});
ctx.show(x, y);
}
return {
columns,
dataList,
showMouseMenu
};
}

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
import { useColumns } from "./columns";
const { columns, dataList, showMouseMenu } = useColumns();
</script>
<template>
<pure-table
row-key="id"
border
:data="dataList"
:columns="columns"
@row-contextmenu="showMouseMenu"
/>
</template>

View File

@@ -0,0 +1,106 @@
import dayjs from "dayjs";
import { clone } from "@pureadmin/utils";
const date = dayjs(new Date()).format("YYYY-MM-DD");
const tableData = [
{
date,
name: "Tom",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Jack",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Dick",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Harry",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Sam",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Lucy",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Mary",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Mike",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Mike1",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Mike2",
address: "No. 189, Grove St, Los Angeles"
}
];
const tableDataMore = clone(tableData, true).map(item =>
Object.assign(item, {
state: "California",
city: "Los Angeles",
"post-code": "CA 90036"
})
);
const tableDataImage = clone(tableData, true).map((item, index) =>
Object.assign(item, {
image: `https://pure-admin.github.io/pure-admin-table/imgs/${index + 1}.jpg`
})
);
const tableDataSortable = clone(tableData, true).map((item, index) => {
delete item.date;
Object.assign(item, {
date: `${dayjs(new Date()).format("YYYY-MM")}-${index + 1}`
});
});
const tableDataDrag = clone(tableData, true).map((item, index) => {
delete item.address;
delete item.date;
return Object.assign(item, {
id: index + 1,
date: `${dayjs(new Date()).format("YYYY-MM")}-${index + 1}`
});
});
const tableDataEdit = clone(tableData, true).map((item, index) => {
delete item.date;
return Object.assign(item, {
id: index + 1,
date: `${dayjs(new Date()).format("YYYY-MM")}-${index + 1}`,
address: "China",
sex: index % 2 === 0 ? "男" : "女"
});
});
export {
tableData,
tableDataDrag,
tableDataMore,
tableDataEdit,
tableDataImage,
tableDataSortable
};

View File

@@ -0,0 +1,69 @@
import Sortable from "sortablejs";
import { clone } from "@pureadmin/utils";
import { tableDataDrag } from "../../data";
import { ref, nextTick, onMounted } from "vue";
// 列拖拽演示
export function useColumns() {
const dataList = ref(clone(tableDataDrag, true));
const columnsDrag = ref<TableColumnList>([
{
label: "ID",
prop: "id"
},
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
}
]);
const columns = ref<TableColumnList>([
{
label: "ID",
prop: index => columnsDrag.value[index].prop as string
},
{
label: "日期",
prop: index => columnsDrag.value[index].prop as string
},
{
label: "姓名",
prop: index => columnsDrag.value[index].prop as string
}
]);
const columnDrop = (event: { preventDefault: () => void }) => {
event.preventDefault();
nextTick(() => {
const wrapper: HTMLElement = document.querySelector(
".el-table__header-wrapper tr"
);
Sortable.create(wrapper, {
animation: 300,
delay: 0,
onEnd: ({ newIndex, oldIndex }) => {
const oldItem = columnsDrag.value[oldIndex];
columnsDrag.value.splice(oldIndex, 1);
columnsDrag.value.splice(newIndex, 0, oldItem);
}
});
});
};
onMounted(() => {
nextTick(() => {
columnDrop(event);
});
});
return {
columns,
dataList,
columnsDrag
};
}

View File

@@ -0,0 +1,16 @@
<script setup lang="ts">
import { useColumns } from "./columns";
const { columns, dataList, columnsDrag } = useColumns();
</script>
<template>
<div class="flex">
<el-scrollbar height="700px">
<code>
<pre class="w-[700px]"> {{ columnsDrag }}</pre>
</code>
</el-scrollbar>
<pure-table row-key="id" :data="dataList" :columns="columns" />
</div>
</template>

View File

@@ -0,0 +1,70 @@
import Sortable from "sortablejs";
import { ref, nextTick } from "vue";
import { clone } from "@pureadmin/utils";
import { tableDataDrag } from "../../data";
// 行拖拽演示
export function useColumns() {
const dataList = ref(clone(tableDataDrag, true));
const rowDrop = (event: { preventDefault: () => void }) => {
event.preventDefault();
nextTick(() => {
const wrapper: HTMLElement = document.querySelector(
".el-table__body-wrapper tbody"
);
Sortable.create(wrapper, {
animation: 300,
handle: ".drag-btn",
onEnd: ({ newIndex, oldIndex }) => {
const currentRow = dataList.value.splice(oldIndex, 1)[0];
dataList.value.splice(newIndex, 0, currentRow);
}
});
});
};
const columns: TableColumnList = [
// {
// width: 60,
// cellRenderer: () => (
// <iconify-icon-online
// icon="icon-park-outline:drag"
// class="drag-btn cursor-grab"
// onMouseenter={(event: { preventDefault: () => void }) =>
// rowDrop(event)
// }
// />
// )
// },
{
label: "ID",
prop: "id",
cellRenderer: ({ row }) => (
<div class="flex items-center">
<iconify-icon-online
icon="icon-park-outline:drag"
class="drag-btn cursor-grab"
onMouseenter={(event: { preventDefault: () => void }) =>
rowDrop(event)
}
/>
<p class="ml-[16px]">{row.id}</p>
</div>
)
},
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
}
];
return {
columns,
dataList
};
}

View File

@@ -0,0 +1,16 @@
<script setup lang="ts">
import { useColumns } from "./columns";
const { columns, dataList } = useColumns();
</script>
<template>
<div class="flex">
<el-scrollbar height="700px">
<code>
<pre class="w-[700px]"> {{ dataList }}</pre>
</code>
</el-scrollbar>
<pure-table row-key="id" :data="dataList" :columns="columns" />
</div>
</template>

View File

@@ -0,0 +1,83 @@
import { ref, computed } from "vue";
import { tableDataDrag } from "../data";
import { message } from "@/utils/message";
import { templateRef } from "@vueuse/core";
import { clone, useDark, useECharts } from "@pureadmin/utils";
export function useColumns() {
const dataList = ref(clone(tableDataDrag, true).splice(0, 4));
const columns: TableColumnList = [
{
label: "ID",
prop: "id"
},
{
label: "姓名",
prop: "name"
},
{
label: "日期",
prop: "date"
},
{
label: "echarts图表",
slot: "echart"
}
];
const { isDark } = useDark();
const theme = computed(() => (isDark.value ? "dark" : "light"));
dataList.value.forEach((_, i) => {
const { setOptions } = useECharts(templateRef(`PieChartRef${i}`), {
theme
});
setOptions(
{
tooltip: {
trigger: "item",
// 将 tooltip 控制在图表区域里
confine: true
},
series: [
{
name: "Github信息",
type: "pie",
// center: ["30%", "50%"],
data: [
{ value: 1067, name: "watchers" },
{ value: 4037, name: "star" },
{ value: 859, name: "forks" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
},
{
name: "click",
callback: ({ data: { name, value } }) => {
message(
`您点击了第 ${i + 1} 行,图表标题为${name},图表数据为:${value}`,
{
type: "success"
}
);
}
}
);
});
return {
columns,
dataList
};
}

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
import { useColumns } from "./columns";
const { columns, dataList } = useColumns();
</script>
<template>
<pure-table row-key="id" border :data="dataList" :columns="columns">
<template #echart="{ index }">
<div :ref="'PieChartRef' + index" class="w-full h-[100px]" />
</template>
</pure-table>
</template>

View File

@@ -0,0 +1,52 @@
import { ref } from "vue";
import { utils, writeFile } from "xlsx";
import { tableDataDrag } from "../data";
import { clone } from "@pureadmin/utils";
import { message } from "@/utils/message";
export function useColumns() {
const dataList = ref(clone(tableDataDrag, true));
const columns: TableColumnList = [
{
label: "ID",
prop: "id"
},
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
}
];
const exportExcel = () => {
const res = dataList.value.map(item => {
const arr = [];
columns.forEach(column => {
arr.push(item[column.prop as string]);
});
return arr;
});
const titleList = [];
columns.forEach(column => {
titleList.push(column.label);
});
res.unshift(titleList);
const workSheet = utils.aoa_to_sheet(res);
const workBook = utils.book_new();
utils.book_append_sheet(workBook, workSheet, "数据报表");
writeFile(workBook, "pure-admin-table.xlsx");
message("导出成功", {
type: "success"
});
};
return {
columns,
dataList,
exportExcel
};
}

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import { useColumns } from "./columns";
const { columns, dataList, exportExcel } = useColumns();
</script>
<template>
<div>
<el-button
type="primary"
class="mb-[20px] float-right"
@click="exportExcel"
>
导出
</el-button>
<pure-table row-key="id" border :data="dataList" :columns="columns" />
</div>
</template>

View File

@@ -0,0 +1,76 @@
import Adaptive from "./adaptive/index.vue";
import Page from "./page/index.vue";
import RowDrag from "./drag/row/index.vue";
import ColumnDrag from "./drag/column/index.vue";
import Contextmenu from "./contextmenu/index.vue";
import Excel from "./excel/index.vue";
import Watermark from "./watermark/index.vue";
import Print from "./prints/index.vue";
import Echarts from "./echarts/index.vue";
import TableSelect from "./table-select/index.vue";
const rendContent = (val: string) =>
`代码位置src/views/table/high/${val}/index.vue`;
export const list = [
{
key: "adaptive",
content: rendContent("adaptive"),
title: "自适应内容区高度",
component: Adaptive
},
{
key: "page",
content: rendContent("page"),
title: "分页、加载动画、动态列",
component: Page
},
{
key: "tableSelect",
content: rendContent("table-select"),
title: "表格选择器",
component: TableSelect
},
{
key: "rowDrag",
content: rendContent("drag/row"),
title: "拖拽表格(行拖拽)",
component: RowDrag
},
{
key: "columnDrag",
content: rendContent("drag/column"),
title: "拖拽表格(列拖拽)",
component: ColumnDrag
},
{
key: "contextmenu",
content: rendContent("contextmenu"),
title: "右键菜单",
component: Contextmenu
},
{
key: "excel",
content: rendContent("excel"),
title: "导出excel",
component: Excel
},
{
key: "print",
content: rendContent("print"),
title: "打印",
component: Print
},
{
key: "watermark",
content: rendContent("watermark"),
title: "水印",
component: Watermark
},
{
key: "echarts",
content: rendContent("echarts"),
title: "内嵌echarts图表",
component: Echarts
}
];

View File

@@ -0,0 +1,116 @@
import { tableData } from "../data";
import { clone, delay } from "@pureadmin/utils";
import { ref, onMounted, reactive, watchEffect } from "vue";
import type { PaginationProps, LoadingConfig, Align } from "@pureadmin/table";
export function useColumns() {
const dataList = ref([]);
const loading = ref(true);
const select = ref("no");
const hideVal = ref("nohide");
const tableSize = ref("default");
const paginationSmall = ref(false);
const paginationAlign = ref("right");
const columns: TableColumnList = [
{
type: "selection",
align: "left",
reserveSelection: true,
hide: () => (select.value === "no" ? true : false)
},
{
label: "日期",
prop: "date",
hide: () => (hideVal.value === "hideDate" ? true : false)
},
{
label: "姓名",
prop: "name",
hide: () => (hideVal.value === "hideName" ? true : false)
},
{
label: "地址",
prop: "address",
hide: () => (hideVal.value === "hideAddress" ? true : false)
}
];
/** 分页配置 */
const pagination = reactive<PaginationProps>({
pageSize: 10,
currentPage: 1,
pageSizes: [10, 15, 20],
total: 0,
align: "right",
background: true,
small: false
});
/** 加载动画配置 */
const loadingConfig = reactive<LoadingConfig>({
text: "正在加载第一页...",
viewBox: "-10, -10, 50, 50",
spinner: `
<path class="path" d="
M 30 15
L 28 17
M 25.61 25.61
A 15 15, 0, 0, 1, 15 30
A 15 15, 0, 1, 1, 27.99 7.5
L 15 15
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
`
// svg: "",
// background: rgba()
});
function onChange(val) {
pagination.small = val;
}
function onSizeChange(val) {
console.log("onSizeChange", val);
}
function onCurrentChange(val) {
loadingConfig.text = `正在加载第${val}页...`;
loading.value = true;
delay(600).then(() => {
loading.value = false;
});
}
watchEffect(() => {
pagination.align = paginationAlign.value as Align;
});
onMounted(() => {
delay(600).then(() => {
const newList = [];
Array.from({ length: 6 }).forEach(() => {
newList.push(clone(tableData, true));
});
newList.flat(Infinity).forEach((item, index) => {
dataList.value.push({ id: index, ...item });
});
pagination.total = dataList.value.length;
loading.value = false;
});
});
return {
loading,
columns,
dataList,
select,
hideVal,
tableSize,
pagination,
loadingConfig,
paginationAlign,
paginationSmall,
onChange,
onSizeChange,
onCurrentChange
};
}

View File

@@ -0,0 +1,80 @@
<script setup lang="ts">
import { useColumns } from "./columns";
const {
loading,
columns,
dataList,
select,
hideVal,
tableSize,
pagination,
loadingConfig,
paginationAlign,
paginationSmall,
onChange,
onSizeChange,
onCurrentChange
} = useColumns();
</script>
<template>
<div>
<el-space class="float-right mb-4">
<p class="text-sm">多选</p>
<el-radio-group v-model="select" size="small">
<el-radio-button value="yes"></el-radio-button>
<el-radio-button value="no"></el-radio-button>
</el-radio-group>
<el-divider direction="vertical" />
<p class="text-sm">动态列</p>
<el-radio-group v-model="hideVal" size="small">
<el-radio-button value="nohide">不隐藏</el-radio-button>
<el-radio-button value="hideDate">隐藏日期</el-radio-button>
<el-radio-button value="hideName">隐藏姓名</el-radio-button>
<el-radio-button value="hideAddress">隐藏地址</el-radio-button>
</el-radio-group>
<el-divider direction="vertical" />
<p class="text-sm">表格大小</p>
<el-radio-group v-model="tableSize" size="small">
<el-radio-button value="large">large</el-radio-button>
<el-radio-button value="default">default</el-radio-button>
<el-radio-button value="small">small</el-radio-button>
</el-radio-group>
<el-divider direction="vertical" />
<p class="text-sm">分页大小</p>
<el-radio-group v-model="paginationSmall" size="small" @change="onChange">
<el-radio-button :value="false">no small</el-radio-button>
<el-radio-button :value="true">small</el-radio-button>
</el-radio-group>
<el-divider direction="vertical" />
<p class="text-sm">分页的对齐方式</p>
<el-radio-group v-model="paginationAlign" size="small">
<el-radio-button value="right">right</el-radio-button>
<el-radio-button value="center">center</el-radio-button>
<el-radio-button value="left">left</el-radio-button>
</el-radio-group>
</el-space>
<pure-table
border
row-key="id"
alignWhole="center"
showOverflowTooltip
:size="tableSize as any"
:loading="loading"
:loading-config="loadingConfig"
:height="tableSize === 'small' ? 352 : 440"
:data="
dataList.slice(
(pagination.currentPage - 1) * pagination.pageSize,
pagination.currentPage * pagination.pageSize
)
"
:columns="columns"
:pagination="pagination"
@page-size-change="onSizeChange"
@page-current-change="onCurrentChange"
/>
</div>
</template>

View File

@@ -0,0 +1,60 @@
import Print from "@/utils/print";
import { ref, type Ref } from "vue";
import { tableDataEdit } from "../data";
import { clone } from "@pureadmin/utils";
export function useColumns(printRef: Ref) {
const dataList = ref(clone(tableDataEdit, true));
const columns: TableColumnList = [
{
label: "ID",
prop: "id"
},
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
];
const print = () => {
Print(printRef.value.getTableDoms().tableWrapper).toPrint;
};
function cellStyle({ column: { property }, rowIndex }) {
if (property === "id") {
return rowIndex < 3
? { background: "#87baf9" }
: { background: "#87e8de" };
}
}
function headerCellStyle({ columnIndex }) {
return columnIndex === 0
? { background: "#f3b2d0" }
: { background: "#fafafa" };
}
function rowStyle({ rowIndex }) {
return rowIndex % 2 === 1
? { background: "#ffa39e" }
: { background: "#91d5ff" };
}
return {
columns,
dataList,
print,
rowStyle,
cellStyle,
headerCellStyle
};
}

View File

@@ -0,0 +1,28 @@
<script setup lang="ts">
import { ref } from "vue";
import { useColumns } from "./columns";
const printRef = ref();
const { columns, dataList, print, cellStyle, rowStyle, headerCellStyle } =
useColumns(printRef);
</script>
<template>
<div>
<el-button type="primary" class="mb-[20px] float-right" @click="print">
打印
</el-button>
<!-- rowHoverBgColor="transparent" 鼠标经过行时去掉行的背景色 -->
<pure-table
ref="printRef"
rowHoverBgColor="transparent"
row-key="id"
border
:data="dataList"
:columns="columns"
:row-style="rowStyle"
:cell-style="cellStyle"
:header-cell-style="headerCellStyle"
/>
</div>
</template>

View File

@@ -0,0 +1,20 @@
<script setup lang="ts">
import { ref } from "vue";
import radioSelectTable from "./radio/index.vue";
import multipleSelectTable from "./multiple/index.vue";
const model = ref("radio");
</script>
<template>
<el-space>
<el-radio-group v-model="model">
<el-radio-button value="radio">单选</el-radio-button>
<el-radio-button value="multiple">多选</el-radio-button>
</el-radio-group>
<el-divider direction="vertical" />
<component
:is="model === 'radio' ? radioSelectTable : multipleSelectTable"
/>
</el-space>
</template>

View File

@@ -0,0 +1,142 @@
import { message } from "@/utils/message";
import { tableDataEdit } from "../../data";
import type { PaginationProps } from "@pureadmin/table";
import { cloneDeep, isAllEmpty } from "@pureadmin/utils";
import { type Ref, ref, reactive, watch, nextTick } from "vue";
export function useColumns(selectRef: Ref, formRef: Ref, tableRef: Ref) {
const tableData = ref(tableDataEdit);
const cloneTableData = cloneDeep(tableData.value);
const selectValue = ref([1, 3, 4]);
const searchForm = reactive({
sexValue: "",
searchDate: ""
});
const sexOptions = [
{
value: 0,
label: "男"
},
{
value: 1,
label: "女"
}
];
const columns: TableColumnList = [
{
type: "selection",
reserveSelection: true,
align: "left"
},
{
label: "ID",
prop: "id",
width: 50
},
{
label: "姓名",
prop: "name"
},
{
label: "性别",
prop: "sex"
},
{
label: "地址",
prop: "address"
},
{
label: "日期",
prop: "date",
minWidth: 120
}
];
/** 分页配置 */
const pagination = reactive<PaginationProps>({
pageSize: 5,
currentPage: 1,
layout: "prev, pager, next",
total: tableData.value.length,
background: true,
small: true
});
const handleSelectionChange = val => {
const arr = [];
val.forEach(v => {
arr.push({ label: v.name, id: v.id });
});
selectValue.value = arr;
};
const onSearch = () => {
tableData.value = cloneTableData;
if (!isAllEmpty(searchForm.sexValue)) {
let sex = sexOptions
.map(sex => sex.value === Number(searchForm.sexValue) && sex.label)
.filter(Boolean)[0];
tableData.value = tableData.value.filter(data => data.sex === sex);
}
if (!isAllEmpty(searchForm.searchDate)) {
tableData.value = tableData.value.filter(
data => data.date === searchForm.searchDate
);
}
pagination.total = tableData.value.length;
};
const onReset = () => {
formRef.value.resetFields();
onClear();
tableData.value = cloneTableData;
pagination.total = tableData.value.length;
};
const removeTag = ({ id }) => {
const { toggleRowSelection } = tableRef.value.getTableRef();
toggleRowSelection(tableData.value.filter(v => v.id == id)?.[0], false);
};
const onClear = () => {
const { clearSelection } = tableRef.value.getTableRef();
clearSelection();
};
const onSure = () => {
selectRef.value.blur();
message(`当前选中的数据为:${JSON.stringify(selectValue.value)}`, {
type: "success"
});
};
watch(
selectValue,
async () => {
await nextTick();
const { toggleRowSelection } = tableRef.value.getTableRef();
selectValue.value.forEach(val => {
tableData.value.forEach(row => {
// 默认回显
row.id === val ? toggleRowSelection(row) : undefined;
});
});
},
{ immediate: true }
);
return {
searchForm,
sexOptions,
columns,
pagination,
selectValue,
tableData,
onSure,
onClear,
onReset,
onSearch,
removeTag,
handleSelectionChange
};
}

View File

@@ -0,0 +1,107 @@
<script setup lang="ts">
import { ref } from "vue";
import { useColumns } from "./columns";
const formRef = ref();
const tableRef = ref();
const selectRef = ref();
const {
searchForm,
sexOptions,
columns,
pagination,
selectValue,
tableData,
onSure,
onClear,
onReset,
onSearch,
removeTag,
handleSelectionChange
} = useColumns(selectRef, formRef, tableRef);
</script>
<template>
<el-select
ref="selectRef"
v-model="selectValue"
class="!w-[200px]"
placeholder="请选择"
clearable
multiple
collapse-tags
value-key="id"
@remove-tag="removeTag"
@clear="onClear"
>
<template #empty>
<div class="m-4">
<!-- <el-config-provider size="small"> -->
<el-form ref="formRef" :inline="true" :model="searchForm">
<el-form-item prop="sexValue">
<el-select
v-model="searchForm.sexValue"
class="!w-[120px]"
placeholder="请选择性别"
:teleported="false"
clearable
>
<el-option
v-for="item in sexOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item prop="searchDate">
<el-date-picker
v-model="searchForm.searchDate"
class="!w-[150px]"
type="date"
placeholder="请选择日期"
format="YYYY/MM/DD"
value-format="YYYY-MM-D"
/>
</el-form-item>
<el-form-item class="float-right !mr-0">
<el-button type="primary" text bg @click="onSearch">
查询
</el-button>
<el-button text bg @click="onReset"> 重置 </el-button>
</el-form-item>
</el-form>
<pure-table
ref="tableRef"
row-key="id"
alignWhole="center"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:data="
tableData.slice(
(pagination.currentPage - 1) * pagination.pageSize,
pagination.currentPage * pagination.pageSize
)
"
:columns="columns"
:pagination="pagination"
@selection-change="handleSelectionChange"
/>
<el-button
class="absolute bottom-[25px] left-[20px]"
type="primary"
size="small"
text
bg
@click="onSure"
>
确定
</el-button>
<!-- </el-config-provider> -->
</div>
</template>
</el-select>
</template>

View File

@@ -0,0 +1,62 @@
import { message } from "@/utils/message";
import { tableDataEdit } from "../../data";
import { ref, reactive, type Ref } from "vue";
import type { PaginationProps } from "@pureadmin/table";
export function useColumns(selectRef: Ref) {
const selectValue = ref("");
const columns: TableColumnList = [
{
label: "ID",
prop: "id",
width: 80
},
{
label: "日期",
prop: "date",
minWidth: 120
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
];
/** 分页配置 */
const pagination = reactive<PaginationProps>({
pageSize: 5,
currentPage: 1,
layout: "prev, pager, next",
total: tableDataEdit.length,
background: true,
small: true
});
/** 高亮当前选中行 */
function rowStyle({ row: { name } }) {
return {
cursor: "pointer",
background: name === selectValue.value ? "var(--el-fill-color-light)" : ""
};
}
/** 行点击 */
function onRowClick(row) {
selectValue.value = row.name;
selectRef.value.blur();
message(`当前选中行的数据为:${JSON.stringify(row)}`, { type: "success" });
}
return {
columns,
pagination,
selectValue,
tableDataEdit,
rowStyle,
onRowClick
};
}

View File

@@ -0,0 +1,48 @@
<script setup lang="ts">
import { ref } from "vue";
import { useColumns } from "./columns";
const selectRef = ref();
const {
columns,
pagination,
selectValue,
tableDataEdit,
rowStyle,
onRowClick
} = useColumns(selectRef);
</script>
<template>
<el-select
ref="selectRef"
v-model="selectValue"
class="!w-[200px]"
placeholder="请选择"
value-key="id"
clearable
>
<template #empty>
<div class="m-4">
<pure-table
row-key="id"
alignWhole="center"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:row-style="rowStyle"
:data="
tableDataEdit.slice(
(pagination.currentPage - 1) * pagination.pageSize,
pagination.currentPage * pagination.pageSize
)
"
:columns="columns"
:pagination="pagination"
@row-click="onRowClick"
/>
</div>
</template>
</el-select>
</template>

View File

@@ -0,0 +1,47 @@
import { tableDataEdit } from "../data";
import { ref, onMounted, type Ref } from "vue";
import { clone, useWatermark, delay } from "@pureadmin/utils";
export function useColumns(waterRef: Ref) {
const dataList = ref(clone(tableDataEdit, true));
const columns: TableColumnList = [
{
label: "ID",
prop: "id"
},
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
];
onMounted(() => {
delay().then(() => {
// https://pure-admin-utils.netlify.app/hooks/useWatermark/useWatermark.html
const { setWatermark } = useWatermark(
waterRef.value.getTableDoms().tableWrapper
);
setWatermark("编程即艺术", {
font: "16px Microsoft YaHei",
globalAlpha: 0.8,
forever: true,
width: 240,
height: 90
});
});
});
return {
columns,
dataList
};
}

View File

@@ -0,0 +1,17 @@
<script setup lang="ts">
import { ref } from "vue";
import { useColumns } from "./columns";
const waterRef = ref();
const { columns, dataList } = useColumns(waterRef);
</script>
<template>
<pure-table
ref="waterRef"
row-key="id"
border
:data="dataList"
:columns="columns"
/>
</template>