From 4c9c57f4da5bda69ce34ca6f97f7b5a7ab6377b1 Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 20 Oct 2021 00:47:36 +0800 Subject: [PATCH 01/23] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20table=20?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8C=E4=BD=BF=E7=94=A8=20setup-render=20?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/table.tsx | 33 ++++++++++++++++----------------- devui/table/src/table.type.ts | 2 +- devui/table/src/use-table.ts | 6 +++--- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index 83146778..58a24bf5 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -1,4 +1,4 @@ -import { provide, defineComponent, getCurrentInstance } from 'vue'; +import { provide, defineComponent, getCurrentInstance, computed } from 'vue'; import { Table, TableProps, TablePropsTypes } from './table.type'; import { useTable } from './use-table'; import { createStore } from './store'; @@ -10,27 +10,26 @@ import './table.scss'; export default defineComponent({ name: 'DTable', props: TableProps, - setup(props: TablePropsTypes) { + setup(props: TablePropsTypes, ctx) { const table = getCurrentInstance() as Table; const store = createStore(props); table.store = store; - const { classes } = useTable(props); provide('table', table); - return { classes, store }; - }, - render() { - const { classes, data, store, $slots } = this; - return ( + const classes = useTable(props); + + const isEmpty = computed(() => props.data.length === 0); + + return () => (
- {$slots.default()} - - - - {!!data.length && } -
- {!data.length &&
No Data
} -
+ {ctx.slots.default()} + + + + {!isEmpty.value && } +
+ {isEmpty.value &&
No Data
} + ); - }, + } }); diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index 563b9bb6..3643af81 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -2,7 +2,7 @@ import { PropType, ExtractPropTypes, ComponentInternalInstance } from 'vue'; export const TableProps = { data: { - type: Array as PropType, + type: Array as PropType[]>, default: [], }, striped: { diff --git a/devui/table/src/use-table.ts b/devui/table/src/use-table.ts index c5e9f1e6..9ab56e2c 100644 --- a/devui/table/src/use-table.ts +++ b/devui/table/src/use-table.ts @@ -1,11 +1,11 @@ -import { computed } from 'vue'; +import { computed, ComputedRef } from 'vue'; import { TablePropsTypes } from './table.type'; -export function useTable(props: TablePropsTypes): any { +export function useTable(props: TablePropsTypes): ComputedRef> { const classes = computed(() => ({ 'devui-table': true, 'devui-table-striped': props.striped, })); - return { classes }; + return classes; } \ No newline at end of file -- Gitee From 67468765deebdaa32b0014e9f196c9aee500c571 Mon Sep 17 00:00:00 2001 From: zcating Date: Thu, 21 Oct 2021 18:17:32 +0800 Subject: [PATCH 02/23] =?UTF-8?q?refactor(table):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=E7=9A=84=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/colgroup/colgroup.tsx | 15 +++++---------- devui/table/src/store/index.ts | 27 ++++++++++++++------------- devui/table/src/table.tsx | 20 ++++++++++---------- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/devui/table/src/colgroup/colgroup.tsx b/devui/table/src/colgroup/colgroup.tsx index 93e7197d..5e52c6b7 100644 --- a/devui/table/src/colgroup/colgroup.tsx +++ b/devui/table/src/colgroup/colgroup.tsx @@ -1,4 +1,4 @@ -import { inject, defineComponent } from 'vue'; +import { inject, defineComponent, Ref } from 'vue'; import { Table } from '../table.type'; import { Column } from '../column/column.type'; @@ -6,18 +6,13 @@ export default defineComponent({ name: 'DColGroup', setup() { const parent: Table = inject('table'); - const columns: Column[] = parent.store.states._columns; - - return { columns }; - }, - render() { - const { columns } = this; - return ( + const columns = parent.store.states._columns; + return () => ( - {columns.map((column, index) => { + {columns.value.map((column, index) => { return ; })} ); - }, + } }); \ No newline at end of file diff --git a/devui/table/src/store/index.ts b/devui/table/src/store/index.ts index b7138064..765a7265 100644 --- a/devui/table/src/store/index.ts +++ b/devui/table/src/store/index.ts @@ -1,20 +1,21 @@ -import { ref, watch } from 'vue'; -import { TablePropsTypes } from '../table.type'; +import { watch, Ref, ref } from 'vue'; import { Column } from '../column/column.type'; -export function createStore(props: TablePropsTypes): any { - const _data = ref([]); - const _columns = ref([]); - updateData(); +export interface TableStore> { + insertColumn(column: Column): void + states: { + _data: Ref + _columns: Ref + } +} - watch(() => props.data, updateData, { deep: true }); +export function createStore(dataSource: Ref): TableStore { + const _data: Ref = ref([]); + const _columns: Ref = ref([]); - function updateData() { - _data.value = []; - props.data.forEach((item) => { - _data.value.push(item); - }); - } + watch(dataSource, (value: T[]) => { + _data.value = [...value]; + }, { deep: true, immediate: true }); const insertColumn = (column: Column) => { _columns.value.push(column); diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index 58a24bf5..d7699b0b 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -1,4 +1,4 @@ -import { provide, defineComponent, getCurrentInstance, computed } from 'vue'; +import { provide, defineComponent, getCurrentInstance, computed, toRef } from 'vue'; import { Table, TableProps, TablePropsTypes } from './table.type'; import { useTable } from './use-table'; import { createStore } from './store'; @@ -12,7 +12,7 @@ export default defineComponent({ props: TableProps, setup(props: TablePropsTypes, ctx) { const table = getCurrentInstance() as Table; - const store = createStore(props); + const store = createStore(toRef(props, 'data')); table.store = store; provide('table', table); @@ -22,14 +22,14 @@ export default defineComponent({ return () => (
- {ctx.slots.default()} - - - - {!isEmpty.value && } -
- {isEmpty.value &&
No Data
} -
+ {ctx.slots.default()} + + + + {!isEmpty.value && } +
+ {isEmpty.value &&
No Data
} + ); } }); -- Gitee From 9f74e7ac3355adb81caf4af1e98d8f3955c65e5d Mon Sep 17 00:00:00 2001 From: zcating Date: Thu, 21 Oct 2021 18:33:45 +0800 Subject: [PATCH 03/23] =?UTF-8?q?feat(table):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20rowHoveredHighlight?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/body/body.scss | 2 +- devui/table/src/body/body.tsx | 27 +++++++++++++++++++++++---- devui/table/src/table.type.ts | 28 ++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/devui/table/src/body/body.scss b/devui/table/src/body/body.scss index ea265727..079defec 100644 --- a/devui/table/src/body/body.scss +++ b/devui/table/src/body/body.scss @@ -8,7 +8,7 @@ border-bottom: 1px solid $devui-dividing-line; background-color: $devui-global-bg-normal; - &:hover { + &.hover-enabled:hover { background-color: $devui-list-item-hover-bg; } diff --git a/devui/table/src/body/body.tsx b/devui/table/src/body/body.tsx index 9b02b867..9d27b1a7 100644 --- a/devui/table/src/body/body.tsx +++ b/devui/table/src/body/body.tsx @@ -1,6 +1,8 @@ -import { defineComponent } from 'vue'; +import { defineComponent, inject, computed } from 'vue'; import { TableBodyProps, TableBodyPropsTypes } from './body.type' import { useTableBody } from './use-body'; +import { Table } from '../table.type'; + import './body.scss'; export default defineComponent({ @@ -9,16 +11,33 @@ export default defineComponent({ setup(props: TableBodyPropsTypes) { const { rowColumns } = useTableBody(props); - return { rowColumns }; + const parent: Table = inject('table'); + const hoverEnabled = computed(() => parent.props.rowHoveredHighlight); + + return () => ( + + {rowColumns.value.map((row, rowIndex) => { + return ( + + {row.columns.map((column, index) => { + return ( + {column.renderCell({ row, column, $index: index })} + ); + })} + + ); + })} + + ) }, render() { - const { rowColumns } = this; + const { rowColumns, hoverDisabled } = this; return ( {rowColumns.map((row, rowIndex) => { return ( - + {row.columns.map((column, index) => { return ( {column.renderCell({ row, column, $index: index })} diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index 3643af81..7bd427eb 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -1,4 +1,7 @@ import { PropType, ExtractPropTypes, ComponentInternalInstance } from 'vue'; +import { TableStore } from './store'; + +export type TableSize = 'sm' | 'md' | 'lg'; export const TableProps = { data: { @@ -9,10 +12,31 @@ export const TableProps = { type: Boolean, default: false, }, + scrollable: { + type: Boolean, + default: false + }, + maxWidth: { + type: String, + }, + maxHeight: { + type: String, + }, + size: { + type: String as PropType, + validator(value: string): boolean { + return value === 'sm' || value === 'md' || value === 'lg'; + } + }, + rowHoveredHighlight: { + type: Boolean, + default: true + } }; export type TablePropsTypes = ExtractPropTypes; -export interface Table extends ComponentInternalInstance { - store: any +export interface Table> extends ComponentInternalInstance { + store: TableStore + props: TablePropsTypes } -- Gitee From 8aee39f96946cef8586b3666fa05949f18004df3 Mon Sep 17 00:00:00 2001 From: zcating Date: Fri, 22 Oct 2021 09:25:45 +0800 Subject: [PATCH 04/23] =?UTF-8?q?feat(table):=20=E6=B7=BB=E5=8A=A0=20maxWi?= =?UTF-8?q?dth=20maxHeight?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/table.tsx | 4 ++-- devui/table/src/use-table.ts | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index d7699b0b..898e973d 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -16,12 +16,12 @@ export default defineComponent({ table.store = store; provide('table', table); - const classes = useTable(props); + const { classes, style } = useTable(props); const isEmpty = computed(() => props.data.length === 0); return () => ( -
+
{ctx.slots.default()} diff --git a/devui/table/src/use-table.ts b/devui/table/src/use-table.ts index 9ab56e2c..3b4ae7f3 100644 --- a/devui/table/src/use-table.ts +++ b/devui/table/src/use-table.ts @@ -1,11 +1,19 @@ -import { computed, ComputedRef } from 'vue'; +import { computed, ComputedRef, CSSProperties } from 'vue'; import { TablePropsTypes } from './table.type'; -export function useTable(props: TablePropsTypes): ComputedRef> { +interface TableConfig { + classes: ComputedRef> + style: ComputedRef +} + +export function useTable(props: TablePropsTypes): TableConfig { const classes = computed(() => ({ 'devui-table': true, 'devui-table-striped': props.striped, })); - - return classes; + const style: ComputedRef = computed(() => ({ + maxHeight: props.maxHeight, + maxWidth: props.maxWidth + })); + return {classes, style}; } \ No newline at end of file -- Gitee From 87c99dbdfd3af0702c3e8ecee1a3055bef55cd01 Mon Sep 17 00:00:00 2001 From: zcating Date: Fri, 22 Oct 2021 16:37:46 +0800 Subject: [PATCH 05/23] =?UTF-8?q?fix(table):=20=E4=BF=AE=E5=A4=8D=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/body/body.type.ts | 5 +++-- devui/table/src/body/use-body.ts | 20 +++++++++++------ devui/table/src/header/header.tsx | 32 ++++++++++++--------------- devui/table/src/header/header.type.ts | 5 +++-- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/devui/table/src/body/body.type.ts b/devui/table/src/body/body.type.ts index c1febde0..bfe63e3c 100644 --- a/devui/table/src/body/body.type.ts +++ b/devui/table/src/body/body.type.ts @@ -1,8 +1,9 @@ -import { ExtractPropTypes } from 'vue'; +import { ExtractPropTypes, PropType } from 'vue'; +import { TableStore } from '../store'; export const TableBodyProps = { store: { - type: Object, + type: Object as PropType, default: {}, }, }; diff --git a/devui/table/src/body/use-body.ts b/devui/table/src/body/use-body.ts index 1657a06b..34f68c25 100644 --- a/devui/table/src/body/use-body.ts +++ b/devui/table/src/body/use-body.ts @@ -1,13 +1,19 @@ -import { computed } from 'vue'; +import { computed, ComputedRef } from 'vue'; +import { Column } from '../column/column.type'; import { TableBodyPropsTypes } from './body.type' -export function useTableBody(props: TableBodyPropsTypes): any { - const storeData = props.store.states; +interface Data { + rowColumns: ComputedRef<(Record & { columns: Column[]; })[]> +} + +export const useTableBody = (props: TableBodyPropsTypes): Data => { + const states = props.store.states; const rowColumns = computed(() => { - return storeData._data.value.map((row) => { - const obj = Object.assign({}, row); - obj.columns = storeData._columns.value; - return obj; + return states._data.value.map((row) => { + return { + ...row, + columns: states._columns.value + }; }); }); diff --git a/devui/table/src/header/header.tsx b/devui/table/src/header/header.tsx index a05a80b7..4ce026d5 100644 --- a/devui/table/src/header/header.tsx +++ b/devui/table/src/header/header.tsx @@ -1,4 +1,4 @@ -import { defineComponent, toRefs } from 'vue'; +import { defineComponent } from 'vue'; import { TableHeaderProps, TableHeaderPropsTypes } from './header.type' import './header.scss'; @@ -6,23 +6,19 @@ export default defineComponent({ name: 'DTableHeader', props: TableHeaderProps, setup(props: TableHeaderPropsTypes) { - const { store } = toRefs(props) - const columns = store.value.states._columns.value; - - return { - columns, + return () => { + const columns = props.store.states._columns; + return ( + + + {columns.value.map((column, index) => ( + + ))} + + + ) } - }, - render() { - const { columns } = this - return ( - - - {columns.map((column, index) => { - return ; - })} - - - ) } }); \ No newline at end of file diff --git a/devui/table/src/header/header.type.ts b/devui/table/src/header/header.type.ts index 3369aa9d..2beda703 100644 --- a/devui/table/src/header/header.type.ts +++ b/devui/table/src/header/header.type.ts @@ -1,8 +1,9 @@ -import { ExtractPropTypes } from 'vue'; +import { ExtractPropTypes, PropType } from 'vue'; +import { TableStore } from '../store'; export const TableHeaderProps = { store: { - type: Object, + type: Object as PropType, default: {}, }, }; -- Gitee From 02f1592927714d1844d1f6035e57fde66c138aa8 Mon Sep 17 00:00:00 2001 From: zcating Date: Fri, 22 Oct 2021 18:44:38 +0800 Subject: [PATCH 06/23] =?UTF-8?q?feat(table):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A=E5=A4=B4=E9=83=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/table.scss | 12 ++++++++++++ devui/table/src/table.tsx | 37 ++++++++++++++++++++++++++++++----- devui/table/src/table.type.ts | 11 +++++++++++ devui/table/src/use-table.ts | 4 +++- 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/devui/table/src/table.scss b/devui/table/src/table.scss index e272211a..b95fed56 100644 --- a/devui/table/src/table.scss +++ b/devui/table/src/table.scss @@ -23,4 +23,16 @@ font-size: $devui-font-size; text-align: center; } + + &-view { + display: flex; + flex-direction: column; + position: relative; + height: 100%; + + & .scroll-view { + flex: 1; + overflow-y: scroll; + } + } } diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index 898e973d..b710b940 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -20,14 +20,41 @@ export default defineComponent({ const isEmpty = computed(() => props.data.length === 0); - return () => ( -
- {ctx.slots.default()} + + const fixHeaderCompo = computed(() => { + return ( +
+
+
+ {column.renderHeader()} +
{column.renderHeader()}
+ + +
+
+
+ + + {!isEmpty.value && } +
+
+
+ ); + }); + + const normalHeaderCompo = computed(() => { + return ( - - {!isEmpty.value && } + + {!isEmpty.value && }
+ ) + }); + + + return () => ( +
+ {ctx.slots.default()} + {props.fixHeader ? fixHeaderCompo.value : normalHeaderCompo.value} {isEmpty.value &&
No Data
}
); diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index 7bd427eb..a5d16e80 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -22,6 +22,13 @@ export const TableProps = { maxHeight: { type: String, }, + tableWidth: { + type: String, + }, + tableHeight: { + type: String, + default: '360px' + }, size: { type: String as PropType, validator(value: string): boolean { @@ -31,6 +38,10 @@ export const TableProps = { rowHoveredHighlight: { type: Boolean, default: true + }, + fixHeader: { + type: Boolean, + default: false } }; diff --git a/devui/table/src/use-table.ts b/devui/table/src/use-table.ts index 3b4ae7f3..bbba4f45 100644 --- a/devui/table/src/use-table.ts +++ b/devui/table/src/use-table.ts @@ -13,7 +13,9 @@ export function useTable(props: TablePropsTypes): TableConfig { })); const style: ComputedRef = computed(() => ({ maxHeight: props.maxHeight, - maxWidth: props.maxWidth + maxWidth: props.maxWidth, + height: props.tableHeight, + width: props.tableWidth })); return {classes, style}; } \ No newline at end of file -- Gitee From 5880b96b69eab3ea6f5ce3f98e2574c40dd489e4 Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:33:41 +0800 Subject: [PATCH 07/23] =?UTF-8?q?fix(table):=20=E5=8F=96=E6=B6=88=20tableH?= =?UTF-8?q?eight=20=E9=BB=98=E8=AE=A4=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/index.ts | 2 +- devui/table/src/table.scss | 2 ++ devui/table/src/table.tsx | 7 +++---- devui/table/src/table.type.ts | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/devui/table/index.ts b/devui/table/index.ts index c40ee5ce..30393dd6 100644 --- a/devui/table/index.ts +++ b/devui/table/index.ts @@ -12,7 +12,7 @@ export { Table, Column } export default { title: 'Table 表格', category: '数据展示', - status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 + status: '10%', install(app: App): void { app.use(Table as any) } diff --git a/devui/table/src/table.scss b/devui/table/src/table.scss index b95fed56..900cff6e 100644 --- a/devui/table/src/table.scss +++ b/devui/table/src/table.scss @@ -6,6 +6,8 @@ width: 100%; border-spacing: 0; border: none; + margin: 0; + padding: 0; &-wrapper { width: 100%; diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index b710b940..18a2c590 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -27,13 +27,13 @@ export default defineComponent({
- +
- {!isEmpty.value && } + {!isEmpty.value && }
@@ -45,12 +45,11 @@ export default defineComponent({ - {!isEmpty.value && } + {!isEmpty.value && }
) }); - return () => (
{ctx.slots.default()} diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index a5d16e80..b60d7d20 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -27,7 +27,6 @@ export const TableProps = { }, tableHeight: { type: String, - default: '360px' }, size: { type: String as PropType, -- Gitee From 6ba53feeadea292266bb6f7e259b086735a4c2da Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:35:44 +0800 Subject: [PATCH 08/23] =?UTF-8?q?feat(table):=20=E6=96=B0=E5=A2=9E=20check?= =?UTF-8?q?able=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/body/body.tsx | 36 ++++++++++---------------- devui/table/src/colgroup/colgroup.tsx | 4 +-- devui/table/src/column/column.tsx | 4 +-- devui/table/src/header/header.tsx | 15 ++++++++++- devui/table/src/store/index.ts | 37 ++++++++++++++++++++++++++- devui/table/src/table.tsx | 5 ++-- devui/table/src/table.type.ts | 8 +++++- 7 files changed, 78 insertions(+), 31 deletions(-) diff --git a/devui/table/src/body/body.tsx b/devui/table/src/body/body.tsx index 9d27b1a7..91d22360 100644 --- a/devui/table/src/body/body.tsx +++ b/devui/table/src/body/body.tsx @@ -1,7 +1,8 @@ import { defineComponent, inject, computed } from 'vue'; import { TableBodyProps, TableBodyPropsTypes } from './body.type' import { useTableBody } from './use-body'; -import { Table } from '../table.type'; +import { Table, TABLE_TOKEN } from '../table.type'; +import { Checkbox } from '../../../checkbox'; import './body.scss'; @@ -11,14 +12,24 @@ export default defineComponent({ setup(props: TableBodyPropsTypes) { const { rowColumns } = useTableBody(props); - const parent: Table = inject('table'); + const parent: Table = inject(TABLE_TOKEN); const hoverEnabled = computed(() => parent.props.rowHoveredHighlight); + const renderCheckbox = (index: number) => { + const checkList = props.store.states._checkList; + return parent.props.checkable ? ( + + + + ) : null + }; + return () => ( {rowColumns.value.map((row, rowIndex) => { return ( + {renderCheckbox(rowIndex)} {row.columns.map((column, index) => { return ( {column.renderCell({ row, column, $index: index })} @@ -29,24 +40,5 @@ export default defineComponent({ })} ) - }, - render() { - const { rowColumns, hoverDisabled } = this; - - return ( - - {rowColumns.map((row, rowIndex) => { - return ( - - {row.columns.map((column, index) => { - return ( - {column.renderCell({ row, column, $index: index })} - ); - })} - - ); - })} - - ); - }, + } }); \ No newline at end of file diff --git a/devui/table/src/colgroup/colgroup.tsx b/devui/table/src/colgroup/colgroup.tsx index 5e52c6b7..cde8a326 100644 --- a/devui/table/src/colgroup/colgroup.tsx +++ b/devui/table/src/colgroup/colgroup.tsx @@ -1,11 +1,11 @@ import { inject, defineComponent, Ref } from 'vue'; -import { Table } from '../table.type'; +import { Table, TABLE_TOKEN } from '../table.type'; import { Column } from '../column/column.type'; export default defineComponent({ name: 'DColGroup', setup() { - const parent: Table = inject('table'); + const parent = inject(TABLE_TOKEN); const columns = parent.store.states._columns; return () => ( diff --git a/devui/table/src/column/column.tsx b/devui/table/src/column/column.tsx index 60ef5e04..94fe8a7f 100644 --- a/devui/table/src/column/column.tsx +++ b/devui/table/src/column/column.tsx @@ -4,7 +4,7 @@ import { TableColumnProps, TableColumnPropsTypes, } from './column.type' -import { Table } from '../table.type'; +import { Table, TABLE_TOKEN } from '../table.type'; import { useRender } from './use-column'; export default defineComponent({ @@ -15,7 +15,7 @@ export default defineComponent({ field: props.field, header: props.header, }; - const parent: Table = inject('table'); + const parent = inject(TABLE_TOKEN); const { setColumnWidth, setColumnRender } = useRender(props); onBeforeMount(() => { diff --git a/devui/table/src/header/header.tsx b/devui/table/src/header/header.tsx index 4ce026d5..f8c29c7d 100644 --- a/devui/table/src/header/header.tsx +++ b/devui/table/src/header/header.tsx @@ -1,16 +1,29 @@ -import { defineComponent } from 'vue'; +import { defineComponent, inject, computed } from 'vue'; import { TableHeaderProps, TableHeaderPropsTypes } from './header.type' import './header.scss'; +import { TABLE_TOKEN } from '../table.type'; +import { Checkbox } from '../../../checkbox'; export default defineComponent({ name: 'DTableHeader', props: TableHeaderProps, setup(props: TableHeaderPropsTypes) { + const table = inject(TABLE_TOKEN); + + const checkbox = computed(() => { + return table.props.checkable ? ( + + + + ) : null + }); + return () => { const columns = props.store.states._columns; return ( + {checkbox.value} {columns.value.map((column, index) => ( {column.renderHeader()} diff --git a/devui/table/src/store/index.ts b/devui/table/src/store/index.ts index 765a7265..9eb0afe2 100644 --- a/devui/table/src/store/index.ts +++ b/devui/table/src/store/index.ts @@ -1,4 +1,4 @@ -import { watch, Ref, ref } from 'vue'; +import { watch, Ref, ref, customRef } from 'vue'; import { Column } from '../column/column.type'; export interface TableStore> { @@ -6,17 +6,50 @@ export interface TableStore> { states: { _data: Ref _columns: Ref + _checkAll: Ref + _checkList: Ref } } export function createStore(dataSource: Ref): TableStore { const _data: Ref = ref([]); const _columns: Ref = ref([]); + const _checkList: Ref = ref([]); + const _checkAllRecord: Ref = ref(false); + const _checkAll: Ref = customRef((track, trigger) => { + return { + get: () => { + track(); + return _checkAllRecord.value; + }, + set: (val: boolean) => { + _checkAllRecord.value = val; + // 只有在 set 的时候变更 _checkList 的数据 + for (let i = 0; i < _checkList.value.length; i++) { + _checkList.value[i] = val; + } + trigger(); + } + } + }); watch(dataSource, (value: T[]) => { _data.value = [...value]; + _checkList.value = new Array(value.length).fill(false); }, { deep: true, immediate: true }); + // // checkList 只有全为true的时候, + // watch(_checkList, (list) => { + // let allFalse + // let allTrue = false; + // for (let i = 0; i < list.length; i++) { + // current &&= list[i]; + // } + // if (status === 1) { + // _checkAllRecord.value = current; + // } + // }, { immediate: true, deep: true }); + const insertColumn = (column: Column) => { _columns.value.push(column); }; @@ -26,6 +59,8 @@ export function createStore(dataSource: Ref): TableStore { states: { _data, _columns, + _checkList, + _checkAll }, }; } \ No newline at end of file diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index 18a2c590..9341bbbb 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -1,5 +1,5 @@ import { provide, defineComponent, getCurrentInstance, computed, toRef } from 'vue'; -import { Table, TableProps, TablePropsTypes } from './table.type'; +import { Table, TableProps, TablePropsTypes, TABLE_TOKEN } from './table.type'; import { useTable } from './use-table'; import { createStore } from './store'; import ColGroup from './colgroup/colgroup'; @@ -7,6 +7,7 @@ import TableHeader from './header/header'; import TableBody from './body/body'; import './table.scss'; + export default defineComponent({ name: 'DTable', props: TableProps, @@ -14,7 +15,7 @@ export default defineComponent({ const table = getCurrentInstance() as Table; const store = createStore(toRef(props, 'data')); table.store = store; - provide('table', table); + provide(TABLE_TOKEN, table); const { classes, style } = useTable(props); diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index b60d7d20..466c7c09 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -1,4 +1,4 @@ -import { PropType, ExtractPropTypes, ComponentInternalInstance } from 'vue'; +import { PropType, ExtractPropTypes, ComponentInternalInstance, InjectionKey } from 'vue'; import { TableStore } from './store'; export type TableSize = 'sm' | 'md' | 'lg'; @@ -41,6 +41,10 @@ export const TableProps = { fixHeader: { type: Boolean, default: false + }, + checkable: { + type: Boolean, + default: true } }; @@ -50,3 +54,5 @@ export interface Table> extends ComponentInternalInstanc store: TableStore props: TablePropsTypes } + +export const TABLE_TOKEN: InjectionKey = Symbol(); -- Gitee From 82c358125b734cce914d61c714632d388e85068c Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:36:25 +0800 Subject: [PATCH 09/23] =?UTF-8?q?feat(table):=20=E5=AE=8C=E5=96=84checkbox?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/store/index.ts | 46 ++++++++++++++++------------------ 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/devui/table/src/store/index.ts b/devui/table/src/store/index.ts index 9eb0afe2..332c1a88 100644 --- a/devui/table/src/store/index.ts +++ b/devui/table/src/store/index.ts @@ -1,4 +1,4 @@ -import { watch, Ref, ref, customRef } from 'vue'; +import { watch, Ref, ref, computed } from 'vue'; import { Column } from '../column/column.type'; export interface TableStore> { @@ -16,19 +16,13 @@ export function createStore(dataSource: Ref): TableStore { const _columns: Ref = ref([]); const _checkList: Ref = ref([]); const _checkAllRecord: Ref = ref(false); - const _checkAll: Ref = customRef((track, trigger) => { - return { - get: () => { - track(); - return _checkAllRecord.value; - }, - set: (val: boolean) => { - _checkAllRecord.value = val; - // 只有在 set 的时候变更 _checkList 的数据 - for (let i = 0; i < _checkList.value.length; i++) { - _checkList.value[i] = val; - } - trigger(); + const _checkAll: Ref = computed({ + get: () => _checkAllRecord.value, + set: (val: boolean) => { + _checkAllRecord.value = val; + // 只有在 set 的时候变更 _checkList 的数据 + for (let i = 0; i < _checkList.value.length; i++) { + _checkList.value[i] = val; } } }); @@ -38,17 +32,19 @@ export function createStore(dataSource: Ref): TableStore { _checkList.value = new Array(value.length).fill(false); }, { deep: true, immediate: true }); - // // checkList 只有全为true的时候, - // watch(_checkList, (list) => { - // let allFalse - // let allTrue = false; - // for (let i = 0; i < list.length; i++) { - // current &&= list[i]; - // } - // if (status === 1) { - // _checkAllRecord.value = current; - // } - // }, { immediate: true, deep: true }); + // checkList 只有全为true的时候 + watch(_checkList, (list) => { + let allTrue = true; + for (let i = 0; i < list.length; i++) { + if (!list[i]) { + allTrue = false; + break; + } + } + if (_checkAllRecord.value !== allTrue) { + _checkAllRecord.value = allTrue; + } + }, { immediate: true, deep: true }); const insertColumn = (column: Column) => { _columns.value.push(column); -- Gitee From 48194769332613a05c3b476a3e84093c2492682b Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:37:14 +0800 Subject: [PATCH 10/23] =?UTF-8?q?feat(table):=20=E6=96=B0=E5=A2=9E=20table?= =?UTF-8?q?Layout=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/colgroup/colgroup.tsx | 8 +++++--- devui/table/src/table.tsx | 1 - devui/table/src/table.type.ts | 7 +++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/devui/table/src/colgroup/colgroup.tsx b/devui/table/src/colgroup/colgroup.tsx index cde8a326..33625862 100644 --- a/devui/table/src/colgroup/colgroup.tsx +++ b/devui/table/src/colgroup/colgroup.tsx @@ -9,9 +9,11 @@ export default defineComponent({ const columns = parent.store.states._columns; return () => ( - {columns.value.map((column, index) => { - return ; - })} + {parent.props.tableLayout === 'fixed' ? ( + columns.value.map((column, index) => { + return ; + }) + ) : null} ); } diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index 9341bbbb..52ef793e 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -21,7 +21,6 @@ export default defineComponent({ const isEmpty = computed(() => props.data.length === 0); - const fixHeaderCompo = computed(() => { return (
diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index 466c7c09..110031cd 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -45,6 +45,13 @@ export const TableProps = { checkable: { type: Boolean, default: true + }, + tableLayout: { + type: String as PropType<'fixed' | 'auto'>, + default: 'auto', + validator(v: string) { + return v === 'fixed' || v === 'auto'; + } } }; -- Gitee From 297e0f315c4809e9e3bd35c0423dbee8b5206177 Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:37:57 +0800 Subject: [PATCH 11/23] =?UTF-8?q?feat(table):=20=E6=96=B0=E5=A2=9E=20getCh?= =?UTF-8?q?eckedRows=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/column/column.tsx | 2 +- devui/table/src/store/index.ts | 13 +++++++++++-- devui/table/src/table.tsx | 8 +++++++- devui/table/src/table.type.ts | 20 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/devui/table/src/column/column.tsx b/devui/table/src/column/column.tsx index 94fe8a7f..8523284d 100644 --- a/devui/table/src/column/column.tsx +++ b/devui/table/src/column/column.tsx @@ -4,7 +4,7 @@ import { TableColumnProps, TableColumnPropsTypes, } from './column.type' -import { Table, TABLE_TOKEN } from '../table.type'; +import { TABLE_TOKEN } from '../table.type'; import { useRender } from './use-column'; export default defineComponent({ diff --git a/devui/table/src/store/index.ts b/devui/table/src/store/index.ts index 332c1a88..ef177edb 100644 --- a/devui/table/src/store/index.ts +++ b/devui/table/src/store/index.ts @@ -2,13 +2,14 @@ import { watch, Ref, ref, computed } from 'vue'; import { Column } from '../column/column.type'; export interface TableStore> { - insertColumn(column: Column): void states: { _data: Ref _columns: Ref _checkAll: Ref _checkList: Ref } + insertColumn(column: Column): void + getCheckedRows(): T[] } export function createStore(dataSource: Ref): TableStore { @@ -34,6 +35,9 @@ export function createStore(dataSource: Ref): TableStore { // checkList 只有全为true的时候 watch(_checkList, (list) => { + if (list.length === 0) { + return; + } let allTrue = true; for (let i = 0; i < list.length; i++) { if (!list[i]) { @@ -50,13 +54,18 @@ export function createStore(dataSource: Ref): TableStore { _columns.value.push(column); }; + const getCheckedRows = () => { + return _data.value.filter((_, index) => _checkList.value[index]); + } + return { - insertColumn, states: { _data, _columns, _checkList, _checkAll }, + insertColumn, + getCheckedRows }; } \ No newline at end of file diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index 52ef793e..83a52c1f 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -1,4 +1,4 @@ -import { provide, defineComponent, getCurrentInstance, computed, toRef } from 'vue'; +import { provide, defineComponent, getCurrentInstance, computed, toRef, defineExpose } from 'vue'; import { Table, TableProps, TablePropsTypes, TABLE_TOKEN } from './table.type'; import { useTable } from './use-table'; import { createStore } from './store'; @@ -50,6 +50,12 @@ export default defineComponent({ ) }); + ctx.expose({ + getCheckedRows() { + return store.getCheckedRows(); + } + }); + return () => (
{ctx.slots.default()} diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index 110031cd..3e5f1d8b 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -62,4 +62,24 @@ export interface Table> extends ComponentInternalInstanc props: TablePropsTypes } + +// export interface TableCheckStatusArg { +// pageAllChecked?: boolean; // 全选 +// pageHalfChecked?: boolean; // 半选 +// } + +// export interface RowToggleStatusEventArg { +// rowItem: any; // 行数据 +// open: boolean; // 子表格是否展开 +// } + +export interface TableMethods> { + getCheckedRows(): T[] + // setRowCheckStatus(arg: TableCheckStatusArg): void + // setTableCheckStatus(arg: RowToggleStatusEventArg): void + // setRowChildToggleStatus(): void + // setTableChildrenToggleStatus(): void + // cancelEditingStatus(): void +} + export const TABLE_TOKEN: InjectionKey
= Symbol(); -- Gitee From 063425af800b0680829f6d50f5ceb8138c7a6ab6 Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:38:55 +0800 Subject: [PATCH 12/23] =?UTF-8?q?feat(table):=20=E6=96=B0=E5=A2=9E=20showL?= =?UTF-8?q?oading=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/table.tsx | 4 +++- devui/table/src/table.type.ts | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/devui/table/src/table.tsx b/devui/table/src/table.tsx index 83a52c1f..598a1144 100644 --- a/devui/table/src/table.tsx +++ b/devui/table/src/table.tsx @@ -5,6 +5,7 @@ import { createStore } from './store'; import ColGroup from './colgroup/colgroup'; import TableHeader from './header/header'; import TableBody from './body/body'; + import './table.scss'; @@ -57,7 +58,8 @@ export default defineComponent({ }); return () => ( -
+
+ {ctx.slots.default()} {props.fixHeader ? fixHeaderCompo.value : normalHeaderCompo.value} {isEmpty.value &&
No Data
} diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index 3e5f1d8b..39a6490a 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -52,6 +52,10 @@ export const TableProps = { validator(v: string) { return v === 'fixed' || v === 'auto'; } + }, + showLoading: { + type: Boolean, + default: false } }; -- Gitee From cd3d1799d0037157580ab1fe9b2bf918677d602f Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:40:17 +0800 Subject: [PATCH 13/23] =?UTF-8?q?feat(table):=20=E6=B7=BB=E5=8A=A0=20sorta?= =?UTF-8?q?ble=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/column/column.tsx | 21 ++++++-- devui/table/src/column/column.type.ts | 8 +++- devui/table/src/header/header.tsx | 31 ++++++++++-- devui/table/src/header/sort/index.ts | 1 + devui/table/src/header/sort/sort.scss | 56 ++++++++++++++++++++++ devui/table/src/header/sort/sort.tsx | 69 +++++++++++++++++++++++++++ devui/table/src/store/index.ts | 10 ++++ devui/table/src/table.scss | 1 + 8 files changed, 188 insertions(+), 9 deletions(-) create mode 100644 devui/table/src/header/sort/index.ts create mode 100644 devui/table/src/header/sort/sort.scss create mode 100644 devui/table/src/header/sort/sort.tsx diff --git a/devui/table/src/column/column.tsx b/devui/table/src/column/column.tsx index 8523284d..c962298a 100644 --- a/devui/table/src/column/column.tsx +++ b/devui/table/src/column/column.tsx @@ -1,4 +1,4 @@ -import { inject, defineComponent, onBeforeMount, onMounted } from 'vue'; +import { inject, defineComponent, onBeforeMount, onBeforeUnmount, onMounted, reactive, watch } from 'vue'; import { Column, TableColumnProps, @@ -11,10 +11,21 @@ export default defineComponent({ name: 'DColumn', props: TableColumnProps, setup(props: TableColumnPropsTypes) { - const column: Column = { + const column: Column = reactive({ field: props.field, header: props.header, - }; + sortable: props.sortable + }); + + watch( + [() => props.field, () => props.header, () => props.sortable], + ([field, header, sortable]) => { + column.field = field; + column.header = header; + column.sortable = sortable; + } + ); + const parent = inject(TABLE_TOKEN); const { setColumnWidth, setColumnRender } = useRender(props); @@ -26,6 +37,10 @@ export default defineComponent({ onMounted(() => { parent.store.insertColumn(column); }); + + onBeforeUnmount(() => { + parent.store.removeColumn(column); + }); }, render() { return null; diff --git a/devui/table/src/column/column.type.ts b/devui/table/src/column/column.type.ts index cdab0409..9d78f1f5 100644 --- a/devui/table/src/column/column.type.ts +++ b/devui/table/src/column/column.type.ts @@ -19,9 +19,14 @@ export const TableColumnProps = { }, formatter: { type: Function as PropType< - (row: any, column: Column, cellValue, index: number) => VNode + (row: any, column: Column, cellValue: any, index: number) => VNode >, }, + sortable: { + type: Boolean, + default: false + }, + }; export type TableColumnPropsTypes = ExtractPropTypes; @@ -32,6 +37,7 @@ export interface Column { minWidth?: number realWidth?: number header?: string + sortable?: boolean renderHeader?: () => void renderCell?: (data: any) => void formatter?: (row: any, column: Column, cellValue, index: number) => VNode diff --git a/devui/table/src/header/header.tsx b/devui/table/src/header/header.tsx index f8c29c7d..9971043a 100644 --- a/devui/table/src/header/header.tsx +++ b/devui/table/src/header/header.tsx @@ -1,8 +1,13 @@ -import { defineComponent, inject, computed } from 'vue'; +import { defineComponent, inject, computed, ref, PropType } from 'vue'; import { TableHeaderProps, TableHeaderPropsTypes } from './header.type' -import './header.scss'; import { TABLE_TOKEN } from '../table.type'; +import { Column } from '../column/column.type'; + import { Checkbox } from '../../../checkbox'; +import { Sort } from './sort'; + +import './header.scss'; + export default defineComponent({ name: 'DTableHeader', @@ -25,13 +30,29 @@ export default defineComponent({
{checkbox.value} {columns.value.map((column, index) => ( - + ) } } +}); + +const Th = defineComponent({ + props: { + column: { + type: Object as PropType, + required: true + } + }, + setup(props: { column: Column; }) { + const directionRef = ref('DESC'); + return () => ( + + ) + } }); \ No newline at end of file diff --git a/devui/table/src/header/sort/index.ts b/devui/table/src/header/sort/index.ts new file mode 100644 index 00000000..72099fcb --- /dev/null +++ b/devui/table/src/header/sort/index.ts @@ -0,0 +1 @@ +export { Sort } from './sort'; \ No newline at end of file diff --git a/devui/table/src/header/sort/sort.scss b/devui/table/src/header/sort/sort.scss new file mode 100644 index 00000000..203b367d --- /dev/null +++ b/devui/table/src/header/sort/sort.scss @@ -0,0 +1,56 @@ +@import '../../../../styles-var/devui-var.scss'; + +.sort-clickable { + cursor: pointer; + position: absolute; + top: -16px; + left: 50%; + transform: translateX(-50%); + padding: 8px; + line-height: 20px; +} + +.sort-icon-default { + > svg g use { + fill: $devui-dividing-line; + } + + > svg g polygon { + fill: $devui-icon-bg; + } + + &:hover { + > svg g use { + fill: $devui-icon-fill-active-hover; + } + } +} + +.sort-icon-asc, +.sort-icon-desc { + > svg g use { + fill: $devui-icon-fill-active; + } + + > svg g polygon { + fill: $devui-icon-bg; + } + + &:hover { + > svg g use { + fill: $devui-icon-fill-active-hover; + } + } +} + +.sort-icon-asc { + > svg g polygon:last-of-type { + opacity: 0.3; + } +} + +.sort-icon-desc { + > svg g polygon:first-of-type { + opacity: 0.3; + } +} diff --git a/devui/table/src/header/sort/sort.tsx b/devui/table/src/header/sort/sort.tsx new file mode 100644 index 00000000..017f983c --- /dev/null +++ b/devui/table/src/header/sort/sort.tsx @@ -0,0 +1,69 @@ +import { defineComponent, PropType } from 'vue'; +import './sort.scss'; + +type SortDirection = 'ASC' | 'DESC' | ''; + +export const Sort = defineComponent({ + props: { + modelValue: { + type: String as PropType, + default: '' + }, + 'onUpdate:modelValue': { + type: Function as PropType<(v: SortDirection) => void> + } + }, + emits: ['update:modelValue'], + setup(props, ctx) { + const changeDirection = () => { + let direction = ''; + if (props.modelValue === 'ASC') { + direction = 'DESC'; + } else if (props.modelValue === 'DESC') { + direction = ''; + } else { + direction = 'ASC'; + } + ctx.emit('update:modelValue', direction); + } + + return () => ( + + + + + + + + + + + + + + + + + + + + ); + } +}) \ No newline at end of file diff --git a/devui/table/src/store/index.ts b/devui/table/src/store/index.ts index ef177edb..8aec09f8 100644 --- a/devui/table/src/store/index.ts +++ b/devui/table/src/store/index.ts @@ -9,6 +9,7 @@ export interface TableStore> { _checkList: Ref } insertColumn(column: Column): void + removeColumn(column: Column): void getCheckedRows(): T[] } @@ -54,6 +55,14 @@ export function createStore(dataSource: Ref): TableStore { _columns.value.push(column); }; + const removeColumn = (column: Column) => { + const i = _columns.value.findIndex((v) => v === column); + if (i === -1) { + return; + } + _columns.value.splice(i, 1); + } + const getCheckedRows = () => { return _data.value.filter((_, index) => _checkList.value[index]); } @@ -66,6 +75,7 @@ export function createStore(dataSource: Ref): TableStore { _checkAll }, insertColumn, + removeColumn, getCheckedRows }; } \ No newline at end of file diff --git a/devui/table/src/table.scss b/devui/table/src/table.scss index 900cff6e..0abf4593 100644 --- a/devui/table/src/table.scss +++ b/devui/table/src/table.scss @@ -12,6 +12,7 @@ &-wrapper { width: 100%; overflow-x: auto; + padding-top: 8px; } &-striped { -- Gitee From 4cba96b5d1904543f006dba7ec978a596c6e9dc9 Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:41:07 +0800 Subject: [PATCH 14/23] =?UTF-8?q?feat(table):=20=E6=96=B0=E5=A2=9E=20heade?= =?UTF-8?q?r=20halfChecked?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/header/header.tsx | 3 ++- devui/table/src/store/index.ts | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/devui/table/src/header/header.tsx b/devui/table/src/header/header.tsx index 9971043a..8b583e24 100644 --- a/devui/table/src/header/header.tsx +++ b/devui/table/src/header/header.tsx @@ -14,11 +14,12 @@ export default defineComponent({ props: TableHeaderProps, setup(props: TableHeaderPropsTypes) { const table = inject(TABLE_TOKEN); + const { _checkAll: checkAll, _halfChecked: halfChecked } = table.store.states; const checkbox = computed(() => { return table.props.checkable ? ( ) : null }); diff --git a/devui/table/src/store/index.ts b/devui/table/src/store/index.ts index 8aec09f8..d8c54344 100644 --- a/devui/table/src/store/index.ts +++ b/devui/table/src/store/index.ts @@ -5,8 +5,9 @@ export interface TableStore> { states: { _data: Ref _columns: Ref - _checkAll: Ref _checkList: Ref + _checkAll: Ref + _halfChecked: Ref } insertColumn(column: Column): void removeColumn(column: Column): void @@ -28,6 +29,7 @@ export function createStore(dataSource: Ref): TableStore { } } }); + const _halfChecked = ref(false); watch(dataSource, (value: T[]) => { _data.value = [...value]; @@ -40,15 +42,15 @@ export function createStore(dataSource: Ref): TableStore { return; } let allTrue = true; + let allFalse = true; for (let i = 0; i < list.length; i++) { - if (!list[i]) { - allTrue = false; - break; - } - } - if (_checkAllRecord.value !== allTrue) { - _checkAllRecord.value = allTrue; + allTrue &&= list[i]; + allFalse &&= !list[i]; } + + _checkAllRecord.value = allTrue; + _halfChecked.value = !(allFalse || allTrue); + }, { immediate: true, deep: true }); const insertColumn = (column: Column) => { @@ -72,7 +74,8 @@ export function createStore(dataSource: Ref): TableStore { _data, _columns, _checkList, - _checkAll + _checkAll, + _halfChecked }, insertColumn, removeColumn, -- Gitee From cde10030a66af29f1209e8aa16845c3ba2b79a21 Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:41:51 +0800 Subject: [PATCH 15/23] =?UTF-8?q?refactor(table):=20=E4=BC=98=E5=8C=96=20T?= =?UTF-8?q?ableBody=20=E5=92=8C=20TableColumn=20=E7=9A=84=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/body/body.tsx | 15 +++--- devui/table/src/column/column.tsx | 25 ++-------- devui/table/src/column/column.type.ts | 12 ++--- devui/table/src/column/use-column.ts | 71 ++++++++++++++------------- devui/table/src/header/header.tsx | 10 ++-- devui/table/src/header/sort/sort.tsx | 2 +- devui/table/src/store/index.ts | 33 ++++++++++++- devui/table/src/table.type.ts | 3 +- 8 files changed, 96 insertions(+), 75 deletions(-) diff --git a/devui/table/src/body/body.tsx b/devui/table/src/body/body.tsx index 91d22360..1d3f4fec 100644 --- a/devui/table/src/body/body.tsx +++ b/devui/table/src/body/body.tsx @@ -1,7 +1,6 @@ import { defineComponent, inject, computed } from 'vue'; import { TableBodyProps, TableBodyPropsTypes } from './body.type' -import { useTableBody } from './use-body'; -import { Table, TABLE_TOKEN } from '../table.type'; +import { TABLE_TOKEN } from '../table.type'; import { Checkbox } from '../../../checkbox'; import './body.scss'; @@ -10,11 +9,13 @@ export default defineComponent({ name: 'DTableBody', props: TableBodyProps, setup(props: TableBodyPropsTypes) { - const { rowColumns } = useTableBody(props); + const parent = inject(TABLE_TOKEN); + const { _data: data, _columns: columns } = parent.store.states; - const parent: Table = inject(TABLE_TOKEN); + // 移动到行上是否高亮 const hoverEnabled = computed(() => parent.props.rowHoveredHighlight); + // 行前的 checkbox const renderCheckbox = (index: number) => { const checkList = props.store.states._checkList; return parent.props.checkable ? ( @@ -26,13 +27,13 @@ export default defineComponent({ return () => ( - {rowColumns.value.map((row, rowIndex) => { + {data.value.map((row, rowIndex) => { return ( {renderCheckbox(rowIndex)} - {row.columns.map((column, index) => { + {columns.value.map((column, index) => { return ( - + ); })} diff --git a/devui/table/src/column/column.tsx b/devui/table/src/column/column.tsx index c962298a..c4745020 100644 --- a/devui/table/src/column/column.tsx +++ b/devui/table/src/column/column.tsx @@ -1,38 +1,19 @@ -import { inject, defineComponent, onBeforeMount, onBeforeUnmount, onMounted, reactive, watch } from 'vue'; +import { inject, defineComponent, onBeforeUnmount, onMounted, toRefs } from 'vue'; import { Column, TableColumnProps, TableColumnPropsTypes, } from './column.type' import { TABLE_TOKEN } from '../table.type'; -import { useRender } from './use-column'; +import { createColumn } from './use-column'; export default defineComponent({ name: 'DColumn', props: TableColumnProps, setup(props: TableColumnPropsTypes) { - const column: Column = reactive({ - field: props.field, - header: props.header, - sortable: props.sortable - }); - - watch( - [() => props.field, () => props.header, () => props.sortable], - ([field, header, sortable]) => { - column.field = field; - column.header = header; - column.sortable = sortable; - } - ); + const column = createColumn(toRefs(props)); const parent = inject(TABLE_TOKEN); - const { setColumnWidth, setColumnRender } = useRender(props); - - onBeforeMount(() => { - setColumnWidth(column); - setColumnRender(column); - }); onMounted(() => { parent.store.insertColumn(column); diff --git a/devui/table/src/column/column.type.ts b/devui/table/src/column/column.type.ts index 9d78f1f5..879d90a9 100644 --- a/devui/table/src/column/column.type.ts +++ b/devui/table/src/column/column.type.ts @@ -18,9 +18,7 @@ export const TableColumnProps = { default: 80, }, formatter: { - type: Function as PropType< - (row: any, column: Column, cellValue: any, index: number) => VNode - >, + type: Function as PropType, }, sortable: { type: Boolean, @@ -31,7 +29,9 @@ export const TableColumnProps = { export type TableColumnPropsTypes = ExtractPropTypes; -export interface Column { +export type Formatter = (row: T, cellValue: R, index: number) => VNode; + +export interface Column = any> { field?: string width?: number minWidth?: number @@ -39,6 +39,6 @@ export interface Column { header?: string sortable?: boolean renderHeader?: () => void - renderCell?: (data: any) => void - formatter?: (row: any, column: Column, cellValue, index: number) => VNode + renderCell?: (row: T, index: number) => void + formatter?: Formatter } \ No newline at end of file diff --git a/devui/table/src/column/use-column.ts b/devui/table/src/column/use-column.ts index 7c5fc4ce..6204c9f8 100644 --- a/devui/table/src/column/use-column.ts +++ b/devui/table/src/column/use-column.ts @@ -1,45 +1,48 @@ -import { ref } from 'vue'; +import { ref, watch, reactive, onBeforeMount, computed, ToRefs } from 'vue'; import { Column, TableColumnPropsTypes } from './column.type' import { formatWidth, formatMinWidth } from '../utils'; -export function useRender(props: TableColumnPropsTypes): any { - const formatedWidth = ref(formatWidth(props.width)); - const formatedMinWidth = ref(formatMinWidth(props.minWidth)); - const setColumnWidth = (column: Column) => { - column.width = formatedWidth.value; - column.minWidth = formatedMinWidth.value; - column.realWidth = column.width || column.minWidth; - return column; - }; - const setColumnRender = (column: Column) => { - column.renderHeader = () => { - return defaultRenderHeader(column); - }; - column.renderCell = (data) => { - return defaultRenderCell(data); - }; - }; +export function createColumn = any>({ + field, + header, + sortable, + width, + minWidth, + formatter +}: ToRefs): Column { + + const column: Column = reactive({}); + watch( + [field, header, sortable], + ([field, header, sortable]) => { + column.field = field; + column.header = header; + column.sortable = sortable; + }, + { immediate: true } + ); + + onBeforeMount(() => { + column.width = formatWidth(width.value); + column.minWidth = formatMinWidth(minWidth.value); + column.realWidth = column.width || column.minWidth; + column.renderHeader = defaultRenderHeader; + column.renderCell = defaultRenderCell; + column.formatter = formatter.value; + }); - return { setColumnWidth, setColumnRender }; + return column; } -function defaultRenderHeader(column: Column) { - return column.header; +function defaultRenderHeader(this: Column) { + return this.header; } -function defaultRenderCell({ - row, - column, - $index, -}: { - row: any - column: Column - $index: number -}) { - const value = row[column.field]; - if (column.formatter) { - return column.formatter(row, column, value, $index); +function defaultRenderCell>(this: Column, rowData: T, index: number) { + const value = rowData[this.field]; + if (this.formatter) { + return this.formatter(rowData, value, index); } - return value?.toString?.() || ''; + return value?.toString?.() ?? ''; } \ No newline at end of file diff --git a/devui/table/src/header/header.tsx b/devui/table/src/header/header.tsx index 8b583e24..9c127d97 100644 --- a/devui/table/src/header/header.tsx +++ b/devui/table/src/header/header.tsx @@ -1,6 +1,6 @@ -import { defineComponent, inject, computed, ref, PropType } from 'vue'; +import { defineComponent, inject, computed, ref, PropType, watch } from 'vue'; import { TableHeaderProps, TableHeaderPropsTypes } from './header.type' -import { TABLE_TOKEN } from '../table.type'; +import { SortDirection, TABLE_TOKEN } from '../table.type'; import { Column } from '../column/column.type'; import { Checkbox } from '../../../checkbox'; @@ -48,7 +48,11 @@ const Th = defineComponent({ } }, setup(props: { column: Column; }) { - const directionRef = ref('DESC'); + const directionRef = ref('DESC'); + const { sortData } = inject(TABLE_TOKEN).store; + watch([directionRef, () => props.column], ([direction, column]) => { + sortData(column.field, direction); + }); return () => (
- {column.renderHeader()} - ))}
+ {props.column.renderHeader()} + {props.column.sortable && } + - +
{column.renderCell({ row, column, $index: index })}{column.renderCell(row, index)}
{props.column.renderHeader()} diff --git a/devui/table/src/header/sort/sort.tsx b/devui/table/src/header/sort/sort.tsx index 017f983c..5ceadb53 100644 --- a/devui/table/src/header/sort/sort.tsx +++ b/devui/table/src/header/sort/sort.tsx @@ -1,7 +1,7 @@ import { defineComponent, PropType } from 'vue'; +import { SortDirection } from '../../table.type'; import './sort.scss'; -type SortDirection = 'ASC' | 'DESC' | ''; export const Sort = defineComponent({ props: { diff --git a/devui/table/src/store/index.ts b/devui/table/src/store/index.ts index d8c54344..df017dcc 100644 --- a/devui/table/src/store/index.ts +++ b/devui/table/src/store/index.ts @@ -1,5 +1,6 @@ import { watch, Ref, ref, computed } from 'vue'; import { Column } from '../column/column.type'; +import { SortDirection } from '../table.type'; export interface TableStore> { states: { @@ -12,6 +13,7 @@ export interface TableStore> { insertColumn(column: Column): void removeColumn(column: Column): void getCheckedRows(): T[] + sortData(field: string, direction: SortDirection): void } export function createStore(dataSource: Ref): TableStore { @@ -53,10 +55,19 @@ export function createStore(dataSource: Ref): TableStore { }, { immediate: true, deep: true }); + /** + * 插入当前列 + * @param {Column} column + */ const insertColumn = (column: Column) => { _columns.value.push(column); }; + /** + * 移除当前列 + * @param {Column} column + * @returns + */ const removeColumn = (column: Column) => { const i = _columns.value.findIndex((v) => v === column); if (i === -1) { @@ -65,10 +76,29 @@ export function createStore(dataSource: Ref): TableStore { _columns.value.splice(i, 1); } + /** + * 获取当前已选数据 + * @returns {T[]} + */ const getCheckedRows = () => { return _data.value.filter((_, index) => _checkList.value[index]); } + /** + * 对数据进行排序 + * @param {string} field + * @param {SortDirection} direction + */ + const sortData = (field: string, direction: SortDirection) => { + if (direction === 'ASC') { + _data.value = _data.value.sort((a, b) => a[field] < b[field] ? 1 : -1); + } else if (direction === 'DESC') { + _data.value = _data.value.sort((a, b) => a[field] > b[field] ? 1 : -1); + } else { + _data.value = [...dataSource.value]; + } + } + return { states: { _data, @@ -79,6 +109,7 @@ export function createStore(dataSource: Ref): TableStore { }, insertColumn, removeColumn, - getCheckedRows + getCheckedRows, + sortData }; } \ No newline at end of file diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index 39a6490a..cd29a58a 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -66,7 +66,6 @@ export interface Table> extends ComponentInternalInstanc props: TablePropsTypes } - // export interface TableCheckStatusArg { // pageAllChecked?: boolean; // 全选 // pageHalfChecked?: boolean; // 半选 @@ -87,3 +86,5 @@ export interface TableMethods> { } export const TABLE_TOKEN: InjectionKey = Symbol(); + +export type SortDirection = 'ASC' | 'DESC' | ''; -- Gitee From 4dd32f9470aca4c9d6155206656f293b9eb437ac Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:42:27 +0800 Subject: [PATCH 16/23] =?UTF-8?q?feat(table):=20TableColumn=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20compareFn=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/column/column.type.ts | 7 ++++++- devui/table/src/column/use-column.ts | 4 +++- devui/table/src/header/header.tsx | 6 ++++-- devui/table/src/store/index.ts | 18 +++++++++++------- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/devui/table/src/column/column.type.ts b/devui/table/src/column/column.type.ts index 879d90a9..850764c2 100644 --- a/devui/table/src/column/column.type.ts +++ b/devui/table/src/column/column.type.ts @@ -24,13 +24,17 @@ export const TableColumnProps = { type: Boolean, default: false }, - + compareFn: { + type: Function as PropType, + default: (field: string, a: any, b: any) => a[field] < b[field] + } }; export type TableColumnPropsTypes = ExtractPropTypes; export type Formatter = (row: T, cellValue: R, index: number) => VNode; +export type CompareFn = (field: string, a: T, b: T) => boolean; export interface Column = any> { field?: string width?: number @@ -41,4 +45,5 @@ export interface Column = any> { renderHeader?: () => void renderCell?: (row: T, index: number) => void formatter?: Formatter + compareFn?: CompareFn } \ No newline at end of file diff --git a/devui/table/src/column/use-column.ts b/devui/table/src/column/use-column.ts index 6204c9f8..b005f821 100644 --- a/devui/table/src/column/use-column.ts +++ b/devui/table/src/column/use-column.ts @@ -9,7 +9,8 @@ export function createColumn = any>({ sortable, width, minWidth, - formatter + formatter, + compareFn }: ToRefs): Column { const column: Column = reactive({}); @@ -30,6 +31,7 @@ export function createColumn = any>({ column.renderHeader = defaultRenderHeader; column.renderCell = defaultRenderCell; column.formatter = formatter.value; + column.compareFn = compareFn.value; }); return column; diff --git a/devui/table/src/header/header.tsx b/devui/table/src/header/header.tsx index 9c127d97..4c107cba 100644 --- a/devui/table/src/header/header.tsx +++ b/devui/table/src/header/header.tsx @@ -51,8 +51,10 @@ const Th = defineComponent({ const directionRef = ref('DESC'); const { sortData } = inject(TABLE_TOKEN).store; watch([directionRef, () => props.column], ([direction, column]) => { - sortData(column.field, direction); - }); + if (props.column.sortable) { + sortData(column.field, direction, column.compareFn); + } + }, { immediate: true }); return () => ( ) } diff --git a/devui/table/src/table.scss b/devui/table/src/table.scss index 0abf4593..1ee0d9bc 100644 --- a/devui/table/src/table.scss +++ b/devui/table/src/table.scss @@ -39,3 +39,7 @@ } } } + +.table-layout-auto { + table-layout: auto; +} diff --git a/devui/table/src/table.type.ts b/devui/table/src/table.type.ts index cd29a58a..369441f9 100644 --- a/devui/table/src/table.type.ts +++ b/devui/table/src/table.type.ts @@ -56,6 +56,10 @@ export const TableProps = { showLoading: { type: Boolean, default: false + }, + headerBg: { + type: Boolean, + default: false } }; diff --git a/devui/table/src/use-table.ts b/devui/table/src/use-table.ts index bbba4f45..06dc72a4 100644 --- a/devui/table/src/use-table.ts +++ b/devui/table/src/use-table.ts @@ -10,6 +10,8 @@ export function useTable(props: TablePropsTypes): TableConfig { const classes = computed(() => ({ 'devui-table': true, 'devui-table-striped': props.striped, + 'header-bg': props.headerBg, + 'table-layout-auto': props.tableLayout === 'auto' })); const style: ComputedRef = computed(() => ({ maxHeight: props.maxHeight, -- Gitee From 629d3bb583874270bd558830c3013c5f3e42e0c2 Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:44:59 +0800 Subject: [PATCH 18/23] =?UTF-8?q?feat(table):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/components/table/index.md | 149 +++++++++++++++++++++++++++------ 1 file changed, 122 insertions(+), 27 deletions(-) diff --git a/docs/components/table/index.md b/docs/components/table/index.md index 07cf4c49..4cc693fd 100644 --- a/docs/components/table/index.md +++ b/docs/components/table/index.md @@ -14,7 +14,7 @@ ```vue
{props.column.renderHeader()} diff --git a/devui/table/src/store/index.ts b/devui/table/src/store/index.ts index df017dcc..86de8a14 100644 --- a/devui/table/src/store/index.ts +++ b/devui/table/src/store/index.ts @@ -1,7 +1,6 @@ import { watch, Ref, ref, computed } from 'vue'; -import { Column } from '../column/column.type'; +import { Column, CompareFn } from '../column/column.type'; import { SortDirection } from '../table.type'; - export interface TableStore> { states: { _data: Ref @@ -13,7 +12,7 @@ export interface TableStore> { insertColumn(column: Column): void removeColumn(column: Column): void getCheckedRows(): T[] - sortData(field: string, direction: SortDirection): void + sortData(field: string, direction: SortDirection, compareFn: CompareFn): void } export function createStore(dataSource: Ref): TableStore { @@ -80,7 +79,7 @@ export function createStore(dataSource: Ref): TableStore { * 获取当前已选数据 * @returns {T[]} */ - const getCheckedRows = () => { + const getCheckedRows = (): T[] => { return _data.value.filter((_, index) => _checkList.value[index]); } @@ -88,12 +87,17 @@ export function createStore(dataSource: Ref): TableStore { * 对数据进行排序 * @param {string} field * @param {SortDirection} direction + * @param {CompareFn} compareFn */ - const sortData = (field: string, direction: SortDirection) => { + const sortData = ( + field: string, + direction: SortDirection, + compareFn: CompareFn = (field: string, a: T, b: T) => a[field] > b[field] + ) => { if (direction === 'ASC') { - _data.value = _data.value.sort((a, b) => a[field] < b[field] ? 1 : -1); + _data.value = _data.value.sort((a, b) => compareFn(field, a, b) ? 1 : -1); } else if (direction === 'DESC') { - _data.value = _data.value.sort((a, b) => a[field] > b[field] ? 1 : -1); + _data.value = _data.value.sort((a, b) => !compareFn(field, a, b) ? 1 : -1); } else { _data.value = [...dataSource.value]; } -- Gitee From d96168961cbfeba649217b2045ede5262d41ae60 Mon Sep 17 00:00:00 2001 From: zcating Date: Wed, 3 Nov 2021 10:43:54 +0800 Subject: [PATCH 17/23] =?UTF-8?q?feat(table):=20=E6=96=B0=E5=A2=9E=20filte?= =?UTF-8?q?r=20=E5=8A=9F=E8=83=BD(=E4=BB=85=E5=9B=BE=E6=A0=87=E5=92=8C?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/table/src/column/column.tsx | 9 ++- devui/table/src/column/column.type.ts | 14 ++++- devui/table/src/column/use-column.ts | 28 +++++---- devui/table/src/header/filter/filter.scss | 0 devui/table/src/header/filter/filter.tsx | 73 +++++++++++++++++++++++ devui/table/src/header/filter/index.ts | 1 + devui/table/src/header/header.scss | 8 +++ devui/table/src/header/header.tsx | 10 +++- devui/table/src/table.scss | 4 ++ devui/table/src/table.type.ts | 4 ++ devui/table/src/use-table.ts | 2 + 11 files changed, 137 insertions(+), 16 deletions(-) create mode 100644 devui/table/src/header/filter/filter.scss create mode 100644 devui/table/src/header/filter/filter.tsx create mode 100644 devui/table/src/header/filter/index.ts diff --git a/devui/table/src/column/column.tsx b/devui/table/src/column/column.tsx index c4745020..0dddad33 100644 --- a/devui/table/src/column/column.tsx +++ b/devui/table/src/column/column.tsx @@ -10,8 +10,13 @@ import { createColumn } from './use-column'; export default defineComponent({ name: 'DColumn', props: TableColumnProps, - setup(props: TableColumnPropsTypes) { - const column = createColumn(toRefs(props)); + setup(props: TableColumnPropsTypes, ctx) { + /* + ctx.slots : { + customFilterTemplate: Slot + } + */ + const column = createColumn(toRefs(props), ctx.slots); const parent = inject(TABLE_TOKEN); diff --git a/devui/table/src/column/column.type.ts b/devui/table/src/column/column.type.ts index 850764c2..e95fa673 100644 --- a/devui/table/src/column/column.type.ts +++ b/devui/table/src/column/column.type.ts @@ -32,9 +32,19 @@ export const TableColumnProps = { export type TableColumnPropsTypes = ExtractPropTypes; -export type Formatter = (row: T, cellValue: R, index: number) => VNode; +export type Formatter = (row: T, cellValue: R, index: number) => VNode[]; export type CompareFn = (field: string, a: T, b: T) => boolean; + +export type FilterList = (string | number)[]; + +export interface CustomFilterProps { + value: FilterList; + onChange: (value: FilterList) => void; +} + +export type CustomFilterSlot = (props: CustomFilterProps) => VNode[]; + export interface Column = any> { field?: string width?: number @@ -42,8 +52,10 @@ export interface Column = any> { realWidth?: number header?: string sortable?: boolean + filterable?: boolean renderHeader?: () => void renderCell?: (row: T, index: number) => void formatter?: Formatter compareFn?: CompareFn + customFilterTemplate?: CustomFilterSlot; } \ No newline at end of file diff --git a/devui/table/src/column/use-column.ts b/devui/table/src/column/use-column.ts index b005f821..5aca87b7 100644 --- a/devui/table/src/column/use-column.ts +++ b/devui/table/src/column/use-column.ts @@ -1,25 +1,30 @@ -import { ref, watch, reactive, onBeforeMount, computed, ToRefs } from 'vue'; +import { ref, watch, reactive, onBeforeMount, computed, ToRefs, Slots } from 'vue'; import { Column, TableColumnPropsTypes } from './column.type' import { formatWidth, formatMinWidth } from '../utils'; -export function createColumn = any>({ - field, - header, - sortable, - width, - minWidth, - formatter, - compareFn -}: ToRefs): Column { - +export function createColumn = any>( + props: ToRefs, + templates: Slots +): Column { + const { + field, + header, + sortable, + width, + minWidth, + formatter, + compareFn + } = props; const column: Column = reactive({}); + watch( [field, header, sortable], ([field, header, sortable]) => { column.field = field; column.header = header; column.sortable = sortable; + column.filterable = true; }, { immediate: true } ); @@ -32,6 +37,7 @@ export function createColumn = any>({ column.renderCell = defaultRenderCell; column.formatter = formatter.value; column.compareFn = compareFn.value; + column.customFilterTemplate = templates.customFilterTemplate; }); return column; diff --git a/devui/table/src/header/filter/filter.scss b/devui/table/src/header/filter/filter.scss new file mode 100644 index 00000000..e69de29b diff --git a/devui/table/src/header/filter/filter.tsx b/devui/table/src/header/filter/filter.tsx new file mode 100644 index 00000000..05ef087d --- /dev/null +++ b/devui/table/src/header/filter/filter.tsx @@ -0,0 +1,73 @@ +import { defineComponent, PropType, ref, Slot } from "vue"; +import { CustomFilterSlot, FilterList } from "../../column/column.type"; + + +export const Filter = defineComponent({ + props: { + modelValue: { + type: Array as PropType, + default: [] + }, + 'onUpdate:modelValue': { + type: Function as PropType<(v: FilterList) => void> + }, + customTemplate: { + type: Function as PropType + }, + }, + emits: ['update:modelValue'], + setup(props) { + + const showDropdown = ref(true); + + const handleFilter = () => { + showDropdown.value = true; + } + + return () => ( + <> + + + + + + + + + + + + + {props.customTemplate?.({ value: props.modelValue, onChange: props["onUpdate:modelValue"] }) ?? ( +
+ )} +
+ + ) + } +}); + + +// TODO: 缺少 dropdown 组件 +const Dropdown = defineComponent({ + props: { + visible: { type: Boolean }, + 'onUpdate:visible': { type: Function }, + }, + setup(props) { + return () => ( +
test
+ ); + } +}); \ No newline at end of file diff --git a/devui/table/src/header/filter/index.ts b/devui/table/src/header/filter/index.ts new file mode 100644 index 00000000..998668a1 --- /dev/null +++ b/devui/table/src/header/filter/index.ts @@ -0,0 +1 @@ +export * from './filter'; \ No newline at end of file diff --git a/devui/table/src/header/header.scss b/devui/table/src/header/header.scss index fc10e53a..21e88bf4 100644 --- a/devui/table/src/header/header.scss +++ b/devui/table/src/header/header.scss @@ -16,3 +16,11 @@ } } } + +.header-bg { + thead.devui-thead { + tr { + background: var(--devui-list-item-hover-bg, #f2f5fc); + } + } +} diff --git a/devui/table/src/header/header.tsx b/devui/table/src/header/header.tsx index 4c107cba..9ddd3a60 100644 --- a/devui/table/src/header/header.tsx +++ b/devui/table/src/header/header.tsx @@ -1,10 +1,11 @@ -import { defineComponent, inject, computed, ref, PropType, watch } from 'vue'; +import { defineComponent, inject, computed, ref, shallowRef, PropType, watch } from 'vue'; import { TableHeaderProps, TableHeaderPropsTypes } from './header.type' import { SortDirection, TABLE_TOKEN } from '../table.type'; -import { Column } from '../column/column.type'; +import { Column, FilterList } from '../column/column.type'; import { Checkbox } from '../../../checkbox'; import { Sort } from './sort'; +import { Filter } from './filter'; import './header.scss'; @@ -55,10 +56,15 @@ const Th = defineComponent({ sortData(column.field, direction, column.compareFn); } }, { immediate: true }); + + // 过滤器 + const filteredRef = shallowRef([]); + return () => (
{props.column.renderHeader()} {props.column.sortable && } + {props.column.filterable && }