Bläddra i källkod

feat: 新增 `@pureadmin/table` 行、列拖拽示例

xiaoxian521 2 år sedan
förälder
incheckning
7472c25c0a
44 ändrade filer med 406 tillägg och 90 borttagningar
  1. 2 0
      locales/en.yaml
  2. 2 0
      locales/zh-CN.yaml
  3. 2 2
      package.json
  4. 5 5
      pnpm-lock.yaml
  5. 1 0
      src/assets/svg/hot.svg
  6. 12 6
      src/router/modules/table.ts
  7. 6 1
      src/store/modules/app.ts
  8. 1 0
      src/store/modules/types.ts
  9. 7 3
      src/views/components/draggable/index.vue
  10. 0 0
      src/views/pure-table/base/base.vue
  11. 0 0
      src/views/pure-table/base/border.vue
  12. 0 0
      src/views/pure-table/base/column-template/columns.tsx
  13. 0 0
      src/views/pure-table/base/column-template/index.vue
  14. 0 0
      src/views/pure-table/base/customIndex.vue
  15. 0 0
      src/views/pure-table/base/data.ts
  16. 0 0
      src/views/pure-table/base/expand.vue
  17. 0 0
      src/views/pure-table/base/filters.vue
  18. 0 0
      src/views/pure-table/base/fixColumn.vue
  19. 0 0
      src/views/pure-table/base/fixHeader.vue
  20. 0 0
      src/views/pure-table/base/fluidHeight.vue
  21. 0 0
      src/views/pure-table/base/groupHeader.vue
  22. 0 0
      src/views/pure-table/base/header-renderer/columns.tsx
  23. 0 0
      src/views/pure-table/base/header-renderer/index.vue
  24. 0 0
      src/views/pure-table/base/imgPreview.vue
  25. 0 0
      src/views/pure-table/base/layout.vue
  26. 23 25
      src/views/pure-table/base/list.tsx
  27. 0 0
      src/views/pure-table/base/merge.vue
  28. 0 0
      src/views/pure-table/base/multipleChoice.vue
  29. 0 0
      src/views/pure-table/base/nestProp.vue
  30. 0 0
      src/views/pure-table/base/radio.vue
  31. 0 0
      src/views/pure-table/base/sortable.vue
  32. 0 0
      src/views/pure-table/base/status.vue
  33. 0 0
      src/views/pure-table/base/stripe.vue
  34. 0 0
      src/views/pure-table/base/totalRow.vue
  35. 0 0
      src/views/pure-table/base/tree.vue
  36. 0 47
      src/views/pure-table/components/index.ts
  37. 56 0
      src/views/pure-table/high.vue
  38. 88 0
      src/views/pure-table/high/data.ts
  39. 68 0
      src/views/pure-table/high/drag/column/columns.tsx
  40. 16 0
      src/views/pure-table/high/drag/column/index.vue
  41. 69 0
      src/views/pure-table/high/drag/row/columns.tsx
  42. 16 0
      src/views/pure-table/high/drag/row/index.vue
  43. 20 0
      src/views/pure-table/high/list.tsx
  44. 12 1
      src/views/pure-table/index.vue

+ 2 - 0
locales/en.yaml

@@ -95,6 +95,8 @@ menus:
   hsExecl: Export Excel
   hsInfiniteScroll: Table Infinite Scroll
   hsdanmaku: Danmaku Components
+  hsPureTableBase: Base Usage
+  hsPureTableHigh: High Usage
 status:
   hsLoad: Loading...
 login:

+ 2 - 0
locales/zh-CN.yaml

@@ -95,6 +95,8 @@ menus:
   hsExecl: 导出Excel
   hsInfiniteScroll: 表格无限滚动
   hsdanmaku: 弹幕组件
+  hsPureTableBase: 基础用法
+  hsPureTableHigh: 高级用法
 status:
   hsLoad: 加载中...
 login:

+ 2 - 2
package.json

