使用了AI重构项目,并完善了一部分后台问题
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<div v-if="loading" class="site-grid site-grid--loading" aria-label="正在加载站点">
|
||||
<span v-for="index in 6" :key="index" class="site-skeleton"></span>
|
||||
</div>
|
||||
<div v-else ref="swiperElement" class="swiper sites-swiper">
|
||||
<div v-else-if="sites.length" ref="swiperElement" class="swiper sites-swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div v-for="(siteChunk, index) in chunkedSites" :key="index" class="swiper-slide">
|
||||
<div class="site-grid">
|
||||
@@ -11,8 +11,8 @@
|
||||
v-for="site in siteChunk"
|
||||
:key="site.id || site.url"
|
||||
:href="site.url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:target="config.openLinksInNewTab ? '_blank' : undefined"
|
||||
:rel="config.openLinksInNewTab ? 'noopener noreferrer' : undefined"
|
||||
class="site-box"
|
||||
>
|
||||
<i :class="site.icon" aria-hidden="true"></i>
|
||||
@@ -23,6 +23,7 @@
|
||||
</div>
|
||||
<div ref="paginationElement" class="swiper-pagination"></div>
|
||||
</div>
|
||||
<div v-else class="site-empty"><i class="fas fa-link" aria-hidden="true"></i><span>暂无站点</span></div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -32,18 +33,20 @@ import Swiper from 'swiper/bundle'
|
||||
import 'swiper/swiper-bundle.css'
|
||||
import { getSites } from '../api'
|
||||
import fallbackSites from '../config/site.json'
|
||||
import { loadPublicConfig, publicConfig as config } from '../composables/usePublicConfig'
|
||||
|
||||
const sites = ref([])
|
||||
const loading = ref(true)
|
||||
const swiperElement = ref(null)
|
||||
const paginationElement = ref(null)
|
||||
const chunkedSites = computed(() => sites.value.reduce((chunks, site, index) => {
|
||||
const chunkIndex = Math.floor(index / 6)
|
||||
const chunkIndex = Math.floor(index / (Number(config.sitePageSize) || 6))
|
||||
if (!chunks[chunkIndex]) chunks[chunkIndex] = []
|
||||
chunks[chunkIndex].push(site)
|
||||
return chunks
|
||||
}, []))
|
||||
let swiperInstance = null
|
||||
let configChannel = null
|
||||
|
||||
const initializeSwiper = async () => {
|
||||
await nextTick()
|
||||
@@ -58,19 +61,33 @@ const initializeSwiper = async () => {
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const loadSites = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const { data } = await getSites()
|
||||
sites.value = Array.isArray(data) && data.length ? data : fallbackSites
|
||||
const [{ data }] = await Promise.all([getSites(), loadPublicConfig()])
|
||||
sites.value = Array.isArray(data) ? data : []
|
||||
} catch {
|
||||
sites.value = fallbackSites
|
||||
} finally {
|
||||
loading.value = false
|
||||
initializeSwiper()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadSites()
|
||||
if (window.BroadcastChannel) {
|
||||
configChannel = new BroadcastChannel('config-update')
|
||||
configChannel.onmessage = ({ data }) => {
|
||||
if (data?.type === 'config-updated') loadSites()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => swiperInstance?.destroy(true, true))
|
||||
onUnmounted(() => {
|
||||
swiperInstance?.destroy(true, true)
|
||||
configChannel?.close()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@@ -90,6 +107,8 @@ onUnmounted(() => swiperInstance?.destroy(true, true))
|
||||
.site-box i { flex: 0 0 auto; font-size: var(--icon-size); }
|
||||
.site-box span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.site-grid--loading { padding: 10px; }
|
||||
.site-empty { min-height: 150px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: var(--text-muted); font-size: 13px; }
|
||||
.site-empty i { color: var(--hover-link-color); font-size: 22px; }
|
||||
.site-skeleton { animation: pulse 1.2s ease-in-out infinite alternate; }
|
||||
@keyframes pulse { to { opacity: 0.45; } }
|
||||
:deep(.swiper-pagination-bullet) { background: var(--text-muted); transition: width 0.3s ease; }
|
||||
|
||||
Reference in New Issue
Block a user