123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- <template>
- <div class="cus-table" :class="{'cus-table-normal': !otherStyle, 'cus-table-full': full !== false}">
- <div class="cus-table-main" ref="ref_tableMain" :class="{'cus-table-main-no-foot': noFoot !== false}">
- <el-table
- v-bind="$attrs"
- class="ct-table"
- ref="ref_table"
- :data="tableData"
- :border="false"
- @sort-change="handleSort"
- @filter-change="handleFilter"
- @selection-change="v => $emit('update:selected', v)"
- >
- <el-table-column v-if="selected" type="selection" :width="selectWidth" align="center" :selectable="selectable"/>
- <el-table-column v-if="singled" :width="singledWidth" align="center" class-name="single-column">
- <template #default="scope">
- <div class="single-circle" :class="{active: scope.row[singledKey] === singled[singledKey]}" @click.stop="$emit('update:singled', scope.row)">
- <div class="single-circle-in"></div>
- </div>
- </template>
- </el-table-column>
- <el-table-column v-if="showIndex" type="index" label="序号" align="center" fixed="left" width="60"/>
- <template v-for="(item, index) in tempTableHead" :key="index">
- <template v-if="item.children && item.children.length > 0">
- <el-table-column :label="item.label" v-if="item.show" align="center">
- <template v-for="(item2, index2) in item.children">
- <template v-if="item2.children && item.children.length > 0">
- <el-table-column :label="item2.label" v-if="item2.show" align="center">
- <template v-for="(item3, index3) in item2.children">
- <CusTableColumn :item="item3">
- <template #[`${item3.value}-column`]="{column}">
- <slot :name="`${item3.value}-column`" :column="column">
- </slot>
- </template>
- <template #[`${item3.value}-column-value`]="{scope}">
- <slot :name="`${item3.value}-column-value`" :scope="scope">
- </slot>
- </template>
- </CusTableColumn>
- </template>
- </el-table-column>
- </template>
- <template v-else>
- <CusTableColumn :item="item2">
- <template #[`${item2.value}-column`]="{column}">
- <slot :name="`${item2.value}-column`" :column="column">
- </slot>
- </template>
- <template #[`${item2.value}-column-value`]="{scope}">
- <slot :name="`${item2.value}-column-value`" :scope="scope">
- </slot>
- </template>
- </CusTableColumn>
- </template>
- </template>
- </el-table-column>
- </template>
- <template v-else>
- <CusTableColumn :item="item">
- <template #[`${item.value}-column`]="{column}">
- <slot :name="`${item.value}-column`" :column="column">
- </slot>
- </template>
- <template #[`${item.value}-column-value`]="{scope}">
- <slot :name="`${item.value}-column-value`" :scope="scope">
- </slot>
- </template>
- </CusTableColumn>
- </template>
- </template>
- </el-table>
- </div>
- <div class="ct-foot" v-if="noFoot === false">
- <div class="total">
- <template v-if="$util.isValue(selectedNum)">
- 已选中 {{ selectedNum }} 条 /
- </template>
- <template v-else-if="$util.isValue(selected?.length)">
- 已选中 {{ selected.length }} 条 /
- </template>
- 共 {{ total }} 条
- </div>
- <el-pagination
- v-if="noPage === false"
- ref="ref_tablePage"
- class="__cus-pagination"
- :currentPage="page"
- :page-size="pageSize"
- background
- :page-sizes="pageSizes"
- :layout="pageLayoutCpt"
- :total="Number(total)"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- />
- </div>
- </div>
- </template>
- <script lang="ts">
- import {
- defineComponent,
- computed,
- onMounted,
- ref,
- reactive,
- watch,
- getCurrentInstance,
- nextTick,
- ComponentInternalInstance, toRefs
- } from 'vue'
- import {useStore} from 'vuex'
- import {useRouter} from 'vue-router'
- export default defineComponent({
- name: 'CusTable',
- props: {
- tableData: {
- required: true
- },
- tableHead: {
- default: () => [],
- required: true
- },
- total: {
- required: true
- },
- page: {},
- pageSize: {},
- pageSizes: {
- default: () => [10, 20, 30, 50, 100]
- },
- selected: {
- default: null
- },
- selectedNum: {
- default: null
- },
- selectWidth: {
- default: 50
- },
- singledWidth: {
- default: 50
- },
- singled: {
- default: null
- },
- singledKey: {
- default: 'id'
- },
- noPage: {
- default: false
- },
- showIndex: {
- default: true
- },
- otherStyle: {
- default: false
- },
- noLayout: {
- default: () => []
- },
- full: {
- default: false
- },
- selectable: {},
- noFoot: {
- default: false
- }
- },
- setup(props, { emit }) {
- const store = useStore();
- const router = useRouter();
- const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties
- const ref_table = ref();
- const ref_tableMain = ref();
- const ref_tablePage = ref();
- const state = reactive({
- tempTableHead: <any>[],
- pageLayout: ['sizes', 'prev', 'pager', 'next', 'jumper']
- });
- watch(() => props.tableHead, (nVal: any) => {
- formatTableHead(nVal)
- }, {deep: true})
- // watch(() => props.tableData, (nVal) => {
- // ref_table.value?.doLayout()
- // }, {deep: true})
- const pageLayoutCpt = computed(() => {
- return state.pageLayout.filter((v: string) => props.noLayout.every((s: string) => v !== s)).join(',')
- })
- const formatTableHead = (tableHead: Array<any>) => {
- const result = tableHead
- const deep = (arr: any[]) => {
- let flag = 0
- arr.forEach(v => {
- if (v.children && v.children.length > 0) {
- v.show = deep(v.children)
- }
- if (v.show) {
- flag++
- }
- })
- return flag > 0
- }
- deep(result)
- state.tempTableHead = result
- }
- const handleSizeChange = (val: Number) => {
- emit('handlePage', {
- page: 1,
- pageSize: val
- })
- }
- const handleCurrentChange = (val: Number) => {
- emit('handlePage', {
- page: val,
- pageSize: props.pageSize
- })
- }
- const handleSort = ({ column, prop, order }: any) => {
- emit('handleSort', {
- key: prop,
- value: order
- })
- }
- const handleFilter = (val: any) => {
- const key = Object.keys(val)[0]
- const head = props.tableHead.filter(v => v.value === key)[0]
- let value = null
- if (val[key].length > 0) {
- if (head.filterMultiple) {
- value = val[key]
- } else {
- value = val[key][0]
- }
- }
- emit('handleFilter', {key, value})
- }
- const resetFilter = (key: any = null) => {
- key ? ref_table.value.clearFilter([key]) : ref_table.value.clearFilter()
- }
- const reset = (key: any = null) => {
- resetFilter(key)
- ref_table.value.clearSort()
- }
- watch(() => props.selected, (n: any) => {
- if (n.length === 0) {
- ref_table.value.clearSelection()
- } else {
- setTimeout(() => {
- n.forEach(v => {
- ref_table.value.toggleRowSelection(v, true)
- })
- }, 100)
- }
- })
- onMounted(() => {
- formatTableHead(props.tableHead)
- })
- return {
- handleSizeChange,
- handleCurrentChange,
- handleSort,
- resetFilter,
- handleFilter,
- ref_table,
- ref_tableMain,
- ref_tablePage,
- ...toRefs(state),
- pageLayoutCpt,
- reset
- }
- },
- })
- </script>
- <style scoped lang="scss">
- .cus-table {
- width: 100%;
- height: 100%;
- max-height: 100%;
- display: flex;
- flex-direction: column;
- $cus-page-height: 32px;
- $cus-page-mt: 25px;
- position: relative;
- :deep(.el-popper) {
- max-width: 60% !important;
- }
- .cus-table-main {
- width: 100%;
- height: calc(100% - #{$cus-page-height} - #{$cus-page-mt}) !important;
- position: absolute;
- &.cus-table-main-no-foot {
- height: 100% !important;
- }
- :deep(.ct-table) {
- height: 100%;
- }
- }
- :deep(.ct-foot) {
- height: $cus-page-height;
- font-size: 14px;
- font-family: Microsoft YaHei;
- font-weight: 400;
- color: #999999;
- display: flex;
- justify-content: space-between;
- .total {
- display: flex;
- align-items: center;
- }
- }
- &.cus-table-normal {
- .cus-table-main {
- :deep(.ct-table) {
- width: 100%;
- //height: calc(100% - #{$cus-page-height} - 20px);
- .el-checkbox__inner {
- &:after {
- }
- }
- $borderColor: #FFFFFF;
- $borderWidth: 2px;
- // 表格左边框
- &::before, .el-table__border-left-patch {
- display: none;
- }
- // 表格上边框
- .el-table__inner-wrapper::after {
- display: none;
- }
- // 表格右边框
- &.el-table--border::after {
- display: none;
- }
- // 表格下边框
- .el-table__inner-wrapper::before {
- display: none;
- }
- .el-table__header-wrapper, .el-table__fixed-right, .el-table__fixed {
- .el-table__header {
- tr {
- >th {
- border-left: $borderWidth solid $borderColor;
- border-top: $borderWidth solid $borderColor;
- border-right: none;
- border-bottom: none;
- background-color: #F5F5F5;
- height: 52px;
- .cell {
- font-size: 14px;
- font-family: 微软雅黑;
- font-weight: 400;
- color: #666666;
- padding: 0 4px;
- &.highlight {
- color: #409eff;
- }
- }
- }
- &:first-child {
- >th {
- border-top: none;
- &:first-child {
- border-left: none;
- }
- }
- }
- }
- }
- }
- .el-table__body-wrapper, .el-table__fixed-body-wrapper {
- .el-table__body {
- .el-table__row {
- >td {
- border-right: none;
- border-bottom-color: #F4F4F4;
- .cell {
- font-size: 14px;
- font-family: 微软雅黑;
- font-weight: 400;
- color: #666666;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- word-break: break-all;
- padding: 0 6px;
- .el-link +.el-link {
- margin-left: 10px;
- }
- }
- }
- }
- }
- }
- }
- }
- :deep(.ct-foot) {
- margin-top: auto;
- }
- }
- &.cus-table-full {
- .cus-table-main {
- position: unset;
- height: 100% !important;
- }
- :deep(.ct-foot) {
- margin-top: $cus-page-mt;
- }
- }
- }
- :deep(.single-column) {
- .cell {
- display: flex;
- justify-content: center;
- align-items: center;
- .single-circle {
- width: 16px;
- height: 16px;
- border: 1px solid rgba(96, 98, 102, 0.6);
- border-radius: 50%;
- cursor: pointer;
- display: flex;
- justify-content: center;
- align-items: center;
- &.active {
- background-color: #22a5fe;
- border-color: #22a5fe;
- }
- .single-circle-in {
- width: 6px;
- height: 6px;
- border-radius: 50%;
- background-color: #FFFFFF;
- }
- }
- }
- }
- </style>
|