103 lines
2.4 KiB
Vue
103 lines
2.4 KiB
Vue
<template>
|
|
<view>
|
|
<template v-if="loading">
|
|
<slot name="loading-top" />
|
|
<component v-if="theme" :is="components[theme]" :size="size" :count="count" />
|
|
<slot name="loading-bottom" />
|
|
</template>
|
|
<template v-else>
|
|
<slot v-if="data" name="content" :data="data" />
|
|
<slot v-else name="error" />
|
|
</template>
|
|
</view>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, onMounted, computed } from 'vue'
|
|
import ImageText from './templates/ImageText.vue'
|
|
import LineList from './templates/LineList.vue'
|
|
import BookCard from './templates/BookCard.vue'
|
|
import ImageCard from './templates/ImageCard.vue'
|
|
import BookInfo from './templates/BookInfo.vue'
|
|
|
|
// 注册组件
|
|
const components = {
|
|
'none': () => null,
|
|
'image-text': ImageText,
|
|
'line-list': LineList,
|
|
'image-card': ImageCard,
|
|
'book-card': BookCard,
|
|
'book-info': BookInfo,
|
|
}
|
|
|
|
type RequestFn = () => Promise<any>
|
|
type ThemeType = keyof typeof components
|
|
|
|
const props = withDefaults(defineProps<{
|
|
theme?: ThemeType
|
|
request: RequestFn | RequestFn[]
|
|
auto?: boolean,
|
|
size?: 'small' | 'medium' | 'large' | any[]
|
|
count?: number
|
|
}>(), {
|
|
theme: 'none',
|
|
auto: true,
|
|
count: 1
|
|
})
|
|
|
|
const emit = defineEmits(['success', 'error', 'complete'])
|
|
|
|
const requestFnType = ref('single')
|
|
const requestList = computed<RequestFn[]>(() => {
|
|
if (Array.isArray(props.request)) {
|
|
requestFnType.value = 'multi'
|
|
return props.request
|
|
}
|
|
requestFnType.value = 'single'
|
|
return [props.request]
|
|
})
|
|
|
|
const loading = ref(true)
|
|
const data = ref<any>(null)
|
|
|
|
const run = async (methods?: RequestFn[]) => {
|
|
loading.value = true
|
|
const reqMethods = methods || requestList.value
|
|
try {
|
|
// await new Promise(resolve => setTimeout(resolve, 3000))
|
|
const results = await Promise.all(
|
|
reqMethods.map(fn => fn())
|
|
)
|
|
// 将每个请求的结果处理成 key-value 格式
|
|
const resolvedData: Record<string, any> = {}
|
|
reqMethods.forEach((fn, index) => {
|
|
const key = fn.name || `request_${index}`
|
|
resolvedData[key] = results[index]
|
|
})
|
|
data.value = requestFnType.value === 'single' ? results[0] : resolvedData
|
|
emit('success', data.value)
|
|
} catch (err) {
|
|
emit('error', err)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const reload = (methods?: RequestFn[]) => {
|
|
run(methods)
|
|
}
|
|
|
|
onMounted(() => {
|
|
if (props.auto) {
|
|
run()
|
|
}
|
|
})
|
|
|
|
defineExpose({
|
|
reload,
|
|
loading
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
</style> |