From cc7726e1c2e8fab2e7a8c90ab5b9341cfed740eb Mon Sep 17 00:00:00 2001 From: xiaoming <1923740402@qq.com> Date: Thu, 2 May 2024 21:34:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E7=BB=84=E4=BB=B6`ReVxeTableB?= =?UTF-8?q?ar`=E6=90=AD=E9=85=8D`vxe-table`=E4=BD=BF=E7=94=A8=20(#1087)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/svg => assets/table-bar}/collapse.svg | 0 .../src/svg => assets/table-bar}/drag.svg | 0 .../src/svg => assets/table-bar}/expand.svg | 0 .../src/svg => assets/table-bar}/refresh.svg | 0 .../src/svg => assets/table-bar}/settings.svg | 0 src/components/RePureTableBar/src/bar.tsx | 10 +- src/components/ReVxeTableBar/index.ts | 5 + src/components/ReVxeTableBar/src/bar.tsx | 362 ++++++++++++++++++ src/plugins/vxeTable.ts | 12 +- src/views/table/virtual/list.tsx | 11 +- src/views/table/virtual/list.vue | 51 ++- src/views/table/virtual/pageList.vue | 86 +++++ src/views/table/virtual/treeList.vue | 77 ++-- 13 files changed, 546 insertions(+), 68 deletions(-) rename src/{components/RePureTableBar/src/svg => assets/table-bar}/collapse.svg (100%) rename src/{components/RePureTableBar/src/svg => assets/table-bar}/drag.svg (100%) rename src/{components/RePureTableBar/src/svg => assets/table-bar}/expand.svg (100%) rename src/{components/RePureTableBar/src/svg => assets/table-bar}/refresh.svg (100%) rename src/{components/RePureTableBar/src/svg => assets/table-bar}/settings.svg (100%) create mode 100644 src/components/ReVxeTableBar/index.ts create mode 100644 src/components/ReVxeTableBar/src/bar.tsx create mode 100644 src/views/table/virtual/pageList.vue diff --git a/src/components/RePureTableBar/src/svg/collapse.svg b/src/assets/table-bar/collapse.svg similarity index 100% rename from src/components/RePureTableBar/src/svg/collapse.svg rename to src/assets/table-bar/collapse.svg diff --git a/src/components/RePureTableBar/src/svg/drag.svg b/src/assets/table-bar/drag.svg similarity index 100% rename from src/components/RePureTableBar/src/svg/drag.svg rename to src/assets/table-bar/drag.svg diff --git a/src/components/RePureTableBar/src/svg/expand.svg b/src/assets/table-bar/expand.svg similarity index 100% rename from src/components/RePureTableBar/src/svg/expand.svg rename to src/assets/table-bar/expand.svg diff --git a/src/components/RePureTableBar/src/svg/refresh.svg b/src/assets/table-bar/refresh.svg similarity index 100% rename from src/components/RePureTableBar/src/svg/refresh.svg rename to src/assets/table-bar/refresh.svg diff --git a/src/components/RePureTableBar/src/svg/settings.svg b/src/assets/table-bar/settings.svg similarity index 100% rename from src/components/RePureTableBar/src/svg/settings.svg rename to src/assets/table-bar/settings.svg diff --git a/src/components/RePureTableBar/src/bar.tsx b/src/components/RePureTableBar/src/bar.tsx index 6157852492..7f5efd1832 100644 --- a/src/components/RePureTableBar/src/bar.tsx +++ b/src/components/RePureTableBar/src/bar.tsx @@ -18,11 +18,11 @@ import { getKeyList } from "@pureadmin/utils"; -import DragIcon from "./svg/drag.svg?component"; -import ExpandIcon from "./svg/expand.svg?component"; -import RefreshIcon from "./svg/refresh.svg?component"; -import SettingIcon from "./svg/settings.svg?component"; -import CollapseIcon from "./svg/collapse.svg?component"; +import DragIcon from "@/assets/table-bar/drag.svg?component"; +import ExpandIcon from "@/assets/table-bar/expand.svg?component"; +import RefreshIcon from "@/assets/table-bar/refresh.svg?component"; +import SettingIcon from "@/assets/table-bar/settings.svg?component"; +import CollapseIcon from "@/assets/table-bar/collapse.svg?component"; const props = { /** 头部最左边的标题 */ diff --git a/src/components/ReVxeTableBar/index.ts b/src/components/ReVxeTableBar/index.ts new file mode 100644 index 0000000000..6ffa7e23ae --- /dev/null +++ b/src/components/ReVxeTableBar/index.ts @@ -0,0 +1,5 @@ +import vxeTableBar from "./src/bar"; +import { withInstall } from "@pureadmin/utils"; + +/** 配合 `vxe-table` 实现快速便捷的表格操作 */ +export const VxeTableBar = withInstall(vxeTableBar); diff --git a/src/components/ReVxeTableBar/src/bar.tsx b/src/components/ReVxeTableBar/src/bar.tsx new file mode 100644 index 0000000000..f2c9ba13de --- /dev/null +++ b/src/components/ReVxeTableBar/src/bar.tsx @@ -0,0 +1,362 @@ +import Sortable from "sortablejs"; +import { transformI18n } from "@/plugins/i18n"; +import { useEpThemeStoreHook } from "@/store/modules/epTheme"; +import { delay, cloneDeep, getKeyList } from "@pureadmin/utils"; +import { + type PropType, + ref, + unref, + computed, + nextTick, + defineComponent, + getCurrentInstance +} from "vue"; + +import DragIcon from "@/assets/table-bar/drag.svg?component"; +import ExpandIcon from "@/assets/table-bar/expand.svg?component"; +import RefreshIcon from "@/assets/table-bar/refresh.svg?component"; +import SettingIcon from "@/assets/table-bar/settings.svg?component"; +import CollapseIcon from "@/assets/table-bar/collapse.svg?component"; + +const props = { + /** 头部最左边的标题 */ + title: { + type: String, + default: "列表" + }, + vxeTableRef: { + type: Object as PropType + }, + /** 需要展示的列 */ + columns: { + type: Array as PropType, + default: () => [] + }, + /** 是否为树列表 */ + tree: { + type: Boolean, + default: false + }, + isExpandAll: { + type: Boolean, + default: true + }, + tableKey: { + type: [String, Number] as PropType, + default: "0" + } +}; + +export default defineComponent({ + name: "VxeTableBar", + props, + emits: ["refresh"], + setup(props, { emit, slots, attrs }) { + const size = ref("small"); + const loading = ref(false); + const checkAll = ref(true); + const isIndeterminate = ref(false); + const instance = getCurrentInstance()!; + const isExpandAll = ref(props.isExpandAll); + let checkColumnList = getKeyList(cloneDeep(props?.columns), "title"); + const checkedColumns = ref(getKeyList(cloneDeep(props?.columns), "title")); + const dynamicColumns = ref(cloneDeep(props?.columns)); + + const getDropdownItemStyle = computed(() => { + return s => { + return { + background: + s === size.value ? useEpThemeStoreHook().epThemeColor : "", + color: s === size.value ? "#fff" : "var(--el-text-color-primary)" + }; + }; + }); + + const iconClass = computed(() => { + return [ + "text-black", + "dark:text-white", + "duration-100", + "hover:!text-primary", + "cursor-pointer", + "outline-none" + ]; + }); + + const topClass = computed(() => { + return [ + "flex", + "justify-between", + "pt-[3px]", + "px-[11px]", + "border-b-[1px]", + "border-solid", + "border-[#dcdfe6]", + "dark:border-[#303030]" + ]; + }); + + function onReFresh() { + loading.value = true; + emit("refresh"); + delay(500).then(() => (loading.value = false)); + } + + function onExpand() { + isExpandAll.value = !isExpandAll.value; + isExpandAll.value + ? props.vxeTableRef.setAllTreeExpand(true) + : props.vxeTableRef.clearTreeExpand(); + props.vxeTableRef.refreshColumn(); + } + + function reloadColumn() { + const curCheckedColumns = cloneDeep(dynamicColumns.value).filter(item => + checkedColumns.value.includes(item.title) + ); + props.vxeTableRef.reloadColumn(curCheckedColumns); + } + + function handleCheckAllChange(val: boolean) { + checkedColumns.value = val ? checkColumnList : []; + isIndeterminate.value = false; + reloadColumn(); + } + + function handleCheckedColumnsChange(value: string[]) { + checkedColumns.value = value; + const checkedCount = value.length; + checkAll.value = checkedCount === checkColumnList.length; + isIndeterminate.value = + checkedCount > 0 && checkedCount < checkColumnList.length; + } + + async function onReset() { + checkAll.value = true; + isIndeterminate.value = false; + dynamicColumns.value = cloneDeep(props?.columns); + checkColumnList = []; + checkColumnList = await getKeyList(cloneDeep(props?.columns), "title"); + checkedColumns.value = getKeyList(cloneDeep(props?.columns), "title"); + props.vxeTableRef.refreshColumn(); + } + + function changeSize(curSize: string) { + size.value = curSize; + props.vxeTableRef.refreshColumn(); + } + + const dropdown = { + dropdown: () => ( + + changeSize("medium")} + > + 宽松 + + changeSize("small")} + > + 默认 + + changeSize("mini")} + > + 紧凑 + + + ) + }; + + /** 列展示拖拽排序 */ + const rowDrop = (event: { preventDefault: () => void }) => { + event.preventDefault(); + nextTick(() => { + const wrapper: HTMLElement = ( + instance?.proxy?.$refs[`VxeGroupRef${unref(props.tableKey)}`] as any + ).$el.firstElementChild; + Sortable.create(wrapper, { + animation: 300, + handle: ".drag-btn", + onEnd: ({ newIndex, oldIndex, item }) => { + const targetThElem = item; + const wrapperElem = targetThElem.parentNode as HTMLElement; + const oldColumn = dynamicColumns.value[oldIndex]; + const newColumn = dynamicColumns.value[newIndex]; + if (oldColumn?.fixed || newColumn?.fixed) { + // 当前列存在fixed属性 则不可拖拽 + const oldThElem = wrapperElem.children[oldIndex] as HTMLElement; + if (newIndex > oldIndex) { + wrapperElem.insertBefore(targetThElem, oldThElem); + } else { + wrapperElem.insertBefore( + targetThElem, + oldThElem ? oldThElem.nextElementSibling : oldThElem + ); + } + return; + } + const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0]; + dynamicColumns.value.splice(newIndex, 0, currentRow); + reloadColumn(); + } + }); + }); + }; + + const isFixedColumn = (title: string) => { + return dynamicColumns.value.filter( + item => transformI18n(item.title) === transformI18n(title) + )[0].fixed + ? true + : false; + }; + + const rendTippyProps = (content: string) => { + // https://vue-tippy.netlify.app/props + return { + content, + offset: [0, 18], + duration: [300, 0], + followCursor: true, + hideOnClick: "toggle" + }; + }; + + const reference = { + reference: () => ( + + ) + }; + + return () => ( + <> +
+
+ {slots?.title ? ( + slots.title() + ) : ( +

{props.title}

+ )} +
+ {slots?.buttons ? ( +
{slots.buttons()}
+ ) : null} + {props.tree ? ( + <> + onExpand()} + /> + + + ) : null} + onReFresh()} + /> + + + + + + + +
+ handleCheckAllChange(value)} + /> + onReset()}> + 重置 + +
+ +
+ + handleCheckedColumnsChange(value)} + > + + {checkColumnList.map((item, index) => { + return ( +
+ void; + }) => rowDrop(event)} + /> + + + {transformI18n(item)} + + +
+ ); + })} +
+
+
+
+
+
+
+ {slots.default({ + size: size.value, + dynamicColumns: dynamicColumns.value + })} +
+ + ); + } +}); diff --git a/src/plugins/vxeTable.ts b/src/plugins/vxeTable.ts index 17bbc64b6f..4bd58d1143 100644 --- a/src/plugins/vxeTable.ts +++ b/src/plugins/vxeTable.ts @@ -20,11 +20,12 @@ import { // 可选组件 Icon, Column, + Grid, + Pager, + Select, // Colgroup, - // Grid, // Tooltip, // Toolbar, - // Pager, // Form, // FormItem, // FormGather, @@ -35,7 +36,6 @@ import { // RadioButton, // Switch, // Input, - // Select, // Optgroup, // Option, // Textarea, @@ -76,11 +76,12 @@ export function useVxeTable(app: App) { // 可选组件 .use(Icon) .use(Column) + .use(Grid) + .use(Pager) + .use(Select) // .use(Colgroup) - // .use(Grid) // .use(Tooltip) // .use(Toolbar) - // .use(Pager) // .use(Form) // .use(FormItem) // .use(FormGather) @@ -91,7 +92,6 @@ export function useVxeTable(app: App) { // .use(RadioButton) // .use(Switch) // .use(Input) - // .use(Select) // .use(Optgroup) // .use(Option) // .use(Textarea) diff --git a/src/views/table/virtual/list.tsx b/src/views/table/virtual/list.tsx index b2be0568fc..f4c5f43c99 100644 --- a/src/views/table/virtual/list.tsx +++ b/src/views/table/virtual/list.tsx @@ -1,5 +1,6 @@ import List from "./list.vue"; import TreeList from "./treeList.vue"; +import PageList from "./pageList.vue"; const rendContent = (val: string) => `代码位置:src/views/table/virtual/${val}.vue`; @@ -8,13 +9,19 @@ export const list = [ { key: "list", content: rendContent("list"), - title: "虚拟列表", + title: "虚拟表格", component: List }, { key: "treeList", content: rendContent("treeList"), - title: "虚拟树", + title: "虚拟树形表格", component: TreeList + }, + { + key: "pageList", + content: rendContent("pageList"), + title: "分页表格", + component: PageList } ]; diff --git a/src/views/table/virtual/list.vue b/src/views/table/virtual/list.vue index 3177d39e85..3316a747d1 100644 --- a/src/views/table/virtual/list.vue +++ b/src/views/table/virtual/list.vue @@ -1,9 +1,20 @@ diff --git a/src/views/table/virtual/pageList.vue b/src/views/table/virtual/pageList.vue new file mode 100644 index 0000000000..21a926f5ac --- /dev/null +++ b/src/views/table/virtual/pageList.vue @@ -0,0 +1,86 @@ + + + diff --git a/src/views/table/virtual/treeList.vue b/src/views/table/virtual/treeList.vue index 787f0f5780..696f1e0edc 100644 --- a/src/views/table/virtual/treeList.vue +++ b/src/views/table/virtual/treeList.vue @@ -1,56 +1,51 @@