Files
airz-uniapp/packages/finance/archive/archive.uvue
T

118 lines
8.5 KiB
Plaintext
Raw Normal View History

2026-09-10 10:57:40 +08:00
<template>
<view class="page" :style="pageStyle()">
<AppHeader :title="selectedId.length > 0 ? '评估记录详情' : '我的融资档案'" :customBack="selectedId.length > 0" @back="backToList" />
<scroll-view scroll-y :style="contentStyle(0, false)">
<view class="archive-content">
<text class="archive-title">{{ selectedId.length > 0 ? '已提交的评估资料' : '已提交的评估记录' }}</text>
<text class="archive-note">提交后的资料不可修改;再次评估请新建记录。未提交的填写内容不会保存。</text>
<view v-if="selectedId.length == 0" class="start-actions">
<button class="primary-button start-button" @click="start('personal')">个人评估</button>
<button class="primary-button start-button" @click="start('enterprise')">企业评估</button>
</view>
<view v-if="error.length > 0" class="notice"><text>{{ error }}</text><text class="action" @click="refresh">重试加载</text></view>
<text v-if="loading" class="archive-note">正在加载…</text>
<template v-if="selectedId.length > 0 && detail != null">
<text class="record-title">{{ detail!.record.type == 'personal' ? '个人' : '企业' }}评估 · #{{ detail!.record.id }}</text>
<text class="record-status">{{ detail!.record.statusLabel }}</text>
<text class="archive-note">{{ detail!.record.message }}</text>
<text class="record-time">提交时间:{{ detail!.record.submittedAt }}</text>
<text class="action" @click="openAnalysis">{{ detail!.record.status == 'succeeded' ? '查看分析报告' : '查看分析状态 / 重试' }}</text>
<view class="detail-row" v-for="field in detail!.fields" :key="field.label"><text class="field-label">{{ field.label }}</text><text class="field-value">{{ field.value }}</text></view>
<text class="action" @click="backToList">返回记录列表</text>
</template>
<template v-if="selectedId.length == 0">
<text v-if="!loading && error.length == 0 && records.length == 0" class="empty-state">暂无已提交的评估记录</text>
<view class="record-card" v-for="item in records" :key="item.id" @click="openRecord(item.id)">
<text class="record-title">{{ item.type == 'personal' ? '个人' : '企业' }}评估 · #{{ item.id }}</text>
<text class="record-status">{{ item.statusLabel }}</text>
<text class="record-time">{{ item.city }} · {{ item.submittedAt }}</text>
<text class="action">查看已提交资料</text>
</view>
<text v-if="hasMore && !loading" class="action" @click="loadMore">加载更多</text>
<text v-if="records.length > 0 && !hasMore && !loading" class="archive-note">已显示全部记录</text>
</template>
</view>
</scroll-view>
</view>
2026-09-10 10:57:40 +08:00
</template>
<script setup lang="uts">
import AppHeader from '@/components/AppHeader.uvue'
import { usePageLayout } from '@/services/layout.uts'
import { getSession } from '@/services/api.uts'
import { clearAssessmentFlow } from '@/services/assessment-flow.uts'
import { AssessmentRecord, AssessmentDetail, fetchAssessments, fetchAssessmentDetail } from '@/packages/finance/services/records.uts'
const { pageStyle, contentStyle } = usePageLayout()
const records = ref<AssessmentRecord[]>([])
const detail = ref<AssessmentDetail | null>(null)
const selectedId = ref(''); const loading = ref(false); const error = ref(''); const hasMore = ref(false)
let cursor = ''; let generation = 0; let visible = false
const sameOwner = (token: string): boolean => { const session = getSession(); return session != null && session['token'] == token }
const refresh = async () => {
const session = getSession()
if (session == null) { records.value = []; detail.value = null; uni.redirectTo({ url: '/packages/account/login/login' }); return }
const owner = session['token'] as string
const request = ++generation
loading.value = true; error.value = ''
try {
if (selectedId.value.length > 0) {
const result = await fetchAssessmentDetail(selectedId.value)
if (visible && request == generation && sameOwner(owner)) detail.value = result
} else {
const result = await fetchAssessments('')
if (visible && request == generation && sameOwner(owner)) { records.value = result.items; hasMore.value = result.hasMore; cursor = result.nextCursor }
}
} catch (err) { if (visible && request == generation) error.value = err instanceof Error ? err.message : '加载失败,请重试' }
finally { if (request == generation) loading.value = false }
}
const loadMore = async () => {
if (loading.value || !hasMore.value) return
const session = getSession()
if (session == null) { refresh(); return }
const owner = session['token'] as string
const request = ++generation
loading.value = true; error.value = ''
try {
const result = await fetchAssessments(cursor)
if (visible && request == generation && sameOwner(owner)) {
const incoming = result.items.filter((item: AssessmentRecord): boolean => !records.value.some((old: AssessmentRecord): boolean => old.id == item.id))
records.value = records.value.concat(incoming); hasMore.value = result.hasMore; cursor = result.nextCursor
}
} catch (err) { if (visible && request == generation) error.value = err instanceof Error ? err.message : '加载失败,请重试' }
finally { if (request == generation) loading.value = false }
}
const start = (type: string) => { clearAssessmentFlow(); uni.navigateTo({ url: '/packages/finance/assessment/assessment?type=' + type }) }
const openRecord = (id: string) => { uni.navigateTo({ url: '/packages/finance/archive/archive?assessmentId=' + encodeURIComponent(id) }) }
const openAnalysis = () => {
const page = detail.value?.record.status == 'succeeded' ? 'report/report' : 'analyzing/analyzing'
uni.navigateTo({ url: '/packages/finance/' + page + '?assessmentId=' + encodeURIComponent(selectedId.value) })
}
const backToList = () => {
const pages = getCurrentPages()
if (pages.length > 1 && pages[pages.length - 2].route == 'packages/finance/archive/archive') uni.navigateBack()
else uni.redirectTo({ url: '/packages/finance/archive/archive' })
}
onBackPress((event): boolean => { if (event.from == 'navigateBack' || selectedId.value.length == 0) return false; backToList(); return true })
onLoad((options) => { if (options != null) selectedId.value = options['assessmentId'] ?? '' })
onShow(() => { visible = true; refresh() })
// 离开时清空敏感详情;迟到的请求不能把其他账户的数据写回页面。
onHide(() => { visible = false; generation++; records.value = []; detail.value = null })
onUnload(() => { visible = false; generation++ })
2026-09-10 10:57:40 +08:00
</script>
<style>
.archive-content { margin: 28rpx; padding: 30rpx; border-radius: 18rpx; background-color: #fff; }
.archive-title { font-size: 32rpx; font-weight: 600; color: #23344e; }
.archive-note { margin: 24rpx 0 30rpx; color: #738198; font-size: 26rpx; line-height: 42rpx; }
.start-actions { flex-direction: row; margin-bottom: 20rpx; }
.start-button { flex: 1; margin: 6rpx; font-size: 27rpx; }
.record-card { padding: 28rpx 0; border-bottom: 1rpx solid #edf1f6; }
.record-title { font-size: 30rpx; font-weight: 600; color: #23344e; }
.record-status { margin-top: 16rpx; color: #0868f7; font-size: 27rpx; }
.record-time { margin-top: 14rpx; color: #738198; font-size: 23rpx; line-height: 36rpx; }
.action { color: #0868f7; font-size: 27rpx; padding: 24rpx 0; }
.notice { color: #ad432d; font-size: 27rpx; line-height: 40rpx; }
.empty-state { padding: 50rpx 0; color: #738198; font-size: 28rpx; }
.detail-row { flex-direction: row; padding: 24rpx 0; border-bottom: 1rpx solid #edf1f6; }
.field-label { width: 210rpx; font-size: 26rpx; color: #738198; }
.field-value { flex: 1; text-align: right; font-size: 27rpx; color: #23344e; }
2026-09-10 10:57:40 +08:00
</style>