2026-09-10 10:57:40 +08:00
|
|
|
<template>
|
2026-09-15 16:16:55 +08:00
|
|
|
<view class="page" :style="pageStyle()">
|
2026-09-18 12:59:43 +08:00
|
|
|
<AppHeader title="匹配融资方案" />
|
|
|
|
|
<view class="filter-bar"><view v-for="item in filters" :key="item.id" :class="filter == item.id ? 'filter active' : 'filter'" @click="filter = item.id"><text :class="filter == item.id ? 'filter-label selected' : 'filter-label'">{{ item.label }}</text></view></view>
|
|
|
|
|
<scroll-view scroll-y :style="contentStyle(314, false)">
|
2026-09-10 10:57:40 +08:00
|
|
|
<view class="match-content">
|
2026-09-18 12:59:43 +08:00
|
|
|
<view v-if="loading" class="state-panel"><text class="state-text">正在匹配融资方案…</text></view>
|
|
|
|
|
<view v-else-if="errorMessage.length > 0" class="state-panel"><text class="state-text">{{ errorMessage }}</text><button class="retry-button" @click="loadMatches">重新加载</button></view>
|
|
|
|
|
<view v-else-if="matches.length == 0" class="state-panel"><text class="state-text">暂无可展示方案,请完善评估资料后重试</text></view>
|
|
|
|
|
<view v-else>
|
2026-09-20 14:18:55 +08:00
|
|
|
<text class="result-summary">共 {{ matches.length }} 个方案 · 了解额度与申请条件</text>
|
2026-09-18 12:59:43 +08:00
|
|
|
<view class="match-card" v-for="item in sortedMatches" :key="item.id" @click="openProduct(item.id)">
|
|
|
|
|
<view class="bank-row"><view class="bank-logo" :style="'background-color:' + item.color"><text class="bank-initial">{{ item.initials }}</text></view><view class="bank-copy"><text class="bank-name">{{ item.bank }}</text><text class="match-tag">个人信用融资</text></view><text class="match-score">{{ item.score }}%匹配</text></view>
|
2026-09-22 17:25:52 +08:00
|
|
|
<view class="metrics"><view class="metric"><text class="metric-value">{{ item.amount }}<text class="metric-unit"> 万元</text></text><text class="metric-label">最高额度</text></view><view class="metric"><text class="metric-value rate-value">{{ item.rate.toFixed(2) }}%</text><text class="metric-label">年化利率(起)</text></view><view class="metric term-metric"><text class="term-value">{{ item.term }}</text><text class="metric-label">贷款期限</text></view></view>
|
2026-09-18 12:59:43 +08:00
|
|
|
<view class="card-footer"><text class="footer-hint">{{ item.advantages.join(' · ') }}</text><view class="detail-link"><text class="detail-label">查看详情</text><AppIcon name="chevron-right" :size="26" /></view></view>
|
|
|
|
|
</view>
|
2026-09-10 10:57:40 +08:00
|
|
|
</view>
|
2026-09-18 12:59:43 +08:00
|
|
|
<text class="list-tip">展示参数仅供参考,实际额度、利率及条件以机构审批为准。银行以文字简称标识。</text>
|
2026-09-10 10:57:40 +08:00
|
|
|
</view>
|
|
|
|
|
</scroll-view>
|
|
|
|
|
<BottomNav active="" />
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="uts">
|
2026-09-15 16:16:55 +08:00
|
|
|
import { usePageLayout } from '@/services/layout.uts'
|
2026-09-20 10:52:10 +08:00
|
|
|
import { FinanceProduct } from '@/packages/finance/services/finance.uts'
|
2026-09-20 14:18:55 +08:00
|
|
|
import { fetchMatches } from '@/packages/finance/services/api.uts'
|
2026-09-10 10:57:40 +08:00
|
|
|
import AppHeader from '@/components/AppHeader.uvue'
|
|
|
|
|
import BottomNav from '@/components/BottomNav.uvue'
|
|
|
|
|
import AppIcon from '@/components/AppIcon.uvue'
|
2026-09-18 12:59:43 +08:00
|
|
|
const { contentStyle, pageStyle } = usePageLayout()
|
|
|
|
|
type MatchFilter = { id: string, label: string }
|
|
|
|
|
const filters: MatchFilter[] = [{ id: 'all', label: '综合排序' }, { id: 'amount', label: '额度优先' }, { id: 'rate', label: '低息优先' }]
|
2026-09-10 10:57:40 +08:00
|
|
|
const filter = ref('all')
|
2026-09-18 12:59:43 +08:00
|
|
|
const matches = ref<FinanceProduct[]>([])
|
2026-09-11 20:23:10 +08:00
|
|
|
const loading = ref(true)
|
|
|
|
|
const errorMessage = ref('')
|
2026-09-18 12:59:43 +08:00
|
|
|
const sortedMatches = computed((): FinanceProduct[] => {
|
|
|
|
|
const items = matches.value.slice()
|
|
|
|
|
items.sort((a: FinanceProduct, b: FinanceProduct): number => {
|
|
|
|
|
if (filter.value == 'amount') return b.amount - a.amount
|
|
|
|
|
if (filter.value == 'rate') return a.rate - b.rate
|
|
|
|
|
return b.score - a.score
|
|
|
|
|
})
|
|
|
|
|
return items
|
|
|
|
|
})
|
2026-09-11 20:23:10 +08:00
|
|
|
const loadMatches = async () => {
|
|
|
|
|
loading.value = true
|
|
|
|
|
errorMessage.value = ''
|
2026-09-18 12:59:43 +08:00
|
|
|
try { matches.value = await fetchMatches() } catch (error) { errorMessage.value = '方案加载失败,请重试' }
|
2026-09-11 20:23:10 +08:00
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
onMounted(() => { loadMatches() })
|
2026-09-20 10:52:10 +08:00
|
|
|
const openProduct = (id: string) => { uni.navigateTo({ url: '/packages/finance/product/product?id=' + id }) }
|
2026-09-10 10:57:40 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style>
|
2026-09-18 12:59:43 +08:00
|
|
|
.filter-bar { height: 88rpx; background-color: #fff; flex-direction: row; padding: 0 28rpx; border-bottom: 1rpx solid #e9eef6; }
|
|
|
|
|
.filter { flex: 1; align-items: center; justify-content: center; }
|
|
|
|
|
.active { border-bottom: 4rpx solid #0868f7; }
|
|
|
|
|
.filter-label { color: #718098; font-size: 25rpx; }
|
|
|
|
|
.selected { color: #0868f7; font-weight: 700; }
|
|
|
|
|
.match-content { padding: 24rpx 28rpx 90rpx; }
|
|
|
|
|
.result-summary { color: #6f7f96; font-size: 22rpx; margin-bottom: 20rpx; }
|
|
|
|
|
.match-card { border-radius: 18rpx; margin-bottom: 20rpx; background-color: #fff; border: 1rpx solid #e4ebf5; padding: 24rpx; }
|
|
|
|
|
.bank-row { flex-direction: row; align-items: center; }
|
|
|
|
|
.bank-logo { width: 64rpx; height: 64rpx; border-radius: 20rpx; align-items: center; justify-content: center; margin-right: 16rpx; flex-shrink: 0; }
|
|
|
|
|
.bank-initial { color: #fff; font-size: 30rpx; font-weight: 700; }
|
|
|
|
|
.bank-copy { flex: 1; }
|
|
|
|
|
.bank-name { font-size: 27rpx; font-weight: 700; color: #20324d; }
|
|
|
|
|
.match-tag { font-size: 21rpx; color: #7a899f; margin-top: 6rpx; }
|
|
|
|
|
.match-score { color: #178461; font-size: 20rpx; }
|
|
|
|
|
.metrics { flex-direction: row; margin-top: 26rpx; margin-bottom: 22rpx; }
|
|
|
|
|
.metric { flex: 1; }
|
|
|
|
|
.term-metric { align-items: flex-end; }
|
|
|
|
|
.metric-value { color: #20324d; font-size: 35rpx; font-weight: 800; line-height: 44rpx; }
|
|
|
|
|
.metric-unit { font-size: 23rpx; }
|
2026-09-15 16:16:55 +08:00
|
|
|
.rate-value { color: #0868f7; }
|
2026-09-18 12:59:43 +08:00
|
|
|
.term-value { color: #20324d; font-size: 25rpx; font-weight: 600; line-height: 44rpx; }
|
|
|
|
|
.metric-label { margin-top: 7rpx; font-size: 21rpx; color: #7c8aa0; }
|
|
|
|
|
.card-footer { border-top: 1rpx solid #edf1f6; padding-top: 18rpx; flex-direction: row; align-items: center; justify-content: space-between; }
|
|
|
|
|
.footer-hint { flex: 1; margin-right: 16rpx; font-size: 20rpx; line-height: 32rpx; color: #78889f; }
|
|
|
|
|
.detail-link { flex-direction: row; align-items: center; flex-shrink: 0; }
|
|
|
|
|
.detail-label { font-size: 24rpx; color: #0868f7; font-weight: 600; margin-right: 6rpx; }
|
|
|
|
|
.list-tip { color: #7a899e; font-size: 21rpx; line-height: 34rpx; margin: 8rpx 8rpx 0; }
|
|
|
|
|
.state-panel { padding: 70rpx 20rpx; align-items: center; }
|
|
|
|
|
.state-text { font-size: 26rpx; line-height: 42rpx; color: #728197; text-align: center; }
|
|
|
|
|
.retry-button { margin-top: 20rpx; color: #0868f7; background-color: #e8f2ff; font-size: 24rpx; }
|
2026-09-10 10:57:40 +08:00
|
|
|
</style>
|