feat: 添加产品记录页面,支持我的业务功能和数据加载

This commit is contained in:
2026-01-25 17:47:35 +07:00
parent 76f286af83
commit 6d440055ce
3 changed files with 145 additions and 2 deletions

View File

@@ -39,6 +39,11 @@ const routes: Array<RouteRecordRaw> = [
},
],
},
{
path: "/product/records",
component: () => import("@/views/product/records.vue"),
meta: { requiresAuth: true },
},
{
path: "/news/:id",
props: true,

View File

@@ -3,7 +3,7 @@ import type { Treaty } from "@elysiajs/eden";
import type { InfiniteScrollCustomEvent } from "@ionic/vue";
import type { TreatyQuery } from "@/api/types";
import { modalController } from "@ionic/vue";
import { calendarOutline, cardOutline, timeOutline, trendingUpOutline } from "ionicons/icons";
import { bagHandleOutline, calendarOutline, cardOutline, timeOutline, trendingUpOutline } from "ionicons/icons";
import { client, safeClient } from "@/api";
import Subscribe from "./components/subscribe.vue";
@@ -82,13 +82,17 @@ onMounted(() => {
<!-- 基金产品列表 -->
<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 justify-between items-center mb-4 w-full">
<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>
<ion-button fill="clear" size="small" @click="$router.push('/product/records')">
<ion-icon slot="start" :icon="bagHandleOutline" />
我的业务
</ion-button>
</div>
</div>
@@ -137,6 +141,12 @@ onMounted(() => {
{{ Number(product.cycleDays) }}
</span>
</div>
<div class="flex flex-col">
<span class="text-xs text-[#999] mb-1">改革先锋扶持金</span>
<span class="text-lg font-bold text-[#52c41a] flex items-center gap-0.5">
¥{{ Number(product.reformPioneerAllowance) }}
</span>
</div>
</div>
<!-- 申购按钮 -->

View File

@@ -0,0 +1,128 @@
<script lang='ts' setup>
import type { Treaty } from "@elysiajs/eden";
import type { InfiniteScrollCustomEvent } from "@ionic/vue";
import type { TreatyQuery } from "@/api/types";
import { client, safeClient } from "@/api";
type Subscribe = Treaty.Data<typeof client.api.subscription.orders.get>["data"][number];
type SubscribeQuery = TreatyQuery<typeof client.api.subscription.orders.get>;
const [query] = useResetRef<SubscribeQuery>({
offset: 0,
limit: 10,
});
const data = ref<Subscribe[]>([]);
const isFinished = ref(false);
async function fetchData() {
const { data: responseData } = await safeClient(client.api.subscription.orders.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);
}
onMounted(() => {
fetchData();
});
</script>
<template>
<ion-page>
<ion-header class="ion-no-border">
<ion-toolbar class="ion-toolbar">
<ion-buttons slot="start">
<back-button />
</ion-buttons>
<ion-title>我的业务</ion-title>
</ion-toolbar>
</ion-header>
<ion-content :fullscreen="true">
<div class="p-4">
<empty v-if="data.length === 0 && !isFinished" class="my-20" />
<div v-else class="flex flex-col gap-3">
<div
v-for="item in data"
:key="item.id"
class="bg-white rounded-2xl p-4 shadow-sm"
>
<!-- 顶部状态栏 -->
<div class="flex items-center justify-between mb-3 pb-3 border-b border-gray-100">
<div class="text-xs text-gray-500">
{{ useDateFormat(item.createdAt, 'YYYY-MM-DD HH:mm') }}
</div>
<div
class="px-3 py-1 rounded-full text-xs font-semibold"
:class="{
'bg-green-50 text-green-600': item.status === 'unlocked',
'bg-blue-50 text-blue-600': item.status === 'locked',
'bg-yellow-50 text-yellow-600': item.status === 'pending',
'bg-red-50 text-red-600': item.status === 'cancelled',
'bg-gray-50 text-gray-600': !['unlocked', 'locked', 'pending', 'cancelled'].includes(item.status),
}"
>
{{ item.status === 'unlocked' ? '已解锁' : item.status === 'locked' ? '锁定中' : item.status === 'pending' ? '待处理' : item.status === 'cancelled' ? '已取消' : item.status }}
</div>
</div>
<!-- 金额信息 -->
<div class="grid grid-cols-2 gap-4 mb-3">
<div>
<div class="text-xs text-gray-500 mb-1">
申购金额
</div>
<div class="text-lg font-bold text-[#c41e3a]">
¥{{ Number(item.price).toFixed(2) }}
</div>
</div>
<div>
<div class="text-xs text-gray-500 mb-1">
改革先锋津贴
</div>
<div class="text-lg font-bold text-green-600">
¥{{ Number(item.reformPioneerAllowance).toFixed(2) }}
</div>
</div>
</div>
<!-- 周期信息 -->
<div class="flex items-center justify-between pt-3 border-t border-gray-100">
<div class="text-sm text-gray-600">
投资周期
</div>
<div class="text-sm font-semibold text-gray-900">
{{ item.cycleDays }}
</div>
</div>
</div>
</div>
</div>
<ion-infinite-scroll threshold="100px" :disabled="isFinished" @ion-infinite="handleInfinite">
<ion-infinite-scroll-content
loading-spinner="bubbles"
loading-text="加载更多..."
/>
</ion-infinite-scroll>
</ion-content>
</ion-page>
</template>
<style lang='css' scoped>
.shadow-sm {
box-shadow:
0 1px 3px 0 rgba(0, 0, 0, 0.1),
0 1px 2px -1px rgba(0, 0, 0, 0.1);
}
</style>