根据业务需要封装公共表格

This commit is contained in:
zhaoweijie 2022-01-05 12:20:16 +08:00
parent 0ffa5598ff
commit 6926fbd9b7
8 changed files with 383 additions and 22 deletions

View File

@ -0,0 +1,39 @@
<template>
<el-table-column v-bind="$attrs" class="ProTableColumn">
<template #default="{ row, column, $index }">
<slot
:row="row"
:column="column"
:$index="$index"
:pageIndex="calcPageIndex($index)"
:deleteRow="deleteRow.bind(null, calcPageIndex($index))"
:updatedRow="updatedRow.bind(null, calcPageIndex($index))"
>
{{ row[props?.prop] }}
</slot>
</template>
</el-table-column>
</template>
<script setup lang="ts">
import { defineProps, withDefaults, inject, Ref } from 'vue'
import { DELETE_ROW, UPDATE_ROW, PAGINATION_INFO } from '~/constants/proTable'
import { IPaginationInfo } from '~/interfaces/proTable'
interface Props {
prop: string
}
const props = withDefaults(defineProps<Props>(), {})
const paginationInfo = inject<Ref<IPaginationInfo>>(PAGINATION_INFO)
const updatedRow = inject(UPDATE_ROW)
const deleteRow = inject(DELETE_ROW)
//
const calcPageIndex = (index: number) => {
const { currentPage, pageSize } = paginationInfo!.value
return (currentPage - 1) * pageSize + index
}
</script>
<!--<style scoped lang="scss"></style>-->

View File

@ -0,0 +1,171 @@
<template>
<div v-loading="loading" class="pro-table">
<div class="header">
<div class="action-container">
<el-button
v-if="props.createText"
type="primary"
size="mini"
:icon="Plus"
@click="onCreate"
>
{{ props.createText }}
</el-button>
</div>
</div>
<el-table :data="displayTableData" v-bind="$attrs">
<slot></slot>
</el-table>
<el-config-provider :locale="zhCn">
<el-pagination
v-if="paginationInfo.showPagination"
class="pagination"
:current-page="paginationInfo.currentPage"
layout="total, jumper, prev, pager, next, sizes"
:page-size="paginationInfo.pageSize"
:total="paginationInfo.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</el-config-provider>
</div>
</template>
<script setup lang="ts">
import { defineProps, withDefaults, provide, ref } from 'vue'
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { Plus } from '@element-plus/icons-vue'
import {
ITableDataItem,
IPaginationInfo,
IOnCreated,
} from '~/interfaces/proTable'
import {
DELETE_ROW,
UPDATE_ROW,
PAGINATION_INFO,
CREATE_ROW,
} from '~/constants/proTable'
import { HandleProTableData } from '~/tools/proTable'
interface Props {
request: () => Promise<{ data: ITableDataItem[] }>
//
showPagination?: boolean
currentPage?: number
pageSize?: number
pageSizes?: number[]
// header
createText?: string
}
const props = withDefaults(defineProps<Props>(), {
currentPage: 1,
pageSize: 10,
pageSizes: () => [10, 20, 30, 40, 50, 100],
showPagination: true,
})
const emit = defineEmits(['onCreated'])
//
const paginationInfo = ref<IPaginationInfo>({
currentPage: props.currentPage,
pageSize: props.pageSize,
pageSizes: props.pageSizes,
showPagination: props.showPagination,
total: 0,
})
const handleSizeChange = (val: number) => {
paginationInfo.value.pageSize = val
updateTheView()
}
const handleCurrentChange = (val: number) => {
paginationInfo.value.currentPage = val
updateTheView()
}
//
const tableData = ref<ITableDataItem[]>([])
const displayTableData = ref<ITableDataItem[]>(tableData.value)
const loading = ref(false)
async function getData() {
try {
loading.value = true
const { data } = await props.request()
tableData.value = data
paginationInfo.value.total = tableData.value?.length
updateTheView()
loading.value = false
} catch (e) {
loading.value = false
console.log((e as Error).message)
}
}
onMounted(async () => {
await getData()
})
const updateTheView = () => {
if (!paginationInfo.value?.showPagination) {
displayTableData.value = tableData.value
}
const { currentPage, pageSize } = paginationInfo.value
const pageStart: number = (currentPage - 1) * pageSize
displayTableData.value = tableData.value.slice(
pageStart,
pageStart + pageSize,
)
paginationInfo.value.total = tableData.value.length
}
const handleTable = computed(() => {
return new HandleProTableData(updateTheView, tableData)
})
const onCreate = () => {
emit('onCreated', handleTable.value.createRow)
}
//
defineExpose({
paginationInfo,
...handleTable.value,
})
// 使
provide(PAGINATION_INFO, paginationInfo)
provide(UPDATE_ROW, handleTable.value.updatedRow)
provide(DELETE_ROW, handleTable.value.deleteRow)
provide(CREATE_ROW, handleTable.value.createRow)
</script>
<style scoped lang="scss">
.pro-table {
width: 100%;
.header {
margin-bottom: 8px;
}
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 15px;
$marginLeft: 15px;
::v-deep(.btn-prev) {
margin-left: $marginLeft !important;
}
::v-deep(.el-input) {
margin-left: $marginLeft !important;
}
::v-deep(.el-pager li) {
margin: 0 2px;
}
}
}
</style>

View File

@ -0,0 +1,8 @@
// 分页信息
export const PAGINATION_INFO = 'PAGINATION_INFO'
// 修改表格数据
export const UPDATE_ROW = 'UPDATE_ROW'
// 删除表格数据
export const DELETE_ROW = 'DELETE_ROW'
// 添加数据
export const CREATE_ROW = 'CREATE_ROW'

