| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- <template>
- <view class="container">
- <!-- 顶部导航 -->
- <!-- 加载状态 -->
- <view class="loading" v-if="loading">加载中...</view>
- <!-- 报告内容 -->
- <template v-else-if="report">
- <!-- 报告头部 -->
- <view class="report-header">
- <view class="report-type-badge" :class="'badge-' + report.reportType">
- <text>{{ typeLabel }}</text>
- </view>
- <text class="report-date">{{ formatDate(report.reportDate) }}</text>
- </view>
- <!-- 综合评分 -->
- <view class="score-section" v-if="report.overallScore">
- <view class="score-circle">
- <text class="score-value">{{ report.overallScore }}</text>
- <text class="score-unit">分</text>
- </view>
- <view class="score-level">
- <text class="level-text">{{ scoreLevel }}</text>
- </view>
- </view>
- <!-- 报告内容 -->
- <view class="report-content">
- <mp-html :content="report.content || ''" />
- </view>
- <!-- 报告附件 -->
- <view class="report-attachment" v-if="report.fileUrl">
- <view class="attachment-label">
- <text>原始报告</text>
- <text class="attachment-size">{{ report.fileSize || '' }}</text>
- </view>
- <button class="attachment-btn" @click="downloadFile">查看原文件</button>
- </view>
- </template>
- <!-- 空状态 -->
- <view v-else class="empty-state">
- <text class="empty-icon">📋</text>
- <text class="empty-title">报告不存在</text>
- <text class="empty-desc">该报告可能已被删除</text>
- <view class="empty-btn" @click="goBack">返回</view>
- </view>
- </view>
- </template>
- <script>
- import MpHtml from '@/components/mp-html/mp-html.vue'
- import { getReportDetail } from '@/utils/api'
- import { parseDate } from '@/utils/format'
- export default {
- components: { MpHtml },
- data() {
- return {
- reportId: null,
- report: null,
- loading: true
- }
- },
- computed: {
- typeLabel() {
- const labels = {
- 'physical_exam': '体检报告',
- 'gut_flora': '肠道检测',
- 'tongue': '舌诊报告'
- }
- return labels[this.report.reportType] || '健康报告'
- },
- scoreLevel() {
- const score = this.report.overallScore
- if (!score) return '--'
- if (score >= 90) return '优秀'
- if (score >= 80) return '良好'
- if (score >= 70) return '一般'
- return '需关注'
- }
- },
- onLoad(options) {
- this.reportId = options.reportId
- if (this.reportId) {
- this.loadReport()
- } else {
- this.loading = false
- }
- },
- methods: {
- loadReport() {
- this.loading = true
- getReportDetail(this.reportId).then(res => {
- if (res.code === 200 && res.data) {
- this.report = res.data
- }
- }).catch(() => {
- uni.showToast({ title: '加载失败', icon: 'none' })
- }).finally(() => {
- this.loading = false
- })
- },
- formatDate(dateStr) {
- if (!dateStr) return '--'
- const d = parseDate(dateStr)
- if (!d) return dateStr
- const y = d.getFullYear()
- const m = ('' + (d.getMonth() + 1)).padStart(2, '0')
- const day = ('' + d.getDate()).padStart(2, '0')
- return y + '-' + m + '-' + day
- },
- downloadFile() {
- if (!this.report.fileUrl) return
- uni.downloadFile({
- url: this.report.fileUrl,
- success: (res) => {
- if (res.statusCode === 200) {
- uni.openDocument({
- filePath: res.tempFilePath,
- fileType: this.getFileType(),
- success: () => {},
- fail: () => {
- uni.showToast({ title: '打开失败', icon: 'none' })
- }
- })
- }
- },
- fail: () => {
- uni.showToast({ title: '下载失败', icon: 'none' })
- }
- })
- },
- getFileType() {
- const url = this.report.fileUrl || ''
- if (url.includes('.pdf')) return 'pdf'
- if (url.includes('.jpg') || url.includes('.jpeg')) return 'jpg'
- if (url.includes('.png')) return 'png'
- return 'pdf'
- },
- goBack() {
- uni.navigateBack()
- }
- }
- }
- </script>
- <style scoped>
- .container {
- min-height: 100vh;
- background: #f5f7fa;
- }
- .nav-placeholder {
- width: 60rpx;
- }
- .loading {
- text-align: center;
- padding: 100rpx;
- color: #999;
- }
- .report-header {
- background: #fff;
- padding: 30rpx;
- margin-bottom: 20rpx;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .report-type-badge {
- padding: 8rpx 20rpx;
- border-radius: 20rpx;
- font-size: 24rpx;
- font-weight: 600;
- }
- .badge-physical_exam {
- background: #e6f7ff;
- color: #1890ff;
- }
- .badge-gut_flora {
- background: #f6ffed;
- color: #52c41a;
- }
- .badge-tongue {
- background: #fff7e6;
- color: #fa8c16;
- }
- .report-date {
- font-size: 26rpx;
- color: #999;
- }
- .score-section {
- background: #fff;
- padding: 40rpx;
- margin-bottom: 20rpx;
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .score-circle {
- position: relative;
- width: 160rpx;
- height: 160rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .score-value {
- font-size: 48rpx;
- font-weight: 700;
- color: #333;
- }
- .score-unit {
- position: absolute;
- bottom: 20rpx;
- right: 30rpx;
- font-size: 24rpx;
- color: #999;
- }
- .score-level {
- margin-top: 16rpx;
- }
- .level-text {
- font-size: 28rpx;
- color: #666;
- }
- .report-content {
- background: #fff;
- padding: 30rpx;
- margin-bottom: 20rpx;
- min-height: 200rpx;
- }
- .report-attachment {
- background: #fff;
- padding: 30rpx;
- margin-bottom: 40rpx;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .attachment-label {
- display: flex;
- flex-direction: column;
- }
- .attachment-label text:first-child {
- font-size: 28rpx;
- color: #333;
- font-weight: 500;
- }
- .attachment-size {
- font-size: 22rpx;
- color: #999;
- margin-top: 4rpx;
- }
- .attachment-btn {
- background: #f97316;
- color: #fff;
- font-size: 24rpx;
- padding: 12rpx 30rpx;
- border-radius: 20rpx;
- border: none;
- }
- .empty-state {
- text-align: center;
- padding: 120rpx 40rpx;
- }
- .empty-icon {
- font-size: 80rpx;
- display: block;
- margin-bottom: 20rpx;
- }
- .empty-title {
- font-size: 32rpx;
- font-weight: 600;
- color: #333;
- display: block;
- margin-bottom: 12rpx;
- }
- .empty-desc {
- font-size: 26rpx;
- color: #999;
- display: block;
- margin-bottom: 40rpx;
- }
- .empty-btn {
- display: inline-block;
- background: #f97316;
- color: #fff;
- font-size: 28rpx;
- padding: 16rpx 60rpx;
- border-radius: 40rpx;
- }
- </style>
|