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

170 lines
5.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang='ts' setup>
import type { Treaty } from "@elysiajs/eden";
import type { InfiniteScrollCustomEvent } from "@ionic/vue";
import type { TreatyQuery } from "@/api/types";
import { calendarOutline, cardOutline, timeOutline, trendingUpOutline } from "ionicons/icons";
import { client, safeClient } from "@/api";
type Product = Treaty.Data<typeof client.api.subscription.products.get>["data"][number];
type ProductQuery = TreatyQuery<typeof client.api.subscription.products.get>;
const [query] = useResetRef<ProductQuery>({
offset: 0,
limit: 10,
});
const data = ref<Product[]>([]);
const isFinished = ref(false);
async function fetchData() {
const { data: responseData } = await safeClient(client.api.subscription.products.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 fetchData();
setTimeout(() => {
event.target.complete();
}, 500);
}
function handleProductClick(product: any) {
console.log("查看产品:", product.name);
// TODO: 跳转到产品详情
}
function handleSubscribe(product: any, event: Event) {
event.stopPropagation();
console.log("申购产品:", product.name);
// TODO: 实现申购功能
}
</script>
<template>
<ion-page>
<ion-content>
<img src="@/assets/images/product-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 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>
</div>
<empty v-if="data.length === 0" message="暂无基金产品信息" />
<div v-else class="flex flex-col gap-4">
<div
v-for="product in data"
:key="product.id"
class="bg-white rounded-2xl overflow-hidden shadow-sm cursor-pointer transition-all active:translate-y-0.5 active:shadow-sm flex"
@click="handleProductClick(product)"
>
<!-- 左侧缩略图 -->
<div class="relative w-28 h-36 shrink-0 overflow-hidden bg-linear-to-br from-[#f5f5f5] to-[#e8e8e8]">
<img :src="product.image" :alt="product.name" class="w-full h-full object-cover">
<!-- <div
class="fund-tag absolute top-2 left-2 text-white px-2 py-0.5 rounded-lg text-xs font-semibold shadow-lg"
>
{{ product.tag }}
</div> -->
</div>
<!-- 右侧信息 -->
<div class="flex-1 p-4 flex flex-col justify-between">
<div>
<h4 class="text-base font-bold text-[#1a1a1a] mb-1 leading-snug">
{{ product.name }}
</h4>
<div class="flex items-center gap-1 text-xs text-[#999] mb-2">
<ion-icon :icon="timeOutline" class="text-sm" />
<span>申购截止{{ product.subscribeEndAt }}</span>
</div>
<!-- 产品信息 -->
<div class="grid grid-cols-3 gap-2 mb-2">
<div class="flex flex-col">
<span class="text-xs text-[#999]">当前价格</span>
<span class="text-lg font-bold text-[#c41e3a]">¥{{ product.price }}</span>
</div>
<div class="flex flex-col">
<span class="text-xs text-[#999]">到期收益</span>
<span class="text-lg font-bold text-[#52c41a] flex items-center gap-0.5">
<ion-icon :icon="trendingUpOutline" class="text-xs" />
{{ product.maturityYield }}
</span>
</div>
<div class="flex flex-col">
<span class="text-xs text-[#999]">产品周期</span>
<span class="text-lg font-bold text-[#1a1a1a] flex items-center gap-0.5">
<ion-icon :icon="calendarOutline" class="text-xs" />
{{ product.cycleDays }}
</span>
</div>
</div>
</div>
<!-- 申购按钮 -->
<div class="flex items-center gap-2 mt-2">
<ion-button
size="small"
class="subscribe-btn flex-1"
@click="handleSubscribe(product, $event)"
>
<div class="flex-center gap-2">
<ion-icon slot="start" :icon="cardOutline" />
<span>我要申购</span>
</div>
</ion-button>
</div>
</div>
</div>
</div>
</section>
</ion-content>
</ion-page>
</template>
<style lang='css' scoped>
.header-toolbar {
--background: #c32120;
--color: #fff;
}
.header-bg {
background: linear-gradient(180deg, #c32120 0%, transparent 100%);
}
.fund-tag {
backdrop-filter: blur(4px);
}
.subscribe-btn {
--background: linear-gradient(135deg, #1778ac 0%, #265166 100%);
--background-activated: linear-gradient(135deg, #1778ac 0%, #265166 100%);
--border-radius: 12px;
--padding-start: 16px;
--padding-end: 16px;
--box-shadow: 0 2px 8px rgba(30, 124, 196, 0.3);
font-weight: 600;
font-size: 13px;
height: 32px;
text-transform: none;
}
.subscribe-btn::part(native) {
font-weight: 600;
}
</style>