View File

@ -0,0 +1,33 @@
export interface ITableDataItem {
[key: string]: any
}
export type IPaginationInfo = {
showPagination: boolean
currentPage: number
pageSize: number
pageSizes: number[]
total: number
}
/**
* @param record
*/
export type ICreateRow = (record: ITableDataItem) => void
/**
* @param index ()
* @param newRecord
*/
export type IUpdateRow = (index: number, newRecord: ITableDataItem) => void
/**
* @param index
*/
export type IDeleteRow = (index: number) => void
export type IOnCreated = (callback: ICreateRow) => void
export interface IHandleProTableData {
createRow: ICreateRow
updatedRow: IUpdateRow
deleteRow: IDeleteRow
}

View File

@ -1,35 +1,71 @@
<config>
{
"name": "index",
"title": "首页"
"name": "index",
"title": "首页"
}
</config>
<template>
<div style="padding: 32px">
<h3>fes & 拉夫德鲁</h3>
<h4>数据字典</h4>
<div v-for="item in enumsGet('status')" :key="item.key">
{{ item.value }}{{ item.key }}
</div>
<section>
计数器
<el-button @click="increment">click me{{ count }}</el-button>
</section>
</div>
<pro-table
ref="proTableRef"
:request="request"
create-text="添加"
@on-created="onCreated"
>
<pro-table-column prop="date" label="Date" width="180" />
<pro-table-column prop="name" label="Name" width="180" />
<pro-table-column prop="address" label="Address" />
<pro-table-column prop="action">
<template #default="{ deleteRow, updatedRow }">
<el-button type="text" size="small" @click.prevent="deleteRow">
Remove
</el-button>
<el-button
type="text"
size="small"
@click.prevent="
updatedRow({
name: 'update',
date: 'wiwiiw',
address: 'rtrtrttrtr',
})
"
>
update
</el-button>
</template>
</pro-table-column>
</pro-table>
</template>
<script setup lang="ts">
import { enums } from '@fesjs/fes'
import useCounterStore from '~/stores/counter'
import ProTable from '~/components/ProTable'
import ProTableColumn from '~/components/ProTable/ProTableColumn'
const store = useCounterStore()
const count = computed(() => store.clicked)
const proTableRef = ref(null)
const increment = () => {
store.clicked++
onMounted(() => {
console.log({ ...proTableRef.value }, 'ppppp')
console.log(proTableRef.value.paginationInfo)
})
const request = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: new Array(10)
.join(',')
.split(',')
.map((i, index) => ({
date: `2016-05-03${index}`,
name: `Tom${index}`,
address: 'No. 189, Grove St, Los Angeles',
})),
})
}, 1500)
})
}
const onCreated = (callback) => {
callback({ name: 'add', date: 'wiwiiw', address: 'rtrtrttrtr' })
}
const enumsGet = enums.get
</script>

49
src/tools/proTable.ts Normal file
View File

@ -0,0 +1,49 @@
import { ITableDataItem, IHandleProTableData } from '~/interfaces/proTable'
import { ElNotification } from 'element-plus/es'
import { Ref } from 'vue'
export class HandleProTableData implements IHandleProTableData {
updateTheView: () => void
tableData: Ref<ITableDataItem[]>
constructor(updateTheView: () => void, tableData: Ref<ITableDataItem[]>) {
this.updateTheView = updateTheView
this.tableData = tableData
}
handleError(e: unknown) {
ElNotification({
title: '提示',
message: (e as Error).message,
type: 'error',
})
}
createRow = (record: ITableDataItem) => {
try {
this.tableData.value.push(record)
this.updateTheView()
} catch (e) {
this.handleError(e)
}
}
updatedRow = (index: number, newRecord: ITableDataItem) => {
try {
this.tableData.value.splice(index, 1, newRecord)
this.updateTheView()
} catch (e) {
this.handleError(e)
}
}
deleteRow = (index: number) => {
try {
this.tableData.value.splice(index, 1)
this.updateTheView()
} catch (e) {
console.log(this)
this.handleError(e)
}
}
}

View File

@ -9,9 +9,20 @@ declare global {
const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope']
const ElButton: typeof import('element-plus/es')['ElButton']
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
const ElDialog: typeof import('element-plus/es')['ElDialog']
const ElForm: typeof import('element-plus/es')['ElForm']
const ElFormItem: typeof import('element-plus/es')['ElFormItem']
const ElIcon: typeof import('element-plus/es')['ElIcon']
const ElInput: typeof import('element-plus/es')['ElInput']
const ElLoadingDirective: typeof import('element-plus/es')['ElLoadingDirective']
const ElOption: typeof import('element-plus/es')['ElOption']
const ElPagination: typeof import('element-plus/es')['ElPagination']
const ElSelect: typeof import('element-plus/es')['ElSelect']
const ElTable: typeof import('element-plus/es')['ElTable']
const ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
const ElTabPane: typeof import('element-plus/es')['ElTabPane']
const ElTabs: typeof import('element-plus/es')['ElTabs']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']

View File

@ -5,10 +5,24 @@
declare module 'vue' {
export interface GlobalComponents {
ElButton: typeof import('element-plus/es')['ElButton']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
'IBi:questionCircle': typeof import('~icons/bi/question-circle')['default']
Loading: typeof import('element-plus/es')['ElLoadingDirective']
PageLoading: typeof import('./../components/PageLoading.vue')['default']
ProTable: typeof import('./../components/ProTable/index.vue')['default']
ProTableColumn: typeof import('./../components/ProTable/ProTableColumn.vue')['default']
UserCenter: typeof import('./../components/UserCenter.vue')['default']
}
}