@@ -34,7 +34,7 @@
     "@logicflow/extension": "^1.1.30",
     "@pureadmin/components": "^1.1.0",
     "@pureadmin/descriptions": "^1.1.0",
-    "@pureadmin/table": "^1.6.0",
+    "@pureadmin/table": "^1.7.0",
     "@pureadmin/utils": "^1.6.7",
     "@vueuse/core": "^9.5.0",
     "@vueuse/motion": "2.0.0-beta.12",
@@ -107,7 +107,7 @@
     "@types/nprogress": "0.2.0",
     "@types/qrcode": "^1.4.2",
     "@types/qs": "^6.9.7",
-    "@types/sortablejs": "^1.13.0",
+    "@types/sortablejs": "^1.15.0",
     "@typescript-eslint/eslint-plugin": "^5.43.0",
     "@typescript-eslint/parser": "^5.43.0",
     "@vitejs/plugin-vue": "^3.2.0",

+ 5 - 5
pnpm-lock.yaml

@@ -20,7 +20,7 @@ specifiers:
   "@logicflow/extension": ^1.1.30
   "@pureadmin/components": ^1.1.0
   "@pureadmin/descriptions": ^1.1.0
-  "@pureadmin/table": ^1.6.0
+  "@pureadmin/table": ^1.7.0
   "@pureadmin/theme": ^2.4.0
   "@pureadmin/utils": ^1.6.7
   "@types/element-resize-detector": 1.1.3
@@ -33,7 +33,7 @@ specifiers:
   "@types/nprogress": 0.2.0
   "@types/qrcode": ^1.4.2
   "@types/qs": ^6.9.7
-  "@types/sortablejs": ^1.13.0
+  "@types/sortablejs": ^1.15.0
   "@typescript-eslint/eslint-plugin": ^5.43.0
   "@typescript-eslint/parser": ^5.43.0
   "@vitejs/plugin-vue": ^3.2.0
@@ -132,7 +132,7 @@ dependencies:
   "@logicflow/extension": 1.1.31
   "@pureadmin/components": 1.1.0_vue@3.2.45
   "@pureadmin/descriptions": 1.1.1_element-plus@2.2.22
-  "@pureadmin/table": 1.6.0_element-plus@2.2.22
+  "@pureadmin/table": 1.7.0_element-plus@2.2.22
   "@pureadmin/utils": 1.6.7_aotapuqn7htzdjltsyimavekky
   "@vueuse/core": 9.5.0_vue@3.2.45
   "@vueuse/motion": 2.0.0-beta.12_vue@3.2.45
@@ -1379,10 +1379,10 @@ packages:
       vue: 3.2.45
     dev: false
 
-  /@pureadmin/table/1.6.0_element-plus@2.2.22:
+  /@pureadmin/table/1.7.0_element-plus@2.2.22:
     resolution:
       {
-        integrity: sha512-ryTZbfkNT/PTUS6pdrq7vuHr3f74lXs6kgRHaAPz64iTZmzaeVzf27TPakf4YDEcnQ/Gw6RqlQzE71W9m+P48w==
+        integrity: sha512-6SWHJFiMf0V3L+Y5/1MZMClZo8QrOvkpLjkqeaZFO5N80Th17Nv1I4Feve6HPPS4dFBf5J0oRPr8L6OjjdaASw==
       }
     peerDependencies:
       element-plus: ^2.0.0

