feat: 添加新闻模块,更新路由和组件,优化新闻列表和详情页
This commit is contained in:
110
src/views/news/index.vue
Normal file
110
src/views/news/index.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<script lang='ts' setup>
|
||||
import type { Treaty } from "@elysiajs/eden";
|
||||
import type { InfiniteScrollCustomEvent } from "@ionic/vue";
|
||||
import type { TreatyQuery } from "@/api/types";
|
||||
import { eyeOutline, timeOutline } from "ionicons/icons";
|
||||
import { client, safeClient } from "@/api";
|
||||
|
||||
type NewsItem = Treaty.Data<typeof client.api.news.get>["data"][number];
|
||||
type NewsQuery = TreatyQuery<typeof client.api.news.get>;
|
||||
|
||||
const [query] = useResetRef<NewsQuery>({
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
});
|
||||
const data = ref<NewsItem[]>([]);
|
||||
const isFinished = ref(false);
|
||||
const router = useRouter();
|
||||
|
||||
async function fetchNews() {
|
||||
const { data: responseData } = await safeClient(client.api.news.get({ query: { ...query.value } }));
|
||||
data.value.push(...(responseData.value?.data || []));
|
||||
isFinished.value = responseData.value?.pagination.hasNextPage === false;
|
||||
}
|
||||
async function handleInfinite(event: InfiniteScrollCustomEvent) {
|
||||
if (isFinished.value) {
|
||||
event.target.complete();
|
||||
event.target.disabled = true;
|
||||
return;
|
||||
}
|
||||
query.value.offset! += query.value.limit!;
|
||||
await fetchNews();
|
||||
setTimeout(() => {
|
||||
event.target.complete();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function handleNewsClick(news: any) {
|
||||
router.push(`/news/${news.id}`);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchNews();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar class="ion-toolbar">
|
||||
<img slot="start" src="@/assets/images/icon-1.png" class="h-8 w-8 ml-2" alt="Logo">
|
||||
<ion-title>革新求进</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content :fullscreen="true">
|
||||
<img src="@/assets/images/service-banner.jpg" class="h-50 w-full object-cover" alt="服务页横幅">
|
||||
|
||||
<!-- 新闻列表区域 -->
|
||||
<section class="mb-5 -mt-5 ion-padding-horizontal">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<img src="@/assets/images/icon.png" class="size-7">
|
||||
<div class="text-xl font-bold text-[#1a1a1a]">
|
||||
新闻动态
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<empty v-if="data.length === 0" class="my-10" />
|
||||
<div v-else class="flex flex-col gap-4">
|
||||
<div
|
||||
v-for="item in data"
|
||||
:key="item.id"
|
||||
class="bg-white rounded-2xl overflow-hidden shadow-sm cursor-pointer transition-all active:translate-y-0.5 active:shadow-sm"
|
||||
@click="handleNewsClick(item)"
|
||||
>
|
||||
<div class="relative w-full h-45 overflow-hidden">
|
||||
<img v-if="item.thumbnailId" :src="item.thumbnailId" :alt="item.title" class="w-full h-full object-cover">
|
||||
<div class="news-badge absolute top-3 left-3 bg-linear-to-br from-[#ff7878] to-[#aa1818] text-white px-3 py-1 rounded-xl text-xs font-semibold shadow-lg">
|
||||
热点
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="text-xl font-bold text-[#1a1a1a] mb-2 leading-snug">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<p class="text-sm text-[#666] mb-3 leading-relaxed line-clamp-2">
|
||||
{{ item.summary }}
|
||||
</p>
|
||||
<div class="flex items-center gap-4 text-xs text-[#999]">
|
||||
<span class="flex items-center gap-1">
|
||||
<ion-icon :icon="timeOutline" class="text-sm" />
|
||||
{{ useDateFormat(item.createdAt, 'YYYY-MM-DD') }}
|
||||
</span>
|
||||
<span class="flex items-center gap-1">
|
||||
<ion-icon :icon="eyeOutline" class="text-sm" />
|
||||
{{ item.viewCount }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<ion-infinite-scroll threshold="100px" disabled @ion-infinite="handleInfinite">
|
||||
<ion-infinite-scroll-content loading-spinner="bubbles" loading-text="加载更多..." />
|
||||
</ion-infinite-scroll>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<style lang='css' scoped></style>
|
||||
Reference in New Issue
Block a user