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

65
mock/table/index.ts Normal file
View File

@ -0,0 +1,65 @@
import { config } from '@/config/axios/config'
import { MockMethod } from 'vite-plugin-mock'
import { toAnyString } from '@/utils'
import Mock from 'mockjs'
const { result_code } = config
const timeout = 1000
const count = 100
const baseContent =
'<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>'
const List: {
id: string
author: string
title: string
content: string
importance: number
display_time: string
pageviews: number
}[] = []
for (let i = 0; i < count; i++) {
List.push(
Mock.mock({
id: toAnyString(),
// timestamp: +Mock.Random.date('T'),
author: '@first',
title: '@title(5, 10)',
content: baseContent,
importance: '@integer(1, 3)',
display_time: '@datetime',
pageviews: '@integer(300, 5000)'
// image_uri
})
)
}
export default [
// 登录接口
{
url: '/example/list',
method: 'get',
timeout,
response: ({ query }) => {
const { title, pageIndex, pageSize } = query
const mockList = List.filter((item) => {
if (title && item.title.indexOf(title) < 0) return false
return true
})
const pageList = mockList.filter(
(_, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1)
)
return {
code: result_code,
data: {
total: mockList.length,
list: pageList
}
}
}
}
] as MockMethod[]

View File

@ -32,15 +32,15 @@
"axios": "^0.25.0",
"echarts": "^5.3.0",
"echarts-wordcloud": "^2.0.0",
"element-plus": "1.3.0-beta.9",
"intro.js": "^4.3.0",
"element-plus": "2.0.0",
"intro.js": "^5.0.0",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"pinia": "^2.0.10",
"pinia": "^2.0.11",
"qrcode": "^1.5.0",
"qs": "^6.10.3",
"vue": "3.2.26",
"vue": "3.2.30",
"vue-i18n": "9.1.9",
"vue-router": "^4.0.12",
"vue-types": "^4.1.1",
@ -49,30 +49,30 @@
"devDependencies": {
"@commitlint/cli": "^16.1.0",
"@commitlint/config-conventional": "^16.0.0",
"@iconify/json": "^2.0.30",
"@intlify/vite-plugin-vue-i18n": "^3.2.1",
"@iconify/json": "^2.0.34",
"@intlify/vite-plugin-vue-i18n": "^3.2.2",
"@purge-icons/generated": "^0.7.0",
"@types/intro.js": "^3.0.2",
"@types/lodash-es": "^4.17.5",
"@types/node": "^17.0.13",
"@types/lodash-es": "^4.17.6",
"@types/node": "^17.0.15",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.4.2",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^5.10.1",
"@typescript-eslint/parser": "^5.10.1",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"@vitejs/plugin-vue": "^2.1.0",
"@vitejs/plugin-vue-jsx": "^1.3.3",
"autoprefixer": "^10.4.2",
"commitizen": "^4.2.4",
"eslint": "^8.8.0",
"eslint-config-prettier": "^8.3.0",
"eslint-define-config": "^1.2.3",
"eslint-define-config": "^1.2.4",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.4.0",
"eslint-plugin-vue": "^8.4.1",
"husky": "^7.0.4",
"less": "^4.1.2",
"lint-staged": "^12.3.2",
"postcss": "^8.4.5",
"lint-staged": "^12.3.3",
"postcss": "^8.4.6",
"postcss-html": "^1.3.0",
"postcss-less": "^6.0.0",
"prettier": "^2.5.1",
@ -92,7 +92,7 @@
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vite-plugin-windicss": "^1.6.3",
"vue-tsc": "^0.31.1",
"vue-tsc": "^0.31.2",
"windicss": "^3.4.3",
"windicss-analysis": "^0.3.5"
},

File diff suppressed because it is too large Load Diff

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),
// schemashowOverflowTooltip,
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>

10
types/componentType/table.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
declare type TableColumn = {
field: string
label?: string
} & Recordable
declare type TableColumnDefault = {
row: Recordable
field: string
index: number
}