沙钢智慧能源系统前端代码
houzhongjian
2024-10-09 314507f8ddadd9c66e98d260c3b2a5dad1a04015
提交 | 用户 | 时间
314507 1 <script lang="tsx">
H 2 import { ElTable, ElTableColumn, ElPagination } from 'element-plus'
3 import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
4 import { propTypes } from '@/utils/propTypes'
5 import { setIndex } from './helper'
6 import { getSlot } from '@/utils/tsxHelper'
7 import type { TableProps } from './types'
8 import { set } from 'lodash-es'
9 import { Pagination, TableColumn, TableSetPropsType, TableSlotDefault } from '@/types/table'
10
11 export default defineComponent({
12   // eslint-disable-next-line vue/no-reserved-component-names
13   name: 'Table',
14   props: {
15     pageSize: propTypes.number.def(10),
16     currentPage: propTypes.number.def(1),
17     // 是否多选
18     selection: propTypes.bool.def(false),
19     // 是否所有的超出隐藏,优先级低于schema中的showOverflowTooltip,
20     showOverflowTooltip: propTypes.bool.def(true),
21     // 表头
22     columns: {
23       type: Array as PropType<TableColumn[]>,
24       default: () => []
25     },
26     // 展开行
27     expand: propTypes.bool.def(false),
28     // 是否展示分页
29     pagination: {
30       type: Object as PropType<Pagination>,
31       default: (): Pagination | undefined => undefined
32     },
33     // 仅对 type=selection 的列有效,类型为 Boolean,为 true 则会在数据更新之后保留之前选中的数据(需指定 row-key)
34     reserveSelection: propTypes.bool.def(false),
35     // 加载状态
36     loading: propTypes.bool.def(false),
37     // 是否叠加索引
38     reserveIndex: propTypes.bool.def(false),
39     // 对齐方式
40     align: propTypes.string
41       .validate((v: string) => ['left', 'center', 'right'].includes(v))
42       .def('center'),
43     // 表头对齐方式
44     headerAlign: propTypes.string
45       .validate((v: string) => ['left', 'center', 'right'].includes(v))
46       .def('center'),
47     data: {
48       type: Array as PropType<Recordable[]>,
49       default: () => []
50     }
51   },
52   emits: ['update:pageSize', 'update:currentPage', 'register'],
53   setup(props, { attrs, slots, emit, expose }) {
54     const elTableRef = ref<ComponentRef<typeof ElTable>>()
55
56     // 注册
57     onMounted(() => {
58       const tableRef = unref(elTableRef)
59       emit('register', tableRef?.$parent, elTableRef)
60     })
61
62     const pageSizeRef = ref(props.pageSize)
63
64     const currentPageRef = ref(props.currentPage)
65
66     // useTable传入的props
67     const outsideProps = ref<TableProps>({})
68
69     const mergeProps = ref<TableProps>({})
70
71     const getProps = computed(() => {
72       const propsObj = { ...props }
73       Object.assign(propsObj, unref(mergeProps))
74       return propsObj
75     })
76
77     const setProps = (props: TableProps = {}) => {
78       mergeProps.value = Object.assign(unref(mergeProps), props)
79       outsideProps.value = props
80     }
81
82     const setColumn = (columnProps: TableSetPropsType[], columnsChildren?: TableColumn[]) => {
83       const { columns } = unref(getProps)
84       for (const v of columnsChildren || columns) {
85         for (const item of columnProps) {
86           if (v.field === item.field) {
87             set(v, item.path, item.value)
88           } else if (v.children?.length) {
89             setColumn(columnProps, v.children)
90           }
91         }
92       }
93     }
94
95     const selections = ref<Recordable[]>([])
96
97     const selectionChange = (selection: Recordable[]) => {
98       selections.value = selection
99     }
100
101     expose({
102       setProps,
103       setColumn,
104       selections
105     })
106
107     const pagination = computed(() => {
108       // update by 芋艿:保持和 Pagination 组件的逻辑一致
109       return Object.assign(
110         {
111           small: false,
112           background: true,
113           pagerCount: document.body.clientWidth < 992 ? 5 : 7,
114           layout: 'total, sizes, prev, pager, next, jumper',
115           pageSizes: [10, 20, 30, 50, 100],
116           disabled: false,
117           hideOnSinglePage: false,
118           total: 10
119         },
120         unref(getProps).pagination
121       )
122     })
123
124     watch(
125       () => unref(getProps).pageSize,
126       (val: number) => {
127         pageSizeRef.value = val
128       }
129     )
130
131     watch(
132       () => unref(getProps).currentPage,
133       (val: number) => {
134         currentPageRef.value = val
135       }
136     )
137
138     watch(
139       () => pageSizeRef.value,
140       (val: number) => {
141         emit('update:pageSize', val)
142       }
143     )
144
145     watch(
146       () => currentPageRef.value,
147       (val: number) => {
148         emit('update:currentPage', val)
149       }
150     )
151
152     const getBindValue = computed(() => {
153       const bindValue: Recordable = { ...attrs, ...props }
154       delete bindValue.columns
155       delete bindValue.data
156       return bindValue
157     })
158
159     const renderTableSelection = () => {
160       const { selection, reserveSelection, align, headerAlign } = unref(getProps)
161       // 渲染多选
162       return selection ? (
163         <ElTableColumn
164           type="selection"
165           reserveSelection={reserveSelection}
166           align={align}
167           headerAlign={headerAlign}
168           width="50"
169         ></ElTableColumn>
170       ) : undefined
171     }
172
173     const renderTableExpand = () => {
174       const { align, headerAlign, expand } = unref(getProps)
175       // 渲染展开行
176       return expand ? (
177         <ElTableColumn type="expand" align={align} headerAlign={headerAlign}>
178           {{
179             // @ts-ignore
180             default: (data: TableSlotDefault) => getSlot(slots, 'expand', data)
181           }}
182         </ElTableColumn>
183       ) : undefined
184     }
185
186     const rnderTreeTableColumn = (columnsChildren: TableColumn[]) => {
187       const { align, headerAlign, showOverflowTooltip } = unref(getProps)
188       return columnsChildren.map((v) => {
189         const props = { ...v }
190         if (props.children) delete props.children
191         return (
192           <ElTableColumn
193             showOverflowTooltip={showOverflowTooltip}
194             align={align}
195             headerAlign={headerAlign}
196             {...props}
197             prop={v.field}
198           >
199             {{
200               default: (data: TableSlotDefault) =>
201                 v.children && v.children.length
202                   ? rnderTableColumn(v.children)
203                   : // @ts-ignore
204                     getSlot(slots, v.field, data) ||
205                     v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
206                     data.row[v.field],
207               // @ts-ignore
208               header: getSlot(slots, `${v.field}-header`)
209             }}
210           </ElTableColumn>
211         )
212       })
213     }
214
215     const rnderTableColumn = (columnsChildren?: TableColumn[]) => {
216       const {
217         columns,
218         reserveIndex,
219         pageSize,
220         currentPage,
221         align,
222         headerAlign,
223         showOverflowTooltip
224       } = unref(getProps)
225       return [...[renderTableExpand()], ...[renderTableSelection()]].concat(
226         (columnsChildren || columns).map((v) => {
227           // 自定生成序号
228           if (v.type === 'index') {
229             return (
230               <ElTableColumn
231                 type="index"
232                 index={
233                   v.index
234                     ? v.index
235                     : (index) => setIndex(reserveIndex, index, pageSize, currentPage)
236                 }
237                 align={v.align || align}
238                 headerAlign={v.headerAlign || headerAlign}
239                 label={v.label}
240                 width="65px"
241               ></ElTableColumn>
242             )
243           } else {
244             const props = { ...v }
245             if (props.children) delete props.children
246             return (
247               <ElTableColumn
248                 showOverflowTooltip={showOverflowTooltip}
249                 align={align}
250                 headerAlign={headerAlign}
251                 {...props}
252                 prop={v.field}
253               >
254                 {{
255                   default: (data: TableSlotDefault) =>
256                     v.children && v.children.length
257                       ? rnderTreeTableColumn(v.children)
258                       : // @ts-ignore
259                         getSlot(slots, v.field, data) ||
260                         v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
261                         data.row[v.field],
262                   // @ts-ignore
263                   header: () => getSlot(slots, `${v.field}-header`) || v.label
264                 }}
265               </ElTableColumn>
266             )
267           }
268         })
269       )
270     }
271
272     return () => (
273       <div v-loading={unref(getProps).loading}>
274         <ElTable
275           // @ts-ignore
276           ref={elTableRef}
277           data={unref(getProps).data}
278           onSelection-change={selectionChange}
279           {...unref(getBindValue)}
280         >
281           {{
282             default: () => rnderTableColumn(),
283             // @ts-ignore
284             append: () => getSlot(slots, 'append')
285           }}
286         </ElTable>
287         {unref(getProps).pagination ? (
288           // update by 芋艿:保持和 Pagination 组件一致
289           <ElPagination
290             v-model:pageSize={pageSizeRef.value}
291             v-model:currentPage={currentPageRef.value}
292             class="float-right mb-15px mt-15px"
293             {...unref(pagination)}
294           ></ElPagination>
295         ) : undefined}
296       </div>
297     )
298   }
299 })
300 </script>
301 <style lang="scss" scoped>
302 :deep(.el-button.is-text) {
303   padding: 8px 4px;
304   margin-left: 0;
305 }
306
307 :deep(.el-button.is-link) {
308   padding: 8px 4px;
309   margin-left: 0;
310 }
311 </style>