wip: Table component developing

This commit is contained in:
kailong321200875
2022-02-07 17:32:37 +08:00
parent 9b4b317817
commit 7b7fcfef59
16 changed files with 1358 additions and 1136 deletions

11
src/api/table/index.ts Normal file
View File

@@ -0,0 +1,11 @@
import { useAxios } from '@/hooks/web/useAxios'
import type { TableData } from './types'
const { request } = useAxios()
export const getTableListApi = ({ params }: AxiosConfig) => {
return request<{
total: number
list: TableData[]
}>({ url: '/example/list', method: 'get', params })
}

9
src/api/table/types.ts Normal file
View File

@@ -0,0 +1,9 @@
export type TableData = {
id: string
author: string
title: string
content: string
importance: number
display_time: string
pageviews: number
}

View File

@@ -39,9 +39,16 @@ const emit = defineEmits(['search', 'reset'])
const visible = ref(true)
const newSchema = computed(() => {
let schema: FormSchema[] = []
let schema: FormSchema[] = cloneDeep(props.schema)
if (props.expand && props.expandField && !unref(visible)) {
const index = findIndex(schema, (v: FormSchema) => v.field === props.expandField)
if (index > -1) {
const length = schema.length
schema.splice(index + 1, length)
}
}
if (props.layout === 'inline') {
schema = cloneDeep(props.schema).concat([
schema = schema.concat([
{
field: 'action',
formItemProps: {
@@ -49,14 +56,6 @@ const newSchema = computed(() => {
}
}
])
} else {
schema = cloneDeep(props.schema)
}
if (props.expand && props.expandField && !unref(visible)) {
const index = findIndex(schema, (v: FormSchema) => v.field === props.expandField)
if (index > -1) {
schema.splice(0, index + 1)
}
}
return schema
})
@@ -86,6 +85,11 @@ const bottonButtonStyle = computed(() => {
textAlign: props.buttomPosition
}
}) as CSSProperties
const setVisible = () => {
unref(elFormRef)?.resetFields()
visible.value = !unref(visible)
}
</script>
<template>
@@ -108,7 +112,7 @@ const bottonButtonStyle = computed(() => {
<Icon icon="ep:refresh-right" class="mr-5px" />
{{ t('common.reset') }}
</ElButton>
<ElButton v-if="showReset" type="text" @click="visible = !visible">
<ElButton v-if="showReset" type="text" @click="setVisible">
{{ t(visible ? 'common.shrink' : 'common.expand') }}
<Icon :icon="visible ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
</ElButton>
@@ -126,7 +130,7 @@ const bottonButtonStyle = computed(() => {
<Icon icon="ep:refresh-right" class="mr-5px" />
{{ t('common.reset') }}
</ElButton>
<ElButton v-if="showReset" type="text" @click="visible = !visible">
<ElButton v-if="showReset" type="text" @click="setVisible">
{{ t(visible ? 'common.shrink' : 'common.expand') }}
<Icon :icon="visible ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
</ElButton>

View File

@@ -0,0 +1,3 @@
import Table from './src/Table.vue'
export { Table }

View File

@@ -0,0 +1,126 @@
<script lang="tsx">
import { ElTable, ElTableColumn } from 'element-plus'
import { defineComponent, PropType, ref, computed, unref } from 'vue'
import { propTypes } from '@/utils/propTypes'
import { setIndex } from './helper'
import { getSlot } from '@/utils/tsxHelper'
export default defineComponent({
name: 'Table',
props: {
// 是否多选
selection: propTypes.bool.def(true),
// 是否所有的超出隐藏优先级低于schema中的showOverflowTooltip,
showOverflowTooltip: propTypes.bool.def(true),
// 表头
columns: {
type: Array as PropType<TableColumn[]>,
default: () => []
},
// 是否展示分页
// pagination: {
// type: [Boolean, Object] as PropType<boolean | IObj>,
// default: false
// },
// 仅对 type=selection 的列有效,类型为 Boolean为 true 则会在数据更新之后保留之前选中的数据(需指定 row-key
reserveSelection: propTypes.bool.def(false),
// 加载状态
loading: propTypes.bool.def(false),
// 是否叠加索引
reserveIndex: propTypes.bool.def(true),
// 对齐方式
align: propTypes.string
.validate((v: string) => ['left', 'center', 'right'].includes(v))
.def('left'),
headerAlign: propTypes.string
.validate((v: string) => ['left', 'center', 'right'].includes(v))
.def('left'),
// 表头对齐方式
data: {
type: Array as PropType<Recordable[]>,
default: () => []
}
},
setup(props, { attrs, slots }) {
const tableRef = ref<ComponentRef<typeof ElTable>>()
const getProps = computed(() => props)
const getBindValue = computed(() => {
const bindValue: Recordable = { ...attrs, ...props }
delete bindValue.columns
delete bindValue.data
return bindValue
})
const renderTableSelection = () => {
return (
<ElTableColumn
type="selection"
reserveSelection={props.reserveSelection}
align={unref(getProps).align}
headerAlign={unref(getProps).headerAlign}
width="50"
></ElTableColumn>
)
}
const rnderTableColumn = (columns: TableColumn[]) => {
return (props.selection ? [renderTableSelection()] : []).concat(
columns.map((v, i) => {
if (v.type === 'index') {
return (
<ElTableColumn
type="index"
index={v.index ? v.index : setIndex()}
align={v.align || unref(getProps).align}
headerAlign={v.headerAlign || unref(getProps).headerAlign}
label={v.label}
width="100px"
></ElTableColumn>
)
} else {
return (
<ElTableColumn
showOverflowTooltip={unref(getProps).showOverflowTooltip}
align={unref(getProps).align}
headerAlign={unref(getProps).headerAlign}
{...v}
prop={v.field}
>
{{
default: () =>
// @ts-ignore
getSlot(slots, v.field, { row: props.data[i], field: v.field, index: i }) ||
v?.formatter?.() ||
props.data[i][v.field],
// @ts-ignore
header: getSlot(slots, `${v.field}-header`)
}}
</ElTableColumn>
)
}
})
)
}
return () => (
<>
<ElTable
// @ts-ignore
ref={tableRef}
data={unref(getProps).data}
{...getBindValue}
v-loading={unref(getProps).loading}
>
{{
default: () => rnderTableColumn(props.columns),
// @ts-ignore
append: () => getSlot(slots, 'append')
}}
</ElTable>
</>
)
}
})
</script>

View File

@@ -0,0 +1,3 @@
export const setIndex = () => {
return 1
}

View File

@@ -100,7 +100,9 @@ export default {
infotip: 'Infotip',
form: 'Form',
defaultForm: 'All examples',
search: 'Search'
search: 'Search',
table: 'Table',
defaultTable: 'Basic example'
},
analysis: {
newUser: 'New user',
@@ -301,5 +303,19 @@ export default {
left: 'left',
center: 'center',
right: 'right'
},
tableDemo: {
table: 'Table',
tableDes: 'Secondary packaging of Table components based on ElementPlus',
index: 'Index',
title: 'Title',
author: 'Author',
displayTime: 'Display time',
importance: 'Importance',
pageviews: 'Pageviews',
action: 'Action',
important: 'Important',
good: 'Good',
commonly: 'Commonly'
}
}

View File

@@ -100,7 +100,9 @@ export default {
infotip: '信息提示',
form: '表单',
defaultForm: '全部示例',
search: '查询'
search: '查询',
table: '表格',
defaultTable: '基础示例'
},
analysis: {
newUser: '新增用户',
@@ -298,5 +300,19 @@ export default {
left: '左',
center: '中',
right: '右'
},
tableDemo: {
table: '表格',
tableDes: '基于 ElementPlus 的 Table 组件二次封装',
index: '序号',
title: '标题',
author: '作者',
displayTime: '创建时间',
importance: '重要性',
pageviews: '阅读数',
action: '操作',
important: '重要',
good: '良好',
commonly: '一般'
}
}

View File

@@ -131,6 +131,25 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
}
]
},
{
path: 'table',
component: getParentLayout(),
name: 'TableDemo',
meta: {
title: t('router.table'),
alwaysShow: true
},
children: [
{
path: 'default-table',
component: () => import('@/views/Components/Table/DefaultTable.vue'),
name: 'DefaultTable',
meta: {
title: t('router.defaultTable')
}
}
]
},
{
path: 'search',
component: () => import('@/views/Components/Search.vue'),

View File

@@ -95,3 +95,15 @@ export function formatTime(time: Date | number | string, fmt: string) {
return fmt
}
}
/**
* 生成随机字符串
*/
export function toAnyString() {
const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => {
const r: number = (Math.random() * 16) | 0
const v: number = c === 'x' ? r : (r & 0x3) | 0x8
return v.toString()
})
return str
}

View File

@@ -100,7 +100,7 @@ const disabledClick = () => {
<ElCol :xl="6" :lg="6" :md="12" :sm="24" :xs="24">
<ElCard shadow="hover" class="mb-10px text-center">
<div class="font-bold">{{ t('qrcodeDemo.size') }}</div>
<Qrcode :text="title" :width="250" />
<Qrcode :text="title" :width="100" />
</ElCard>
</ElCol>
</ElRow>

View File

@@ -0,0 +1,95 @@
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n'
import { Table } from '@/components/Table'
import { getTableListApi } from '@/api/table'
import { TableData } from '@/api/table/types'
import { ref, h } from 'vue'
import { ElTag, ElButton } from 'element-plus'
const { t } = useI18n()
const columns: TableColumn[] = [
{
field: 'index',
label: t('tableDemo.index'),
type: 'index'
},
{
field: 'title',
label: t('tableDemo.title')
},
{
field: 'author',
label: t('tableDemo.author')
},
{
field: 'display_time',
label: t('tableDemo.displayTime')
},
{
field: 'importance',
label: t('tableDemo.importance'),
formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
return h(
ElTag,
{
type: cellValue === 1 ? 'success' : cellValue === 1 ? 'warning' : 'danger'
},
() =>
cellValue === 1
? t('tableDemo.important')
: cellValue === 1
? t('tableDemo.good')
: t('tableDemo.commonly')
)
}
},
{
field: 'pageviews',
label: t('tableDemo.pageviews')
},
{
field: 'action',
label: t('tableDemo.action')
}
]
const loading = ref(true)
let tableDataList = ref<TableData[]>([])
const getTableList = async () => {
const res = await getTableListApi({
params: {
pageIndex: 1,
pageSize: 20
}
})
.catch(() => {})
.finally(() => {
loading.value = false
})
if (res) {
tableDataList.value = res.data.list
}
}
getTableList()
const acitonFn = (data: TableColumnDefault) => {
console.log(data)
}
</script>
<template>
<ContentWrap :title="t('tableDemo.table')" :message="t('tableDemo.tableDes')">
<Table :columns="columns" :data="tableDataList" :loading="loading">
<template #action="data">
<ElButton @click="acitonFn(data as TableColumnDefault)">{{
t('tableDemo.action')
}}</ElButton>
</template>
</Table>
</ContentWrap>
</template>