105 lines
2.6 KiB
Vue
105 lines
2.6 KiB
Vue
<template>
|
|
<div class="q-px-xs">
|
|
<div v-if="!isLoaded" class="spinner flex flex-center">
|
|
<q-spinner color="primary" size="3em" />
|
|
</div>
|
|
<q-table v-else class="app-table" :selection="type" row-key="id" v-model:selected="selected" flat bordered
|
|
virtual-scroll :columns="columns" :rows="rows" :pagination="pagination" :rows-per-page-options="[0]"
|
|
:filter="filter" style="max-height: 65vh;" @update:selected="emitSelected">
|
|
|
|
<template v-for="col in columns" :key="col.name" v-slot:[`body-cell-${col.name}`]="props">
|
|
<q-td :props="props">
|
|
<!-- 使用动态插槽名称 -->
|
|
<slot v-if="col.name !== detailField" :name="`body-cell-${col.name}`" :row="props.row" :column="props.col">
|
|
<!-- 默认内容 -->
|
|
<span>{{ props.row[col.name] }}</span>
|
|
</slot>
|
|
<q-scroll-area v-else class="description-cell">
|
|
<div v-html="props.row[detailField]"></div>
|
|
</q-scroll-area>
|
|
</q-td>
|
|
</template>
|
|
|
|
</q-table>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { ref, onMounted, reactive, PropType } from 'vue'
|
|
|
|
interface IRow {
|
|
[key: string]: any;
|
|
}
|
|
|
|
export default {
|
|
name: 'DetailFieldTable',
|
|
props: {
|
|
name: String,
|
|
type: String,
|
|
filter: String,
|
|
detailField: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
columns: {
|
|
type: Array as PropType<any[]>,
|
|
required: true
|
|
},
|
|
fetchData: {
|
|
type: Function as PropType<() => Promise<IRow[]>>,
|
|
required: true
|
|
},
|
|
sortBy: {
|
|
type: String,
|
|
required: false
|
|
},
|
|
sortDesc: {
|
|
type: Boolean,
|
|
required: false
|
|
}
|
|
},
|
|
emits: ['update:selected'],
|
|
setup(props, { emit }) {
|
|
const isLoaded = ref(false);
|
|
const rows = reactive<IRow[]>([]);
|
|
const selected = ref([]);
|
|
|
|
onMounted(async () => {
|
|
const data = await props.fetchData();
|
|
rows.push(...data);
|
|
isLoaded.value = true;
|
|
});
|
|
|
|
const emitSelected = (selectedItems: any[]) => {
|
|
emit('update:selected', selectedItems);
|
|
};
|
|
|
|
return {
|
|
rows,
|
|
selected,
|
|
isLoaded,
|
|
pagination: ref({
|
|
sortBy: props.sortBy || undefined,
|
|
descending: props.sortDesc || undefined,
|
|
rowsPerPage: 10
|
|
}),
|
|
emitSelected
|
|
};
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.description-cell {
|
|
height: 60px;
|
|
width: 300px;
|
|
max-height: 60px;
|
|
max-width: 300px;
|
|
white-space: break-spaces;
|
|
}
|
|
|
|
.spinner {
|
|
min-height: 300px;
|
|
min-width: 400px;
|
|
}
|
|
</style> |