Commit faf3f4602ecf4b16ff57994668edc8433a43945d

Authored by 陈文彬
1 parent 5b0a21ec

feat(table): add table component

Showing 71 changed files with 3937 additions and 191 deletions
.github/release-drafter.yml
@@ -30,5 +30,5 @@ categories: @@ -30,5 +30,5 @@ categories:
30 - 'workflow' 30 - 'workflow'
31 change-template: '- $TITLE (#$NUMBER) @$AUTHOR' 31 change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
32 template: | 32 template: |
33 - # Changes 33 + # What's Changed
34 $CHANGES 34 $CHANGES
README.md
@@ -7,20 +7,18 @@ @@ -7,20 +7,18 @@
7 7
8 **中文** 8 **中文**
9 9
10 -该分支为2.0新分支,使用vue3进行开发。 10 +该分支为 2.0 新分支,使用 vue3 进行开发。
11 11
12 -1.0分支请切换到`master`分支。1.0采用`vue2.6`+`vue-composition-api`+`vue-cli`开发 12 +1.0 分支请切换到`master`分支。1.0 采用`vue2.6`+`vue-composition-api`+`vue-cli`开发
13 13
14 一个适合开发中大型项目的基础框架,需要对`vue`,`typescript`有一定的了解,也可以作为了解新写法的一个例子来看,提前适应后续新版本的开发方式 14 一个适合开发中大型项目的基础框架,需要对`vue`,`typescript`有一定的了解,也可以作为了解新写法的一个例子来看,提前适应后续新版本的开发方式
15 15
16 项目基于`ant-design-vue`,`typescript`,`vue3.0`,`vite`,`tailwindcss`,`tsx`实现的 vue3 风格的后台管理系统, 16 项目基于`ant-design-vue`,`typescript`,`vue3.0`,`vite`,`tailwindcss`,`tsx`实现的 vue3 风格的后台管理系统,
17 17
18 -  
19 ### gitHub 地址 18 ### gitHub 地址
20 19
21 [vue-vben-admin2.0](https://github.com/anncwb/vue-vben-admin) 20 [vue-vben-admin2.0](https://github.com/anncwb/vue-vben-admin)
22 21
23 -  
24 <p align="center"> 22 <p align="center">
25 <img alt="VbenAdmin Logo" width="100%" src="./build/docs/imgs/preview1.png"> 23 <img alt="VbenAdmin Logo" width="100%" src="./build/docs/imgs/preview1.png">
26 <img alt="VbenAdmin Logo" width="100%" src="./build/docs/imgs/preview2.png"> 24 <img alt="VbenAdmin Logo" width="100%" src="./build/docs/imgs/preview2.png">
@@ -29,11 +27,7 @@ @@ -29,11 +27,7 @@
29 27
30 ### 文档 28 ### 文档
31 29
32 -2.0文档还没开始写。后续补上。。  
33 -  
34 -  
35 -  
36 - 30 +2.0 文档还没开始写。后续补上。。
37 31
38 ## 使用到的技术 32 ## 使用到的技术
39 33
@@ -84,7 +78,6 @@ VSCode 插件 @@ -84,7 +78,6 @@ VSCode 插件
84 - `stylelint`: 样式代码检查 78 - `stylelint`: 样式代码检查
85 - `Prettier - Code formatter`:代码格式化 79 - `Prettier - Code formatter`:代码格式化
86 80
87 -  
88 ## 安装 81 ## 安装
89 82
90 ```js 83 ```js
@@ -122,7 +115,6 @@ yarn build:no-cache # 打包 不会使用hardSource进行打包 @@ -122,7 +115,6 @@ yarn build:no-cache # 打包 不会使用hardSource进行打包
122 yarn report # 生成构建包表表预览 115 yarn report # 生成构建包表表预览
123 ``` 116 ```
124 117
125 -  
126 ### 格式化 118 ### 格式化
127 119
128 ```bash 120 ```bash
@@ -159,7 +151,6 @@ yarn log # 生成CHANGELOG @@ -159,7 +151,6 @@ yarn log # 生成CHANGELOG
159 - `mod` 不确定分类的修改 151 - `mod` 不确定分类的修改
160 - `wip` 删除文件 152 - `wip` 删除文件
161 153
162 -  
163 ## 代码贡献 154 ## 代码贡献
164 155
165 1. Fork 代码! 156 1. Fork 代码!
@@ -205,20 +196,19 @@ yarn log # 生成CHANGELOG @@ -205,20 +196,19 @@ yarn log # 生成CHANGELOG
205 - [x] 树组件 196 - [x] 树组件
206 - [x] 系统性能优化 197 - [x] 系统性能优化
207 - [x] 兼容最新`vuex`,`vue-router` 198 - [x] 兼容最新`vuex`,`vue-router`
208 -- [] 图片预览组件 199 +- [x] 图片预览组件
  200 +- [ ] 表格组件
  201 +- [ ] 可编辑表格
209 - [ ] 图表库 202 - [ ] 图表库
210 - [ ] 数字动画 203 - [ ] 数字动画
211 - [ ] 主题配置 204 - [ ] 主题配置
212 -- [ ] 表格组件  
213 - [ ] 富文本组件 205 - [ ] 富文本组件
214 - [ ] 首屏加载等待动画 206 - [ ] 首屏加载等待动画
215 - [ ] 上传组件 207 - [ ] 上传组件
216 -- [ ] 可编辑表格  
217 - [ ] 数据导入导出 208 - [ ] 数据导入导出
218 -- [ ] 搭建`vite`版本  
219 -- [ ] 懒加载组件  
220 - [ ] 黑暗主题 209 - [ ] 黑暗主题
221 -- [ ] 更多组件/功能/建议/bug/欢迎提交 pr 或者 issue 210 +
  211 +更多组件/功能/建议/bug/欢迎提交 pr 或者 issue
222 212
223 ## 加入我们 213 ## 加入我们
224 214
mock/_createProductionServer.ts
1 import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'; 1 import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer';
2 import userMock from './sys/user'; 2 import userMock from './sys/user';
3 import menuMock from './sys/menu'; 3 import menuMock from './sys/menu';
  4 +import tableDemoMock from './demo/table-demo';
4 5
5 export function setupProdMockServer() { 6 export function setupProdMockServer() {
6 - createProdMockServer([...userMock, ...menuMock]); 7 + createProdMockServer([...userMock, ...menuMock, ...tableDemoMock]);
7 } 8 }
mock/_util.ts
@@ -9,12 +9,19 @@ export function resultSuccess&lt;T = any&gt;(result: T, { message = &#39;ok&#39; } = {}) { @@ -9,12 +9,19 @@ export function resultSuccess&lt;T = any&gt;(result: T, { message = &#39;ok&#39; } = {}) {
9 }; 9 };
10 } 10 }
11 11
12 -export function resultPageSuccess<T = any>(items: T[], total: number, { message = 'ok' } = {}) { 12 +export function resultPageSuccess<T = any>(
  13 + page: number,
  14 + pageSize: number,
  15 + list: T[],
  16 + { message = 'ok' } = {}
  17 +) {
  18 + const pageData = pagination(page, pageSize, list);
  19 +
13 return { 20 return {
14 code: 0, 21 code: 0,
15 result: { 22 result: {
16 - items,  
17 - total, 23 + items: pageData,
  24 + total: list.length,
18 }, 25 },
19 message, 26 message,
20 type: 'success', 27 type: 'success',
mock/demo/table-demo.ts 0 → 100644
  1 +import { MockMethod } from 'vite-plugin-mock';
  2 +import { resultPageSuccess } from '../_util';
  3 +
  4 +const demoList = (() => {
  5 + const result: any[] = [];
  6 + for (let index = 0; index < 60; index++) {
  7 + result.push({
  8 + id: `${index}`,
  9 + beginTime: '@datetime',
  10 + endTime: '@datetime',
  11 + address: '@city()',
  12 + name: '@cname()',
  13 + 'no|100000-10000000': 100000,
  14 + 'status|1': ['正常', '启用', '停用'],
  15 + });
  16 + }
  17 + return result;
  18 +})();
  19 +
  20 +export default [
  21 + {
  22 + url: '/api/table/getDemoList',
  23 + timeout: 1000,
  24 + method: 'get',
  25 + response: ({ query }) => {
  26 + const { page = 1, pageSize = 20 } = query;
  27 + return resultPageSuccess(page, pageSize, demoList);
  28 + },
  29 + },
  30 +] as MockMethod[];
src/App.vue
1 <template> 1 <template>
2 - <ConfigProvider  
3 - :locale="zhCN"  
4 - :renderEmpty="renderEmpty"  
5 - :transformCellText="transformCellText"  
6 - v-bind="lockOn"  
7 - > 2 + <ConfigProvider :locale="zhCN" :transformCellText="transformCellText" v-bind="lockOn">
8 <router-view /> 3 <router-view />
9 </ConfigProvider> 4 </ConfigProvider>
10 </template> 5 </template>
@@ -28,10 +23,9 @@ @@ -28,10 +23,9 @@
28 useInitAppConfigStore(); 23 useInitAppConfigStore();
29 useListenerNetWork(); 24 useListenerNetWork();
30 createBreakpointListen(); 25 createBreakpointListen();
31 - const { renderEmpty, transformCellText } = useConfigProvider(); 26 + const { transformCellText } = useConfigProvider();
32 const { on: lockOn } = useLockPage(); 27 const { on: lockOn } = useLockPage();
33 return { 28 return {
34 - renderEmpty,  
35 transformCellText, 29 transformCellText,
36 zhCN, 30 zhCN,
37 lockOn, 31 lockOn,
src/api/demo/model/tableModel.ts 0 → 100644
  1 +import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel';
  2 +/**
  3 + * @description: 请求列表接口参数
  4 + */
  5 +export type DemoParams = BasicPageParams;
  6 +
  7 +export interface DemoListItem {
  8 + id: string;
  9 + beginTime: string;
  10 + endTime: string;
  11 + address: string;
  12 + name: string;
  13 + no: number;
  14 + status: number;
  15 +}
  16 +
  17 +/**
  18 + * @description: 请求列表返回值
  19 + */
  20 +export type DemoListGetResultModel = BasicFetchResult<DemoListItem>;
src/api/demo/table.ts 0 → 100644
  1 +import { defHttp } from '/@/utils/http/axios';
  2 +import { DemoParams, DemoListGetResultModel } from './model/tableModel';
  3 +
  4 +enum Api {
  5 + DEMO_LIST = '/table/getDemoList',
  6 +}
  7 +
  8 +/**
  9 + * @description: 获取示例列表值
  10 + */
  11 +export function demoListApi(params: DemoParams) {
  12 + return defHttp.request<DemoListGetResultModel>({
  13 + url: Api.DEMO_LIST,
  14 + method: 'GET',
  15 + params,
  16 + });
  17 +}
src/api/model/baseModel.ts 0 → 100644
  1 +export interface BasicPageParams {
  2 + page: number;
  3 + pageSize: number;
  4 +}
  5 +
  6 +export interface BasicFetchResult<T extends any> {
  7 + items: T;
  8 + total: number;
  9 +}
src/assets/images/lock-page.png deleted 100644 → 0

372 KB

src/assets/images/page_null.png deleted 100644 → 0

9.9 KB

src/components/Basic/index.ts
1 export { default as BasicArrow } from './src/BasicArrow.vue'; 1 export { default as BasicArrow } from './src/BasicArrow.vue';
2 export { default as BasicHelp } from './src/BasicHelp'; 2 export { default as BasicHelp } from './src/BasicHelp';
3 export { default as BasicTitle } from './src/BasicTitle.vue'; 3 export { default as BasicTitle } from './src/BasicTitle.vue';
4 -export { default as BasicEmpty } from './src/BasicEmpty.vue';  
src/components/Basic/src/BasicArrow.vue
@@ -43,11 +43,16 @@ @@ -43,11 +43,16 @@
43 43
44 &.right { 44 &.right {
45 transform: rotate(0deg); 45 transform: rotate(0deg);
  46 +
  47 + > span {
  48 + transition: all 0.3s ease 0.1s !important;
  49 + }
46 } 50 }
47 51
48 &__active { 52 &__active {
49 - transform: rotate(90deg) !important;  
50 - transition: all 0.3s ease 0.1s !important; 53 + > span {
  54 + transform: rotate(90deg) !important;
  55 + }
51 } 56 }
52 } 57 }
53 </style> 58 </style>
src/components/Basic/src/BasicEmpty.vue deleted 100644 → 0
1 -<template>  
2 - <Empty :image="image" :description="description" />  
3 -</template>  
4 -<script lang="ts">  
5 - import { defineComponent } from 'vue';  
6 - import { Empty } from 'ant-design-vue';  
7 -  
8 - import emptySrc from '/@/assets/images/page_null.png';  
9 -  
10 - export default defineComponent({  
11 - extends: Empty as any,  
12 - components: { Empty },  
13 - props: {  
14 - description: {  
15 - type: String,  
16 - default: '暂无内容',  
17 - },  
18 - image: {  
19 - type: String,  
20 - default: emptySrc,  
21 - required: false,  
22 - },  
23 - },  
24 - setup() {  
25 - return {};  
26 - },  
27 - });  
28 -</script>  
src/components/Button/index.vue
1 <template> 1 <template>
2 <Button v-bind="getBindValue" :class="[getColor, $attrs.class]"> 2 <Button v-bind="getBindValue" :class="[getColor, $attrs.class]">
3 - <template v-slot:[item] v-for="item in Object.keys($slots)">  
4 - <slot :name="item" /> 3 + <template #[item]="data" v-for="item in Object.keys($slots)">
  4 + <slot :name="item" v-bind="data" />
5 </template> 5 </template>
6 </Button> 6 </Button>
7 </template> 7 </template>
src/components/Container/src/collapse/CollapseContainer.vue
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 <div class="collapse-container__body" v-else v-show="show"> 6 <div class="collapse-container__body" v-else v-show="show">
7 <LazyContainer :timeout="lazyTime" v-if="lazy"> 7 <LazyContainer :timeout="lazyTime" v-if="lazy">
8 <slot /> 8 <slot />
9 - <template v-slot:skeleton> 9 + <template #skeleton>
10 <slot name="lazySkeleton" /> 10 <slot name="lazySkeleton" />
11 </template> 11 </template>
12 </LazyContainer> 12 </LazyContainer>
src/components/Form/src/BasicForm.vue
@@ -9,8 +9,8 @@ @@ -9,8 +9,8 @@
9 :allDefaultValues="getAllDefaultValues" 9 :allDefaultValues="getAllDefaultValues"
10 :formModel="formModel" 10 :formModel="formModel"
11 > 11 >
12 - <template v-slot:[item] v-for="item in Object.keys($slots)">  
13 - <slot :name="item" /> 12 + <template #[item]="data" v-for="item in Object.keys($slots)">
  13 + <slot :name="item" v-bind="data" />
14 </template> 14 </template>
15 </FormItem> 15 </FormItem>
16 </template> 16 </template>
src/components/Table/index.ts 0 → 100644
  1 +export { default as BasicTable } from './src/BasicTable.vue';
  2 +export { default as TableAction } from './src/components/TableAction';
  3 +export { default as TableImg } from './src/components/TableImg.vue';
  4 +export { renderEditableCell } from './src/components/renderEditableCell';
  5 +export { default as EditTableHeaderIcon } from './src/components/EditTableHeaderIcon.vue';
  6 +
  7 +export * from './src/types/table';
  8 +export * from './src/types/pagination';
  9 +export * from './src/types/tableAction';
  10 +
  11 +export { useTable } from './src/hooks/useTable';
  12 +
  13 +export type { FormSchema, FormProps } from '/@/components/Form/src/types/form';
src/components/Table/src/BasicTable.vue 0 → 100644
  1 +<template>
  2 + <div
  3 + class="basic-table"
  4 + :class="{
  5 + 'table-form-container': getBindValues.useSearchForm,
  6 + }"
  7 + >
  8 + <BasicForm
  9 + v-bind="getFormProps"
  10 + v-if="getBindValues.useSearchForm"
  11 + :submitButtonOptions="{ loading }"
  12 + @register="registerForm"
  13 + @submit="handleSearchInfoChange"
  14 + @advanced-change="redoHeight"
  15 + >
  16 + <template #[item]="data" v-for="item in Object.keys($slots)">
  17 + <slot :name="`form-${item}`" v-bind="data" />
  18 + </template>
  19 + </BasicForm>
  20 + <Table
  21 + ref="tableElRef"
  22 + v-bind="getBindValues"
  23 + :rowClassName="getRowClassName"
  24 + :class="{
  25 + hidden: !getEmptyDataIsShowTable,
  26 + }"
  27 + @change="handleTableChange"
  28 + >
  29 + <template #[item]="data" v-for="item in Object.keys($slots)">
  30 + <slot :name="item" v-bind="data" />
  31 + </template>
  32 + </Table>
  33 + </div>
  34 +</template>
  35 +<script lang="ts">
  36 + import { defineComponent, ref, computed, unref, watch, nextTick } from 'vue';
  37 + import { Table } from 'ant-design-vue';
  38 + import { basicProps } from './props';
  39 + import type {
  40 + BasicTableProps,
  41 + FetchParams,
  42 + GetColumnsParams,
  43 + TableActionType,
  44 + } from './types/table';
  45 + import { isFunction, isString } from '/@/utils/is';
  46 +
  47 + import renderTitle from './components/renderTitle';
  48 + import renderFooter from './components/renderFooter';
  49 + import renderExpandIcon from './components/renderExpandIcon';
  50 +
  51 + import { usePagination } from './hooks/usePagination';
  52 + import { useColumns } from './hooks/useColumns';
  53 + import { useDataSource } from './hooks/useDataSource';
  54 + import { useLoading } from './hooks/useLoading';
  55 + import { useRowSelection } from './hooks/useRowSelection';
  56 + import { useTableScroll } from './hooks/useTableScroll';
  57 + import { provideTable } from './hooks/useProvinceTable';
  58 + import { BasicForm, FormProps, useForm } from '/@/components/Form/index';
  59 + import { omit } from 'lodash-es';
  60 + import './style/index.less';
  61 + import { ROW_KEY } from './const';
  62 + import { PaginationProps } from './types/pagination';
  63 + import { deepMerge } from '/@/utils';
  64 + import { TableCustomRecord } from 'ant-design-vue/types/table/table';
  65 + import { useEvent } from '/@/hooks/event/useEvent';
  66 + export default defineComponent({
  67 + props: basicProps,
  68 + components: { Table, BasicForm },
  69 + emits: ['fetch-success', 'fetch-error', 'selection-change', 'register'],
  70 + setup(props, { attrs, emit, slots }) {
  71 + const tableElRef = ref<any>(null);
  72 + const innerPropsRef = ref<Partial<BasicTableProps>>();
  73 + const [registerForm, { getFieldsValue }] = useForm();
  74 +
  75 + const getMergeProps = computed(
  76 + (): BasicTableProps => {
  77 + return {
  78 + ...props,
  79 + ...unref(innerPropsRef),
  80 + } as BasicTableProps;
  81 + }
  82 + );
  83 + const { loadingRef } = useLoading(getMergeProps);
  84 + const { getPaginationRef, setPagination } = usePagination(getMergeProps);
  85 + const { getColumnsRef, setColumns } = useColumns(getMergeProps, getPaginationRef);
  86 + const { getDataSourceRef, setTableData, fetch, getAutoCreateKey } = useDataSource(
  87 + getMergeProps,
  88 + {
  89 + getPaginationRef,
  90 + loadingRef,
  91 + setPagination,
  92 + getFieldsValue,
  93 + },
  94 + emit
  95 + );
  96 + const { getScrollRef, redoHeight } = useTableScroll(getMergeProps, tableElRef);
  97 + const {
  98 + getRowSelectionRef,
  99 + getSelectRows,
  100 + clearSelectedRowKeys,
  101 + getSelectRowKeys,
  102 + deleteSelectRowByKey,
  103 + setSelectedRowKeys,
  104 + } = useRowSelection(getMergeProps, emit);
  105 +
  106 + const getRowKey = computed(() => {
  107 + const { rowKey } = unref(getMergeProps);
  108 +
  109 + return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
  110 + });
  111 + const getBindValues = computed(() => {
  112 + const { title, titleHelpMessage, showSummary } = unref(getMergeProps);
  113 + const titleData: any =
  114 + !slots.tableTitle && !isString(title) && !title && !slots.toolbar
  115 + ? {}
  116 + : {
  117 + title:
  118 + !slots.tableTitle && !title && !slots.toolbar
  119 + ? null
  120 + : renderTitle.bind(null, title, titleHelpMessage, slots),
  121 + };
  122 + const pagination = unref(getPaginationRef);
  123 + const rowSelection = unref(getRowSelectionRef);
  124 + const scroll = unref(getScrollRef);
  125 + const loading = unref(loadingRef);
  126 + const rowKey = unref(getRowKey);
  127 + const columns = unref(getColumnsRef);
  128 + const dataSource = unref(getDataSourceRef);
  129 + let propsData = {
  130 + size: 'middle',
  131 + ...(slots.expandedRowRender ? { expandIcon: renderExpandIcon() } : {}),
  132 + ...attrs,
  133 + ...unref(getMergeProps),
  134 + ...titleData,
  135 + scroll,
  136 + loading,
  137 + tableLayout: 'fixed',
  138 + rowSelection,
  139 + rowKey,
  140 + columns,
  141 + pagination,
  142 + dataSource,
  143 + };
  144 + if (slots.expandedRowRender) {
  145 + propsData = omit(propsData, 'scroll');
  146 + }
  147 + if (showSummary) {
  148 + propsData.footer = renderFooter.bind(null, {
  149 + scroll,
  150 + columnsRef: getColumnsRef,
  151 + summaryFunc: unref(getMergeProps).summaryFunc,
  152 + dataSourceRef: getDataSourceRef,
  153 + rowSelectionRef: getRowSelectionRef,
  154 + });
  155 + }
  156 + return propsData;
  157 + });
  158 + const getFormProps = computed(() => {
  159 + const { formConfig } = unref(getBindValues);
  160 + const formProps: FormProps = {
  161 + showAdvancedButton: true,
  162 + ...(formConfig as FormProps),
  163 + compact: true,
  164 + };
  165 + return formProps;
  166 + });
  167 +
  168 + const getEmptyDataIsShowTable = computed(() => {
  169 + const { emptyDataIsShowTable, useSearchForm } = unref(getMergeProps);
  170 + if (emptyDataIsShowTable || !useSearchForm) {
  171 + return true;
  172 + }
  173 + return !!unref(getDataSourceRef).length;
  174 + });
  175 +
  176 + function getRowClassName(record: TableCustomRecord<any>, index: number) {
  177 + const { striped, rowClassName } = unref(getMergeProps);
  178 + if (!striped) return;
  179 + if (rowClassName && isFunction(rowClassName)) {
  180 + return rowClassName(record);
  181 + }
  182 + return (index || 0) % 2 === 1 ? 'basic-table-row__striped' : '';
  183 + }
  184 +
  185 + function handleSearchInfoChange(info: any) {
  186 + const { handleSearchInfoFn } = unref(getMergeProps);
  187 + if (handleSearchInfoFn && isFunction(handleSearchInfoFn)) {
  188 + info = handleSearchInfoFn(info) || info;
  189 + }
  190 + fetch({ searchInfo: info, page: 1 });
  191 + }
  192 +
  193 + function handleTableChange(pagination: PaginationProps) {
  194 + const { clearSelectOnPageChange } = unref(getMergeProps);
  195 + if (clearSelectOnPageChange) {
  196 + clearSelectedRowKeys();
  197 + }
  198 + setPagination(pagination);
  199 + fetch();
  200 + }
  201 + watch(
  202 + () => unref(getDataSourceRef),
  203 + () => {
  204 + if (unref(getMergeProps).showSummary) {
  205 + nextTick(() => {
  206 + const tableEl = unref(tableElRef);
  207 + if (!tableEl) {
  208 + return;
  209 + }
  210 + const bodyDomList = tableEl.$el.querySelectorAll(
  211 + '.ant-table-body'
  212 + ) as HTMLDivElement[];
  213 + const bodyDom = bodyDomList[0];
  214 + useEvent({
  215 + el: bodyDom,
  216 + name: 'scroll',
  217 + listener: () => {
  218 + const footerBodyDom = tableEl.$el.querySelector(
  219 + '.ant-table-footer .ant-table-body'
  220 + ) as HTMLDivElement;
  221 + if (!footerBodyDom || !bodyDom) return;
  222 + footerBodyDom.scrollLeft = bodyDom.scrollLeft;
  223 + },
  224 + wait: 0,
  225 + options: true,
  226 + });
  227 + });
  228 + }
  229 + },
  230 + { immediate: true }
  231 + );
  232 +
  233 + const tableAction: TableActionType = {
  234 + reload: async (opt?: FetchParams) => {
  235 + await fetch(opt);
  236 + },
  237 + getSelectRows,
  238 + clearSelectedRowKeys,
  239 + getSelectRowKeys,
  240 + deleteSelectRowByKey,
  241 + setPagination,
  242 + setTableData,
  243 + redoHeight,
  244 + setSelectedRowKeys,
  245 + setColumns,
  246 + getPaginationRef: () => {
  247 + return unref(getPaginationRef);
  248 + },
  249 + getColumns: (opt?: GetColumnsParams) => {
  250 + const { ignoreIndex } = opt || {};
  251 + let columns = unref(getColumnsRef);
  252 + if (ignoreIndex) {
  253 + columns = columns.filter((item) => item.flag !== 'INDEX');
  254 + }
  255 + return columns;
  256 + },
  257 + getDataSource: () => {
  258 + return unref(getDataSourceRef);
  259 + },
  260 + setLoading: (loading: boolean) => {
  261 + loadingRef.value = loading;
  262 + },
  263 + setProps: (props: Partial<BasicTableProps>) => {
  264 + innerPropsRef.value = deepMerge(unref(innerPropsRef) || {}, props);
  265 + },
  266 + };
  267 +
  268 + provideTable(tableAction);
  269 +
  270 + emit('register', tableAction);
  271 + return {
  272 + tableElRef,
  273 + getBindValues,
  274 + loading: loadingRef,
  275 + registerForm,
  276 + handleSearchInfoChange,
  277 + getFormProps,
  278 + getEmptyDataIsShowTable,
  279 + handleTableChange,
  280 + getRowClassName,
  281 + ...tableAction,
  282 + };
  283 + },
  284 + });
  285 +</script>
src/components/Table/src/componentMap.ts 0 → 100644
  1 +import { Component } from 'vue';
  2 +
  3 +import { Input, Select, Checkbox, InputNumber, Switch } from 'ant-design-vue';
  4 +
  5 +import { ComponentType } from './types/componentType';
  6 +
  7 +const componentMap = new Map<ComponentType, Component>();
  8 +
  9 +componentMap.set('Input', Input);
  10 +componentMap.set('InputPassword', Input.Password);
  11 +componentMap.set('InputNumber', InputNumber);
  12 +
  13 +componentMap.set('Select', Select);
  14 +componentMap.set('Switch', Switch);
  15 +componentMap.set('Checkbox', Checkbox);
  16 +componentMap.set('CheckboxGroup', Checkbox.Group);
  17 +
  18 +export function add(compName: ComponentType, component: Component) {
  19 + componentMap.set(compName, component);
  20 +}
  21 +
  22 +export function del(compName: ComponentType) {
  23 + componentMap.delete(compName);
  24 +}
  25 +
  26 +export { componentMap };
src/components/Table/src/components/CellResize.tsx 0 → 100644
  1 +import { defineComponent, ref, computed, unref } from 'vue';
  2 +import { injectTable } from '../hooks/useProvinceTable';
  3 +import { getSlot } from '/@/utils/helper/tsxHelper';
  4 +
  5 +import VueDraggableResizable from 'vue-draggable-resizable';
  6 +export default defineComponent({
  7 + name: 'DragResize',
  8 + setup(props, { slots, attrs }) {
  9 + const elRef = ref<HTMLTableRowElement | null>(null);
  10 + const draggingMapRef = ref<{ [key in string]: number | string }>({});
  11 +
  12 + const tableInstance = injectTable();
  13 +
  14 + const getColumnsRef = computed(() => {
  15 + const columns = tableInstance.getColumns();
  16 + columns.forEach((col) => {
  17 + const { key } = col;
  18 + if (key) {
  19 + draggingMapRef.value[key] = col.width as number;
  20 + }
  21 + });
  22 + return columns;
  23 + });
  24 +
  25 + return () => {
  26 + const { key = '', ...restProps } = { ...attrs };
  27 + const col = unref(getColumnsRef).find((col) => {
  28 + const k = col.dataIndex || col.key;
  29 + return k === key;
  30 + });
  31 + if (!col || !col.width) {
  32 + return <th {...restProps}>{getSlot(slots, 'default')}</th>;
  33 + }
  34 + const onDrag = (x: number) => {
  35 + draggingMapRef.value[key] = 0;
  36 + col.width = Math.max(x, 1);
  37 + };
  38 +
  39 + const onDragstop = () => {
  40 + const el = unref(elRef);
  41 + if (!el) {
  42 + return;
  43 + }
  44 + draggingMapRef.value[key] = el.getBoundingClientRect().width;
  45 + };
  46 + return (
  47 + <th
  48 + {...restProps}
  49 + class="resize-table-th"
  50 + ref={elRef}
  51 + style={{
  52 + width: `${col.width}px`,
  53 + }}
  54 + >
  55 + {getSlot(slots, 'default')}
  56 + <VueDraggableResizable
  57 + key={col.key}
  58 + class="table-draggable-handle"
  59 + w={10}
  60 + x={draggingMapRef.value[key] || col.width}
  61 + z={1}
  62 + axis="x"
  63 + draggable={true}
  64 + resizable={false}
  65 + onDragging={onDrag}
  66 + onDragstop={onDragstop}
  67 + />
  68 + </th>
  69 + );
  70 + };
  71 + },
  72 +});
src/components/Table/src/components/EditTableHeaderIcon.vue 0 → 100644
  1 +<template>
  2 + <span>
  3 + {{ title }}
  4 + <FormOutlined class="ml-2" />
  5 + </span>
  6 +</template>
  7 +<script lang="ts">
  8 + import { defineComponent, PropType } from 'vue';
  9 + import { FormOutlined } from '@ant-design/icons-vue';
  10 + export default defineComponent({
  11 + name: 'EditTableHeaderIcon',
  12 + components: { FormOutlined },
  13 + props: {
  14 + title: {
  15 + type: String as PropType<string>,
  16 + default: '',
  17 + },
  18 + },
  19 + setup() {},
  20 + });
  21 +</script>
src/components/Table/src/components/TableAction.tsx 0 → 100644
  1 +import { defineComponent, PropType } from 'vue';
  2 +import { Dropdown, Menu, Popconfirm } from 'ant-design-vue';
  3 +import Icon from '/@/components/Icon/index';
  4 +import { DownOutlined } from '@ant-design/icons-vue';
  5 +import { ActionItem } from '../types/tableAction';
  6 +import Button from '/@/components/Button/index.vue';
  7 +const prefixCls = 'basic-table-action';
  8 +export default defineComponent({
  9 + name: 'TableAction',
  10 + props: {
  11 + actions: {
  12 + type: Array as PropType<ActionItem[]>,
  13 + default: null,
  14 + },
  15 + dropDownActions: {
  16 + type: Array as PropType<ActionItem[]>,
  17 + default: null,
  18 + },
  19 + },
  20 + setup(props) {
  21 + // 增加按钮的TYPE和COLOR
  22 + return () => {
  23 + const { dropDownActions = [], actions } = props;
  24 + return (
  25 + <div class={prefixCls}>
  26 + {actions &&
  27 + actions.length &&
  28 + actions.map((action, index) => {
  29 + const {
  30 + disabled = false,
  31 + label,
  32 + props,
  33 + icon,
  34 + color = '',
  35 + type = 'link',
  36 + popConfirm = null,
  37 + } = action;
  38 + const button = (
  39 + <Button
  40 + type={type}
  41 + size="small"
  42 + disabled={disabled}
  43 + color={color}
  44 + {...props}
  45 + key={index}
  46 + >
  47 + {() => (
  48 + <>
  49 + {label}
  50 + {icon && <Icon icon={icon} />}
  51 + </>
  52 + )}
  53 + </Button>
  54 + );
  55 + if (popConfirm !== null) {
  56 + const {
  57 + title,
  58 + okText = '确定',
  59 + cancelText = '取消',
  60 + confirm = () => {},
  61 + cancel = () => {},
  62 + icon = '',
  63 + } = popConfirm;
  64 + return (
  65 + <Popconfirm
  66 + key={`P-${index}`}
  67 + title={title}
  68 + onConfirm={confirm}
  69 + onCancel={cancel}
  70 + okText={okText}
  71 + cancelText={cancelText}
  72 + icon={icon}
  73 + >
  74 + {() => button}
  75 + </Popconfirm>
  76 + );
  77 + }
  78 + return button;
  79 + })}
  80 + {dropDownActions && dropDownActions.length && (
  81 + <Dropdown>
  82 + {{
  83 + default: () => (
  84 + <Button type="link" size="small">
  85 + {{
  86 + default: () => (
  87 + <>
  88 + 更多
  89 + <DownOutlined />
  90 + </>
  91 + ),
  92 + }}
  93 + </Button>
  94 + ),
  95 + overlay: () => {
  96 + return (
  97 + <Menu>
  98 + {{
  99 + default: () => {
  100 + return dropDownActions.map((action, index) => {
  101 + const {
  102 + disabled = false,
  103 + label,
  104 + props,
  105 + icon,
  106 + color = '',
  107 + type = 'link',
  108 + } = action;
  109 + return (
  110 + <Menu.Item key={`${index}`} disabled={disabled}>
  111 + {() => (
  112 + <Button
  113 + type={type}
  114 + size="small"
  115 + {...props}
  116 + disabled={disabled}
  117 + color={color}
  118 + >
  119 + {{
  120 + default: () => (
  121 + <>
  122 + {label}
  123 + {icon && <Icon icon={icon} />}
  124 + </>
  125 + ),
  126 + }}
  127 + </Button>
  128 + )}
  129 + </Menu.Item>
  130 + );
  131 + });
  132 + },
  133 + }}
  134 + </Menu>
  135 + );
  136 + },
  137 + }}
  138 + </Dropdown>
  139 + )}
  140 + </div>
  141 + );
  142 + };
  143 + },
  144 +});
src/components/Table/src/components/TableImg.vue 0 → 100644
  1 +<template>
  2 + <div class="basic-table-img__preview" v-if="imgList && imgList.length">
  3 + <template v-for="(img, index) in imgList" :key="img">
  4 + <img :width="size" @click="handlePreview(index)" :src="img" />
  5 + </template>
  6 + </div>
  7 +</template>
  8 +<script lang="ts">
  9 + import { defineComponent, PropType } from 'vue';
  10 + import { createImgPreview } from '/@/components/Preview/index';
  11 +
  12 + export default defineComponent({
  13 + name: 'TableAction',
  14 + props: {
  15 + imgList: {
  16 + type: Array as PropType<string[]>,
  17 + default: null,
  18 + },
  19 + size: {
  20 + type: Number as PropType<number>,
  21 + default: 40,
  22 + },
  23 + },
  24 + setup(props) {
  25 + function handlePreview(index: number) {
  26 + const { imgList } = props;
  27 +
  28 + createImgPreview({
  29 + imageList: imgList as string[],
  30 + index: index,
  31 + });
  32 + }
  33 + return { handlePreview };
  34 + },
  35 + });
  36 +</script>
src/components/Table/src/components/TableTitle.vue 0 → 100644
  1 +<template>
  2 + <BasicTitle class="basic-table-title" v-if="tableTitle" :helpMessage="helpMessage">
  3 + {{ tableTitle }}
  4 + </BasicTitle>
  5 +</template>
  6 +<script lang="ts">
  7 + import { computed, defineComponent, PropType } from 'vue';
  8 +
  9 + import { BasicTitle } from '/@/components/Basic/index';
  10 + import { isFunction } from '/@/utils/is';
  11 + export default defineComponent({
  12 + name: 'TableTitle',
  13 + components: { BasicTitle },
  14 + props: {
  15 + title: {
  16 + type: [Function, String] as PropType<string | ((data: any) => string)>,
  17 + },
  18 + getSelectRows: {
  19 + type: Function as PropType<() => any[]>,
  20 + },
  21 + helpMessage: {
  22 + type: [String, Array] as PropType<string | string[]>,
  23 + },
  24 + },
  25 + setup(props) {
  26 + const tableTitle = computed(() => {
  27 + const { title, getSelectRows = () => {} } = props;
  28 + let tit = title;
  29 +
  30 + if (isFunction(title)) {
  31 + tit = title({
  32 + selectRows: getSelectRows(),
  33 + });
  34 + }
  35 + return tit;
  36 + });
  37 +
  38 + return { tableTitle };
  39 + },
  40 + });
  41 +</script>
src/components/Table/src/components/renderEditableCell.tsx 0 → 100644
  1 +import { defineComponent, PropType, ref, unref, nextTick } from 'vue';
  2 +import { injectTable } from '../hooks/useProvinceTable';
  3 +import ClickOutSide from '/@/components/ClickOutSide/index.vue';
  4 +
  5 +import { RenderEditableCellParams } from '../types/table';
  6 +import { ComponentType } from '../types/componentType';
  7 +
  8 +import { componentMap } from '../componentMap';
  9 +import '../style/editable-cell.less';
  10 +import { isString, isBoolean } from '/@/utils/is';
  11 +import { FormOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons-vue';
  12 +
  13 +const prefixCls = 'editable-cell';
  14 +const EditableCell = defineComponent({
  15 + name: 'EditableCell',
  16 + props: {
  17 + value: {
  18 + type: String as PropType<string>,
  19 + default: '',
  20 + },
  21 + componentProps: {
  22 + type: Object as PropType<any>,
  23 + default: null,
  24 + },
  25 +
  26 + dataKey: {
  27 + type: String as PropType<string>,
  28 + default: '',
  29 + },
  30 +
  31 + dataIndex: {
  32 + type: String as PropType<string>,
  33 + default: '',
  34 + },
  35 +
  36 + component: {
  37 + type: String as PropType<ComponentType>,
  38 + default: 'Input',
  39 + },
  40 + },
  41 + setup(props, { attrs }) {
  42 + const table = injectTable();
  43 + const elRef = ref<any>(null);
  44 +
  45 + const isEditRef = ref(false);
  46 + const currentValueRef = ref<string | boolean>('');
  47 +
  48 + function handleChange(e: ChangeEvent | string | boolean) {
  49 + if ((e as ChangeEvent).target && Reflect.has((e as ChangeEvent).target, 'value')) {
  50 + currentValueRef.value = (e as ChangeEvent).target.value;
  51 + }
  52 + if (isString(e) || isBoolean(e)) {
  53 + currentValueRef.value = e;
  54 + }
  55 + }
  56 +
  57 + function handleEdit() {
  58 + isEditRef.value = true;
  59 + nextTick(() => {
  60 + const el = unref(elRef);
  61 + el && el.focus && el.focus();
  62 + });
  63 + }
  64 +
  65 + function handleCancel() {
  66 + isEditRef.value = false;
  67 + }
  68 +
  69 + function handleSubmit() {
  70 + const { dataKey, dataIndex } = props;
  71 + if (!dataKey || !dataIndex) {
  72 + return;
  73 + }
  74 + isEditRef.value = false;
  75 +
  76 + const { getDataSource } = table;
  77 + const dataSource = getDataSource();
  78 + const target = dataSource.find((item) => item.key === dataKey);
  79 + if (target) {
  80 + target[dataIndex] = unref(currentValueRef);
  81 + }
  82 + }
  83 +
  84 + function onClickOutside() {
  85 + const { component } = props;
  86 +
  87 + if (component?.includes('Input')) {
  88 + handleCancel();
  89 + }
  90 + }
  91 + return () => {
  92 + const { value, component, componentProps = {} } = props;
  93 +
  94 + const Comp = componentMap.get(component!) as any;
  95 + // const propsData: any = {};
  96 + return (
  97 + <div class={prefixCls}>
  98 + {unref(isEditRef) && (
  99 + <ClickOutSide onClickOutside={onClickOutside}>
  100 + {() => (
  101 + <div class={`${prefixCls}__wrapper`}>
  102 + <Comp
  103 + {...{
  104 + ...attrs,
  105 + ...componentProps,
  106 + }}
  107 + style={{ width: 'calc(100% - 48px)' }}
  108 + ref={elRef}
  109 + value={value}
  110 + size="small"
  111 + onChange={handleChange}
  112 + onPressEnter={handleSubmit}
  113 + />
  114 + <div class={`${prefixCls}__action`}>
  115 + <CheckOutlined class={[`${prefixCls}__icon`, 'mx-2']} onClick={handleSubmit} />
  116 + <CloseOutlined class={[`${prefixCls}__icon `]} onClick={handleCancel} />
  117 + </div>
  118 + </div>
  119 + )}
  120 + </ClickOutSide>
  121 + )}
  122 +
  123 + {!unref(isEditRef) && (
  124 + <div class={`${prefixCls}__normal`} onClick={handleEdit}>
  125 + {value}
  126 + <FormOutlined class={`${prefixCls}__normal-icon`} />
  127 + </div>
  128 + )}
  129 + </div>
  130 + );
  131 + };
  132 + },
  133 +});
  134 +
  135 +export function renderEditableCell({
  136 + dataIndex,
  137 + component,
  138 + componentOn = {},
  139 + componentProps = {},
  140 +}: RenderEditableCellParams) {
  141 + return ({ text, record }: { text: string; record: any }) => {
  142 + return (
  143 + <EditableCell
  144 + value={text}
  145 + dataKey={record.key}
  146 + dataIndex={dataIndex}
  147 + component={component}
  148 + on={componentOn}
  149 + componentProps={componentProps}
  150 + />
  151 + );
  152 + };
  153 +}
src/components/Table/src/components/renderExpandIcon.tsx 0 → 100644
  1 +import { BasicArrow } from '/@/components/Basic';
  2 +
  3 +export default () => {
  4 + return (props: any) => {
  5 + return (
  6 + <BasicArrow
  7 + onClick={(e: Event) => {
  8 + props.onExpand(props.record, e);
  9 + }}
  10 + expand={props.expanded}
  11 + class="right"
  12 + />
  13 + );
  14 + };
  15 +};
src/components/Table/src/components/renderFooter.tsx 0 → 100644
  1 +import { Table } from 'ant-design-vue';
  2 +import { TableRowSelection } from 'ant-design-vue/types/table/table';
  3 +import { cloneDeep } from 'lodash-es';
  4 +import { unref, ComputedRef } from 'vue';
  5 +import { BasicColumn } from '../types/table';
  6 +import { isFunction } from '/@/utils/is';
  7 +export default ({
  8 + scroll = {},
  9 + columnsRef,
  10 + summaryFunc,
  11 + rowKey = 'key',
  12 + dataSourceRef,
  13 + rowSelectionRef,
  14 +}: {
  15 + scroll: { x?: number | true; y?: number };
  16 + columnsRef: ComputedRef<BasicColumn[]>;
  17 + summaryFunc: any;
  18 + rowKey?: string;
  19 + dataSourceRef: ComputedRef<any[]>;
  20 + rowSelectionRef: ComputedRef<TableRowSelection<any> | null>;
  21 +}) => {
  22 + if (!summaryFunc) {
  23 + return;
  24 + }
  25 + const dataSource: any[] = isFunction(summaryFunc) ? summaryFunc(unref(dataSourceRef)) : [];
  26 + const columns: BasicColumn[] = cloneDeep(unref(columnsRef));
  27 + const index = columns.findIndex((item) => item.flag === 'INDEX');
  28 + const hasRowSummary = dataSource.some((item) => Reflect.has(item, '_row'));
  29 + const hasIndexSummary = dataSource.some((item) => Reflect.has(item, '_index'));
  30 +
  31 + if (index !== -1) {
  32 + if (hasIndexSummary) {
  33 + columns[index].customRender = ({ record }) => record._index;
  34 + columns[index].ellipsis = false;
  35 + } else {
  36 + Reflect.deleteProperty(columns[index], 'customRender');
  37 + }
  38 + }
  39 + if (unref(rowSelectionRef) && hasRowSummary) {
  40 + columns.unshift({
  41 + width: 60,
  42 + title: 'selection',
  43 + key: 'selectionKey',
  44 + align: 'center',
  45 + customRender: ({ record }) => record._row,
  46 + });
  47 + }
  48 +
  49 + dataSource.forEach((item, i) => {
  50 + item[rowKey] = i;
  51 + });
  52 + return (
  53 + <Table
  54 + showHeader={false}
  55 + bordered={false}
  56 + pagination={false}
  57 + dataSource={dataSource}
  58 + rowKey={rowKey}
  59 + columns={columns}
  60 + tableLayout="fixed"
  61 + scroll={scroll as any}
  62 + />
  63 + );
  64 +};
src/components/Table/src/components/renderTitle.tsx 0 → 100644
  1 +import { Slots } from 'vue';
  2 +import TableTitle from './TableTitle.vue';
  3 +import { getSlot } from '/@/utils/helper/tsxHelper';
  4 +export default (title: any, titleHelpMessage: string | string[], slots: Slots) => {
  5 + return (
  6 + <>
  7 + {getSlot(slots, 'tableTitle') ||
  8 + (title && <TableTitle helpMessage={titleHelpMessage} title={title} />) || (
  9 + <span>&nbsp;</span>
  10 + )}
  11 + {slots.toolbar && <div class="basic-table-toolbar">{getSlot(slots, 'toolbar')}</div>}
  12 + </>
  13 + );
  14 +};
src/components/Table/src/const.ts 0 → 100644
  1 +export const ROW_KEY = 'key';
  2 +
  3 +export const PAGE_SIZE_OPTIONS = ['10', '50', '80', '100'];
  4 +
  5 +export const PAGE_SIZE = ~~PAGE_SIZE_OPTIONS[0];
  6 +
  7 +export const FETCH_SETTING = {
  8 + pageField: 'page',
  9 + sizeField: 'pageSize',
  10 + listField: 'items',
  11 + totalField: 'total',
  12 +};
src/components/Table/src/hooks/useColumns.ts 0 → 100644
  1 +import { BasicColumn, BasicTableProps } from '../types/table';
  2 +import { PaginationProps } from '../types/pagination';
  3 +import { unref, ComputedRef, Ref, computed, watch, ref } from 'vue';
  4 +import { isBoolean, isArray, isObject } from '/@/utils/is';
  5 +import { PAGE_SIZE } from '../const';
  6 +import { useProps } from './useProps';
  7 +
  8 +export function useColumns(
  9 + refProps: ComputedRef<BasicTableProps>,
  10 + getPaginationRef: ComputedRef<false | PaginationProps>
  11 +) {
  12 + const { propsRef } = useProps(refProps);
  13 +
  14 + const columnsRef = (ref(unref(propsRef).columns) as unknown) as Ref<BasicColumn[]>;
  15 + const cacheColumnsRef = (ref(unref(propsRef).columns) as unknown) as Ref<BasicColumn[]>;
  16 +
  17 + watch(
  18 + () => unref(propsRef).columns,
  19 + (columns) => {
  20 + columnsRef.value = columns;
  21 + cacheColumnsRef.value = columns;
  22 + },
  23 + {
  24 + immediate: true,
  25 + }
  26 + );
  27 + const getColumnsRef = computed(() => {
  28 + const props = unref(propsRef);
  29 + const { showIndexColumn, indexColumnProps, ellipsis, actionColumn, isTreeTable } = props;
  30 +
  31 + const columns = unref(columnsRef);
  32 + if (!columns) {
  33 + return [];
  34 + }
  35 + let pushIndexColumns = false;
  36 + columns.forEach((item) => {
  37 + const { key, dataIndex } = item;
  38 + item.align = item.align || 'center';
  39 + if (ellipsis) {
  40 + if (!key) {
  41 + item.key = dataIndex;
  42 + }
  43 + if (!isBoolean(item.ellipsis)) {
  44 + Object.assign(item, {
  45 + ellipsis,
  46 + });
  47 + }
  48 + }
  49 + const indIndex = columns.findIndex((column) => column.flag === 'INDEX');
  50 + if (showIndexColumn && !isTreeTable) {
  51 + pushIndexColumns = indIndex === -1;
  52 + } else if (!showIndexColumn && !isTreeTable && indIndex !== -1) {
  53 + columns.splice(indIndex, 1);
  54 + }
  55 + });
  56 +
  57 + if (pushIndexColumns) {
  58 + const isFixedLeft = columns.some((item) => item.fixed === 'left');
  59 +
  60 + columns.unshift({
  61 + flag: 'INDEX',
  62 + width: 50,
  63 + title: '序号',
  64 + align: 'center',
  65 + customRender: ({ index }) => {
  66 + const getPagination = unref(getPaginationRef);
  67 + if (isBoolean(getPagination)) {
  68 + return `${index + 1}`;
  69 + }
  70 + const { current = 1, pageSize = PAGE_SIZE } = getPagination;
  71 + const currentIndex = (current - 1) * pageSize + index + 1;
  72 + return currentIndex;
  73 + },
  74 + ...(isFixedLeft
  75 + ? {
  76 + fixed: 'left',
  77 + }
  78 + : {}),
  79 + ...indexColumnProps,
  80 + });
  81 + }
  82 + if (actionColumn) {
  83 + const hasIndex = columns.findIndex((column) => column.flag === 'ACTION');
  84 + if (hasIndex === -1) {
  85 + columns.push({
  86 + fixed: 'right',
  87 + ...actionColumn,
  88 + flag: 'ACTION',
  89 + });
  90 + } else {
  91 + columns[hasIndex] = {
  92 + ...columns[hasIndex],
  93 + fixed: 'right',
  94 + ...actionColumn,
  95 + flag: 'ACTION',
  96 + };
  97 + }
  98 + }
  99 + return columns;
  100 + });
  101 +
  102 + function setColumns(columns: BasicColumn[] | string[]) {
  103 + if (!isArray(columns)) {
  104 + return;
  105 + }
  106 + if (columns.length <= 0) {
  107 + columnsRef.value = [];
  108 + return;
  109 + }
  110 +
  111 + const firstColumn = columns[0];
  112 + if (isObject(firstColumn)) {
  113 + columnsRef.value = columns as any;
  114 + } else {
  115 + const newColumns = unref(cacheColumnsRef).filter((item) =>
  116 + (columns as string[]).includes(item.key! || item.dataIndex!)
  117 + );
  118 + columnsRef.value = newColumns;
  119 + }
  120 + }
  121 +
  122 + return { getColumnsRef, setColumns };
  123 +}
src/components/Table/src/hooks/useDataSource.ts 0 → 100644
  1 +import { useTimeout } from '/@/hooks/core/useTimeout';
  2 +import { BasicTableProps, FetchParams } from '../types/table';
  3 +import { PaginationProps } from '../types/pagination';
  4 +import { watch, ref, unref, ComputedRef, computed, onMounted, Ref } from 'vue';
  5 +import { buildUUID } from '/@/utils/uuid';
  6 +import { isFunction, isBoolean } from '/@/utils/is';
  7 +import { FETCH_SETTING, ROW_KEY } from '../const';
  8 +import { get } from 'lodash-es';
  9 +import { useProps } from './useProps';
  10 +
  11 +interface ActionType {
  12 + getPaginationRef: ComputedRef<false | PaginationProps>;
  13 + setPagination: (info: Partial<PaginationProps>) => void;
  14 + loadingRef: Ref<boolean | undefined>;
  15 + getFieldsValue: () => {
  16 + [field: string]: any;
  17 + };
  18 +}
  19 +export function useDataSource(
  20 + refProps: ComputedRef<BasicTableProps>,
  21 + { getPaginationRef, setPagination, loadingRef, getFieldsValue }: ActionType,
  22 + emit: EmitType
  23 +) {
  24 + const { propsRef } = useProps(refProps);
  25 +
  26 + const dataSourceRef = ref<any[]>([]);
  27 +
  28 + watch(
  29 + () => unref(propsRef).dataSource,
  30 + (data: any[]) => {
  31 + const { api } = unref(propsRef);
  32 + !api && (dataSourceRef.value = data);
  33 + },
  34 + { immediate: true }
  35 + );
  36 +
  37 + function setTableKey(items: any[]) {
  38 + if (!items || !Array.isArray(items)) {
  39 + return;
  40 + }
  41 + items.forEach((item) => {
  42 + if (!item[ROW_KEY]) {
  43 + item[ROW_KEY] = buildUUID();
  44 + }
  45 + if (item.children && item.children.length) {
  46 + setTableKey(item.children);
  47 + }
  48 + });
  49 + }
  50 + const getAutoCreateKey = computed(() => {
  51 + return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
  52 + });
  53 +
  54 + const getDataSourceRef = computed(() => {
  55 + const dataSource = unref(dataSourceRef);
  56 + if (!dataSource || dataSource.length === 0) {
  57 + return [];
  58 + }
  59 + if (unref(getAutoCreateKey)) {
  60 + const firstItem = dataSource[0];
  61 + const lastItem = dataSource[dataSource.length - 1];
  62 +
  63 + if (firstItem && lastItem) {
  64 + if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
  65 + unref(dataSourceRef).forEach((item) => {
  66 + if (!item[ROW_KEY]) {
  67 + item[ROW_KEY] = buildUUID();
  68 + }
  69 + if (item.children && item.children.length) {
  70 + setTableKey(item.children);
  71 + }
  72 + });
  73 + }
  74 + }
  75 + }
  76 + return unref(dataSourceRef);
  77 + });
  78 +
  79 + async function fetch(opt?: FetchParams) {
  80 + const { api, searchInfo, fetchSetting, beforeFetch, afterFetch, useSearchForm } = unref(
  81 + propsRef
  82 + );
  83 + if (!api && !isFunction(api)) return;
  84 + try {
  85 + loadingRef.value = true;
  86 + const { pageField, sizeField, listField, totalField } = fetchSetting || FETCH_SETTING;
  87 + let pageParams: any = {};
  88 + if (isBoolean(getPaginationRef)) {
  89 + pageParams = {};
  90 + } else {
  91 + const { current, pageSize } = unref(getPaginationRef) as PaginationProps;
  92 + pageParams[pageField] = opt?.page || current;
  93 + pageParams[sizeField] = pageSize;
  94 + }
  95 +
  96 + let params: any = {
  97 + ...pageParams,
  98 + ...(useSearchForm ? getFieldsValue() : {}),
  99 + ...searchInfo,
  100 + ...(opt ? opt.searchInfo : {}),
  101 + };
  102 + if (beforeFetch && isFunction(beforeFetch)) {
  103 + params = beforeFetch(params) || params;
  104 + }
  105 +
  106 + const res = await api(params);
  107 + let resultItems: any[] = get(res, listField);
  108 + const resultTotal: number = get(res, totalField);
  109 + if (afterFetch && isFunction(afterFetch)) {
  110 + resultItems = afterFetch(resultItems) || resultItems;
  111 + }
  112 +
  113 + dataSourceRef.value = resultItems;
  114 + setPagination({
  115 + total: resultTotal || 0,
  116 + });
  117 + if (opt && opt.page) {
  118 + setPagination({
  119 + current: opt.page || 1,
  120 + });
  121 + }
  122 + emit('fetch-success', {
  123 + items: unref(resultItems),
  124 + total: resultTotal,
  125 + });
  126 + } catch (error) {
  127 + emit('fetch-error', error);
  128 + dataSourceRef.value = [];
  129 + setPagination({
  130 + total: 0,
  131 + });
  132 + } finally {
  133 + loadingRef.value = false;
  134 + }
  135 + }
  136 +
  137 + function setTableData(values: any[]) {
  138 + dataSourceRef.value = values;
  139 + }
  140 + onMounted(() => {
  141 + // 转异步任务
  142 + useTimeout(() => {
  143 + unref(propsRef).immediate && fetch();
  144 + }, 0);
  145 + });
  146 +
  147 + return { getDataSourceRef, setTableData, getAutoCreateKey, fetch: fetch };
  148 +}
src/components/Table/src/hooks/useLoading.ts 0 → 100644
  1 +import { watch, ref, ComputedRef, unref } from 'vue';
  2 +import { BasicTableProps } from '../types/table';
  3 +import { useProps } from './useProps';
  4 +export function useLoading(refProps: ComputedRef<BasicTableProps>) {
  5 + const { propsRef } = useProps(refProps);
  6 +
  7 + const loadingRef = ref(unref(propsRef).loading);
  8 + watch(
  9 + () => unref(propsRef).loading,
  10 + (v: boolean) => {
  11 + loadingRef.value = v;
  12 + }
  13 + );
  14 + return { loadingRef };
  15 +}
src/components/Table/src/hooks/usePagination.tsx 0 → 100644
  1 +import { computed, unref, ref, ComputedRef } from 'vue';
  2 +import { PaginationProps } from '../types/pagination';
  3 +import { isBoolean } from '/@/utils/is';
  4 +import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
  5 +
  6 +import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '../const';
  7 +import { useProps } from './useProps';
  8 +import { BasicTableProps } from '../..';
  9 +export function usePagination(refProps: ComputedRef<BasicTableProps>) {
  10 + const configRef = ref<PaginationProps>({});
  11 + const { propsRef } = useProps(refProps);
  12 +
  13 + const getPaginationRef = computed((): PaginationProps | false => {
  14 + const { pagination } = unref(propsRef);
  15 + if (isBoolean(pagination) && !pagination) {
  16 + return false;
  17 + }
  18 + return {
  19 + current: 1,
  20 + pageSize: PAGE_SIZE,
  21 + size: 'small',
  22 + defaultPageSize: PAGE_SIZE,
  23 + showTotal: (total) => `共 ${total} 条数据`,
  24 + showSizeChanger: true,
  25 + pageSizeOptions: PAGE_SIZE_OPTIONS,
  26 + itemRender: ({ page, type, originalElement }) => {
  27 + if (type === 'prev') {
  28 + if (page === 0) {
  29 + return null;
  30 + }
  31 + return <LeftOutlined />;
  32 + } else if (type === 'next') {
  33 + if (page === 1) {
  34 + return null;
  35 + }
  36 + return <RightOutlined />;
  37 + }
  38 + return originalElement;
  39 + },
  40 + showQuickJumper: true,
  41 + ...(isBoolean(pagination) ? {} : pagination),
  42 + ...unref(configRef),
  43 + };
  44 + });
  45 +
  46 + function setPagination(info: Partial<PaginationProps>) {
  47 + configRef.value = {
  48 + ...unref(getPaginationRef),
  49 + ...info,
  50 + };
  51 + }
  52 + return { getPaginationRef, setPagination };
  53 +}
src/components/Table/src/hooks/useProps.ts 0 → 100644
  1 +/*
  2 + * @description:
  3 + * @author: wenbin.chen
  4 + * @Date: 2020-05-12 13:20:26
  5 + * @LastEditors: vben
  6 + * @LastEditTime: 2020-10-07 14:52:34
  7 + * @email: 190848757@qq.com
  8 + */
  9 +
  10 +import { Ref, ref, watch, unref } from 'vue';
  11 +import { BasicTableProps } from '../types/table';
  12 +
  13 +/**
  14 + * @description:
  15 + * @Date: 2020-05-12 13:20:37
  16 + */
  17 +export function useProps(props: Readonly<Ref<BasicTableProps>>) {
  18 + const propsRef = (ref<BasicTableProps>(unref(props)) as unknown) as Ref<BasicTableProps>;
  19 + watch(
  20 + () => props.value,
  21 + (v) => {
  22 + propsRef.value = unref(v);
  23 + },
  24 + {
  25 + immediate: false,
  26 + }
  27 + );
  28 + return { propsRef };
  29 +}
src/components/Table/src/hooks/useProvinceTable.ts 0 → 100644
  1 +import { provide, inject } from 'vue';
  2 +import { TableActionType } from '../types/table';
  3 +
  4 +const key = Symbol('table');
  5 +
  6 +export function provideTable(instance: TableActionType) {
  7 + provide(key, instance);
  8 +}
  9 +
  10 +export function injectTable(): TableActionType {
  11 + return inject(key) as TableActionType;
  12 +}
src/components/Table/src/hooks/useRowSelection.ts 0 → 100644
  1 +import { computed, ref, unref, ComputedRef } from 'vue';
  2 +import { BasicTableProps } from '../types/table';
  3 +import { TableRowSelection } from 'ant-design-vue/types/table/table';
  4 +import { useProps } from './useProps';
  5 +
  6 +/* eslint-disable */
  7 +export function useRowSelection(refProps: ComputedRef<BasicTableProps>, emit: EmitType) {
  8 + const { propsRef } = useProps(refProps);
  9 +
  10 + const selectedRowKeysRef = ref<string[]>([]);
  11 + const selectedRowRef = ref<any[]>([]);
  12 +
  13 + const getRowSelectionRef = computed((): TableRowSelection<any> | null => {
  14 + const rowSelection = unref(propsRef).rowSelection;
  15 + if (!rowSelection) {
  16 + return null;
  17 + }
  18 + return {
  19 + selectedRowKeys: unref(selectedRowKeysRef),
  20 + hideDefaultSelections: false,
  21 + onChange: (selectedRowKeys: string[], selectedRows: any[]) => {
  22 + selectedRowKeysRef.value = selectedRowKeys;
  23 + selectedRowRef.value = selectedRows;
  24 + emit('selection-change', {
  25 + keys: selectedRowKeys,
  26 + rows: selectedRows,
  27 + });
  28 + },
  29 + ...rowSelection,
  30 + };
  31 + });
  32 + function setSelectedRowKeys(rowKeys: string[]) {
  33 + selectedRowKeysRef.value = rowKeys;
  34 + }
  35 +
  36 + function clearSelectedRowKeys() {
  37 + selectedRowRef.value = [];
  38 + selectedRowKeysRef.value = [];
  39 + }
  40 +
  41 + function deleteSelectRowByKey(key: string) {
  42 + const selectedRowKeys = unref(selectedRowKeysRef);
  43 + const index = selectedRowKeys.findIndex((item) => item === key);
  44 + if (index !== -1) {
  45 + unref(selectedRowKeysRef).splice(index, 1);
  46 + }
  47 + }
  48 + function getSelectRowKeys() {
  49 + return unref(selectedRowKeysRef);
  50 + }
  51 + function getSelectRows() {
  52 + return unref(selectedRowRef);
  53 + }
  54 +
  55 + return {
  56 + getRowSelectionRef,
  57 + getSelectRows,
  58 + getSelectRowKeys,
  59 + setSelectedRowKeys,
  60 + clearSelectedRowKeys,
  61 + deleteSelectRowByKey,
  62 + };
  63 +}
src/components/Table/src/hooks/useTable.ts 0 → 100644
  1 +import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table';
  2 +import type { PaginationProps } from '../types/pagination';
  3 +import { ref, getCurrentInstance, onUnmounted, unref } from 'vue';
  4 +import { isProdMode } from '/@/utils/env';
  5 +
  6 +export function useTable(
  7 + tableProps?: Partial<BasicTableProps>
  8 +): [(instance: TableActionType) => void, TableActionType] {
  9 + if (!getCurrentInstance()) {
  10 + throw new Error('Please put useTable function in the setup function!');
  11 + }
  12 +
  13 + const tableRef = ref<TableActionType | null>(null);
  14 + const loadedRef = ref<boolean | null>(false);
  15 +
  16 + function register(instance: TableActionType) {
  17 + onUnmounted(() => {
  18 + tableRef.value = null;
  19 + loadedRef.value = null;
  20 + });
  21 + if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) {
  22 + return;
  23 + }
  24 + tableRef.value = instance;
  25 + tableProps && instance.setProps(tableProps);
  26 + loadedRef.value = true;
  27 + }
  28 +
  29 + function getTableInstance(): TableActionType {
  30 + const table = unref(tableRef);
  31 + if (!table) {
  32 + throw new Error('table is undefined!');
  33 + }
  34 + return table;
  35 + }
  36 +
  37 + const methods: TableActionType = {
  38 + reload: (opt?: FetchParams) => {
  39 + getTableInstance().reload(opt);
  40 + },
  41 + setProps: (props: Partial<BasicTableProps>) => {
  42 + getTableInstance().setProps(props);
  43 + },
  44 + redoHeight: () => {
  45 + getTableInstance().redoHeight();
  46 + },
  47 + setLoading: (loading: boolean) => {
  48 + getTableInstance().setLoading(loading);
  49 + },
  50 + getDataSource: () => {
  51 + return getTableInstance().getDataSource();
  52 + },
  53 + getColumns: ({ ignoreIndex = false }: { ignoreIndex?: boolean } = {}) => {
  54 + const columns = getTableInstance().getColumns({ ignoreIndex }) || [];
  55 +
  56 + return columns;
  57 + },
  58 + setColumns: (columns: BasicColumn[]) => {
  59 + getTableInstance().setColumns(columns);
  60 + },
  61 + setTableData: (values: any[]) => {
  62 + return getTableInstance().setTableData(values);
  63 + },
  64 + setPagination: (info: Partial<PaginationProps>) => {
  65 + return getTableInstance().setPagination(info);
  66 + },
  67 + deleteSelectRowByKey: (key: string) => {
  68 + getTableInstance().deleteSelectRowByKey(key);
  69 + },
  70 + getSelectRowKeys: () => {
  71 + return getTableInstance().getSelectRowKeys();
  72 + },
  73 + getSelectRows: () => {
  74 + return getTableInstance().getSelectRows();
  75 + },
  76 + clearSelectedRowKeys: () => {
  77 + getTableInstance().clearSelectedRowKeys();
  78 + },
  79 + setSelectedRowKeys: (keys: string[] | number[]) => {
  80 + getTableInstance().setSelectedRowKeys(keys);
  81 + },
  82 + getPaginationRef: () => {
  83 + return getTableInstance().getPaginationRef();
  84 + },
  85 + } as TableActionType;
  86 +
  87 + return [register, methods];
  88 +}
src/components/Table/src/hooks/useTableScroll.ts 0 → 100644
  1 +import { BasicTableProps } from '../types/table';
  2 +import { computed, Ref, onMounted, unref, ref, nextTick, ComputedRef, watch } from 'vue';
  3 +import { getViewportOffset } from '/@/utils/domUtils';
  4 +import { triggerWindowResize } from '/@/utils/event/triggerWindowResizeEvent';
  5 +import { isBoolean } from '/@/utils/is';
  6 +import { useTimeout } from '/@/hooks/core/useTimeout';
  7 +import { useWindowSizeFn } from '/@/hooks/event/useWindowSize';
  8 +import { useProps } from './useProps';
  9 +
  10 +export function useTableScroll(refProps: ComputedRef<BasicTableProps>, tableElRef: Ref<any>) {
  11 + const { propsRef } = useProps(refProps);
  12 +
  13 + const tableHeightRef: Ref<number | null> = ref(null);
  14 +
  15 + watch(
  16 + () => unref(propsRef).canResize,
  17 + () => {
  18 + redoHeight();
  19 + }
  20 + );
  21 + function redoHeight() {
  22 + const { canResize } = unref(propsRef);
  23 +
  24 + if (!canResize) {
  25 + return;
  26 + }
  27 + calcTableHeight();
  28 + }
  29 +
  30 + async function calcTableHeight(cb?: () => void) {
  31 + const { canResize, resizeHeightOffset, pagination, maxHeight } = unref(propsRef);
  32 + if (!canResize) {
  33 + return;
  34 + }
  35 + await nextTick();
  36 + const table = unref(tableElRef) as any;
  37 +
  38 + if (!table) {
  39 + return;
  40 + }
  41 + const tableEl: Element = table.$el;
  42 + if (!tableEl) {
  43 + return;
  44 + }
  45 + const el: HTMLElement | null = tableEl.querySelector('.ant-table-thead ');
  46 + // const layoutMain: Element | null = document.querySelector('.default-layout__main ');
  47 + if (!el) {
  48 + return;
  49 + }
  50 + // 表格距离底部高度
  51 + const { bottomIncludeBody } = getViewportOffset(el);
  52 + // 表格高度+距离底部高度-自定义偏移量
  53 +
  54 + const paddingHeight = 32;
  55 + const borderHeight = 2 * 2;
  56 + // 分页器高度
  57 +
  58 + // TODO 先固定20
  59 + const paginationHeight = 20;
  60 + // if (!isBoolean(pagination)) {
  61 + // const paginationDom = tableEl.querySelector('.ant-pagination') as HTMLElement;
  62 + // if (paginationDom) {
  63 + // const offsetHeight = paginationDom.offsetHeight;
  64 + // paginationHeight += offsetHeight || 0;
  65 + // }
  66 + // }
  67 +
  68 + let footerHeight = 0;
  69 + if (!isBoolean(pagination)) {
  70 + const footerEl = tableEl.querySelector('.ant-table-footer') as HTMLElement;
  71 + if (footerEl) {
  72 + const offsetHeight = footerEl.offsetHeight;
  73 + footerHeight += offsetHeight || 0;
  74 + }
  75 + }
  76 + let headerHeight = 0;
  77 + if (el) {
  78 + headerHeight = (el as HTMLElement).offsetHeight;
  79 + }
  80 + tableHeightRef.value =
  81 + bottomIncludeBody -
  82 + (resizeHeightOffset || 0) -
  83 + paddingHeight -
  84 + borderHeight -
  85 + paginationHeight -
  86 + footerHeight -
  87 + headerHeight;
  88 + useTimeout(() => {
  89 + tableHeightRef.value =
  90 + tableHeightRef.value! > maxHeight! ? (maxHeight as number) : tableHeightRef.value;
  91 + cb && cb();
  92 + }, 0);
  93 + }
  94 +
  95 + const getCanResize = computed(() => {
  96 + const { canResize, scroll } = unref(propsRef);
  97 + return canResize && !(scroll || {}).y;
  98 + });
  99 +
  100 + useWindowSizeFn(calcTableHeight, 100);
  101 +
  102 + // function clear() {
  103 + // window.clearInterval(timer);
  104 + // }
  105 +
  106 + onMounted(() => {
  107 + if (unref(getCanResize)) {
  108 + calcTableHeight();
  109 + const hasFixedLeft = (unref(propsRef).columns || []).some((item) => item.fixed === 'left');
  110 + // TODO antv table问题情况太多,只能先用下面方式定时器hack
  111 + useTimeout(() => {
  112 + calcTableHeight(() => {
  113 + // 有左侧固定列的时候才有问题
  114 + hasFixedLeft &&
  115 + useTimeout(() => {
  116 + triggerWindowResize();
  117 + }, 300);
  118 + });
  119 + }, 200);
  120 + }
  121 + });
  122 + const getScrollRef = computed(() => {
  123 + const tableHeight = unref(tableHeightRef);
  124 + const { canResize, scroll } = unref(propsRef);
  125 +
  126 + return {
  127 + x: '100%',
  128 + y: canResize ? tableHeight : null,
  129 + scrollToFirstRowOnChange: false,
  130 + ...scroll,
  131 + };
  132 + });
  133 + return { getScrollRef, redoHeight };
  134 +}
src/components/Table/src/props.ts 0 → 100644
  1 +import { PropType } from 'vue';
  2 +import { PaginationProps } from './types/pagination';
  3 +import { BasicColumn, FetchSetting } from './types/table';
  4 +import { TableCustomRecord, TableRowSelection } from 'ant-design-vue/types/table/table';
  5 +import { FormProps } from '/@/components/Form/index';
  6 +import { FETCH_SETTING } from './const';
  7 +
  8 +// 注释看 types/table
  9 +export const basicProps = {
  10 + autoCreateKey: {
  11 + type: Boolean as PropType<boolean>,
  12 + default: true,
  13 + },
  14 + striped: {
  15 + type: Boolean as PropType<boolean>,
  16 + default: true,
  17 + },
  18 + showSummary: {
  19 + type: Boolean as PropType<boolean>,
  20 + default: false,
  21 + },
  22 +
  23 + summaryFunc: {
  24 + type: [Function, Array] as PropType<(...arg: any[]) => any[]>,
  25 + default: null,
  26 + },
  27 +
  28 + canColDrag: {
  29 + type: Boolean as PropType<boolean>,
  30 + default: true,
  31 + },
  32 + isTreeTable: {
  33 + type: Boolean as PropType<boolean>,
  34 + default: false,
  35 + },
  36 + api: {
  37 + type: Function as PropType<(...arg: any[]) => Promise<any>>,
  38 + default: null,
  39 + },
  40 + beforeFetch: {
  41 + type: Function as PropType<Fn>,
  42 + default: null,
  43 + },
  44 + afterFetch: {
  45 + type: Function as PropType<Fn>,
  46 + default: null,
  47 + },
  48 + handleSearchInfoFn: {
  49 + type: Function as PropType<Fn>,
  50 + default: null,
  51 + },
  52 + fetchSetting: {
  53 + type: Object as PropType<FetchSetting>,
  54 + default: () => {
  55 + return FETCH_SETTING;
  56 + },
  57 + },
  58 + // 立即请求接口
  59 + immediate: { type: Boolean as PropType<boolean>, default: true },
  60 +
  61 + emptyDataIsShowTable: {
  62 + type: Boolean as PropType<boolean>,
  63 + default: true,
  64 + },
  65 + // 额外的请求参数
  66 + searchInfo: {
  67 + type: Object as PropType<any>,
  68 + default: null,
  69 + },
  70 + // 使用搜索表单
  71 + useSearchForm: {
  72 + type: Boolean as PropType<boolean>,
  73 + default: false,
  74 + },
  75 + // 表单配置
  76 + formConfig: {
  77 + type: Object as PropType<Partial<FormProps>>,
  78 + default: null,
  79 + },
  80 + columns: {
  81 + type: [Array] as PropType<BasicColumn[]>,
  82 + default: null,
  83 + },
  84 + showIndexColumn: {
  85 + type: Boolean as PropType<boolean>,
  86 + default: true,
  87 + },
  88 + indexColumnProps: {
  89 + type: Object as PropType<BasicColumn>,
  90 + default: null,
  91 + },
  92 + actionColumn: {
  93 + type: Object as PropType<BasicColumn>,
  94 + default: null,
  95 + },
  96 + ellipsis: {
  97 + type: Boolean as PropType<boolean>,
  98 + default: true,
  99 + },
  100 + canResize: {
  101 + type: Boolean as PropType<boolean>,
  102 + default: true,
  103 + },
  104 + clearSelectOnPageChange: {
  105 + type: Boolean as PropType<boolean>,
  106 + default: false,
  107 + },
  108 + resizeHeightOffset: {
  109 + type: Number as PropType<number>,
  110 + default: 0,
  111 + },
  112 + rowSelection: {
  113 + type: Object as PropType<TableRowSelection<any> | null>,
  114 + default: null,
  115 + },
  116 + title: {
  117 + type: [String, Function] as PropType<string | ((data: any) => any)>,
  118 + default: null,
  119 + },
  120 + titleHelpMessage: {
  121 + type: [String, Array] as PropType<string | string[]>,
  122 + },
  123 + maxHeight: {
  124 + type: Number as PropType<number>,
  125 + },
  126 + dataSource: {
  127 + type: Array as PropType<any[]>,
  128 + default: null,
  129 + },
  130 + rowKey: {
  131 + type: [String, Function] as PropType<string | ((record: any) => string)>,
  132 + default: '',
  133 + },
  134 + bordered: {
  135 + type: Boolean as PropType<boolean>,
  136 + default: true,
  137 + },
  138 + pagination: {
  139 + type: [Object, Boolean] as PropType<PaginationProps | boolean>,
  140 + default: null,
  141 + },
  142 +
  143 + loading: {
  144 + type: Boolean as PropType<boolean>,
  145 + default: false,
  146 + },
  147 + rowClassName: {
  148 + type: Function as PropType<(record: TableCustomRecord<any>, index: number) => string>,
  149 + },
  150 +
  151 + scroll: {
  152 + type: Object as PropType<{ x: number | true; y: number }>,
  153 + default: null,
  154 + },
  155 +};
src/components/Table/src/style/editable-cell.less 0 → 100644
  1 +@import (reference) '../../../../design/index.less';
  2 +
  3 +@prefix-cls: ~'editable-cell';
  4 +
  5 +.@{prefix-cls} {
  6 + position: relative;
  7 +
  8 + &__wrapper {
  9 + display: flex;
  10 + align-items: center;
  11 + }
  12 +
  13 + &__icon {
  14 + &:hover {
  15 + transform: scale(1.2);
  16 +
  17 + svg {
  18 + color: @primary-color;
  19 + }
  20 + }
  21 + }
  22 +
  23 + &__normal {
  24 + padding-right: 48px;
  25 +
  26 + &-icon {
  27 + position: absolute;
  28 + top: 4px;
  29 + right: 0;
  30 + display: none;
  31 + width: 20px;
  32 + cursor: pointer;
  33 + }
  34 + }
  35 +
  36 + &:hover {
  37 + .@{prefix-cls}__normal-icon {
  38 + display: inline-block;
  39 + }
  40 + }
  41 +}
src/components/Table/src/style/index.less 0 → 100644
  1 +@import (reference) '../../../../design/index.less';
  2 +@border-color: hsla(0, 0%, 80.8%, 0.25);
  3 +
  4 +.basic-table {
  5 + &-title {
  6 + display: flex;
  7 + justify-content: space-between;
  8 + align-items: center;
  9 + }
  10 +
  11 + &-row__striped {
  12 + td {
  13 + background: #fafafa;
  14 + }
  15 + }
  16 +
  17 + &-img__preview {
  18 + display: flex;
  19 +
  20 + img {
  21 + margin-right: 4px;
  22 + }
  23 + }
  24 +
  25 + &-action {
  26 + display: flex;
  27 + }
  28 +
  29 + &-toolbar {
  30 + > * {
  31 + margin-right: 10px;
  32 + }
  33 + }
  34 +
  35 + .resize-table-th {
  36 + position: relative !important;
  37 +
  38 + .table-draggable-handle {
  39 + position: absolute;
  40 + right: -5px;
  41 + bottom: 0;
  42 + left: auto !important;
  43 + height: 100% !important;
  44 + cursor: col-resize;
  45 + transform: none !important;
  46 + touch-action: none;
  47 + }
  48 + }
  49 +
  50 + &-drag-body {
  51 + position: relative;
  52 + cursor: move;
  53 + }
  54 +
  55 + .drag-line td {
  56 + border-top: 2px dashed @primary-color;
  57 + }
  58 +
  59 + .ant-table-wrapper {
  60 + padding: 8px;
  61 + background: #fff;
  62 + border-radius: 2px;
  63 +
  64 + .ant-table-title {
  65 + padding: 0 0 10px 0 !important;
  66 + }
  67 +
  68 + .ant-table.ant-table-bordered .ant-table-title {
  69 + border: none !important;
  70 + }
  71 + }
  72 +
  73 + //
  74 + .ant-table {
  75 + &-title {
  76 + display: flex;
  77 + justify-content: space-between;
  78 + align-items: center;
  79 + padding: 8px 6px;
  80 + }
  81 +
  82 + .ant-table-thead > tr > th,
  83 + .ant-table-header {
  84 + background: #f1f3f4;
  85 + }
  86 +
  87 + .ant-table-tbody > tr.ant-table-row-selected td {
  88 + background: fade(@primary-color, 8%) !important;
  89 + }
  90 + }
  91 +
  92 + .ant-table-bordered .ant-table-header > table,
  93 + .ant-table-bordered .ant-table-body > table,
  94 + .ant-table-bordered .ant-table-fixed-left table,
  95 + .ant-table-bordered .ant-table-fixed-right table {
  96 + border: 1px solid @border-color;
  97 + }
  98 +
  99 + .ant-table-thead {
  100 + th {
  101 + border: none;
  102 + }
  103 + }
  104 +
  105 + .ant-table-bordered .ant-table-tbody > tr > td {
  106 + border-bottom: 1px solid @border-color;
  107 +
  108 + &:last-child {
  109 + border-right: none !important;
  110 + }
  111 + }
  112 +
  113 + .ant-table.ant-table-bordered .ant-table-footer,
  114 + .ant-table.ant-table-bordered .ant-table-title {
  115 + border: 1px solid @border-color !important;
  116 + }
  117 +
  118 + .ant-table-bordered.ant-table-empty .ant-table-placeholder {
  119 + border: 1px solid @border-color !important;
  120 + }
  121 +
  122 + .ant-table td {
  123 + white-space: nowrap;
  124 + }
  125 +
  126 + .ant-table-row-cell-last {
  127 + border-right: none !important;
  128 + }
  129 +
  130 + .ant-table-bordered .ant-table-thead > tr > th,
  131 + .ant-table-bordered .ant-table-tbody > tr > td {
  132 + border-right: 1px solid @border-color;
  133 + }
  134 +
  135 + .ant-table-thead > tr > th,
  136 + .ant-table-tbody > tr > td {
  137 + padding: 9px 8px !important;
  138 + }
  139 +
  140 + .ant-pagination {
  141 + margin: 10px 0 0 0;
  142 + }
  143 +
  144 + .ant-table-body {
  145 + overflow-x: auto !important;
  146 + overflow-y: scroll !important;
  147 + }
  148 +
  149 + .ant-table-header {
  150 + margin-bottom: 0 !important;
  151 + overflow-x: hidden !important;
  152 + overflow-y: scroll !important;
  153 + }
  154 +
  155 + .ant-table-fixed-right .ant-table-header {
  156 + border-left: 1px solid @border-color;
  157 +
  158 + .ant-table-fixed {
  159 + border-bottom: none;
  160 + }
  161 + }
  162 +
  163 + .ant-table-fixed-left {
  164 + .ant-table-header {
  165 + overflow-y: hidden !important;
  166 + }
  167 +
  168 + .ant-table-fixed {
  169 + border-bottom: none;
  170 + }
  171 + }
  172 +
  173 + .ant-radio {
  174 + &-inner {
  175 + border-color: @text-color-base;
  176 + }
  177 + }
  178 +
  179 + .ant-checkbox {
  180 + &:not(.ant-checkbox-checked) {
  181 + .ant-checkbox-inner {
  182 + border-color: @text-color-base;
  183 + }
  184 + }
  185 + }
  186 +
  187 + .ant-table-bordered .ant-table-thead > tr:not(:last-child) > th,
  188 + .ant-table-tbody > tr > td {
  189 + word-break: break-word;
  190 + border-color: @border-color;
  191 + }
  192 +
  193 + .ant-table-footer {
  194 + padding: 0;
  195 +
  196 + .ant-table-wrapper {
  197 + padding: 0;
  198 + }
  199 +
  200 + table {
  201 + border: none !important;
  202 + }
  203 +
  204 + .ant-table-body {
  205 + overflow-x: hidden !important;
  206 + overflow-y: scroll !important;
  207 + }
  208 +
  209 + td {
  210 + padding: 12px 8px;
  211 + }
  212 + }
  213 +}
  214 +
  215 +.table-form-container {
  216 + padding: 16px;
  217 +
  218 + .ant-form {
  219 + padding: 12px 12px 4px 12px;
  220 + margin-bottom: 12px;
  221 + background: #fff;
  222 + border-radius: 2px;
  223 + }
  224 +
  225 + .ant-table-wrapper {
  226 + border-radius: 2px;
  227 + }
  228 +}
src/components/Table/src/types/componentType.ts 0 → 100644
  1 +export type ComponentType =
  2 + | 'Input'
  3 + | 'InputPassword'
  4 + | 'InputNumber'
  5 + | 'Select'
  6 + | 'Checkbox'
  7 + | 'CheckboxGroup'
  8 + | 'Switch';
src/components/Table/src/types/pagination.ts 0 → 100644
  1 +import { VNodeChild } from 'vue';
  2 +import { PaginationRenderProps } from 'ant-design-vue/types/pagination';
  3 +export interface PaginationProps {
  4 + /**
  5 + * total number of data items
  6 + * @default 0
  7 + * @type number
  8 + */
  9 + total?: number;
  10 +
  11 + /**
  12 + * default initial page number
  13 + * @default 1
  14 + * @type number
  15 + */
  16 + defaultCurrent?: number;
  17 +
  18 + /**
  19 + * current page number
  20 + * @type number
  21 + */
  22 + current?: number;
  23 +
  24 + /**
  25 + * default number of data items per page
  26 + * @default 10
  27 + * @type number
  28 + */
  29 + defaultPageSize?: number;
  30 +
  31 + /**
  32 + * number of data items per page
  33 + * @type number
  34 + */
  35 + pageSize?: number;
  36 +
  37 + /**
  38 + * Whether to hide pager on single page
  39 + * @default false
  40 + * @type boolean
  41 + */
  42 + hideOnSinglePage?: boolean;
  43 +
  44 + /**
  45 + * determine whether pageSize can be changed
  46 + * @default false
  47 + * @type boolean
  48 + */
  49 + showSizeChanger?: boolean;
  50 +
  51 + /**
  52 + * specify the sizeChanger options
  53 + * @default ['10', '20', '30', '40']
  54 + * @type string[]
  55 + */
  56 + pageSizeOptions?: string[];
  57 +
  58 + /**
  59 + * determine whether you can jump to pages directly
  60 + * @default false
  61 + * @type boolean
  62 + */
  63 + showQuickJumper?: boolean | object;
  64 +
  65 + /**
  66 + * to display the total number and range
  67 + * @type Function
  68 + */
  69 + showTotal?: (total: number, range: [number, number]) => any;
  70 +
  71 + /**
  72 + * specify the size of Pagination, can be set to small
  73 + * @default ''
  74 + * @type string
  75 + */
  76 + size?: string;
  77 +
  78 + /**
  79 + * whether to use simple mode
  80 + * @type boolean
  81 + */
  82 + simple?: boolean;
  83 +
  84 + /**
  85 + * to customize item innerHTML
  86 + * @type Function
  87 + */
  88 + itemRender?: (props: PaginationRenderProps) => VNodeChild | JSX.Element;
  89 +}
src/components/Table/src/types/table.ts 0 → 100644
  1 +import { VNodeChild } from 'vue';
  2 +import { PaginationProps } from './pagination';
  3 +import { FormProps } from '/@/components/Form/index';
  4 +import {
  5 + ExpandedRowRenderRecord,
  6 + PaginationConfig,
  7 + SorterResult,
  8 + TableCurrentDataSource,
  9 + TableCustomRecord,
  10 + TableRowSelection,
  11 +} from 'ant-design-vue/types/table/table';
  12 +import { ColumnProps } from 'ant-design-vue/types/table/column';
  13 +import { ComponentType } from './componentType';
  14 +export declare type SortOrder = 'ascend' | 'descend';
  15 +export interface ColumnFilterItem {
  16 + text?: string;
  17 + value?: string;
  18 + children?: any;
  19 +}
  20 +
  21 +export interface RenderEditableCellParams {
  22 + dataIndex: string;
  23 + component?: ComponentType;
  24 + componentOn?: { [key: string]: Fn };
  25 + componentProps?: any;
  26 +}
  27 +
  28 +export interface FetchParams {
  29 + searchInfo?: any;
  30 + page?: number;
  31 +}
  32 +
  33 +export interface GetColumnsParams {
  34 + ignoreIndex?: boolean;
  35 +}
  36 +export interface TableActionType {
  37 + reload: (opt?: FetchParams) => Promise<void>;
  38 + getSelectRows: () => any[];
  39 + clearSelectedRowKeys: () => void;
  40 + getSelectRowKeys: () => string[];
  41 + deleteSelectRowByKey: (key: string) => void;
  42 + setPagination: (info: Partial<PaginationProps>) => void;
  43 + setTableData: (values: any[]) => void;
  44 + getColumns: ({ ignoreIndex }?: GetColumnsParams) => BasicColumn[];
  45 + setColumns: (columns: BasicColumn[] | string[]) => void;
  46 + getDataSource: () => any[];
  47 + setLoading: (loading: boolean) => void;
  48 + setProps: (props: Partial<BasicTableProps>) => void;
  49 + redoHeight: () => void;
  50 + setSelectedRowKeys: (rowKeys: string[] | number[]) => void;
  51 + getPaginationRef: () => PaginationProps | boolean;
  52 +}
  53 +
  54 +export interface FetchSetting {
  55 + // 请求接口当前页数
  56 + pageField: string;
  57 + // 每页显示多少条
  58 + sizeField: string;
  59 + // 请求结果列表字段 支持 a.b.c
  60 + listField: string;
  61 + // 请求结果总数字段 支持 a.b.c
  62 + totalField: string;
  63 +}
  64 +export interface BasicTableProps<T = any> {
  65 + // 斑马纹
  66 + striped?: boolean;
  67 + // 是否自动生成key
  68 + autoCreateKey?: boolean;
  69 + // 计算合计行的方法
  70 + summaryFunc?: (...arg: any) => any[];
  71 + // 是否显示合计行
  72 + showSummary?: boolean;
  73 + // 是否可拖拽列
  74 + canColDrag?: boolean;
  75 + // 是否树表
  76 + isTreeTable?: boolean;
  77 + // 接口请求对象
  78 + api?: (...arg: any) => Promise<any>;
  79 + // 请求之前处理参数
  80 + beforeFetch?: Fn;
  81 + // 自定义处理接口返回参数
  82 + afterFetch?: Fn;
  83 + // 查询条件请求之前处理
  84 + handleSearchInfoFn?: Fn;
  85 + // 请求接口配置
  86 + fetchSetting?: FetchSetting;
  87 + // 立即请求接口
  88 + immediate?: boolean;
  89 + // 在开起搜索表单的时候,如果没有数据是否显示表格
  90 + emptyDataIsShowTable?: boolean;
  91 + // 额外的请求参数
  92 + searchInfo?: any;
  93 +
  94 + // 使用搜索表单
  95 + useSearchForm?: boolean;
  96 + // 表单配置
  97 + formConfig?: FormProps;
  98 + // 列配置
  99 + columns: BasicColumn[];
  100 + // 是否显示序号列
  101 + showIndexColumn?: boolean;
  102 + // 序号列配置
  103 + indexColumnProps?: BasicColumn;
  104 + actionColumn?: BasicColumn;
  105 + // 文本超过宽度是否显示。。。
  106 + ellipsis?: boolean;
  107 + // 是否可以自适应高度
  108 + canResize?: boolean;
  109 + // 自适应高度偏移, 计算结果-偏移量
  110 + resizeHeightOffset?: number;
  111 +
  112 + // 在分页改变的时候清空选项
  113 + clearSelectOnPageChange?: boolean;
  114 + //
  115 + rowKey?: string | ((record: any) => string);
  116 + // 数据
  117 + dataSource?: any[];
  118 + // 标题右侧提示
  119 + titleHelpMessage?: string | string[];
  120 + // 表格滚动最大高度
  121 + maxHeight?: number;
  122 + // 是否显示边框
  123 + bordered?: boolean;
  124 + // 分页配置
  125 + pagination?: PaginationProps | boolean;
  126 + // loading加载
  127 + loading?: boolean;
  128 +
  129 + /**
  130 + * The column contains children to display
  131 + * @default 'children'
  132 + * @type string | string[]
  133 + */
  134 + childrenColumnName?: string | string[];
  135 +
  136 + /**
  137 + * Override default table elements
  138 + * @type object
  139 + */
  140 + components?: object;
  141 +
  142 + /**
  143 + * Expand all rows initially
  144 + * @default false
  145 + * @type boolean
  146 + */
  147 + defaultExpandAllRows?: boolean;
  148 +
  149 + /**
  150 + * Initial expanded row keys
  151 + * @type string[]
  152 + */
  153 + defaultExpandedRowKeys?: string[];
  154 +
  155 + /**
  156 + * Current expanded row keys
  157 + * @type string[]
  158 + */
  159 + expandedRowKeys?: string[];
  160 +
  161 + /**
  162 + * Expanded container render for each row
  163 + * @type Function
  164 + */
  165 + expandedRowRender?: (record?: ExpandedRowRenderRecord<T>) => VNodeChild | JSX.Element;
  166 +
  167 + /**
  168 + * Customize row expand Icon.
  169 + * @type Function | VNodeChild
  170 + */
  171 + expandIcon?: Function | VNodeChild | JSX.Element;
  172 +
  173 + /**
  174 + * Whether to expand row by clicking anywhere in the whole row
  175 + * @default false
  176 + * @type boolean
  177 + */
  178 + expandRowByClick?: boolean;
  179 +
  180 + /**
  181 + * The index of `expandIcon` which column will be inserted when `expandIconAsCell` is false. default 0
  182 + */
  183 + expandIconColumnIndex?: number;
  184 +
  185 + /**
  186 + * Table footer renderer
  187 + * @type Function | VNodeChild
  188 + */
  189 + footer?: Function | VNodeChild | JSX.Element;
  190 +
  191 + /**
  192 + * Indent size in pixels of tree data
  193 + * @default 15
  194 + * @type number
  195 + */
  196 + indentSize?: number;
  197 +
  198 + /**
  199 + * i18n text including filter, sort, empty text, etc
  200 + * @default { filterConfirm: 'Ok', filterReset: 'Reset', emptyText: 'No Data' }
  201 + * @type object
  202 + */
  203 + locale?: object;
  204 +
  205 + /**
  206 + * Row's className
  207 + * @type Function
  208 + */
  209 + rowClassName?: (record: TableCustomRecord<T>) => string;
  210 +
  211 + /**
  212 + * Row selection config
  213 + * @type object
  214 + */
  215 + rowSelection?: TableRowSelection<T>;
  216 +
  217 + /**
  218 + * Set horizontal or vertical scrolling, can also be used to specify the width and height of the scroll area.
  219 + * It is recommended to set a number for x, if you want to set it to true,
  220 + * you need to add style .ant-table td { white-space: nowrap; }.
  221 + * @type object
  222 + */
  223 + scroll?: { x?: number | true; y?: number };
  224 +
  225 + /**
  226 + * Whether to show table header
  227 + * @default true
  228 + * @type boolean
  229 + */
  230 + showHeader?: boolean;
  231 +
  232 + /**
  233 + * Size of table
  234 + * @default 'default'
  235 + * @type string
  236 + */
  237 + size?: 'default' | 'middle' | 'small' | 'large';
  238 +
  239 + /**
  240 + * Table title renderer
  241 + * @type Function | ScopedSlot
  242 + */
  243 + title?: VNodeChild | JSX.Element;
  244 +
  245 + /**
  246 + * Set props on per header row
  247 + * @type Function
  248 + */
  249 + customHeaderRow?: (column: ColumnProps<T>, index: number) => object;
  250 +
  251 + /**
  252 + * Set props on per row
  253 + * @type Function
  254 + */
  255 + customRow?: (record: T, index: number) => object;
  256 +
  257 + /**
  258 + * `table-layout` attribute of table element
  259 + * `fixed` when header/columns are fixed, or using `column.ellipsis`
  260 + *
  261 + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout
  262 + * @version 1.5.0
  263 + */
  264 + tableLayout?: 'auto' | 'fixed' | string;
  265 +
  266 + /**
  267 + * the render container of dropdowns in table
  268 + * @param triggerNode
  269 + * @version 1.5.0
  270 + */
  271 + getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
  272 +
  273 + /**
  274 + * Data can be changed again before rendering.
  275 + * The default configuration of general user empty data.
  276 + * You can configured globally through [ConfigProvider](https://antdv.com/components/config-provider-cn/)
  277 + *
  278 + * @version 1.5.4
  279 + */
  280 + transformCellText?: Function;
  281 +
  282 + /**
  283 + * Callback executed when pagination, filters or sorter is changed
  284 + * @param pagination
  285 + * @param filters
  286 + * @param sorter
  287 + * @param currentDataSource
  288 + */
  289 + onChange?: (
  290 + pagination: PaginationConfig,
  291 + filters: Partial<Record<keyof T, string[]>>,
  292 + sorter: SorterResult<T>,
  293 + extra: TableCurrentDataSource<T>
  294 + ) => void;
  295 +
  296 + /**
  297 + * Callback executed when the row expand icon is clicked
  298 + *
  299 + * @param expanded
  300 + * @param record
  301 + */
  302 + onExpand?: (expande: boolean, record: T) => void;
  303 +
  304 + /**
  305 + * Callback executed when the expanded rows change
  306 + * @param expandedRows
  307 + */
  308 + onExpandedRowsChange?: (expandedRows: string[] | number[]) => void;
  309 +}
  310 +
  311 +export interface BasicColumn<T = any> extends ColumnProps<T> {
  312 + children?: BasicColumn[];
  313 + //
  314 + flag?: 'INDEX' | 'DEFAULT' | 'CHECKBOX' | 'RADIO' | 'ACTION';
  315 +}
src/components/Table/src/types/tableAction.ts 0 → 100644
  1 +export interface ActionItem {
  2 + on?: any;
  3 + label: string;
  4 + disabled?: boolean;
  5 + color?: 'success' | 'error' | 'warning';
  6 + type?: string;
  7 + props?: any;
  8 + icon?: string;
  9 + popConfirm?: PopConfirm;
  10 +}
  11 +
  12 +export interface PopConfirm {
  13 + title: string;
  14 + okText?: string;
  15 + cancelText?: string;
  16 + confirm: any;
  17 + cancel?: any;
  18 + icon?: string;
  19 +}
src/design/ant/pagination.less
1 -body {  
2 - .ant-pagination {  
3 - &.mini { 1 +.ant-pagination {
  2 + &.mini {
  3 + height: 20px;
  4 + font-size: 13px;
  5 +
  6 + .ant-pagination-prev,
  7 + .ant-pagination-next {
  8 + width: 20px;
4 height: 20px; 9 height: 20px;
5 - font-size: 13px;  
6 -  
7 - .ant-pagination-prev,  
8 - .ant-pagination-next {  
9 - width: 20px;  
10 - height: 20px;  
11 - min-width: 20px;  
12 - line-height: 17px;  
13 - color: @border-color-shallow-dark;  
14 - border: 1px solid;  
15 - } 10 + min-width: 20px;
  11 + line-height: 20px;
  12 + color: @border-color-shallow-dark;
  13 + border: 1px solid;
  14 + }
16 15
17 - .ant-pagination-prev:hover,  
18 - .ant-pagination-next:hover,  
19 - .ant-pagination-item:focus,  
20 - .ant-pagination-item:hover {  
21 - color: @primary-color;  
22 - border: 1px solid @primary-color;  
23 - } 16 + .ant-pagination-prev:hover,
  17 + .ant-pagination-next:hover,
  18 + .ant-pagination-item:focus,
  19 + .ant-pagination-item:hover {
  20 + color: @primary-color;
  21 + border: 1px solid @primary-color;
  22 + }
24 23
25 - .ant-pagination-item {  
26 - height: 20px;  
27 - min-width: 20px;  
28 - margin: 0 3px;  
29 - line-height: 20px; 24 + .ant-pagination-item {
  25 + height: 20px;
  26 + min-width: 20px;
  27 + margin: 0 3px;
  28 + line-height: 20px;
30 29
31 - &:last-child {  
32 - margin-right: 0 !important;  
33 - } 30 + &:last-child {
  31 + margin-right: 0 !important;
34 } 32 }
  33 + }
35 34
36 - .ant-pagination-item-active {  
37 - background: @primary-color; 35 + .ant-pagination-item-active {
  36 + background: @primary-color;
38 37
39 - a {  
40 - color: @white;  
41 - }  
42 - }  
43 -  
44 - .ant-pagination-options {  
45 - margin-left: 20px; 38 + a {
  39 + color: @white;
46 } 40 }
  41 + }
47 42
48 - .ant-select-sm .ant-select-selection--single {  
49 - height: 20px;  
50 - } 43 + .ant-pagination-options {
  44 + margin-left: 20px;
  45 + }
51 46
52 - .ant-pagination-options,  
53 - .ant-pagination-total-text,  
54 - .ant-pagination-options-quick-jumper {  
55 - height: 20px;  
56 - line-height: 20px;  
57 - } 47 + .ant-select-sm .ant-select-selection--single {
  48 + height: 20px;
  49 + }
58 50
59 - .ant-select-selection__rendered {  
60 - height: 18px;  
61 - line-height: 18px;  
62 - } 51 + .ant-pagination-options,
  52 + .ant-pagination-total-text,
  53 + .ant-pagination-options-quick-jumper {
  54 + height: 20px;
  55 + line-height: 20px;
  56 + }
63 57
64 - .ant-pagination-total-text,  
65 - .ant-select-selection__rendered,  
66 - .ant-select-dropdown-menu-item,  
67 - .ant-pagination-options-quick-jumper {  
68 - font-size: 13px;  
69 - } 58 + .ant-select-selection__rendered {
  59 + height: 18px;
  60 + line-height: 18px;
  61 + }
70 62
71 - .ant-pagination-options-quick-jumper input {  
72 - width: 40px;  
73 - height: 20px;  
74 - margin: 0 6px;  
75 - line-height: 20px;  
76 - text-align: center;  
77 - } 63 + .ant-pagination-total-text,
  64 + .ant-select-selection__rendered,
  65 + .ant-select-dropdown-menu-item,
  66 + .ant-pagination-options-quick-jumper {
  67 + font-size: 13px;
  68 + }
78 69
79 - .ant-pagination-jump-prev,  
80 - .ant-pagination-jump-next {  
81 - height: 20px;  
82 - line-height: 20px;  
83 - } 70 + .ant-pagination-options-quick-jumper input {
  71 + width: 40px;
  72 + height: 20px;
  73 + margin: 0 6px;
  74 + line-height: 20px;
  75 + text-align: center;
  76 + }
84 77
85 - .ant-pagination-options-size-changer.ant-select {  
86 - margin-right: 20px;  
87 - } 78 + .ant-pagination-jump-prev,
  79 + .ant-pagination-jump-next {
  80 + height: 20px;
  81 + line-height: 20px;
  82 + }
88 83
89 - .ant-select-arrow {  
90 - color: @border-color-shallow-dark;  
91 - } 84 + .ant-pagination-options-size-changer.ant-select {
  85 + margin-right: 20px;
92 } 86 }
93 87
94 - &-disabled {  
95 - display: none; 88 + .ant-select-arrow {
  89 + color: @border-color-shallow-dark;
96 } 90 }
97 } 91 }
  92 +
  93 + &-disabled {
  94 + display: none;
  95 + }
98 } 96 }
src/layouts/default/LayoutContent.tsx
@@ -6,17 +6,23 @@ import { ContentEnum } from &#39;/@/enums/appEnum&#39;; @@ -6,17 +6,23 @@ import { ContentEnum } from &#39;/@/enums/appEnum&#39;;
6 import { appStore } from '/@/store/modules/app'; 6 import { appStore } from '/@/store/modules/app';
7 // import { RouterView } from 'vue-router'; 7 // import { RouterView } from 'vue-router';
8 import PageLayout from '/@/layouts/page/index'; 8 import PageLayout from '/@/layouts/page/index';
  9 +import FrameLayout from '/@/layouts/iframe/index.vue';
  10 +
  11 +import { useSetting } from '/@/hooks/core/useSetting';
9 export default defineComponent({ 12 export default defineComponent({
10 name: 'DefaultLayoutContent', 13 name: 'DefaultLayoutContent',
11 setup() { 14 setup() {
  15 + const { projectSetting } = useSetting();
  16 +
12 return () => { 17 return () => {
13 const { getProjectConfig } = appStore; 18 const { getProjectConfig } = appStore;
14 const { contentMode } = getProjectConfig; 19 const { contentMode } = getProjectConfig;
  20 +
15 const wrapClass = contentMode === ContentEnum.FULL ? 'full' : 'fixed'; 21 const wrapClass = contentMode === ContentEnum.FULL ? 'full' : 'fixed';
16 return ( 22 return (
17 <Layout.Content class={`layout-content ${wrapClass} `}> 23 <Layout.Content class={`layout-content ${wrapClass} `}>
18 {{ 24 {{
19 - default: () => <PageLayout />, 25 + default: () => [<PageLayout />, projectSetting.canEmbedIFramePage && <FrameLayout />],
20 }} 26 }}
21 </Layout.Content> 27 </Layout.Content>
22 ); 28 );
src/layouts/page/index.tsx
@@ -6,9 +6,7 @@ import { useTransition } from &#39;./useTransition&#39;; @@ -6,9 +6,7 @@ import { useTransition } from &#39;./useTransition&#39;;
6 6
7 import { RouterView, RouteLocation } from 'vue-router'; 7 import { RouterView, RouteLocation } from 'vue-router';
8 import { tabStore } from '/@/store/modules/tab'; 8 import { tabStore } from '/@/store/modules/tab';
9 -import FrameLayout from '/@/layouts/iframe/index.vue';  
10 9
11 -import { useSetting } from '/@/hooks/core/useSetting';  
12 // import { useRouter } from 'vue-router'; 10 // import { useRouter } from 'vue-router';
13 export default defineComponent({ 11 export default defineComponent({
14 name: 'PageLayout', 12 name: 'PageLayout',
@@ -24,7 +22,6 @@ export default defineComponent({ @@ -24,7 +22,6 @@ export default defineComponent({
24 const { on: transitionOn } = useTransition(); 22 const { on: transitionOn } = useTransition();
25 on = transitionOn; 23 on = transitionOn;
26 } 24 }
27 - const { projectSetting } = useSetting();  
28 return () => { 25 return () => {
29 const { 26 const {
30 routerTransition, 27 routerTransition,
@@ -35,35 +32,32 @@ export default defineComponent({ @@ -35,35 +32,32 @@ export default defineComponent({
35 32
36 const openCache = openKeepAlive && show; 33 const openCache = openKeepAlive && show;
37 const cacheTabs = toRaw(tabStore.getKeepAliveTabsState) as string[]; 34 const cacheTabs = toRaw(tabStore.getKeepAliveTabsState) as string[];
38 - return (  
39 - <div>  
40 - <RouterView>  
41 - {{  
42 - default: ({ Component, route }: { Component: any; route: RouteLocation }) => {  
43 - const Content = openCache ? (  
44 - <KeepAlive max={max} include={cacheTabs}>  
45 - <Component {...route.params} />  
46 - </KeepAlive>  
47 - ) : ( 35 + return [
  36 + <RouterView>
  37 + {{
  38 + default: ({ Component, route }: { Component: any; route: RouteLocation }) => {
  39 + const Content = openCache ? (
  40 + <KeepAlive max={max} include={cacheTabs}>
48 <Component {...route.params} /> 41 <Component {...route.params} />
49 - );  
50 - return openRouterTransition ? (  
51 - <Transition  
52 - {...on}  
53 - name={route.meta.transitionName || routerTransition}  
54 - mode="out-in"  
55 - >  
56 - {() => Content}  
57 - </Transition>  
58 - ) : (  
59 - Content  
60 - );  
61 - },  
62 - }}  
63 - </RouterView>  
64 - {projectSetting.canEmbedIFramePage && <FrameLayout />}  
65 - </div>  
66 - ); 42 + </KeepAlive>
  43 + ) : (
  44 + <Component {...route.params} />
  45 + );
  46 + return openRouterTransition ? (
  47 + <Transition
  48 + {...on}
  49 + name={route.meta.transitionName || routerTransition}
  50 + mode="out-in"
  51 + >
  52 + {() => Content}
  53 + </Transition>
  54 + ) : (
  55 + Content
  56 + );
  57 + },
  58 + }}
  59 + </RouterView>,
  60 + ];
67 }; 61 };
68 }, 62 },
69 }); 63 });
src/router/guard/progressGuard.ts
@@ -3,10 +3,10 @@ import type { Router } from &#39;vue-router&#39;; @@ -3,10 +3,10 @@ import type { Router } from &#39;vue-router&#39;;
3 import NProgress from 'nprogress'; 3 import NProgress from 'nprogress';
4 import 'nprogress/nprogress.css'; 4 import 'nprogress/nprogress.css';
5 5
6 -NProgress.inc(0.4);  
7 -NProgress.configure({ easing: 'ease', speed: 1000, showSpinner: false });  
8 -  
9 export function createProgressGuard(router: Router) { 6 export function createProgressGuard(router: Router) {
  7 + NProgress.inc(0.1);
  8 + NProgress.configure({ easing: 'ease', speed: 200, showSpinner: false });
  9 +
10 router.beforeEach(async () => { 10 router.beforeEach(async () => {
11 NProgress.start(); 11 NProgress.start();
12 return true; 12 return true;
src/router/menus/modules/demo/comp.ts
@@ -18,6 +18,68 @@ const menu: MenuModule = { @@ -18,6 +18,68 @@ const menu: MenuModule = {
18 name: 'ClickOutSide组件', 18 name: 'ClickOutSide组件',
19 }, 19 },
20 { 20 {
  21 + path: '/table',
  22 + name: '表格组件',
  23 + children: [
  24 + {
  25 + path: '/basic',
  26 + name: '基础表格',
  27 + },
  28 + {
  29 + path: '/treeTable',
  30 + name: '树形表格',
  31 + },
  32 + {
  33 + path: '/fetchTable',
  34 + name: '远程加载',
  35 + },
  36 + {
  37 + path: '/fixedColumn',
  38 + name: '固定列',
  39 + },
  40 + {
  41 + path: '/customerCell',
  42 + name: '自定义列',
  43 + },
  44 + {
  45 + path: '/formTable',
  46 + name: '开启搜索区域',
  47 + },
  48 + {
  49 + path: '/useTable',
  50 + name: 'UseTable',
  51 + },
  52 + {
  53 + path: '/refTable',
  54 + name: 'RefTable',
  55 + },
  56 + {
  57 + path: '/multipleHeader',
  58 + name: '多级表头',
  59 + },
  60 + {
  61 + path: '/mergeHeader',
  62 + name: '合并表头',
  63 + },
  64 + {
  65 + path: '/expandTable',
  66 + name: '可展开表格',
  67 + },
  68 + {
  69 + path: '/fixedHeight',
  70 + name: '定高/头部自定义',
  71 + },
  72 + {
  73 + path: '/footerTable',
  74 + name: '表尾行合计',
  75 + },
  76 + {
  77 + path: '/editCellTable',
  78 + name: '可编辑单元格',
  79 + },
  80 + ],
  81 + },
  82 + {
21 path: '/form', 83 path: '/form',
22 name: '表单组件', 84 name: '表单组件',
23 children: [ 85 children: [
src/router/routes/modules/demo/comp.ts
@@ -99,6 +99,128 @@ export default { @@ -99,6 +99,128 @@ export default {
99 ], 99 ],
100 }, 100 },
101 { 101 {
  102 + path: '/table',
  103 + name: 'TableDemo',
  104 + redirect: '/comp/table/basic',
  105 + meta: {
  106 + title: '表格组件',
  107 + },
  108 + children: [
  109 + {
  110 + path: 'basic',
  111 + name: 'TableBasicDemo',
  112 + component: () => import('/@/views/demo/table/Basic.vue'),
  113 + meta: {
  114 + title: '基础表格',
  115 + },
  116 + },
  117 + {
  118 + path: 'treeTable',
  119 + name: 'TreeTableDemo',
  120 + component: () => import('/@/views/demo/table/TreeTable.vue'),
  121 + meta: {
  122 + title: '树形表格',
  123 + },
  124 + },
  125 + {
  126 + path: 'fetchTable',
  127 + name: 'FetchTableDemo',
  128 + component: () => import('/@/views/demo/table/FetchTable.vue'),
  129 + meta: {
  130 + title: '远程加载示例',
  131 + },
  132 + },
  133 + {
  134 + path: 'fixedColumn',
  135 + name: 'FixedColumnDemo',
  136 + component: () => import('/@/views/demo/table/FixedColumn.vue'),
  137 + meta: {
  138 + title: '固定列',
  139 + },
  140 + },
  141 + {
  142 + path: 'customerCell',
  143 + name: 'CustomerCellDemo',
  144 + component: () => import('/@/views/demo/table/CustomerCell.vue'),
  145 + meta: {
  146 + title: '自定义列',
  147 + },
  148 + },
  149 + {
  150 + path: 'formTable',
  151 + name: 'FormTableDemo',
  152 + component: () => import('/@/views/demo/table/FormTable.vue'),
  153 + meta: {
  154 + title: '开启搜索区域',
  155 + },
  156 + },
  157 + {
  158 + path: 'useTable',
  159 + name: 'UseTableDemo',
  160 + component: () => import('/@/views/demo/table/UseTable.vue'),
  161 + meta: {
  162 + title: 'UseTable',
  163 + },
  164 + },
  165 + {
  166 + path: 'refTable',
  167 + name: 'RefTableDemo',
  168 + component: () => import('/@/views/demo/table/RefTable.vue'),
  169 + meta: {
  170 + title: 'RefTable',
  171 + },
  172 + },
  173 + {
  174 + path: 'multipleHeader',
  175 + name: 'MultipleHeaderDemo',
  176 + component: () => import('/@/views/demo/table/MultipleHeader.vue'),
  177 + meta: {
  178 + title: '多级表头',
  179 + },
  180 + },
  181 + {
  182 + path: 'mergeHeader',
  183 + name: 'MergeHeaderDemo',
  184 + component: () => import('/@/views/demo/table/MergeHeader.vue'),
  185 + meta: {
  186 + title: '合并表头',
  187 + },
  188 + },
  189 + {
  190 + path: 'expandTable',
  191 + name: 'ExpandTableDemo',
  192 + component: () => import('/@/views/demo/table/ExpandTable.vue'),
  193 + meta: {
  194 + title: '可展开表格',
  195 + },
  196 + },
  197 + {
  198 + path: 'fixedHeight',
  199 + name: 'FixedHeightDemo',
  200 + component: () => import('/@/views/demo/table/FixedHeight.vue'),
  201 + meta: {
  202 + title: '定高/头部自定义',
  203 + },
  204 + },
  205 + {
  206 + path: 'footerTable',
  207 + name: 'FooterTableDemo',
  208 + component: () => import('/@/views/demo/table/FooterTable.vue'),
  209 + meta: {
  210 + title: '表尾行合计',
  211 + },
  212 + },
  213 + {
  214 + path: 'editCellTable',
  215 + name: 'EditCellTableDemo',
  216 + component: () => import('/@/views/demo/table/EditCellTable.vue'),
  217 + meta: {
  218 + title: '可编辑单元格',
  219 + },
  220 + },
  221 + ],
  222 + },
  223 + {
102 path: '/tree', 224 path: '/tree',
103 name: 'TreeDemo', 225 name: 'TreeDemo',
104 redirect: '/comp/tree/basic', 226 redirect: '/comp/tree/basic',
src/store/index.ts
1 import type { App } from 'vue'; 1 import type { App } from 'vue';
2 -import { createStore, createLogger, Plugin } from 'vuex'; 2 +import {
  3 + createStore,
  4 + // createLogger, Plugin
  5 +} from 'vuex';
3 import { config } from 'vuex-module-decorators'; 6 import { config } from 'vuex-module-decorators';
4 import { isDevMode } from '/@/utils/env'; 7 import { isDevMode } from '/@/utils/env';
5 8
6 config.rawError = true; 9 config.rawError = true;
7 const isDev = isDevMode(); 10 const isDev = isDevMode();
8 -const plugins: Plugin<any>[] = isDev ? [createLogger()] : []; 11 +// const plugins: Plugin<any>[] = isDev ? [createLogger()] : [];
9 12
10 const store = createStore({ 13 const store = createStore({
11 modules: {}, 14 modules: {},
12 strict: isDev, 15 strict: isDev,
13 - plugins, 16 + // plugins,
14 }); 17 });
15 export function setupStore(app: App<Element>) { 18 export function setupStore(app: App<Element>) {
16 app.use(store); 19 app.use(store);
src/types/source.d.ts
1 declare module 'ant-design-vue/es/locale/zh_CN'; 1 declare module 'ant-design-vue/es/locale/zh_CN';
  2 +declare module 'vue-draggable-resizable';
2 declare const React: string; 3 declare const React: string;
3 declare module '*.bmp' { 4 declare module '*.bmp' {
4 const src: string; 5 const src: string;
src/useApp.tsx
@@ -2,8 +2,6 @@ import type { ProjectConfig } from &#39;/@/types/config&#39;; @@ -2,8 +2,6 @@ import type { ProjectConfig } from &#39;/@/types/config&#39;;
2 2
3 import { computed, ref } from 'vue'; 3 import { computed, ref } from 'vue';
4 4
5 -import { BasicEmpty } from '/@/components/Basic';  
6 -  
7 import { ThemeModeEnum } from '/@/enums/appEnum'; 5 import { ThemeModeEnum } from '/@/enums/appEnum';
8 import { PROJ_CFG_KEY } from '/@/enums/cacheEnum'; 6 import { PROJ_CFG_KEY } from '/@/enums/cacheEnum';
9 7
@@ -59,10 +57,6 @@ export function useInitAppConfigStore() { @@ -59,10 +57,6 @@ export function useInitAppConfigStore() {
59 57
60 // Config Provider 58 // Config Provider
61 export function useConfigProvider() { 59 export function useConfigProvider() {
62 - function renderEmpty() {  
63 - return <BasicEmpty />;  
64 - }  
65 -  
66 function transformCellText({ text }: { text: string }) { 60 function transformCellText({ text }: { text: string }) {
67 if (isNull(text) || isUnDef(text)) { 61 if (isNull(text) || isUnDef(text)) {
68 return ' - '; 62 return ' - ';
@@ -70,7 +64,6 @@ export function useConfigProvider() { @@ -70,7 +64,6 @@ export function useConfigProvider() {
70 return text; 64 return text;
71 } 65 }
72 return { 66 return {
73 - renderEmpty,  
74 transformCellText, 67 transformCellText,
75 }; 68 };
76 } 69 }
src/views/demo/comp/verify/index.vue
@@ -25,7 +25,7 @@ @@ -25,7 +25,7 @@
25 25
26 <div class="flex justify-center p-4 items-center bg-gray-700"> 26 <div class="flex justify-center p-4 items-center bg-gray-700">
27 <BasicDragVerify ref="el4" @success="handleSuccess"> 27 <BasicDragVerify ref="el4" @success="handleSuccess">
28 - <template v-slot:actionIcon="isPassing"> 28 + <template #actionIcon="isPassing">
29 <BugOutlined v-if="isPassing" /> 29 <BugOutlined v-if="isPassing" />
30 <RightOutlined v-else /> 30 <RightOutlined v-else />
31 </template> 31 </template>
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 35
36 <div class="flex justify-center p-4 items-center bg-gray-700"> 36 <div class="flex justify-center p-4 items-center bg-gray-700">
37 <BasicDragVerify ref="el5" @success="handleSuccess"> 37 <BasicDragVerify ref="el5" @success="handleSuccess">
38 - <template v-slot:text="isPassing"> 38 + <template #text="isPassing">
39 <div v-if="isPassing"> 39 <div v-if="isPassing">
40 <BugOutlined /> 40 <BugOutlined />
41 成功 41 成功
src/views/demo/table/Basic.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable
  4 + title="基础示例"
  5 + titleHelpMessage="温馨提醒"
  6 + :columns="columns"
  7 + :dataSource="data"
  8 + :canResize="canResize"
  9 + :loading="loading"
  10 + :striped="striped"
  11 + :bordered="border"
  12 + :pagination="{ pageSize: 20 }"
  13 + >
  14 + <template #toolbar>
  15 + <a-button type="primary" @click="toggleCanResize">
  16 + {{ !canResize ? '自适应高度' : '取消自适应' }}
  17 + </a-button>
  18 + <a-button type="primary" @click="toggleBorder">
  19 + {{ !border ? '显示边框' : '隐藏边框' }}
  20 + </a-button>
  21 + <a-button type="primary" @click="toggleLoading"> 开启loading </a-button>
  22 + <a-button type="primary" @click="toggleStriped">
  23 + {{ !striped ? '显示斑马纹' : '隐藏斑马纹' }}
  24 + </a-button>
  25 + </template>
  26 + </BasicTable>
  27 + </div>
  28 +</template>
  29 +<script lang="ts">
  30 + import { defineComponent, ref } from 'vue';
  31 + import { BasicTable } from '/@/components/Table';
  32 + import { getBasicColumns, getBasicData } from './tableData';
  33 +
  34 + export default defineComponent({
  35 + components: { BasicTable },
  36 + setup() {
  37 + const canResize = ref(false);
  38 + const loading = ref(false);
  39 + const striped = ref(true);
  40 + const border = ref(true);
  41 + function toggleCanResize() {
  42 + canResize.value = !canResize.value;
  43 + }
  44 + function toggleStriped() {
  45 + striped.value = !striped.value;
  46 + }
  47 + function toggleLoading() {
  48 + loading.value = true;
  49 + setTimeout(() => {
  50 + loading.value = false;
  51 + }, 3000);
  52 + }
  53 + function toggleBorder() {
  54 + border.value = !border.value;
  55 + }
  56 + return {
  57 + columns: getBasicColumns(),
  58 + data: getBasicData(),
  59 + canResize,
  60 + loading,
  61 + striped,
  62 + border,
  63 + toggleStriped,
  64 + toggleCanResize,
  65 + toggleLoading,
  66 + toggleBorder,
  67 + };
  68 + },
  69 + });
  70 +</script>
src/views/demo/table/CustomerCell.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable">
  4 + <template #id="{ record }"> ID: {{ record.id }} </template>
  5 + <template #no="{ record }"
  6 + ><Tag color="green">{{ record.no }}</Tag>
  7 + </template>
  8 + <template #img>
  9 + <TableImg
  10 + :imgList="['https://picsum.photos/id/66/346/216', 'https://picsum.photos/id/67/346/216']"
  11 + />
  12 + </template>
  13 + </BasicTable>
  14 + </div>
  15 +</template>
  16 +<script lang="ts">
  17 + import { defineComponent } from 'vue';
  18 + import { BasicTable, useTable, BasicColumn, TableImg } from '/@/components/Table';
  19 + import { Tag } from 'ant-design-vue';
  20 + import { demoListApi } from '/@/api/demo/table';
  21 + const columns: BasicColumn[] = [
  22 + {
  23 + title: 'ID',
  24 + dataIndex: 'id',
  25 + slots: { customRender: 'id' },
  26 + },
  27 + {
  28 + title: '姓名',
  29 + dataIndex: 'name',
  30 + width: 120,
  31 + },
  32 + {
  33 + title: '头像',
  34 + dataIndex: 'img',
  35 + width: 120,
  36 + slots: { customRender: 'img' },
  37 + },
  38 + {
  39 + title: '地址',
  40 + dataIndex: 'address',
  41 + },
  42 + {
  43 + title: '编号',
  44 + dataIndex: 'no',
  45 + slots: { customRender: 'no' },
  46 + },
  47 + {
  48 + title: '开始时间',
  49 + dataIndex: 'beginTime',
  50 + },
  51 + {
  52 + title: '结束时间',
  53 + dataIndex: 'endTime',
  54 + },
  55 + ];
  56 + export default defineComponent({
  57 + components: { BasicTable, TableImg, Tag },
  58 + setup() {
  59 + const [registerTable] = useTable({
  60 + title: '自定义列内容',
  61 + api: demoListApi,
  62 + columns: columns,
  63 + });
  64 +
  65 + return {
  66 + registerTable,
  67 + };
  68 + },
  69 + });
  70 +</script>
src/views/demo/table/EditCellTable.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable">
  4 + <template #customId>
  5 + <EditTableHeaderIcon title="Id" />
  6 + </template>
  7 + <template #customName>
  8 + <EditTableHeaderIcon title="姓名" />
  9 + </template>
  10 + </BasicTable>
  11 + </div>
  12 +</template>
  13 +<script lang="ts">
  14 + import { defineComponent } from 'vue';
  15 + import {
  16 + BasicTable,
  17 + useTable,
  18 + BasicColumn,
  19 + renderEditableCell,
  20 + EditTableHeaderIcon,
  21 + } from '/@/components/Table';
  22 +
  23 + import { demoListApi } from '/@/api/demo/table';
  24 + const columns: BasicColumn[] = [
  25 + {
  26 + // title: 'ID',
  27 + dataIndex: 'id',
  28 + slots: { title: 'customId' },
  29 + customRender: renderEditableCell({ dataIndex: 'id' }),
  30 + },
  31 + {
  32 + // title: '姓名',
  33 + dataIndex: 'name',
  34 + slots: { title: 'customName' },
  35 + customRender: renderEditableCell({
  36 + dataIndex: 'name',
  37 + }),
  38 + },
  39 + {
  40 + title: '地址',
  41 + dataIndex: 'address',
  42 + sorter: true,
  43 + },
  44 + ];
  45 + export default defineComponent({
  46 + components: { BasicTable, EditTableHeaderIcon },
  47 + setup() {
  48 + const [registerTable] = useTable({
  49 + title: '可编辑单元格示例',
  50 + api: demoListApi,
  51 + columns: columns,
  52 + showIndexColumn: false,
  53 + });
  54 +
  55 + return {
  56 + registerTable,
  57 + };
  58 + },
  59 + });
  60 +</script>
src/views/demo/table/ExpandTable.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable">
  4 + <template #expandedRowRender="{ record }">
  5 + <span>No: {{ record.no }} </span>
  6 + </template>
  7 + </BasicTable>
  8 + </div>
  9 +</template>
  10 +<script lang="ts">
  11 + import { defineComponent } from 'vue';
  12 + import { BasicTable, useTable } from '/@/components/Table';
  13 + import { getBasicColumns } from './tableData';
  14 +
  15 + import { demoListApi } from '/@/api/demo/table';
  16 +
  17 + export default defineComponent({
  18 + components: { BasicTable },
  19 + setup() {
  20 + const [registerTable] = useTable({
  21 + title: '可展开表格',
  22 + api: demoListApi,
  23 + titleHelpMessage: '不能与scroll共用',
  24 + columns: getBasicColumns(),
  25 + rowKey: 'id',
  26 + canResize: false,
  27 + });
  28 +
  29 + return {
  30 + registerTable,
  31 + };
  32 + },
  33 + });
  34 +</script>
src/views/demo/table/FetchTable.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable">
  4 + <template #toolbar>
  5 + <a-button type="primary" @click="handleReloadCurrent"> 刷新当前页 </a-button>
  6 + <a-button type="primary" @click="handleReload"> 刷新并返回第一页 </a-button>
  7 + </template>
  8 + </BasicTable>
  9 + </div>
  10 +</template>
  11 +<script lang="ts">
  12 + import { defineComponent } from 'vue';
  13 + import { BasicTable, useTable } from '/@/components/Table';
  14 + import { getBasicColumns } from './tableData';
  15 +
  16 + import { demoListApi } from '/@/api/demo/table';
  17 + export default defineComponent({
  18 + components: { BasicTable },
  19 + setup() {
  20 + const [registerTable, { reload }] = useTable({
  21 + title: '远程加载示例',
  22 + api: demoListApi,
  23 + columns: getBasicColumns(),
  24 + });
  25 + function handleReloadCurrent() {
  26 + reload();
  27 + // reload({
  28 + // searchInfo: 'xxx',
  29 + // });
  30 + }
  31 +
  32 + function handleReload() {
  33 + reload({
  34 + page: 1,
  35 + });
  36 + }
  37 + return {
  38 + registerTable,
  39 + handleReloadCurrent,
  40 + handleReload,
  41 + };
  42 + },
  43 + });
  44 +</script>
src/views/demo/table/FixedColumn.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable">
  4 + <template #action>
  5 + <TableAction
  6 + :actions="[
  7 + {
  8 + label: '删除',
  9 + props: {
  10 + onClick: handleDelete,
  11 + },
  12 + },
  13 + ]"
  14 + :dropDownActions="[
  15 + {
  16 + label: '启用',
  17 + props: {
  18 + onClick: handleOpen,
  19 + },
  20 + },
  21 + ]"
  22 + />
  23 + </template>
  24 + </BasicTable>
  25 + </div>
  26 +</template>
  27 +<script lang="ts">
  28 + import { defineComponent } from 'vue';
  29 + import { BasicTable, useTable, BasicColumn, TableAction } from '/@/components/Table';
  30 +
  31 + import { demoListApi } from '/@/api/demo/table';
  32 + const columns: BasicColumn[] = [
  33 + {
  34 + title: 'ID',
  35 + dataIndex: 'id',
  36 + fixed: 'left',
  37 + width: 280,
  38 + },
  39 + {
  40 + title: '姓名',
  41 + dataIndex: 'name',
  42 + width: 260,
  43 + },
  44 + {
  45 + title: '地址',
  46 + dataIndex: 'address',
  47 + width: 260,
  48 + },
  49 + {
  50 + title: '编号',
  51 + dataIndex: 'no',
  52 + width: 300,
  53 + },
  54 + {
  55 + title: '开始时间',
  56 + width: 200,
  57 + dataIndex: 'beginTime',
  58 + },
  59 + {
  60 + title: '结束时间',
  61 + dataIndex: 'endTime',
  62 + width: 200,
  63 + },
  64 + ];
  65 + export default defineComponent({
  66 + components: { BasicTable, TableAction },
  67 + setup() {
  68 + const [registerTable] = useTable({
  69 + title: 'TableAction组件及固定列示例',
  70 + api: demoListApi,
  71 + columns: columns,
  72 + rowSelection: { type: 'radio' },
  73 + actionColumn: {
  74 + width: 160,
  75 + title: 'Action',
  76 + dataIndex: 'action',
  77 + slots: { customRender: 'action' },
  78 + },
  79 + });
  80 + function handleDelete() {
  81 + console.log('点击了删除');
  82 + }
  83 + function handleOpen() {
  84 + console.log('点击了启用');
  85 + }
  86 + return {
  87 + registerTable,
  88 + handleDelete,
  89 + handleOpen,
  90 + };
  91 + },
  92 + });
  93 +</script>
src/views/demo/table/FixedHeight.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable">
  4 + <template #customTitle>
  5 + <span>
  6 + 姓名
  7 + <BaseHelp class="ml-2" text="姓名" />
  8 + </span>
  9 + </template>
  10 + <template #customAddress>
  11 + 地址
  12 + <FormOutlined class="ml-2" />
  13 + </template>
  14 + </BasicTable>
  15 + </div>
  16 +</template>
  17 +<script lang="ts">
  18 + import { defineComponent } from 'vue';
  19 + import { BasicTable, useTable } from '/@/components/Table';
  20 + import { getCustomHeaderColumns } from './tableData';
  21 + import { FormOutlined } from '@ant-design/icons-vue';
  22 + import { demoListApi } from '/@/api/demo/table';
  23 +
  24 + export default defineComponent({
  25 + components: { BasicTable, FormOutlined },
  26 + setup() {
  27 + const [registerTable] = useTable({
  28 + title: '定高/头部自定义',
  29 + api: demoListApi,
  30 + columns: getCustomHeaderColumns(),
  31 + canResize: false,
  32 + scroll: { y: 100 },
  33 + });
  34 +
  35 + return {
  36 + registerTable,
  37 + };
  38 + },
  39 + });
  40 +</script>
src/views/demo/table/FooterTable.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable" />
  4 + </div>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent } from 'vue';
  8 + import { BasicTable, useTable } from '/@/components/Table';
  9 + import { getBasicColumns } from './tableData';
  10 +
  11 + import { demoListApi } from '/@/api/demo/table';
  12 +
  13 + export default defineComponent({
  14 + components: { BasicTable },
  15 + setup() {
  16 + function handleSummary(tableData: any[]) {
  17 + const totalNo = tableData.reduce((prev, next) => {
  18 + prev += next.no;
  19 + return prev;
  20 + }, 0);
  21 + return [
  22 + {
  23 + _row: '合计',
  24 + _index: '平均值',
  25 + no: totalNo,
  26 + },
  27 + {
  28 + _row: '合计',
  29 + _index: '平均值',
  30 + no: totalNo,
  31 + },
  32 + ];
  33 + }
  34 + const [registerTable] = useTable({
  35 + title: '表尾行合计示例',
  36 + api: demoListApi,
  37 + rowSelection: { type: 'checkbox' },
  38 + columns: getBasicColumns(),
  39 + showSummary: true,
  40 + summaryFunc: handleSummary,
  41 + scroll: { x: 2000 },
  42 + canResize: false,
  43 + });
  44 +
  45 + return {
  46 + registerTable,
  47 + };
  48 + },
  49 + });
  50 +</script>
src/views/demo/table/FormTable.vue 0 → 100644
  1 +<template>
  2 + <BasicTable @register="registerTable" />
  3 +</template>
  4 +<script lang="ts">
  5 + import { defineComponent } from 'vue';
  6 + import { BasicTable, useTable } from '/@/components/Table';
  7 + import { getBasicColumns, getFormConfig } from './tableData';
  8 +
  9 + import { demoListApi } from '/@/api/demo/table';
  10 +
  11 + export default defineComponent({
  12 + components: { BasicTable },
  13 + setup() {
  14 + const [registerTable] = useTable({
  15 + title: '开启搜索区域',
  16 + api: demoListApi,
  17 + columns: getBasicColumns(),
  18 + useSearchForm: true,
  19 + formConfig: getFormConfig(),
  20 + });
  21 +
  22 + return {
  23 + registerTable,
  24 + };
  25 + },
  26 + });
  27 +</script>
src/views/demo/table/MergeHeader.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable" />
  4 + </div>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent } from 'vue';
  8 + import { BasicTable, useTable } from '/@/components/Table';
  9 + import { getMergeHeaderColumns } from './tableData';
  10 +
  11 + import { demoListApi } from '/@/api/demo/table';
  12 +
  13 + export default defineComponent({
  14 + components: { BasicTable },
  15 + setup() {
  16 + const [registerTable] = useTable({
  17 + title: '多级表头示例',
  18 + api: demoListApi,
  19 + columns: getMergeHeaderColumns(),
  20 + });
  21 +
  22 + return {
  23 + registerTable,
  24 + };
  25 + },
  26 + });
  27 +</script>
src/views/demo/table/MultipleHeader.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable @register="registerTable" />
  4 + </div>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent } from 'vue';
  8 + import { BasicTable, useTable } from '/@/components/Table';
  9 + import { getMultipleHeaderColumns } from './tableData';
  10 +
  11 + import { demoListApi } from '/@/api/demo/table';
  12 + export default defineComponent({
  13 + components: { BasicTable },
  14 + setup() {
  15 + const [registerTable] = useTable({
  16 + title: '多级表头示例',
  17 + api: demoListApi,
  18 + columns: getMultipleHeaderColumns(),
  19 + });
  20 +
  21 + return {
  22 + registerTable,
  23 + };
  24 + },
  25 + });
  26 +</script>
src/views/demo/table/RefTable.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <div class="mb-4">
  4 + <a-button class="mr-2" @click="reloadTable">还原</a-button>
  5 + <a-button class="mr-2" @click="changeLoading">开启loading</a-button>
  6 + <a-button class="mr-2" @click="changeColumns">更改Columns</a-button>
  7 + <a-button class="mr-2" @click="getColumn">获取Columns</a-button>
  8 + <a-button class="mr-2" @click="getTableData">获取表格数据</a-button>
  9 + <a-button class="mr-2" @click="setPaginationInfo">跳转到第2页</a-button>
  10 + </div>
  11 + <div class="mb-4">
  12 + <a-button class="mr-2" @click="getSelectRowList">获取选中行</a-button>
  13 + <a-button class="mr-2" @click="getSelectRowKeyList">获取选中行Key</a-button>
  14 + <a-button class="mr-2" @click="setSelectedRowKeyList">设置选中行</a-button>
  15 + <a-button class="mr-2" @click="clearSelect">清空选中行</a-button>
  16 + <a-button class="mr-2" @click="getPagination">获取分页信息</a-button>
  17 + </div>
  18 + <BasicTable
  19 + :canResize="false"
  20 + title="RefTable示例"
  21 + titleHelpMessage="使用Ref调用表格内方法"
  22 + ref="tableRef"
  23 + :api="api"
  24 + :columns="columns"
  25 + rowKey="id"
  26 + :rowSelection="{ type: 'checkbox' }"
  27 + />
  28 + </div>
  29 +</template>
  30 +<script lang="ts">
  31 + import { defineComponent, ref, unref } from 'vue';
  32 + import { BasicTable, TableActionType } from '/@/components/Table';
  33 + import { getBasicColumns, getBasicShortColumns } from './tableData';
  34 + import { useMessage } from '/@/hooks/web/useMessage';
  35 + import { demoListApi } from '/@/api/demo/table';
  36 + export default defineComponent({
  37 + components: { BasicTable },
  38 + setup() {
  39 + const tableRef = ref<Nullable<TableActionType>>(null);
  40 + const { createMessage } = useMessage();
  41 +
  42 + function getTableAction() {
  43 + const tableAction = unref(tableRef);
  44 + if (!tableAction) {
  45 + throw new Error('tableAction is null');
  46 + }
  47 + return tableAction;
  48 + }
  49 + function changeLoading() {
  50 + getTableAction().setLoading(true);
  51 + setTimeout(() => {
  52 + getTableAction().setLoading(false);
  53 + }, 1000);
  54 + }
  55 + function changeColumns() {
  56 + getTableAction().setColumns(getBasicShortColumns());
  57 + }
  58 + function reloadTable() {
  59 + getTableAction().setColumns(getBasicColumns());
  60 +
  61 + getTableAction().reload({
  62 + page: 1,
  63 + });
  64 + }
  65 + function getColumn() {
  66 + createMessage.info('请在控制台查看!');
  67 + console.log(getTableAction().getColumns());
  68 + }
  69 +
  70 + function getTableData() {
  71 + createMessage.info('请在控制台查看!');
  72 + console.log(getTableAction().getDataSource());
  73 + }
  74 +
  75 + function getPagination() {
  76 + createMessage.info('请在控制台查看!');
  77 + console.log(getTableAction().getPaginationRef());
  78 + }
  79 +
  80 + function setPaginationInfo() {
  81 + getTableAction().setPagination({
  82 + current: 2,
  83 + });
  84 + getTableAction().reload();
  85 + }
  86 + function getSelectRowList() {
  87 + createMessage.info('请在控制台查看!');
  88 + console.log(getTableAction().getSelectRows());
  89 + }
  90 + function getSelectRowKeyList() {
  91 + createMessage.info('请在控制台查看!');
  92 + console.log(getTableAction().getSelectRowKeys());
  93 + }
  94 + function setSelectedRowKeyList() {
  95 + getTableAction().setSelectedRowKeys(['0', '1', '2']);
  96 + }
  97 + function clearSelect() {
  98 + getTableAction().clearSelectedRowKeys();
  99 + }
  100 +
  101 + return {
  102 + tableRef,
  103 + api: demoListApi,
  104 + columns: getBasicColumns(),
  105 + changeLoading,
  106 + changeColumns,
  107 + reloadTable,
  108 + getColumn,
  109 + getTableData,
  110 + getPagination,
  111 + setPaginationInfo,
  112 + getSelectRowList,
  113 + getSelectRowKeyList,
  114 + setSelectedRowKeyList,
  115 + clearSelect,
  116 + };
  117 + },
  118 + });
  119 +</script>
src/views/demo/table/TreeTable.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <BasicTable
  4 + :rowSelection="{ type: 'checkbox' }"
  5 + :isTreeTable="true"
  6 + title="树形表格"
  7 + titleHelpMessage="树形组件不能和序列号列同时存在"
  8 + :columns="columns"
  9 + :dataSource="data"
  10 + rowKey="id"
  11 + :indentSize="20"
  12 + />
  13 + </div>
  14 +</template>
  15 +<script lang="ts">
  16 + import { defineComponent } from 'vue';
  17 + import { BasicTable } from '/@/components/Table';
  18 + import { getBasicColumns, getTreeTableData } from './tableData';
  19 +
  20 + export default defineComponent({
  21 + components: { BasicTable },
  22 + setup() {
  23 + return {
  24 + columns: getBasicColumns(),
  25 + data: getTreeTableData(),
  26 + };
  27 + },
  28 + });
  29 +</script>
src/views/demo/table/UseTable.vue 0 → 100644
  1 +<template>
  2 + <div class="p-4">
  3 + <div class="mb-4">
  4 + <a-button class="mr-2" @click="reloadTable">还原</a-button>
  5 + <a-button class="mr-2" @click="changeLoading">开启loading</a-button>
  6 + <a-button class="mr-2" @click="changeColumns">更改Columns</a-button>
  7 + <a-button class="mr-2" @click="getColumn">获取Columns</a-button>
  8 + <a-button class="mr-2" @click="getTableData">获取表格数据</a-button>
  9 + <a-button class="mr-2" @click="setPaginationInfo">跳转到第2页</a-button>
  10 + </div>
  11 + <div class="mb-4">
  12 + <a-button class="mr-2" @click="getSelectRowList">获取选中行</a-button>
  13 + <a-button class="mr-2" @click="getSelectRowKeyList">获取选中行Key</a-button>
  14 + <a-button class="mr-2" @click="setSelectedRowKeyList">设置选中行</a-button>
  15 + <a-button class="mr-2" @click="clearSelect">清空选中行</a-button>
  16 + <a-button class="mr-2" @click="getPagination">获取分页信息</a-button>
  17 + </div>
  18 + <BasicTable @register="registerTable" />
  19 + </div>
  20 +</template>
  21 +<script lang="ts">
  22 + import { defineComponent } from 'vue';
  23 + import { BasicTable, useTable } from '/@/components/Table';
  24 + import { getBasicColumns, getBasicShortColumns } from './tableData';
  25 + import { useMessage } from '/@/hooks/web/useMessage';
  26 + import { demoListApi } from '/@/api/demo/table';
  27 + export default defineComponent({
  28 + components: { BasicTable },
  29 + setup() {
  30 + const { createMessage } = useMessage();
  31 + const [
  32 + registerTable,
  33 + {
  34 + setLoading,
  35 + setColumns,
  36 + getColumns,
  37 + getDataSource,
  38 + reload,
  39 + getPaginationRef,
  40 + setPagination,
  41 + getSelectRows,
  42 + getSelectRowKeys,
  43 + setSelectedRowKeys,
  44 + clearSelectedRowKeys,
  45 + },
  46 + ] = useTable({
  47 + canResize: false,
  48 + title: 'useTable示例',
  49 + titleHelpMessage: '使用useTable调用表格内方法',
  50 + api: demoListApi,
  51 + columns: getBasicColumns(),
  52 + rowKey: 'id',
  53 + rowSelection: {
  54 + type: 'checkbox',
  55 + },
  56 + });
  57 +
  58 + function changeLoading() {
  59 + setLoading(true);
  60 + setTimeout(() => {
  61 + setLoading(false);
  62 + }, 1000);
  63 + }
  64 + function changeColumns() {
  65 + setColumns(getBasicShortColumns());
  66 + }
  67 + function reloadTable() {
  68 + setColumns(getBasicColumns());
  69 +
  70 + reload({
  71 + page: 1,
  72 + });
  73 + }
  74 + function getColumn() {
  75 + createMessage.info('请在控制台查看!');
  76 + console.log(getColumns());
  77 + }
  78 +
  79 + function getTableData() {
  80 + createMessage.info('请在控制台查看!');
  81 + console.log(getDataSource());
  82 + }
  83 +
  84 + function getPagination() {
  85 + createMessage.info('请在控制台查看!');
  86 + console.log(getPaginationRef());
  87 + }
  88 +
  89 + function setPaginationInfo() {
  90 + setPagination({
  91 + current: 2,
  92 + });
  93 + reload();
  94 + }
  95 + function getSelectRowList() {
  96 + createMessage.info('请在控制台查看!');
  97 + console.log(getSelectRows());
  98 + }
  99 + function getSelectRowKeyList() {
  100 + createMessage.info('请在控制台查看!');
  101 + console.log(getSelectRowKeys());
  102 + }
  103 + function setSelectedRowKeyList() {
  104 + setSelectedRowKeys(['0', '1', '2']);
  105 + }
  106 + function clearSelect() {
  107 + clearSelectedRowKeys();
  108 + }
  109 +
  110 + return {
  111 + registerTable,
  112 + changeLoading,
  113 + changeColumns,
  114 + reloadTable,
  115 + getColumn,
  116 + getTableData,
  117 + getPagination,
  118 + setPaginationInfo,
  119 + getSelectRowList,
  120 + getSelectRowKeyList,
  121 + setSelectedRowKeyList,
  122 + clearSelect,
  123 + };
  124 + },
  125 + });
  126 +</script>
src/views/demo/table/tableData.tsx 0 → 100644
  1 +import { FormProps, FormSchema } from '/@/components/Table';
  2 +import { BasicColumn } from '/@/components/Table/src/types/table';
  3 +
  4 +export function getBasicColumns(): BasicColumn[] {
  5 + return [
  6 + {
  7 + title: 'ID',
  8 + width: 150,
  9 + dataIndex: 'id',
  10 + },
  11 + {
  12 + title: '姓名',
  13 + dataIndex: 'name',
  14 + width: 120,
  15 + },
  16 + {
  17 + title: '地址',
  18 + dataIndex: 'address',
  19 + },
  20 + {
  21 + title: '编号',
  22 + dataIndex: 'no',
  23 + width: 80,
  24 + },
  25 + {
  26 + title: '开始时间',
  27 + dataIndex: 'beginTime',
  28 + },
  29 + {
  30 + title: '结束时间',
  31 + sorter: true,
  32 + dataIndex: 'endTime',
  33 + },
  34 + ];
  35 +}
  36 +
  37 +export function getBasicShortColumns(): BasicColumn[] {
  38 + return [
  39 + {
  40 + title: 'ID',
  41 + width: 150,
  42 + dataIndex: 'id',
  43 + },
  44 + {
  45 + title: '姓名',
  46 + dataIndex: 'name',
  47 + width: 120,
  48 + },
  49 + {
  50 + title: '地址',
  51 + dataIndex: 'address',
  52 + },
  53 + {
  54 + title: '编号',
  55 + dataIndex: 'no',
  56 + width: 80,
  57 + },
  58 + ];
  59 +}
  60 +
  61 +export function getMultipleHeaderColumns(): BasicColumn[] {
  62 + return [
  63 + {
  64 + title: 'ID',
  65 + dataIndex: 'id',
  66 + width: 200,
  67 + },
  68 + {
  69 + title: '姓名',
  70 + dataIndex: 'name',
  71 + width: 120,
  72 + },
  73 + {
  74 + title: '地址',
  75 + dataIndex: 'address',
  76 + sorter: true,
  77 + children: [
  78 + {
  79 + title: '编号',
  80 + dataIndex: 'no',
  81 + width: 120,
  82 + filters: [
  83 + { text: 'Male', value: 'male' },
  84 + { text: 'Female', value: 'female' },
  85 + ],
  86 + },
  87 +
  88 + {
  89 + title: '开始时间',
  90 + dataIndex: 'beginTime',
  91 + width: 120,
  92 + },
  93 + {
  94 + title: '结束时间',
  95 + dataIndex: 'endTime',
  96 + width: 120,
  97 + },
  98 + ],
  99 + },
  100 + ];
  101 +}
  102 +
  103 +export function getCustomHeaderColumns(): BasicColumn[] {
  104 + return [
  105 + {
  106 + title: 'ID',
  107 + dataIndex: 'id',
  108 + width: 200,
  109 + },
  110 + {
  111 + // title: '姓名',
  112 + dataIndex: 'name',
  113 + width: 120,
  114 + slots: { title: 'customTitle' },
  115 + },
  116 + {
  117 + // title: '地址',
  118 + dataIndex: 'address',
  119 + slots: { title: 'customAddress' },
  120 + sorter: true,
  121 + },
  122 +
  123 + {
  124 + title: '编号',
  125 + dataIndex: 'no',
  126 + width: 120,
  127 + filters: [
  128 + { text: 'Male', value: 'male' },
  129 + { text: 'Female', value: 'female' },
  130 + ],
  131 + },
  132 + {
  133 + title: '开始时间',
  134 + dataIndex: 'beginTime',
  135 + width: 120,
  136 + },
  137 + {
  138 + title: '结束时间',
  139 + dataIndex: 'endTime',
  140 + width: 120,
  141 + },
  142 + ];
  143 +}
  144 +const renderContent = ({ text, index }: { text: any; index: number }) => {
  145 + const obj: any = {
  146 + children: text,
  147 + attrs: {},
  148 + };
  149 + if (index === 9) {
  150 + obj.attrs.colSpan = 0;
  151 + }
  152 + return obj;
  153 +};
  154 +export function getMergeHeaderColumns(): BasicColumn[] {
  155 + return [
  156 + {
  157 + title: 'ID',
  158 + dataIndex: 'id',
  159 + width: 300,
  160 + customRender: renderContent,
  161 + },
  162 + {
  163 + title: '姓名',
  164 + dataIndex: 'name',
  165 + width: 300,
  166 + customRender: renderContent,
  167 + },
  168 + {
  169 + title: '地址',
  170 + dataIndex: 'address',
  171 + colSpan: 2,
  172 + width: 120,
  173 + sorter: true,
  174 + customRender: ({ text, index }: { text: any; index: number }) => {
  175 + const obj: any = {
  176 + children: text,
  177 + attrs: {},
  178 + };
  179 + if (index === 2) {
  180 + obj.attrs.rowSpan = 2;
  181 + }
  182 + if (index === 3) {
  183 + obj.attrs.colSpan = 0;
  184 + }
  185 + return obj;
  186 + },
  187 + },
  188 + {
  189 + title: '编号',
  190 + dataIndex: 'no',
  191 + colSpan: 0,
  192 + filters: [
  193 + { text: 'Male', value: 'male' },
  194 + { text: 'Female', value: 'female' },
  195 + ],
  196 + customRender: renderContent,
  197 + },
  198 + {
  199 + title: '开始时间',
  200 + dataIndex: 'beginTime',
  201 + width: 200,
  202 + customRender: renderContent,
  203 + },
  204 + {
  205 + title: '结束时间',
  206 + dataIndex: 'endTime',
  207 + width: 200,
  208 + customRender: renderContent,
  209 + },
  210 + ];
  211 +}
  212 +export const getAdvanceSchema = (itemNumber = 6): FormSchema[] => {
  213 + const arr: any = [];
  214 + for (let index = 0; index < itemNumber; index++) {
  215 + arr.push({
  216 + field: `field${index}`,
  217 + label: `字段${index}`,
  218 + component: 'Input',
  219 + colProps: {
  220 + xl: 12,
  221 + xxl: 8,
  222 + },
  223 + });
  224 + }
  225 + return arr;
  226 +};
  227 +export function getFormConfig(): Partial<FormProps> {
  228 + return {
  229 + labelWidth: 100,
  230 + schemas: getAdvanceSchema(6),
  231 + };
  232 +}
  233 +export function getBasicData() {
  234 + const data: any = (() => {
  235 + const arr: any = [];
  236 + for (let index = 0; index < 40; index++) {
  237 + arr.push({
  238 + id: `${index}`,
  239 + name: 'John Brown',
  240 + age: `1${index}`,
  241 + no: `${index + 10}`,
  242 + address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park',
  243 + beginTime: new Date().toLocaleString(),
  244 + endTime: new Date().toLocaleString(),
  245 + });
  246 + }
  247 + return arr;
  248 + })();
  249 + return data;
  250 +}
  251 +
  252 +export function getTreeTableData() {
  253 + const data: any = (() => {
  254 + const arr: any = [];
  255 + for (let index = 0; index < 40; index++) {
  256 + arr.push({
  257 + id: `${index}`,
  258 + name: 'John Brown',
  259 + age: `1${index}`,
  260 + no: `${index + 10}`,
  261 + address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park',
  262 + beginTime: new Date().toLocaleString(),
  263 + endTime: new Date().toLocaleString(),
  264 + children: [
  265 + {
  266 + id: `l2-${index}`,
  267 + name: 'John Brown',
  268 + age: `1${index}`,
  269 + no: `${index + 10}`,
  270 + address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park',
  271 + beginTime: new Date().toLocaleString(),
  272 + endTime: new Date().toLocaleString(),
  273 + children: [
  274 + {
  275 + id: `l3-${index}`,
  276 + name: 'John Brown',
  277 + age: `1${index}`,
  278 + no: `${index + 10}`,
  279 + address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park',
  280 + beginTime: new Date().toLocaleString(),
  281 + endTime: new Date().toLocaleString(),
  282 + },
  283 + ],
  284 + },
  285 + ],
  286 + });
  287 + }
  288 + return arr;
  289 + })();
  290 +
  291 + return data;
  292 +}