Files
financial/src/views/news/index.vue

111 lines
3.9 KiB
Vue

<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>