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