From a9dbd1f7500a1cca59f54de7b0ffaa558757c58a Mon Sep 17 00:00:00 2001 From: Rocky Date: Fri, 30 May 2025 10:05:04 +0800 Subject: [PATCH 1/5] =?UTF-8?q?refactor(TableToolbar):=20TableToolbar.vue?= =?UTF-8?q?=20=E6=96=87=E4=BB=B6=E9=87=8D=E6=9E=84=E4=B8=BA=20render=20?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=87=BD=E6=95=B0=E9=A3=8E=E6=A0=BC=E4=B8=94?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=B8=B2=E6=9F=93=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/components/TableToolbar.tsx | 163 ++++++++++++++++++ .../component/component/table/constant.ts | 2 +- packages/component/component/table/index.vue | 2 +- packages/component/component/table/typing.ts | 2 + play/main.ts | 3 +- 5 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 packages/component/component/table/components/TableToolbar.tsx diff --git a/packages/component/component/table/components/TableToolbar.tsx b/packages/component/component/table/components/TableToolbar.tsx new file mode 100644 index 00000000..74158661 --- /dev/null +++ b/packages/component/component/table/components/TableToolbar.tsx @@ -0,0 +1,163 @@ +import type { PropType } from "vue"; +import type { LayTableContextType } from "../constant"; +import type { TableColumn, TableDefaultToolbar } from "../typing"; +import type { TableToolBarType } from "./types"; + +import LayRender from "@layui/component/component/_components/render"; +import LayCheckboxV2 from "@layui/component/component/checkboxV2/index.vue"; +import LayDropdown from "@layui/component/component/dropdown/index.vue"; +import LayIcon from "@layui/component/component/icon"; +import { isValueArray } from "@layui/component/utils"; +import { defineComponent, h, inject } from "vue"; +import { LAY_TABLE_CONTEXT } from "../constant"; +import { useToolBar } from "../hooks/useToolbar"; + +const clsPrefix = (cls: string) => `layui-${cls}`; + +function handleCheckChange(column: TableColumn) { + column.hide = !column.hide; +} + +const ToolbarItem = defineComponent({ + name: "ToolbarItem", + + props: { + resetParams: { + required: true, + type: Object as PropType< + Omit, "showToolbars"> & { + hierarchicalColumns: TableToolBarType["hierarchicalColumns"]; + } + >, + }, + + toolbar: { + required: true, + type: [String, Object] as PropType, + }, + }, + + setup(props) { + return () => { + const { toolbar, resetParams: { t, exportData, toolbarStyle, hierarchicalColumns } } = props; + + // filter + if (toolbar === "filter") { + return h(LayDropdown, { placement: "bottom-end" }, { + default: () => h( + "div", + { + "lay-event": true, + "class": clsPrefix("inline"), + "title": t("table.filter"), + "style": toolbarStyle(toolbar), + }, + h(LayIcon, { type: clsPrefix("icon-slider") }), + ), + + content: () => h( + "div", + { class: clsPrefix("table-tool-checkbox") }, + hierarchicalColumns[0].map((column, columnIndex) => h(LayCheckboxV2, { + skin: "primary", + key: column.key || column.type || columnIndex, + value: columnIndex, + modelValue: !column.hide, + disabled: isValueArray(column.children), + + onChange: () => handleCheckChange(column), + }, () => column.title)), + ), + }); + } + + // export + if (toolbar === "export") { + return h("div", { + "lay-event": true, + "title": t("table.export"), + "style": toolbarStyle(toolbar), + "class": clsPrefix("inline"), + + "onClick": exportData, + }, h(LayIcon, { type: clsPrefix("icon-export") })); + } + + // print + if (toolbar === "print") { + return h("div", { + "lay-event": true, + "title": t("table.print"), + "class": clsPrefix("inline"), + "style": toolbarStyle(toolbar), + + "onClick": print, + }, h(LayIcon, { type: clsPrefix("icon-print") })); + } + + // render + if (toolbar?.render) { + return toolbar.render(h, toolbar); + } + + return h("div", { + "lay-event": true, + "title": toolbar.title, + "style": toolbarStyle(toolbar), + "class": clsPrefix("inline"), + + "onClick": toolbar.onClick, + }, h(LayIcon, { type: toolbar.icon })); + }; + }, +}); + +const TableToolbar = defineComponent({ + name: "TableToolbar", + + props: { + defaultToolbar: { + required: true, + type: Array as PropType, + }, + + hierarchicalColumns: { + required: true, + type: Array as PropType, + }, + }, + + setup(props) { + const { tableSlots } = inject(LAY_TABLE_CONTEXT) as LayTableContextType; + const { showToolbars, ...resetToolBar } = useToolBar(props); + + return () => { + if (!isValueArray(showToolbars.value) && !tableSlots.toolbar) { + return null; + } + + return h("div", { class: clsPrefix("table-tool") }, [ + h("div", { class: clsPrefix("table-tool-temp") }, [ + h(LayRender, { slots: tableSlots, render: "toolbar" }), + ]), + + isValueArray(showToolbars.value) && h( + "div", + { class: "table-tool-self" }, + showToolbars.value.map((toolbar, index) => { + return h(ToolbarItem, { + toolbar, + key: index, + resetParams: { + ...resetToolBar, + hierarchicalColumns: props.hierarchicalColumns, + }, + }); + }), + ), + ]); + }; + }, +}); + +export default TableToolbar; diff --git a/packages/component/component/table/constant.ts b/packages/component/component/table/constant.ts index 0cf5c6da..1feb894d 100644 --- a/packages/component/component/table/constant.ts +++ b/packages/component/component/table/constant.ts @@ -8,7 +8,7 @@ import type { RequiredTableProps, TableEmit, TableProps } from "./typing"; export const columnsTypeList = ["radio", "checkbox", "number"]; -interface LayTableContextType { +export interface LayTableContextType { tableEmits: TableEmit; tableProps: RequiredTableProps; tableSlots: Slots; diff --git a/packages/component/component/table/index.vue b/packages/component/component/table/index.vue index b0697e32..117e1377 100644 --- a/packages/component/component/table/index.vue +++ b/packages/component/component/table/index.vue @@ -19,7 +19,7 @@ import LayEmpty from "../empty/index.vue"; import TableHeader from "./components/TableHeader.vue"; import TableMain from "./components/TableMain"; import TablePage from "./components/TablePage.vue"; -import TableToolbar from "./components/TableToolbar.vue"; +import TableToolbar from "./components/TableToolbar.tsx"; import TableTotal from "./components/TableTotal.vue"; import { LAY_TABLE_CONTEXT } from "./constant"; diff --git a/packages/component/component/table/typing.ts b/packages/component/component/table/typing.ts index 888b9556..a1e2d262 100644 --- a/packages/component/component/table/typing.ts +++ b/packages/component/component/table/typing.ts @@ -2,6 +2,7 @@ import type { RenderProps } from "@layui/component/component/_components/render" import type { PageProps } from "@layui/component/component/page/interface"; // import type { TooltipProps } from "@layui/component/component/tooltip/types"; import type { CommonAlign, Recordable } from "@layui/component/types"; +import type { h, VNode } from "vue"; export interface TableProps { id?: string; @@ -121,4 +122,5 @@ export interface TableDefaultToolbarComplex { title: string; icon: string; onClick?: () => void; + render?: (_h: typeof h, params: Record) => VNode; } diff --git a/play/main.ts b/play/main.ts index c1868e78..a5789235 100644 --- a/play/main.ts +++ b/play/main.ts @@ -1,12 +1,11 @@ import { createApp } from "vue"; import layui from "../packages/component/index"; -import layer from "../packages/layer/src/index"; // import LayJsonSchemaForm from "../packages/json-schema-form/src/index"; // import LayJsonSchemaForm from "../packages/json-schema-form/lib/json-schema-form.es.js"; // import "../packages/component/lib/index.css"; (async () => { - const apps = import.meta.glob("./src/*.vue"); + const apps = import.meta.glob(["./src/*.vue", "./src/*.tsx"]); const name = location.pathname.replace(/^\//, "") || "App"; const file = apps[`./src/${name}.vue`]; if (!file) { -- Gitee From 205172077b7ebfd12672a452a6bfbf6281036f24 Mon Sep 17 00:00:00 2001 From: Rocky Date: Fri, 30 May 2025 13:48:57 +0800 Subject: [PATCH 2/5] =?UTF-8?q?refactor(TableToolbar):=20TableToolbar.vue?= =?UTF-8?q?=20=E6=96=87=E4=BB=B6=E9=87=8D=E6=9E=84=E4=B8=BA=20render=20?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=87=BD=E6=95=B0=E9=A3=8E=E6=A0=BC=E4=B8=94?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=B8=B2=E6=9F=93=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=20v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/src/document/zh-CN/components/table.md | 5 +- .../component/table/__tests__/table.test.tsx | 69 +++++++++++++++++-- .../table/components/TableToolbar.tsx | 41 +++++------ packages/component/component/table/index.less | 15 ++++ packages/component/component/table/typing.ts | 4 +- 5 files changed, 102 insertions(+), 32 deletions(-) diff --git a/docs/src/document/zh-CN/components/table.md b/docs/src/document/zh-CN/components/table.md index b1e46ca5..f704a260 100644 --- a/docs/src/document/zh-CN/components/table.md +++ b/docs/src/document/zh-CN/components/table.md @@ -235,11 +235,11 @@ const clearSelectedKeys3 = () => { const getSelectedKeys3 = () => { layer.msg(selectedKeys3.value); -} +} const getCheckData3 = () => { layer.msg(JSON.stringify(tableRef3.value.getCheckData())); -} +} const columns3 = [ { fixed: "left", type: "checkbox", title: "复选"}, @@ -1020,6 +1020,7 @@ interface TableDefaultToolbarComplex { title: string; icon: string; onClick?: () => void; + render?: () => VNode; } ``` diff --git a/packages/component/component/table/__tests__/table.test.tsx b/packages/component/component/table/__tests__/table.test.tsx index fd33112f..bb9501c7 100644 --- a/packages/component/component/table/__tests__/table.test.tsx +++ b/packages/component/component/table/__tests__/table.test.tsx @@ -1,9 +1,10 @@ import { DOMWrapper, type VueWrapper, mount } from "@vue/test-utils"; import LayTable from "../index.vue"; import LayCheckboxV2 from "@layui/component/component/checkboxV2/index.vue"; +import Button from '@layui/component/component/button/index.vue' import { describe, expect, test, vi } from "vitest"; -import { nextTick, reactive, ref } from "vue"; +import {h, nextTick, reactive, ref} from "vue"; import { sleep } from "../../../test-utils"; describe("LayTable", () => { @@ -492,17 +493,77 @@ describe("LayTable", () => { }, }); const iconBoxs = wrapper.findAll( - ".layui-table-view .layui-table-tool-self .layui-inline" + ".layui-table-view .layui-table-tool-self .layui-space-item" ); expect(iconBoxs.length).toBe(3); - expect(iconBoxs[1].attributes().title).toBe("刷新"); + expect(iconBoxs[1].find('div').attributes().title).toBe("刷新"); - await iconBoxs[1].trigger("click"); + await iconBoxs[1].find('div').trigger("click"); expect(value).toBe(2); }); + test("default-toolbar 渲染自定义组件", async () => { + const columns = [ + { + fixed: "left" as const, + type: "checkbox", + title: "复选", + key: "checkbox", + }, + { + title: "编号", + width: "100px", + key: "id", + }, + ]; + + const dataSource = ref([ + { + id: "1", + }, + { + id: "2", + }, + ]); + + let value = 1; + + const defaultToolbars = [ + "filter", + { + render: () => h(Button, { + onClick: () => { + value++; + }, + }) + }, + ]; + + const wrapper = mount({ + setup() { + return () => ( + + ); + }, + }); + + const iconBoxs = wrapper.findAll( + ".layui-table-view .layui-table-tool-self .layui-space-item" + ); + + expect(iconBoxs[1].find('.layui-btn').attributes().type).toBe('button') + + await iconBoxs[1].find('.layui-btn').trigger("click"); + + expect(value).toBe(2) + }); + test("page change", async () => { const columns = [ { diff --git a/packages/component/component/table/components/TableToolbar.tsx b/packages/component/component/table/components/TableToolbar.tsx index 74158661..fe49208f 100644 --- a/packages/component/component/table/components/TableToolbar.tsx +++ b/packages/component/component/table/components/TableToolbar.tsx @@ -7,6 +7,7 @@ import LayRender from "@layui/component/component/_components/render"; import LayCheckboxV2 from "@layui/component/component/checkboxV2/index.vue"; import LayDropdown from "@layui/component/component/dropdown/index.vue"; import LayIcon from "@layui/component/component/icon"; +import LaySpace from "@layui/component/component/space/index.vue"; import { isValueArray } from "@layui/component/utils"; import { defineComponent, h, inject } from "vue"; import { LAY_TABLE_CONTEXT } from "../constant"; @@ -39,7 +40,7 @@ const ToolbarItem = defineComponent({ setup(props) { return () => { - const { toolbar, resetParams: { t, exportData, toolbarStyle, hierarchicalColumns } } = props; + const { toolbar, resetParams: { t, exportData, hierarchicalColumns } } = props; // filter if (toolbar === "filter") { @@ -47,10 +48,8 @@ const ToolbarItem = defineComponent({ default: () => h( "div", { - "lay-event": true, - "class": clsPrefix("inline"), - "title": t("table.filter"), - "style": toolbarStyle(toolbar), + class: clsPrefix("table-toolbar-item"), + title: t("table.filter"), }, h(LayIcon, { type: clsPrefix("icon-slider") }), ), @@ -74,39 +73,33 @@ const ToolbarItem = defineComponent({ // export if (toolbar === "export") { return h("div", { - "lay-event": true, - "title": t("table.export"), - "style": toolbarStyle(toolbar), - "class": clsPrefix("inline"), + title: t("table.export"), + class: clsPrefix("table-toolbar-item"), - "onClick": exportData, + onClick: exportData, }, h(LayIcon, { type: clsPrefix("icon-export") })); } // print if (toolbar === "print") { return h("div", { - "lay-event": true, - "title": t("table.print"), - "class": clsPrefix("inline"), - "style": toolbarStyle(toolbar), + title: t("table.print"), + class: clsPrefix("table-toolbar-item"), - "onClick": print, + onClick: print, }, h(LayIcon, { type: clsPrefix("icon-print") })); } // render if (toolbar?.render) { - return toolbar.render(h, toolbar); + return toolbar.render(); } return h("div", { - "lay-event": true, - "title": toolbar.title, - "style": toolbarStyle(toolbar), - "class": clsPrefix("inline"), + title: toolbar.title, + class: clsPrefix("table-toolbar-item"), - "onClick": toolbar.onClick, + onClick: toolbar.onClick, }, h(LayIcon, { type: toolbar.icon })); }; }, @@ -143,8 +136,8 @@ const TableToolbar = defineComponent({ isValueArray(showToolbars.value) && h( "div", - { class: "table-tool-self" }, - showToolbars.value.map((toolbar, index) => { + { class: clsPrefix("table-tool-self") }, + h(LaySpace, () => showToolbars.value.map((toolbar, index) => { return h(ToolbarItem, { toolbar, key: index, @@ -153,7 +146,7 @@ const TableToolbar = defineComponent({ hierarchicalColumns: props.hierarchicalColumns, }, }); - }), + })), ), ]); }; diff --git a/packages/component/component/table/index.less b/packages/component/component/table/index.less index 77c3ef59..b0200324 100644 --- a/packages/component/component/table/index.less +++ b/packages/component/component/table/index.less @@ -287,6 +287,21 @@ } } +.layui-table-toolbar-item { + position: relative; + width: 26px; + height: 26px; + line-height: 26px; + border-radius: var(--global-border-radius); + text-align: center; + color: #333; + border: 1px solid #ccc; + cursor: pointer; + .layui-icon { + font-size: 15px; + } +} + .layui-table-tool .layui-inline[lay-event]:hover { border: 1px solid #999; } diff --git a/packages/component/component/table/typing.ts b/packages/component/component/table/typing.ts index a1e2d262..dd2414bb 100644 --- a/packages/component/component/table/typing.ts +++ b/packages/component/component/table/typing.ts @@ -2,7 +2,7 @@ import type { RenderProps } from "@layui/component/component/_components/render" import type { PageProps } from "@layui/component/component/page/interface"; // import type { TooltipProps } from "@layui/component/component/tooltip/types"; import type { CommonAlign, Recordable } from "@layui/component/types"; -import type { h, VNode } from "vue"; +import type { VNode } from "vue"; export interface TableProps { id?: string; @@ -122,5 +122,5 @@ export interface TableDefaultToolbarComplex { title: string; icon: string; onClick?: () => void; - render?: (_h: typeof h, params: Record) => VNode; + render?: () => VNode; } -- Gitee From 0bf2b1a1c2178aa0e7ef2b1f19a3aa4ddf06244b Mon Sep 17 00:00:00 2001 From: Rocky Date: Fri, 30 May 2025 14:06:05 +0800 Subject: [PATCH 3/5] =?UTF-8?q?refactor(TableToolbar):=20TableToolbar.vue?= =?UTF-8?q?=20=E6=96=87=E4=BB=B6=E9=87=8D=E6=9E=84=E4=B8=BA=20render=20?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=87=BD=E6=95=B0=E9=A3=8E=E6=A0=BC=E4=B8=94?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=B8=B2=E6=9F=93=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=20v1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/components/TableToolbar.vue | 104 ------------------ packages/component/component/table/index.less | 4 + 2 files changed, 4 insertions(+), 104 deletions(-) delete mode 100644 packages/component/component/table/components/TableToolbar.vue diff --git a/packages/component/component/table/components/TableToolbar.vue b/packages/component/component/table/components/TableToolbar.vue deleted file mode 100644 index e549a200..00000000 --- a/packages/component/component/table/components/TableToolbar.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - diff --git a/packages/component/component/table/index.less b/packages/component/component/table/index.less index b0200324..3832042f 100644 --- a/packages/component/component/table/index.less +++ b/packages/component/component/table/index.less @@ -302,6 +302,10 @@ } } +.layui-table-toolbar-item:hover { + border: 1px solid #999; +} + .layui-table-tool .layui-inline[lay-event]:hover { border: 1px solid #999; } -- Gitee From b36060bb377fe92fce0b2fb4dfd4bb4e29f22b06 Mon Sep 17 00:00:00 2001 From: Rocky Date: Fri, 30 May 2025 16:45:50 +0800 Subject: [PATCH 4/5] =?UTF-8?q?refactor(TableToolbar):=20TableToolbar.vue?= =?UTF-8?q?=20=E6=96=87=E4=BB=B6=E9=87=8D=E6=9E=84=E4=B8=BA=20render=20?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=87=BD=E6=95=B0=E9=A3=8E=E6=A0=BC=E4=B8=94?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=B8=B2=E6=9F=93=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=20v1.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/components/TableToolbar.tsx | 20 +++++++++++++++++++ packages/component/component/table/index.vue | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/component/component/table/components/TableToolbar.tsx b/packages/component/component/table/components/TableToolbar.tsx index fe49208f..c17ecb70 100644 --- a/packages/component/component/table/components/TableToolbar.tsx +++ b/packages/component/component/table/components/TableToolbar.tsx @@ -118,6 +118,26 @@ const TableToolbar = defineComponent({ required: true, type: Array as PropType, }, + + spanMethod: { + required: true, + type: Function as PropType, + }, + + lastLevelAllColumns: { + required: true, + type: Array as PropType, + }, + + tableDataSource: { + required: true, + type: Array as PropType, + }, + + tableRef: { + required: true, + type: Object as PropType, + }, }, setup(props) { diff --git a/packages/component/component/table/index.vue b/packages/component/component/table/index.vue index 117e1377..df5f0787 100644 --- a/packages/component/component/table/index.vue +++ b/packages/component/component/table/index.vue @@ -19,7 +19,7 @@ import LayEmpty from "../empty/index.vue"; import TableHeader from "./components/TableHeader.vue"; import TableMain from "./components/TableMain"; import TablePage from "./components/TablePage.vue"; -import TableToolbar from "./components/TableToolbar.tsx"; +import TableToolbar from "./components/TableToolbar"; import TableTotal from "./components/TableTotal.vue"; import { LAY_TABLE_CONTEXT } from "./constant"; -- Gitee From 1d1f114fa953454f60ecc2e7fba48aa95a92c373 Mon Sep 17 00:00:00 2001 From: Rocky Date: Fri, 30 May 2025 17:06:30 +0800 Subject: [PATCH 5/5] =?UTF-8?q?refactor(TableToolbar):=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E9=BB=98=E8=AE=A4=E7=B4=A2=E5=BC=95=E5=90=8E=E7=BC=80?= =?UTF-8?q?=20*/index.vue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/component/table/components/TableToolbar.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/component/component/table/components/TableToolbar.tsx b/packages/component/component/table/components/TableToolbar.tsx index c17ecb70..85209d4c 100644 --- a/packages/component/component/table/components/TableToolbar.tsx +++ b/packages/component/component/table/components/TableToolbar.tsx @@ -4,10 +4,10 @@ import type { TableColumn, TableDefaultToolbar } from "../typing"; import type { TableToolBarType } from "./types"; import LayRender from "@layui/component/component/_components/render"; -import LayCheckboxV2 from "@layui/component/component/checkboxV2/index.vue"; -import LayDropdown from "@layui/component/component/dropdown/index.vue"; +import LayCheckboxV2 from "@layui/component/component/checkboxV2"; +import LayDropdown from "@layui/component/component/dropdown"; import LayIcon from "@layui/component/component/icon"; -import LaySpace from "@layui/component/component/space/index.vue"; +import LaySpace from "@layui/component/component/space"; import { isValueArray } from "@layui/component/utils"; import { defineComponent, h, inject } from "vue"; import { LAY_TABLE_CONTEXT } from "../constant"; -- Gitee