From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/components/Table/src/Table.vue |  311 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 311 insertions(+), 0 deletions(-)

diff --git a/src/components/Table/src/Table.vue b/src/components/Table/src/Table.vue
new file mode 100644
index 0000000..e9e50af
--- /dev/null
+++ b/src/components/Table/src/Table.vue
@@ -0,0 +1,311 @@
+<script lang="tsx">
+import { ElTable, ElTableColumn, ElPagination } from 'element-plus'
+import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
+import { propTypes } from '@/utils/propTypes'
+import { setIndex } from './helper'
+import { getSlot } from '@/utils/tsxHelper'
+import type { TableProps } from './types'
+import { set } from 'lodash-es'
+import { Pagination, TableColumn, TableSetPropsType, TableSlotDefault } from '@/types/table'
+
+export default defineComponent({
+  // eslint-disable-next-line vue/no-reserved-component-names
+  name: 'Table',
+  props: {
+    pageSize: propTypes.number.def(10),
+    currentPage: propTypes.number.def(1),
+    // 鏄惁澶氶��
+    selection: propTypes.bool.def(false),
+    // 鏄惁鎵�鏈夌殑瓒呭嚭闅愯棌锛屼紭鍏堢骇浣庝簬schema涓殑showOverflowTooltip,
+    showOverflowTooltip: propTypes.bool.def(true),
+    // 琛ㄥご
+    columns: {
+      type: Array as PropType<TableColumn[]>,
+      default: () => []
+    },
+    // 灞曞紑琛�
+    expand: propTypes.bool.def(false),
+    // 鏄惁灞曠ず鍒嗛〉
+    pagination: {
+      type: Object as PropType<Pagination>,
+      default: (): Pagination | undefined => undefined
+    },
+    // 浠呭 type=selection 鐨勫垪鏈夋晥锛岀被鍨嬩负 Boolean锛屼负 true 鍒欎細鍦ㄦ暟鎹洿鏂颁箣鍚庝繚鐣欎箣鍓嶉�変腑鐨勬暟鎹紙闇�鎸囧畾 row-key锛�
+    reserveSelection: propTypes.bool.def(false),
+    // 鍔犺浇鐘舵��
+    loading: propTypes.bool.def(false),
+    // 鏄惁鍙犲姞绱㈠紩
+    reserveIndex: propTypes.bool.def(false),
+    // 瀵归綈鏂瑰紡
+    align: propTypes.string
+      .validate((v: string) => ['left', 'center', 'right'].includes(v))
+      .def('center'),
+    // 琛ㄥご瀵归綈鏂瑰紡
+    headerAlign: propTypes.string
+      .validate((v: string) => ['left', 'center', 'right'].includes(v))
+      .def('center'),
+    data: {
+      type: Array as PropType<Recordable[]>,
+      default: () => []
+    }
+  },
+  emits: ['update:pageSize', 'update:currentPage', 'register'],
+  setup(props, { attrs, slots, emit, expose }) {
+    const elTableRef = ref<ComponentRef<typeof ElTable>>()
+
+    // 娉ㄥ唽
+    onMounted(() => {
+      const tableRef = unref(elTableRef)
+      emit('register', tableRef?.$parent, elTableRef.value)
+    })
+
+    const pageSizeRef = ref(props.pageSize)
+
+    const currentPageRef = ref(props.currentPage)
+
+    // useTable浼犲叆鐨刾rops
+    const outsideProps = ref<TableProps>({})
+
+    const mergeProps = ref<TableProps>({})
+
+    const getProps = computed(() => {
+      const propsObj = { ...props }
+      Object.assign(propsObj, unref(mergeProps))
+      return propsObj
+    })
+
+    const setProps = (props: TableProps = {}) => {
+      mergeProps.value = Object.assign(unref(mergeProps), props)
+      outsideProps.value = props
+    }
+
+    const setColumn = (columnProps: TableSetPropsType[], columnsChildren?: TableColumn[]) => {
+      const { columns } = unref(getProps)
+      for (const v of columnsChildren || columns) {
+        for (const item of columnProps) {
+          if (v.field === item.field) {
+            set(v, item.path, item.value)
+          } else if (v.children?.length) {
+            setColumn(columnProps, v.children)
+          }
+        }
+      }
+    }
+
+    const selections = ref<Recordable[]>([])
+
+    const selectionChange = (selection: Recordable[]) => {
+      selections.value = selection
+    }
+
+    expose({
+      setProps,
+      setColumn,
+      selections
+    })
+
+    const pagination = computed(() => {
+      // update by 鑺嬭壙锛氫繚鎸佸拰 Pagination 缁勪欢鐨勯�昏緫涓�鑷�
+      return Object.assign(
+        {
+          small: false,
+          background: true,
+          pagerCount: document.body.clientWidth < 992 ? 5 : 7,
+          layout: 'total, sizes, prev, pager, next, jumper',
+          pageSizes: [10, 20, 30, 50, 100],
+          disabled: false,
+          hideOnSinglePage: false,
+          total: 10
+        },
+        unref(getProps).pagination
+      )
+    })
+
+    watch(
+      () => unref(getProps).pageSize,
+      (val: number) => {
+        pageSizeRef.value = val
+      }
+    )
+
+    watch(
+      () => unref(getProps).currentPage,
+      (val: number) => {
+        currentPageRef.value = val
+      }
+    )
+
+    watch(
+      () => pageSizeRef.value,
+      (val: number) => {
+        emit('update:pageSize', val)
+      }
+    )
+
+    watch(
+      () => currentPageRef.value,
+      (val: number) => {
+        emit('update:currentPage', val)
+      }
+    )
+
+    const getBindValue = computed(() => {
+      const bindValue: Recordable = { ...attrs, ...props }
+      delete bindValue.columns
+      delete bindValue.data
+      return bindValue
+    })
+
+    const renderTableSelection = () => {
+      const { selection, reserveSelection, align, headerAlign } = unref(getProps)
+      // 娓叉煋澶氶��
+      return selection ? (
+        <ElTableColumn
+          type="selection"
+          reserveSelection={reserveSelection}
+          align={align}
+          headerAlign={headerAlign}
+          width="50"
+        ></ElTableColumn>
+      ) : undefined
+    }
+
+    const renderTableExpand = () => {
+      const { align, headerAlign, expand } = unref(getProps)
+      // 娓叉煋灞曞紑琛�
+      return expand ? (
+        <ElTableColumn type="expand" align={align} headerAlign={headerAlign}>
+          {{
+            // @ts-ignore
+            default: (data: TableSlotDefault) => getSlot(slots, 'expand', data)
+          }}
+        </ElTableColumn>
+      ) : undefined
+    }
+
+    const rnderTreeTableColumn = (columnsChildren: TableColumn[]) => {
+      const { align, headerAlign, showOverflowTooltip } = unref(getProps)
+      return columnsChildren.map((v) => {
+        const props = { ...v }
+        if (props.children) delete props.children
+        return (
+          <ElTableColumn
+            showOverflowTooltip={showOverflowTooltip}
+            align={align}
+            headerAlign={headerAlign}
+            {...props}
+            prop={v.field}
+          >
+            {{
+              default: (data: TableSlotDefault) =>
+                v.children && v.children.length
+                  ? rnderTableColumn(v.children)
+                  : // @ts-ignore
+                    getSlot(slots, v.field, data) ||
+                    v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
+                    data.row[v.field],
+              // @ts-ignore
+              header: getSlot(slots, `${v.field}-header`)
+            }}
+          </ElTableColumn>
+        )
+      })
+    }
+
+    const rnderTableColumn = (columnsChildren?: TableColumn[]) => {
+      const {
+        columns,
+        reserveIndex,
+        pageSize,
+        currentPage,
+        align,
+        headerAlign,
+        showOverflowTooltip
+      } = unref(getProps)
+      return [...[renderTableExpand()], ...[renderTableSelection()]].concat(
+        (columnsChildren || columns).map((v) => {
+          // 鑷畾鐢熸垚搴忓彿
+          if (v.type === 'index') {
+            return (
+              <ElTableColumn
+                type="index"
+                index={
+                  v.index
+                    ? v.index
+                    : (index) => setIndex(reserveIndex, index, pageSize, currentPage)
+                }
+                align={v.align || align}
+                headerAlign={v.headerAlign || headerAlign}
+                label={v.label}
+                width="65px"
+              ></ElTableColumn>
+            )
+          } else {
+            const props = { ...v }
+            if (props.children) delete props.children
+            return (
+              <ElTableColumn
+                showOverflowTooltip={showOverflowTooltip}
+                align={align}
+                headerAlign={headerAlign}
+                {...props}
+                prop={v.field}
+              >
+                {{
+                  default: (data: TableSlotDefault) =>
+                    v.children && v.children.length
+                      ? rnderTreeTableColumn(v.children)
+                      : // @ts-ignore
+                        getSlot(slots, v.field, data) ||
+                        v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
+                        data.row[v.field],
+                  // @ts-ignore
+                  header: () => getSlot(slots, `${v.field}-header`) || v.label
+                }}
+              </ElTableColumn>
+            )
+          }
+        })
+      )
+    }
+
+    return () => (
+      <div v-loading={unref(getProps).loading}>
+        <ElTable
+          // @ts-ignore
+          ref={elTableRef}
+          data={unref(getProps).data}
+          onSelection-change={selectionChange}
+          {...unref(getBindValue)}
+        >
+          {{
+            default: () => rnderTableColumn(),
+            // @ts-ignore
+            append: () => getSlot(slots, 'append')
+          }}
+        </ElTable>
+        {unref(getProps).pagination ? (
+          // update by 鑺嬭壙锛氫繚鎸佸拰 Pagination 缁勪欢涓�鑷�
+          <ElPagination
+            v-model:pageSize={pageSizeRef.value}
+            v-model:currentPage={currentPageRef.value}
+            class="float-right mb-15px mt-15px"
+            {...unref(pagination)}
+          ></ElPagination>
+        ) : undefined}
+      </div>
+    )
+  }
+})
+</script>
+<style lang="scss" scoped>
+:deep(.el-button.is-text) {
+  padding: 8px 4px;
+  margin-left: 0;
+}
+
+:deep(.el-button.is-link) {
+  padding: 8px 4px;
+  margin-left: 0;
+}
+</style>

--
Gitblit v1.8.0