|
|
@@ -43,8 +43,24 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
+ <!-- 采集中:上传成功后后台解析,页面需展示进度,避免看起来像卡住 -->
|
|
|
+ <view class="collecting-panel" v-if="collecting">
|
|
|
+ <view class="collecting-card">
|
|
|
+ <view class="collecting-icon">
|
|
|
+ <view class="spinner" v-if="!collectError"></view>
|
|
|
+ <text class="collecting-fail-mark" v-else>!</text>
|
|
|
+ </view>
|
|
|
+ <view class="collecting-info">
|
|
|
+ <text class="collecting-title">{{ collectError ? '采集失败' : '数据采集中' }}</text>
|
|
|
+ <text class="collecting-file">{{ collectFileName || '健康报告' }}</text>
|
|
|
+ <text class="collecting-hint">{{ collectError || '后台正在解析报告,完成后自动入库,无需重复上传' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="collecting-btn" @click="goReportList">去报告列表查看</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
<!-- 上传方式 -->
|
|
|
- <view class="upload-methods" v-if="reportKind">
|
|
|
+ <view class="upload-methods" v-if="reportKind && !collecting">
|
|
|
<view class="upload-card card-file" @click="pickFile">
|
|
|
<view class="upload-card-icon">📄</view>
|
|
|
<text class="upload-card-title">从聊天选择文件</text>
|
|
|
@@ -207,7 +223,11 @@ export default {
|
|
|
showKindSheet: false,
|
|
|
pendingIsPhoto: false,
|
|
|
collectDraftId: null,
|
|
|
- collectTimer: null
|
|
|
+ collectTimer: null,
|
|
|
+ collecting: false,
|
|
|
+ collectFileName: '',
|
|
|
+ collectError: '',
|
|
|
+ collectPollCount: 0
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -245,10 +265,7 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
onUnload: function() {
|
|
|
- if (this.collectTimer) {
|
|
|
- clearInterval(this.collectTimer)
|
|
|
- this.collectTimer = null
|
|
|
- }
|
|
|
+ this.stopCollectPolling()
|
|
|
},
|
|
|
methods: {
|
|
|
selectReportKind: function(kind) {
|
|
|
@@ -399,7 +416,9 @@ export default {
|
|
|
return
|
|
|
}
|
|
|
self.collectDraftId = draftId
|
|
|
- uni.showToast({ title: '数据采集中,完成后可在报告列表查看', icon: 'none', duration: 3000 })
|
|
|
+ self.collecting = true
|
|
|
+ self.collectError = ''
|
|
|
+ self.collectFileName = (self.selectedFile && (self.selectedFile.name || self.selectedFile.path)) || '健康报告'
|
|
|
self.startCollectPolling(draftId)
|
|
|
}).catch(function(err) {
|
|
|
uni.hideLoading()
|
|
|
@@ -408,29 +427,62 @@ export default {
|
|
|
uni.showToast({ title: msg, icon: 'none' })
|
|
|
})
|
|
|
},
|
|
|
- // 轮询采集状态,完成后仅提示,用户可前往报告列表查看
|
|
|
+ stopCollectPolling: function() {
|
|
|
+ if (this.collectTimer) {
|
|
|
+ clearInterval(this.collectTimer)
|
|
|
+ this.collectTimer = null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 轮询采集状态:立即查一次,再每 4 秒查,完成后跳转详情/列表
|
|
|
startCollectPolling: function(draftId) {
|
|
|
var self = this
|
|
|
- if (self.collectTimer) {
|
|
|
- clearInterval(self.collectTimer)
|
|
|
- }
|
|
|
+ self.stopCollectPolling()
|
|
|
+ self.collectPollCount = 0
|
|
|
+ self.pollCollectStatus(draftId)
|
|
|
self.collectTimer = setInterval(function() {
|
|
|
- getReportCollectStatus(draftId).then(function(res) {
|
|
|
- var data = res.data || {}
|
|
|
- var status = data.parseStatus
|
|
|
- if (status === 'completed' || status === 'failed') {
|
|
|
- clearInterval(self.collectTimer)
|
|
|
- self.collectTimer = null
|
|
|
- if (status === 'completed') {
|
|
|
- uni.showToast({ title: '报告已采集完成', icon: 'success', duration: 2000 })
|
|
|
+ self.pollCollectStatus(draftId)
|
|
|
+ }, 4000)
|
|
|
+ },
|
|
|
+ pollCollectStatus: function(draftId) {
|
|
|
+ var self = this
|
|
|
+ self.collectPollCount = (self.collectPollCount || 0) + 1
|
|
|
+ // 约 6 分钟仍未完成:停轮询,提示去列表看进度(后台任务可能仍在跑)
|
|
|
+ if (self.collectPollCount > 90) {
|
|
|
+ self.stopCollectPolling()
|
|
|
+ self.collectError = '解析耗时较长,可去报告列表查看进度,无需重复上传'
|
|
|
+ return
|
|
|
+ }
|
|
|
+ getReportCollectStatus(draftId).then(function(res) {
|
|
|
+ var data = res.data || {}
|
|
|
+ var status = data.parseStatus
|
|
|
+ if (status === 'completed') {
|
|
|
+ self.stopCollectPolling()
|
|
|
+ self.collecting = false
|
|
|
+ uni.showToast({ title: '报告已采集完成', icon: 'success', duration: 2000 })
|
|
|
+ var reportId = data.reportId
|
|
|
+ var reportType = data.reportType || 'gut_flora'
|
|
|
+ setTimeout(function() {
|
|
|
+ if (reportId) {
|
|
|
+ var url = reportType === 'gut_flora'
|
|
|
+ ? '/pages/health/gut-flora-detail?reportId=' + reportId
|
|
|
+ : '/pages/health/report-detail?reportType=' + reportType + '&reportId=' + reportId
|
|
|
+ uni.redirectTo({ url: url })
|
|
|
} else {
|
|
|
- uni.showToast({ title: (data.parseError || '报告采集失败,请重试'), icon: 'none', duration: 3000 })
|
|
|
+ uni.redirectTo({ url: '/pages/health/report-list' })
|
|
|
}
|
|
|
- }
|
|
|
- }).catch(function() {
|
|
|
- // 轮询失败静默,下次继续
|
|
|
- })
|
|
|
- }, 4000)
|
|
|
+ }, 600)
|
|
|
+ } else if (status === 'failed') {
|
|
|
+ self.stopCollectPolling()
|
|
|
+ self.collectError = data.parseError || '报告采集失败,请重试'
|
|
|
+ uni.showToast({ title: self.collectError, icon: 'none', duration: 3000 })
|
|
|
+ }
|
|
|
+ }).catch(function() {
|
|
|
+ // 轮询失败静默,下次继续
|
|
|
+ })
|
|
|
+ },
|
|
|
+ goReportList: function() {
|
|
|
+ this.stopCollectPolling()
|
|
|
+ uni.redirectTo({ url: '/pages/health/report-list' })
|
|
|
},
|
|
|
// DAN测评:parse-preview → 预览确认页
|
|
|
uploadDanAndGoPreview: function(filePath) {
|
|
|
@@ -699,6 +751,82 @@ export default {
|
|
|
line-height: 1.6;
|
|
|
}
|
|
|
|
|
|
+.collecting-panel {
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+.collecting-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: flex-start;
|
|
|
+ background: #FFF8E6;
|
|
|
+ border: 1rpx solid #F5D78E;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 28rpx 24rpx;
|
|
|
+}
|
|
|
+.collecting-icon {
|
|
|
+ width: 56rpx;
|
|
|
+ height: 56rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #F0B429;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-right: 20rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.spinner {
|
|
|
+ width: 28rpx;
|
|
|
+ height: 28rpx;
|
|
|
+ border: 4rpx solid rgba(255,255,255,0.4);
|
|
|
+ border-top-color: #fff;
|
|
|
+ border-radius: 50%;
|
|
|
+ animation: collecting-spin 1s linear infinite;
|
|
|
+}
|
|
|
+@keyframes collecting-spin {
|
|
|
+ 0% { transform: rotate(0deg); }
|
|
|
+ 100% { transform: rotate(360deg); }
|
|
|
+}
|
|
|
+.collecting-fail-mark {
|
|
|
+ font-size: 32rpx;
|
|
|
+ color: #fff;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+.collecting-info {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+.collecting-title {
|
|
|
+ font-size: 30rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #7A5C00;
|
|
|
+}
|
|
|
+.collecting-file {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #A08A45;
|
|
|
+ margin-top: 6rpx;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.collecting-hint {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #C0A75A;
|
|
|
+ margin-top: 8rpx;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+.collecting-btn {
|
|
|
+ margin-top: 20rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ text-align: center;
|
|
|
+ background: #5B9BD5;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 28rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+}
|
|
|
+
|
|
|
.upload-methods {
|
|
|
display: flex;
|
|
|
flex-direction: row;
|