Commit faf3f4602ecf4b16ff57994668edc8433a43945d
1 parent
5b0a21ec
feat(table): add table component
Showing
71 changed files
with
3937 additions
and
191 deletions
.github/release-drafter.yml
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<T = any>(result: T, { message = 'ok' } = {}) { | @@ -9,12 +9,19 @@ export function resultSuccess<T = any>(result: T, { message = 'ok' } = {}) { | ||
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
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
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> </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
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 '/@/enums/appEnum'; | @@ -6,17 +6,23 @@ import { ContentEnum } from '/@/enums/appEnum'; | ||
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 './useTransition'; | @@ -6,9 +6,7 @@ import { useTransition } from './useTransition'; | ||
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 'vue-router'; | @@ -3,10 +3,10 @@ import type { Router } from 'vue-router'; | ||
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 '/@/types/config'; | @@ -2,8 +2,6 @@ import type { ProjectConfig } from '/@/types/config'; | ||
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 | +} |