+ 1 - 0
src/assets/svg/hot.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="20" height="20"><path d="M428.698 107.315c-6.503 72.192-36.352 207.258-160.256 337.408 3.686-48.025-7.117-83.763-19.047-107.673-6.605-13.159-26.06-10.599-28.877 3.84-5.734 29.44-20.582 75.059-57.6 137.779-71.628 121.395-62.566 459.878 340.736 459.878S934.093 585.728 876.8 442.522c-37.376-93.44-93.952-152.525-128.82-182.324-11.417-9.779-29.132-1.945-29.593 13.056-.921 30.464-7.321 73.37-33.075 102.144-.666-52.787-38.144-208.384-202.445-296.857-23.296-12.544-51.763 2.457-54.17 28.774z" fill="#FF5D50"/><path d="M702.26 678.4c-4.2-45.056-60.673-166.554-212.634-246.426-10.599-5.58-23.092 3.124-21.504 15.002 6.246 46.848 12.953 140.493-24.064 184.73 4.044-40.397-18.125-73.83-36.66-94.31-8.396-9.217-23.552-4.66-25.497 7.68-3.533 22.322-12.851 56.268-36.557 97.945-42.086 74.035-86.989 188.672 124.57 294.656 10.956.563 22.17.87 33.74.87 11.213 0 22.068-.307 32.717-.87C694.631 878.182 709.837 759.706 702.26 678.4z" fill="#FFDF99"/></svg>

+ 12 - 6
src/router/modules/table.ts

@@ -1,10 +1,12 @@
+import { $t } from "@/plugins/i18n";
+import hot from "@/assets/svg/hot.svg?component";
 import type { RouteConfigsTable } from "/#/index";
 
 const flowChartRouter: RouteConfigsTable = {
   path: "/pure-table",
   redirect: "/pure-table/index",
   meta: {
-    icon: "mdi:table-large",
+    icon: hot,
     title: "pure-admin-table",
     rank: 4
   },
@@ -14,11 +16,15 @@ const flowChartRouter: RouteConfigsTable = {
       name: "PureTable",
       component: () => import("@/views/pure-table/index.vue"),
       meta: {
-        title: "pure-admin-table",
-        extraIcon: {
-          svg: true,
-          name: "team-iconxinpin"
-        }
+        title: $t("menus.hsPureTableBase")
+      }
+    },
+    {
+      path: "/pure-table/high",
+      name: "PureTableHigh",
+      component: () => import("@/views/pure-table/high.vue"),
+      meta: {
+        title: $t("menus.hsPureTableHigh")
       }
     }
   ]

+ 6 - 1
src/store/modules/app.ts

@@ -19,7 +19,9 @@ export const useAppStore = defineStore({
     layout:
       storageLocal.getItem<StorageConfigs>("responsive-layout")?.layout ??
       getConfig().Layout,
-    device: deviceDetection() ? "mobile" : "desktop"
+    device: deviceDetection() ? "mobile" : "desktop",
+    // 作用于 src/views/components/draggable/index.vue 页面,当离开页面并不会销毁 new Swap(),sortablejs 官网也没有提供任何销毁的 api
+    sortSwap: false
   }),
   getters: {
     getSidebarStatus() {
@@ -56,6 +58,9 @@ export const useAppStore = defineStore({
     },
     setLayout(layout) {
       this.layout = layout;
+    },
+    setSortSwap(val) {
+      this.sortSwap = val;
     }
   }
 });

+ 1 - 0
src/store/modules/types.ts

@@ -19,6 +19,7 @@ export type appType = {
   };
   layout: string;
   device: string;
