feat: 实现协议全文与同意记录功能
新增协议全文后台管理、版本化发布及本人同意记录功能,支持可撤销授权;完善资料与授权相关边界提示,调整评估提交时的资料与授权校验逻辑,同步更新相关页面文案与路由。
This commit is contained in:
@@ -7,13 +7,14 @@
|
||||
<view v-if="error.length > 0" class="error-panel"><text class="heading">暂时无法读取</text><text class="body">{{ error }}</text><button class="secondary" @click="load">重新加载</button><text class="link" @click="back">返回选择产品</text></view>
|
||||
<template v-if="product != null">
|
||||
<view class="bank-header">
|
||||
<view class="bank-mark"><image class="bank-icon" src="/static/mobile/icons-generated/building.png" mode="aspectFit" /></view>
|
||||
<view class="bank-mark"><image class="bank-icon" :src="product!.logo.length > 0 ? product!.logo : '/static/mobile/icons-generated/building.png'" @error="product!.logo = ''" mode="aspectFit" /></view>
|
||||
<view class="bank-info">
|
||||
<view class="bank-title-row"><text class="bank-name">{{ product!.bank }}</text><text v-if="match != null" :class="match!.state == 'eligible' ? 'badge good' : (match!.state == 'ineligible' ? 'badge blocked' : 'badge pending')">{{ match!.state == 'eligible' ? '可供参考' : (match!.state == 'ineligible' ? '暂不推荐' : '待核实') }}</text></view>
|
||||
<view class="bank-title-row"><text v-if="product!.bank.length > 0" class="bank-name">{{ product!.bank }}</text><text v-if="match != null" :class="match!.state == 'eligible' ? 'badge good' : (match!.state == 'ineligible' ? 'badge blocked' : 'badge pending')">{{ match!.state == 'eligible' ? (match!.score != null ? '匹配度 ' + match!.score!.toString() + '%' : '可供参考') : (match!.state == 'ineligible' ? '暂不推荐' : match!.stateLabel) }}</text></view>
|
||||
<text v-if="match != null" :class="match!.state == 'eligible' ? 'state good-text' : 'state attention-text'">{{ match!.stateLabel }}</text>
|
||||
<text class="product-name">{{ product!.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="hasProductValue(product!.amount) || hasProductValue(product!.rate)" class="product-summary"><text v-if="hasProductValue(product!.amount)" class="summary-tag">额度范围 {{ product!.amount }}</text><text v-if="hasProductValue(product!.rate)" class="summary-tag">年化利率 {{ product!.rate }}</text></view>
|
||||
<view class="tabs">
|
||||
<view v-if="assessmentId.length > 0" :class="tab == 'explanation' ? 'tab active' : 'tab'" @click="switchTab('explanation')"><text :class="tab == 'explanation' ? 'tab-label selected' : 'tab-label'">AI解释</text></view>
|
||||
<view :class="tab == 'details' ? 'tab active' : 'tab'" @click="switchTab('details')"><text :class="tab == 'details' ? 'tab-label selected' : 'tab-label'">产品详情</text></view>
|
||||
@@ -21,7 +22,7 @@
|
||||
</view>
|
||||
<template v-if="tab == 'explanation' && match != null">
|
||||
<view class="reason-section">
|
||||
<text class="heading good-text">{{ match!.state == 'eligible' ? '推荐依据(' + match!.positive.length + '条已满足条件)' : '已满足的条件(' + match!.positive.length + '条)' }}</text>
|
||||
<text class="heading good-text">{{ match!.state == 'eligible' ? '推荐理由(' + match!.positive.length + '条)' : '参考理由(' + match!.positive.length + '条)' }}</text>
|
||||
<text v-if="match!.positive.length == 0" class="empty-note">暂无已确认满足的条件,不补充未经验证的推荐理由。</text>
|
||||
<view v-for="(reason, index) in positiveVisible" :key="reason.id" class="reason-row">
|
||||
<text class="number green-number">{{ index + 1 }}</text>
|
||||
@@ -53,28 +54,27 @@
|
||||
</template>
|
||||
<template v-if="tab == 'details'">
|
||||
<view class="details-section"><text class="heading">产品信息</text>
|
||||
<view class="row"><text class="label">额度范围</text><text class="value emphasis">{{ product!.amount }}</text></view>
|
||||
<view class="row"><text class="label">年化利率</text><text class="value">{{ product!.rate }}</text></view>
|
||||
<view class="row"><text class="label">贷款期限</text><text class="value">{{ product!.term }}</text></view>
|
||||
<view v-if="hasProductValue(product!.amount)" class="row"><text class="label">额度范围</text><text class="value emphasis">{{ product!.amount }}</text></view>
|
||||
<view v-if="hasProductValue(product!.rate)" class="row"><text class="label">年化利率</text><text class="value">{{ product!.rate }}</text></view>
|
||||
<view v-if="hasProductValue(product!.term)" class="row"><text class="label">贷款期限</text><text class="value">{{ product!.term }}</text></view>
|
||||
<view class="row"><text class="label">适用主体</text><text class="value">{{ product!.objects }}</text></view>
|
||||
<view class="row"><text class="label">适用地区</text><text class="value">{{ product!.regions }}</text></view>
|
||||
<view class="row"><text class="label">有效期</text><text class="value">{{ product!.valid }}</text></view>
|
||||
<view class="row"><text class="label">还款方式</text><text class="value">未提供</text></view>
|
||||
<view class="row"><text class="label">办理渠道</text><text class="value">未提供</text></view>
|
||||
<view class="row"><text class="label">审批时长</text><text class="value">未提供</text></view>
|
||||
<view v-if="hasProductValue(product!.repayment)" class="row"><text class="label">还款方式</text><text class="value">{{ product!.repayment }}</text></view>
|
||||
<view v-if="hasProductValue(product!.channel)" class="row"><text class="label">办理渠道</text><text class="value">{{ product!.channel }}</text></view>
|
||||
<view v-if="hasProductValue(product!.approval)" class="row"><text class="label">审批时长</text><text class="value">{{ product!.approval }}</text></view>
|
||||
</view>
|
||||
<view class="details-section"><text class="heading">资料来源</text><text class="body">{{ product!.source }}</text><text class="evidence">引用:{{ product!.sourceRef }}</text><text class="evidence">核对日期:{{ product!.checkedOn }}</text></view>
|
||||
<view v-if="hasProductValue(product!.source) || hasProductValue(product!.sourceRef) || hasProductValue(product!.checkedOn)" class="details-section"><text class="heading">资料来源</text><text v-if="hasProductValue(product!.source)" class="body">{{ product!.source }}</text><text v-if="hasProductValue(product!.sourceRef)" class="evidence">引用:{{ product!.sourceRef }}</text><text v-if="hasProductValue(product!.checkedOn)" class="evidence">核对日期:{{ product!.checkedOn }}</text></view>
|
||||
</template>
|
||||
<template v-if="tab == 'conditions'">
|
||||
<view class="details-section"><text class="heading">产品准入条件</text><text class="muted">公开条件不代表个人已符合,缺少核验依据时仍需核实。</text><text v-for="(condition, index) in product!.conditions" :key="index" class="condition">{{ condition }}</text></view>
|
||||
<view class="details-section"><text class="heading">资料准备说明</text><text class="body">{{ product!.materials }}</text><text class="muted">仅提供材料引导,不向机构提交申请。实际条件和材料须向机构核实。</text></view>
|
||||
<view class="details-section"><text class="heading">资料准备说明</text><view v-for="(material, index) in product!.materialList" :key="index" class="material-item"><text class="condition">{{ material.name }} · {{ material.required ? '必需' : '补充' }} · {{ material.objects }}</text><text v-if="material.note.length > 0" class="evidence">{{ material.note }}</text></view><text v-if="product!.materialList.length == 0 || product!.materials != '未提供'" class="body">{{ product!.materials }}</text><text class="muted">仅提供材料引导,不向机构提交申请。实际条件和材料须向机构核实。</text></view>
|
||||
</template>
|
||||
<view class="footnotes"><text class="record-note">{{ assessmentId.length > 0 ? '本次评估 #' + assessmentId : '公共产品资料' }} · 产品版本 v{{ product!.version }}</text><text v-if="match != null" class="record-note">{{ match!.availabilityLabel }},历史参数与结论保留。</text><text v-if="match != null && !canPrepare" class="record-note">{{ match!.state != 'eligible' ? '请先核对不符条件或待核实项。' : '当前产品不可用或状态未知,暂不提供准备入口。' }}</text><text class="record-note">自填信息未经核验;本页面不承诺额度、放款或获批。</text><text v-if="assessmentId.length > 0" class="link" @click="openCompare">查看同类产品对比</text><text v-if="assessmentId.length > 0" class="link" @click="toMatches">返回本次匹配</text><text v-else class="link" @click="history">选择评估查看匹配结果</text></view>
|
||||
<view class="footnotes"><text class="record-note">{{ assessmentId.length > 0 ? '本次评估 #' + assessmentId : '公共产品资料' }} · 产品版本 v{{ product!.version }}</text><text v-if="match != null" class="record-note">{{ match!.availabilityLabel }},历史参数与结论保留。</text><text v-if="match != null && !canPrepare" class="record-note">{{ match!.state != 'eligible' ? '请先核对不符条件或待核实项。' : '当前产品不可用或状态未知,暂不提供准备入口。' }}</text><text v-if="match != null && match!.score != null" class="record-note">匹配度表示条件匹配程度,不代表获批概率。</text><text class="record-note">自填信息未经核验;本页面不承诺额度、放款或获批。</text><text v-if="assessmentId.length > 0" class="link" @click="openCompare">查看同类产品对比</text><text v-if="assessmentId.length > 0" class="link" @click="toMatches">返回本次匹配</text><text v-else class="link" @click="history">选择评估查看匹配结果</text></view>
|
||||
</template>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view v-if="pageActive && product != null" class="action-bar" :style="bottomStyle(22)">
|
||||
<template v-if="match != null && canPrepare"><button class="footer-button secondary" @click="openCompare">查看同类产品对比</button><button class="footer-button primary" @click="prepare">准备申请</button></template>
|
||||
<template v-if="match != null && canPrepare"><button class="footer-button secondary" @click="consultAdvisor">咨询顾问</button><button class="footer-button primary" @click="prepare">申请办理</button></template>
|
||||
<template v-else-if="match != null"><button class="footer-button secondary" @click="switchTab(tab == 'details' ? 'explanation' : 'details')">{{ tab == 'details' ? '查看匹配解释' : '查看产品详情' }}</button><button class="footer-button primary" @click="consult">我有疑问,咨询AI</button></template>
|
||||
<button v-else class="footer-button primary" @click="switchTab(tab == 'conditions' ? 'details' : 'conditions')">{{ tab == 'conditions' ? '查看产品详情' : '查看申请条件' }}</button>
|
||||
</view>
|
||||
@@ -84,7 +84,7 @@
|
||||
import AppHeader from '@/components/AppHeader.uvue'
|
||||
import { usePageLayout } from '@/services/layout.uts'
|
||||
import { getSession } from '@/services/api.uts'
|
||||
import { MatchView, MatchReason, MatchDetail, ProductView, fetchMatchDetailRecord, fetchPublicProduct, validRecordId, requestProductExplanation } from '@/packages/finance/services/matches.uts'
|
||||
import { MatchView, MatchReason, MatchDetail, ProductView, fetchMatchDetailRecord, fetchPublicProduct, validRecordId, requestProductExplanation, hasProductValue } from '@/packages/finance/services/matches.uts'
|
||||
import { parseCompareIds, compareSelection, saveCompareSelection, compareQuery, sameMatchSnapshot, matchReturnPath } from '@/packages/finance/services/compare.uts'
|
||||
import { assistantRoute } from '@/packages/finance/services/assistant.uts'
|
||||
const { pageStyle, contentStyle, bottomStyle } = usePageLayout()
|
||||
@@ -189,6 +189,13 @@
|
||||
uni.redirectTo({ url: '/packages/finance/product/product' + query + 'productId=' + productId.value + '&tab=' + value + '&from=' + from })
|
||||
}
|
||||
// 下一步页重新核对当前可用性,避免沿用产品详情进入时的旧状态。
|
||||
const consultAdvisor = () => {
|
||||
if (!ready() || product.value == null) return
|
||||
if (match.value != null && match.value!.availability != 'available') { uni.showToast({ title: '产品当前不可用,请联系平台核对。', icon: 'none' }); return }
|
||||
const phone = product.value!.consultPhone
|
||||
if (phone.length == 0) { uni.showToast({ title: '暂未配置顾问电话,请联系平台。', icon: 'none' }); return }
|
||||
uni.makePhoneCall({ phoneNumber: phone })
|
||||
}
|
||||
const prepare = () => { if (ready() && canPrepare.value) uni.navigateTo({ url: '/packages/finance/next-step/next-step?assessmentId=' + assessmentId.value + (revisionId.value.length > 0 ? '&revisionId=' + revisionId.value : '') + '&productId=' + productId.value + '§ion=prepare' }) }
|
||||
const back = () => { if (owner.length > 0 && !current(generation, owner)) return; if (getCurrentPages().length > 1) uni.navigateBack(); else if (from == 'compare') uni.redirectTo({ url: '/packages/finance/compare/compare' + compareQuery(assessmentId.value, selectedIds.value, revisionId.value) }); else toMatches() }
|
||||
const openCompare = () => {
|
||||
@@ -238,6 +245,9 @@
|
||||
.state { font-size: 24rpx; line-height: 36rpx; margin-top: 5rpx; }
|
||||
.product-name { color: #788294; font-size: 24rpx; line-height: 36rpx; margin-top: 3rpx; }
|
||||
.demo { color: #8d96a4; font-size: 21rpx; line-height: 32rpx; margin-top: 10rpx; }
|
||||
.product-summary { flex-direction: row; flex-wrap: wrap; margin-top: 12rpx; }
|
||||
.summary-tag { color: #1670ed; background-color: #edf4ff; font-size: 23rpx; line-height: 38rpx; padding: 4rpx 12rpx; border-radius: 6rpx; margin-right: 10rpx; margin-top: 6rpx; }
|
||||
.material-item { margin-top: 12rpx; }
|
||||
.tabs { flex-direction: row; border-bottom: 1rpx solid #e8edf4; margin-top: 18rpx; }
|
||||
.tab { flex: 1; align-items: center; padding: 22rpx 0; }
|
||||
.active { border-bottom: 4rpx solid #0868f7; }
|
||||
|
||||
Reference in New Issue
Block a user