|
@@ -1,6 +1,13 @@
|
|
|
<script lang="tsx">
|
|
|
-import { ElTable, ElTableColumn, ElPagination, ComponentSize, ElTooltipProps } from 'element-plus'
|
|
|
-import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
|
|
|
+import {
|
|
|
+ ElTable,
|
|
|
+ ElTableColumn,
|
|
|
+ ElPagination,
|
|
|
+ ComponentSize,
|
|
|
+ ElTooltipProps,
|
|
|
+ ElImage
|
|
|
+} from 'element-plus'
|
|
|
+import { defineComponent, PropType, ref, computed, unref, watch, onMounted, nextTick } from 'vue'
|
|
|
import { propTypes } from '@/utils/propTypes'
|
|
|
import { setIndex } from './helper'
|
|
|
import type { TableProps, TableColumn, Pagination, TableSetProps } from './types'
|
|
@@ -8,6 +15,8 @@ import { set } from 'lodash-es'
|
|
|
import { CSSProperties } from 'vue'
|
|
|
import { getSlot } from '@/utils/tsxHelper'
|
|
|
import TableActions from './components/TableActions.vue'
|
|
|
+import Sortable from 'sortablejs'
|
|
|
+import { Icon } from '@/components/Icon'
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'Table',
|
|
@@ -48,6 +57,12 @@ export default defineComponent({
|
|
|
type: Array as PropType<Recordable[]>,
|
|
|
default: () => []
|
|
|
},
|
|
|
+ // 是否自动预览
|
|
|
+ preview: {
|
|
|
+ type: Array as PropType<string[]>,
|
|
|
+ default: () => []
|
|
|
+ },
|
|
|
+ sortable: propTypes.bool.def(false),
|
|
|
height: propTypes.oneOfType([Number, String]),
|
|
|
maxHeight: propTypes.oneOfType([Number, String]),
|
|
|
stripe: propTypes.bool.def(false),
|
|
@@ -173,7 +188,7 @@ export default defineComponent({
|
|
|
scrollbarAlwaysOn: propTypes.bool.def(false),
|
|
|
flexible: propTypes.bool.def(false)
|
|
|
},
|
|
|
- emits: ['update:pageSize', 'update:currentPage', 'register', 'refresh'],
|
|
|
+ emits: ['update:pageSize', 'update:currentPage', 'register', 'refresh', 'sortable-change'],
|
|
|
setup(props, { attrs, emit, slots, expose }) {
|
|
|
const elTableRef = ref<ComponentRef<typeof ElTable>>()
|
|
|
|
|
@@ -198,6 +213,33 @@ export default defineComponent({
|
|
|
return propsObj
|
|
|
})
|
|
|
|
|
|
+ const sortableEl = ref()
|
|
|
+ // 初始化拖拽
|
|
|
+ const initDropTable = () => {
|
|
|
+ const el = unref(elTableRef)?.$el.querySelector('.el-table__body tbody')
|
|
|
+ if (!el) return
|
|
|
+ if (unref(sortableEl)) unref(sortableEl).destroy()
|
|
|
+
|
|
|
+ sortableEl.value = Sortable.create(el, {
|
|
|
+ handle: '.table-move',
|
|
|
+ animation: 180,
|
|
|
+ onEnd(e: any) {
|
|
|
+ emit('sortable-change', e)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => getProps.value.sortable,
|
|
|
+ async (v) => {
|
|
|
+ await nextTick()
|
|
|
+ v && initDropTable()
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
const setProps = (props: TableProps = {}) => {
|
|
|
mergeProps.value = Object.assign(unref(mergeProps), props)
|
|
|
outsideProps.value = { ...props } as any
|
|
@@ -301,7 +343,7 @@ export default defineComponent({
|
|
|
})
|
|
|
|
|
|
const renderTreeTableColumn = (columnsChildren: TableColumn[]) => {
|
|
|
- const { align, headerAlign, showOverflowTooltip } = unref(getProps)
|
|
|
+ const { align, headerAlign, showOverflowTooltip, preview } = unref(getProps)
|
|
|
return columnsChildren.map((v) => {
|
|
|
if (v.hidden) return null
|
|
|
const props = { ...v } as any
|
|
@@ -312,12 +354,20 @@ export default defineComponent({
|
|
|
const slots = {
|
|
|
default: (...args: any[]) => {
|
|
|
const data = args[0]
|
|
|
+ let isImageUrl = false
|
|
|
+ if (preview.length) {
|
|
|
+ isImageUrl = preview.some((item) => (item as string) === v.field)
|
|
|
+ }
|
|
|
+
|
|
|
return children && children.length
|
|
|
? renderTreeTableColumn(children)
|
|
|
: props?.slots?.default
|
|
|
? props.slots.default(args)
|
|
|
- : v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
|
|
|
- data.row[v.field]
|
|
|
+ : v?.formatter
|
|
|
+ ? v?.formatter?.(data.row, data.column, data.row[v.field], data.$index)
|
|
|
+ : isImageUrl
|
|
|
+ ? renderPreview(data.row[v.field])
|
|
|
+ : data.row[v.field]
|
|
|
}
|
|
|
}
|
|
|
if (props?.slots?.header) {
|
|
@@ -338,6 +388,21 @@ export default defineComponent({
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ const renderPreview = (url: string) => {
|
|
|
+ return (
|
|
|
+ <div class="flex items-center">
|
|
|
+ <ElImage
|
|
|
+ src={url}
|
|
|
+ fit="cover"
|
|
|
+ class="w-[100%] h-100px"
|
|
|
+ lazy
|
|
|
+ preview-src-list={[url]}
|
|
|
+ preview-teleported
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
const renderTableColumn = (columnsChildren?: TableColumn[]) => {
|
|
|
const {
|
|
|
columns,
|
|
@@ -347,7 +412,8 @@ export default defineComponent({
|
|
|
align,
|
|
|
headerAlign,
|
|
|
showOverflowTooltip,
|
|
|
- reserveSelection
|
|
|
+ reserveSelection,
|
|
|
+ preview
|
|
|
} = unref(getProps)
|
|
|
|
|
|
return (columnsChildren || columns).map((v) => {
|
|
@@ -384,12 +450,21 @@ export default defineComponent({
|
|
|
const slots = {
|
|
|
default: (...args: any[]) => {
|
|
|
const data = args[0]
|
|
|
+
|
|
|
+ let isImageUrl = false
|
|
|
+ if (preview.length) {
|
|
|
+ isImageUrl = preview.some((item) => (item as string) === v.field)
|
|
|
+ }
|
|
|
+
|
|
|
return children && children.length
|
|
|
? renderTreeTableColumn(children)
|
|
|
: props?.slots?.default
|
|
|
? props.slots.default(args)
|
|
|
- : v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
|
|
|
- data.row[v.field]
|
|
|
+ : v?.formatter
|
|
|
+ ? v?.formatter?.(data.row, data.column, data.row[v.field], data.$index)
|
|
|
+ : isImageUrl
|
|
|
+ ? renderPreview(data.row[v.field])
|
|
|
+ : data.row[v.field]
|
|
|
}
|
|
|
}
|
|
|
if (props?.slots?.header) {
|
|
@@ -419,6 +494,21 @@ export default defineComponent({
|
|
|
if (getSlot(slots, 'append')) {
|
|
|
tableSlots['append'] = (...args: any[]) => getSlot(slots, 'append', args)
|
|
|
}
|
|
|
+
|
|
|
+ const { sortable } = unref(getProps)
|
|
|
+
|
|
|
+ const sortableEl = sortable ? (
|
|
|
+ <ElTableColumn
|
|
|
+ className="table-move cursor-move"
|
|
|
+ type="sortable"
|
|
|
+ prop="sortable"
|
|
|
+ width="60px"
|
|
|
+ align="center"
|
|
|
+ >
|
|
|
+ <Icon icon="ant-design:drag-outlined" />
|
|
|
+ </ElTableColumn>
|
|
|
+ ) : null
|
|
|
+
|
|
|
return (
|
|
|
<div v-loading={unref(getProps).loading}>
|
|
|
{unref(getProps).showAction ? (
|
|
@@ -426,7 +516,7 @@ export default defineComponent({
|
|
|
) : null}
|
|
|
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
|
|
|
{{
|
|
|
- default: () => renderTableColumn(),
|
|
|
+ default: () => [sortableEl, ...renderTableColumn()],
|
|
|
...tableSlots
|
|
|
}}
|
|
|
</ElTable>
|