+  sortSwap: boolean;
 };
 
 export type multiType = {

+ 7 - 3
src/views/components/draggable/index.vue

@@ -1,13 +1,16 @@
 <script setup lang="ts">
-import Sortable from "sortablejs";
 import { ref, onMounted } from "vue";
+import Sortable, { Swap } from "sortablejs";
 import draggable from "vuedraggable/src/vuedraggable";
+import { useAppStoreHook } from "@/store/modules/app";
 import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 
 defineOptions({
   name: "Draggable"
 });
 
+const { setSortSwap } = useAppStoreHook();
+
 const gridLists = ref<Array<Object>>([
   { grid: "cn", num: 1 },
   { grid: "cn", num: 2 },
@@ -39,7 +42,8 @@ const change = (evt): void => {
 };
 
 onMounted(() => {
-  // 使用原生sortable实现元素位置切换
+  if (!useAppStoreHook().sortSwap) Sortable.mount(new Swap());
+  setSortSwap(true);
   new Sortable(document.querySelector(".cut-container"), {
     swap: true,
     forceFallback: true,
@@ -121,7 +125,7 @@ onMounted(() => {
           <el-card>
             <template #header>
               <div class="card-header">
-                <span>拖拽实现元素位置换</span>
+                <span>拖拽实现元素位置换</span>
               </div>
             </template>
             <!-- 拖拽实现元素位置切换 -->

+ 0 - 0
src/views/pure-table/components/base.vue → src/views/pure-table/base/base.vue


+ 0 - 0
src/views/pure-table/components/border.vue → src/views/pure-table/base/border.vue


+ 0 - 0
src/views/pure-table/components/column-template/columns.tsx → src/views/pure-table/base/column-template/columns.tsx


+ 0 - 0
src/views/pure-table/components/column-template/index.vue → src/views/pure-table/base/column-template/index.vue


+ 0 - 0
src/views/pure-table/components/customIndex.vue → src/views/pure-table/base/customIndex.vue


+ 0 - 0
src/views/pure-table/components/data.ts → src/views/pure-table/base/data.ts


+ 0 - 0
src/views/pure-table/components/expand.vue → src/views/pure-table/base/expand.vue


+ 0 - 0
src/views/pure-table/components/filters.vue → src/views/pure-table/base/filters.vue


+ 0 - 0
src/views/pure-table/components/fixColumn.vue → src/views/pure-table/base/fixColumn.vue


+ 0 - 0
src/views/pure-table/components/fixHeader.vue → src/views/pure-table/base/fixHeader.vue


+ 0 - 0
src/views/pure-table/components/fluidHeight.vue → src/views/pure-table/base/fluidHeight.vue


+ 0 - 0
src/views/pure-table/components/groupHeader.vue → src/views/pure-table/base/groupHeader.vue


+ 0 - 0
src/views/pure-table/components/header-renderer/columns.tsx → src/views/pure-table/base/header-renderer/columns.tsx


+ 0 - 0
src/views/pure-table/components/header-renderer/index.vue → src/views/pure-table/base/header-renderer/index.vue


+ 0 - 0
src/views/pure-table/components/imgPreview.vue → src/views/pure-table/base/imgPreview.vue


+ 0 - 0
src/views/pure-table/components/layout.vue → src/views/pure-table/base/layout.vue


+ 23 - 25
src/views/pure-table/list.tsx → src/views/pure-table/base/list.tsx

@@ -1,30 +1,28 @@
-import {
-  Base,
-  Stripe,
-  Border,
-  Status,
-  FixHeader,
-  FixColumn,
-  FluidHeight,
-  GroupHeader,
-  Radio,
-  MultipleChoice,
-  Sortable,
-  Filters,
-  ColumnTemplate,
-  HeaderRenderer,
-  Expand,
-  TreeTable,
-  TotalRow,
-  Merge,
-  CustomIndex,
-  Layout,
-  NestProp,
-  ImgPreview
-} from "./components";
+import Base from "./base.vue";
+import Stripe from "./stripe.vue";
+import Border from "./border.vue";
+import Status from "./status.vue";
+import FixHeader from "./fixHeader.vue";
+import FixColumn from "./fixColumn.vue";
+import FluidHeight from "./fluidHeight.vue";
+import GroupHeader from "./groupHeader.vue";
+import Radio from "./radio.vue";
+import MultipleChoice from "./multipleChoice.vue";
+import Sortable from "./sortable.vue";
+import Filters from "./filters.vue";
+import ColumnTemplate from "./column-template/index.vue";
+import HeaderRenderer from "./header-renderer/index.vue";
+import Expand from "./expand.vue";
+import TreeTable from "./tree.vue";
+import TotalRow from "./totalRow.vue";
+import Merge from "./merge.vue";
+import CustomIndex from "./customIndex.vue";
+import Layout from "./layout.vue";
+import NestProp from "./nestProp.vue";
+import ImgPreview from "./imgPreview.vue";
 
 const rendContent = (val: string) =>
-  `代码位置:src/views/pure-table/components/${val}.vue`;
+  `代码位置:src/views/pure-table/base/${val}.vue`;
 
 export const list = [
   {

+ 0 - 0
src/views/pure-table/components/merge.vue → src/views/pure-table/base/merge.vue


+ 0 - 0
src/views/pure-table/components/multipleChoice.vue → src/views/pure-table/base/multipleChoice.vue


+ 0 - 0
src/views/pure-table/components/nestProp.vue → src/views/pure-table/base/nestProp.vue


+ 0 - 0
src/views/pure-table/components/radio.vue → src/views/pure-table/base/radio.vue


+ 0 - 0
src/views/pure-table/components/sortable.vue → src/views/pure-table/base/sortable.vue


+ 0 - 0
src/views/pure-table/components/status.vue → src/views/pure-table/base/status.vue


+ 0 - 0
src/views/pure-table/components/stripe.vue → src/views/pure-table/base/stripe.vue


+ 0 - 0
src/views/pure-table/components/totalRow.vue → src/views/pure-table/base/totalRow.vue


+ 0 - 0
src/views/pure-table/components/tree.vue → src/views/pure-table/base/tree.vue


+ 0 - 47
src/views/pure-table/components/index.ts

@@ -1,47 +0,0 @@
-import Base from "./base.vue";
-import Stripe from "./stripe.vue";
-import Border from "./border.vue";
-import Status from "./status.vue";
-import FixHeader from "./fixHeader.vue";
-import FixColumn from "./fixColumn.vue";
-import FluidHeight from "./fluidHeight.vue";
-import GroupHeader from "./groupHeader.vue";
-import Radio from "./radio.vue";
-import MultipleChoice from "./multipleChoice.vue";
-import Sortable from "./sortable.vue";
-import Filters from "./filters.vue";
-import ColumnTemplate from "./column-template/index.vue";
-import HeaderRenderer from "./header-renderer/index.vue";
-import Expand from "./expand.vue";
-import TreeTable from "./tree.vue";
-import TotalRow from "./totalRow.vue";
-import Merge from "./merge.vue";
-import CustomIndex from "./customIndex.vue";
-import Layout from "./layout.vue";
-import NestProp from "./nestProp.vue";
-import ImgPreview from "./imgPreview.vue";
-
-export {
-  Base,
-  Stripe,
-  Border,
-  Status,
-  FixHeader,
-  FixColumn,
-  FluidHeight,
-  GroupHeader,
-  Radio,
-  MultipleChoice,
-  Sortable,
-  Filters,
-  ColumnTemplate,
-  HeaderRenderer,
-  Expand,
-  TreeTable,
-  TotalRow,
-  Merge,
-  CustomIndex,
-  Layout,
-  NestProp,
-  ImgPreview
-};

+ 56 - 0
src/views/pure-table/high.vue

@@ -0,0 +1,56 @@
+<script setup lang="ts">
+import { list } from "./high/list";
+import { Tabs, TabPane } from "@pureadmin/components";
+
+defineOptions({
+  name: "PureTableHigh"
+});
+</script>
+
+<template>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">
+          高级用法全部采用 tsx 语法,充分发挥
+          <el-link
+            href="https://github.com/xiaoxian521/pure-admin-table"
+            target="_blank"
+            style="font-size: 16px; margin: 0 4px 5px"
+          >
+            @pureadmin/table
+          </el-link>
+          的灵活性,维护整体表格只需操作 columns 配置即可
+        </span>
+      </div>
+    </template>
+
+    <el-alert
+      title="高级用法中所有表格都设置了 row-key ,后端需返回唯一值的字段,比如id 作用:1. 用来优化 Table
+      的渲染,尤其当字段在深层结构中;2. 防止拖拽后表格组件内部混乱(拖拽必须设置哦,坑都帮您们踩过啦 ❤️)"
+      type="info"
+      :closable="false"
+    />
+
+    <Tabs :destroyInactiveTabPane="true">
+      <TabPane v-for="item of list" :key="item.key">
+        <template #tab>
+          <el-tooltip :content="item.content" placement="top-end">
+            <span>{{ item.title }}</span>
+          </el-tooltip>
+        </template>
+        <component :is="item.component" />
+      </TabPane>
+    </Tabs>
+  </el-card>
+</template>
+
+<style scoped>
+:deep(.ant-tabs-content-holder) {
+  margin-top: 10px;
+}
+
+:deep(.el-alert__title) {
+  font-size: 16px;
+}
+</style>

+ 88 - 0
src/views/pure-table/high/data.ts

@@ -0,0 +1,88 @@
+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"
+  }
+];
+
+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://xiaoxian521.github.io/pure-admin-table/imgs/${
+      index + 1
+    }.jpg`
+  })
+);
+
+const tableDataSortable = clone(tableData, true).map((item, index) =>
+  Object.assign(item, {
+    date: `${dayjs(new Date()).format("YYYY-MM")}-${index + 1}`
+  })
+);
+
+const tableDataDrag = clone(tableData, true).map((item, index) => {
+  delete item["address"];
+  return Object.assign(
+    {
+      id: index + 1,
+      date: `${dayjs(new Date()).format("YYYY-MM")}-${index + 1}`
+    },
+    item
+  );
+});
+
+export {
+  tableData,
+  tableDataDrag,
+  tableDataMore,
+  tableDataImage,
+  tableDataSortable
+};

+ 68 - 0
src/views/pure-table/high/drag/column/columns.tsx

@@ -0,0 +1,68 @@
+import Sortable from "sortablejs";
+import { tableDataDrag } from "../../data";
+import { ref, nextTick, onMounted } from "vue";
+
+// 行拖拽演示
+export function useColumns() {
+  const dataList = ref(tableDataDrag);
+
+  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
+  };
+}

+ 16 - 0
src/views/pure-table/high/drag/column/index.vue

@@ -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>

+ 69 - 0
src/views/pure-table/high/drag/row/columns.tsx

@@ -0,0 +1,69 @@
+import Sortable from "sortablejs";
+import { ref, nextTick } from "vue";
+import { tableDataDrag } from "../../data";
+
+// 行拖拽演示
+export function useColumns() {
+  const dataList = ref(tableDataDrag);
+
+  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
+  };
+}

+ 16 - 0
src/views/pure-table/high/drag/row/index.vue

@@ -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>

+ 20 - 0
src/views/pure-table/high/list.tsx

@@ -0,0 +1,20 @@
+import RowDrag from "./drag/row/index.vue";
+import ColumnDrag from "./drag/column/index.vue";
+
+const rendContent = (val: string) =>
+  `代码位置:src/views/pure-table/high/${val}/index.vue`;
+
+export const list = [
+  {
+    key: "rowDrag",
+    content: rendContent("drag/row"),
+    title: "拖拽表格(行拖拽)",
+    component: RowDrag
+  },
+  {
+    key: "columnDrag",
+    content: rendContent("drag/column"),
+    title: "拖拽表格(列拖拽)",
+    component: ColumnDrag
+  }
+];

+ 12 - 1
src/views/pure-table/index.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { list } from "./list";
+import { list } from "./base/list";
 import { Tabs, TabPane } from "@pureadmin/components";
 
 defineOptions({
@@ -26,6 +26,13 @@ defineOptions({
       </div>
     </template>
 
+    <el-alert
+      title="基础用法中大部分表格都没设置 row-key ,不过最好都设置一下,后端需返回唯一值的字段,比如id 作用:1. 用来优化 Table
+      的渲染,尤其当字段在深层结构中;2. 防止某些操作导致表格组件内部混乱"
+      type="info"
+      :closable="false"
+    />
+
     <Tabs :destroyInactiveTabPane="true">
       <TabPane v-for="item of list" :key="item.key">
         <template #tab>
@@ -43,4 +50,8 @@ defineOptions({
 :deep(.ant-tabs-content-holder) {
   margin-top: 10px;
 }
+
+:deep(.el-alert__title) {
+  font-size: 16px;
+}
 </style>