|
|
@@ -3,47 +3,30 @@
|
|
|
<!-- 说明提示 -->
|
|
|
<view class="tip-banner">
|
|
|
<text class="tip-icon">📋</text>
|
|
|
- <text class="tip-text">{{ tipText }}</text>
|
|
|
+ <text class="tip-text">上传体检/菌群/DAN测评等报告,后台自动识别类型并解析</text>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 表单 -->
|
|
|
+ <!-- 上传方式 -->
|
|
|
<view class="form-section">
|
|
|
- <!-- 步骤1:报告大类 -->
|
|
|
- <view class="form-item category-box">
|
|
|
- <text class="form-label">选择报告类型</text>
|
|
|
- <view class="category-row">
|
|
|
- <view
|
|
|
- :class="['category-card', reportKind === 'health' ? 'category-active' : '']"
|
|
|
- @click="selectReportKind('health')">
|
|
|
- <text class="category-icon">🏥</text>
|
|
|
- <text class="category-title">健康报告</text>
|
|
|
- <text class="category-desc">体检 / 菌群 / 舌诊 / 体脂</text>
|
|
|
- </view>
|
|
|
- <view
|
|
|
- :class="['category-card', reportKind === 'dan' ? 'category-active category-dan' : '']"
|
|
|
- @click="selectReportKind('dan')">
|
|
|
- <text class="category-icon">🧠</text>
|
|
|
- <text class="category-title">DAN测评</text>
|
|
|
- <text class="category-desc">A2 / B4 等成长测评</text>
|
|
|
- </view>
|
|
|
+ <view class="upload-methods">
|
|
|
+ <view class="upload-card card-chat" @click="pickFromChat">
|
|
|
+ <view class="upload-card-icon">💬</view>
|
|
|
+ <text class="upload-card-title">从聊天选取</text>
|
|
|
+ <text class="upload-card-desc">微信聊天中的 PDF/图片</text>
|
|
|
</view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 步骤2:DAN 维度(仅 DAN) -->
|
|
|
- <view class="form-item" v-if="reportKind === 'dan'">
|
|
|
- <text class="form-label">选择 DAN 测评维度</text>
|
|
|
- <view class="dim-grid">
|
|
|
- <view
|
|
|
- v-for="item in danDimensions"
|
|
|
- :key="item.code"
|
|
|
- :class="['dim-chip', danDimension === item.code ? 'dim-active' : '']"
|
|
|
- @click="selectDanDimension(item.code)">
|
|
|
- <text class="dim-chip-text">{{ item.label }}</text>
|
|
|
- </view>
|
|
|
+ <view class="upload-card card-photo" @click="takePhoto">
|
|
|
+ <view class="upload-card-icon">📷</view>
|
|
|
+ <text class="upload-card-title">拍照上传</text>
|
|
|
+ <text class="upload-card-desc">拍摄纸质报告或舌象</text>
|
|
|
+ </view>
|
|
|
+ <view class="upload-card card-folder" @click="pickFromFolder">
|
|
|
+ <view class="upload-card-icon">📁</view>
|
|
|
+ <text class="upload-card-title">从文件夹选取</text>
|
|
|
+ <text class="upload-card-desc">手机本地文件</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 采集中:上传成功后后台解析,页面需展示进度,避免看起来像卡住 -->
|
|
|
+ <!-- 采集中面板 -->
|
|
|
<view class="collecting-panel" v-if="collecting">
|
|
|
<view class="collecting-card">
|
|
|
<view class="collecting-icon">
|
|
|
@@ -52,35 +35,22 @@
|
|
|
</view>
|
|
|
<view class="collecting-info">
|
|
|
<text class="collecting-title">{{ collectError ? '采集失败' : '数据采集中' }}</text>
|
|
|
- <text class="collecting-file">{{ collectFileName || '健康报告' }}</text>
|
|
|
- <text class="collecting-hint">{{ 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 && !collecting">
|
|
|
- <view class="upload-card card-file" @click="pickFile">
|
|
|
- <view class="upload-card-icon">📄</view>
|
|
|
- <text class="upload-card-title">从聊天选择文件</text>
|
|
|
- <text class="upload-card-desc" v-if="reportKind === 'health'">PDF / 图片<br/>体检、菌群等健康报告</text>
|
|
|
- <text class="upload-card-desc" v-else>PDF<br/>DAN 测评报告(推荐)</text>
|
|
|
- </view>
|
|
|
- <view class="upload-card card-photo" @click="takePhoto" v-if="reportKind === 'health'">
|
|
|
- <view class="upload-card-icon">📷</view>
|
|
|
- <text class="upload-card-title">拍照上传</text>
|
|
|
- <text class="upload-card-desc">拍摄舌象照片<br/>或单页纸质报告</text>
|
|
|
- </view>
|
|
|
- <view class="upload-card card-photo" @click="goBodyFatScale" v-if="reportKind === 'health'">
|
|
|
- <view class="upload-card-icon">⚖️</view>
|
|
|
- <text class="upload-card-title">体脂秤</text>
|
|
|
- <text class="upload-card-desc">拍摄体脂秤<br/>显示屏照片</text>
|
|
|
+ <view class="collecting-actions">
|
|
|
+ <view class="collecting-btn" @click="goReportList">去报告列表查看</view>
|
|
|
+ <view class="collecting-cancel" @click="cancelCollect">取消</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <view class="kind-hint" v-if="!reportKind">
|
|
|
- <text class="kind-hint-text">请先选择「健康报告」或「DAN测评」,再上传文件</text>
|
|
|
+ <!-- 上传中 -->
|
|
|
+ <view class="form-item" v-if="uploading">
|
|
|
+ <text class="form-label">上传中...</text>
|
|
|
+ <view class="analyzing-status">
|
|
|
+ <text class="analyzing-text">{{ uploadingText }}</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 责任声明 -->
|
|
|
@@ -95,23 +65,15 @@
|
|
|
<text class="disclaimer-text">我同意平台使用本报告数据进行分析,为我提供个性化健康解决方案;未经我授权,平台不会以任何形式将我的报告内容提供给其他任何个人或机构。</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
-
|
|
|
- <!-- 上传中 -->
|
|
|
- <view class="form-item" v-if="uploading">
|
|
|
- <text class="form-label">上传中...</text>
|
|
|
- <view class="analyzing-status">
|
|
|
- <text class="analyzing-text">{{ uploadingText }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 上传说明:随类型切换 -->
|
|
|
+ <!-- 上传说明 -->
|
|
|
<view class="guide-section">
|
|
|
<view class="guide-header">
|
|
|
<text class="guide-header-icon">📖</text>
|
|
|
- <text class="guide-header-title">{{ reportKind === 'dan' ? 'DAN 测评说明' : '健康报告说明' }}</text>
|
|
|
+ <text class="guide-header-title">支持的报告类型</text>
|
|
|
</view>
|
|
|
- <view class="guide-list" v-if="reportKind !== 'dan'">
|
|
|
+ <view class="guide-list">
|
|
|
<view class="guide-item">
|
|
|
<view class="guide-icon-box guide-icon-blue"><text class="guide-icon">📄</text></view>
|
|
|
<view class="guide-info">
|
|
|
@@ -126,6 +88,13 @@
|
|
|
<text class="guide-desc">支持 PDF 或清晰照片,AI 自动解读菌群健康</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
+ <view class="guide-item">
|
|
|
+ <view class="guide-icon-box guide-icon-purple"><text class="guide-icon">🧠</text></view>
|
|
|
+ <view class="guide-info">
|
|
|
+ <text class="guide-name">DAN 测评报告</text>
|
|
|
+ <text class="guide-desc">A2/B4 等成长测评 PDF,自动解析维度数据</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
<view class="guide-item">
|
|
|
<view class="guide-icon-box guide-icon-orange"><text class="guide-icon">👅</text></view>
|
|
|
<view class="guide-info">
|
|
|
@@ -141,87 +110,26 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <view class="guide-list" v-else>
|
|
|
- <view class="guide-item">
|
|
|
- <view class="guide-icon-box guide-icon-teal"><text class="guide-icon">💖</text></view>
|
|
|
- <view class="guide-info">
|
|
|
- <text class="guide-name">心维度 A2</text>
|
|
|
- <text class="guide-desc">人格、情绪、自我概念与自驱力等心理测评报告</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="guide-item">
|
|
|
- <view class="guide-icon-box guide-icon-purple"><text class="guide-icon">🧠</text></view>
|
|
|
- <view class="guide-info">
|
|
|
- <text class="guide-name">智维度 B4</text>
|
|
|
- <text class="guide-desc">认知能力、学习力等双培强基 DAN 智维度报告</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="guide-item">
|
|
|
- <view class="guide-icon-box guide-icon-blue"><text class="guide-icon">📚</text></view>
|
|
|
- <view class="guide-info">
|
|
|
- <text class="guide-name">其他 DAN 维度</text>
|
|
|
- <text class="guide-desc">认知 / 学习 / 行为 / 生涯 / 校园 / 青春期等专项报告</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
<view class="guide-tips">
|
|
|
<text class="guide-tips-title">温馨提示</text>
|
|
|
- <text class="guide-tips-item">· 请先选择报告类型,再选择文件上传</text>
|
|
|
- <text class="guide-tips-item">· 健康报告走菌群/体检解析;DAN 走测评维度解析</text>
|
|
|
+ <text class="guide-tips-item">· 上传后系统自动识别报告类型,无需手动选择</text>
|
|
|
+ <text class="guide-tips-item">· 请确保报告清晰完整,以便准确解析</text>
|
|
|
<text class="guide-tips-item">· 确认入库后将自动生成成长方案,可再分解为每日任务</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
-
|
|
|
- <!-- 点击上传后的类型选择弹层(未预选时兜底) -->
|
|
|
- <view class="sheet-mask" v-if="showKindSheet" @click="closeKindSheet">
|
|
|
- <view class="sheet-panel" @click.stop>
|
|
|
- <text class="sheet-title">请选择要上传的报告</text>
|
|
|
- <view class="sheet-item" @click="onKindSheetPick('health')">
|
|
|
- <text class="sheet-item-title">健康报告</text>
|
|
|
- <text class="sheet-item-desc">体检、肠道菌群、舌诊、体脂等</text>
|
|
|
- </view>
|
|
|
- <view class="sheet-item" @click="onKindSheetPick('dan')">
|
|
|
- <text class="sheet-item-title">DAN测评</text>
|
|
|
- <text class="sheet-item-desc">A2 / B4 等成长测评 PDF</text>
|
|
|
- </view>
|
|
|
- <view class="sheet-cancel" @click="closeKindSheet">
|
|
|
- <text class="sheet-cancel-text">取消</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { uploadReportOnly, danParsePreview, getReportCollectStatus } from '../../utils/api.js'
|
|
|
-import config from '@/config.js'
|
|
|
-
|
|
|
-var DAN_DIMENSIONS = [
|
|
|
- { code: 'mind', label: '心 A2' },
|
|
|
- { code: 'wisdom', label: '智 B4' },
|
|
|
- { code: 'cognition', label: '认知' },
|
|
|
- { code: 'learning', label: '学习' },
|
|
|
- { code: 'behavior', label: '行为' },
|
|
|
- { code: 'career', label: '生涯' },
|
|
|
- { code: 'campus', label: '校园' },
|
|
|
- { code: 'adolescent', label: '青春期' }
|
|
|
-]
|
|
|
+import { uploadReportOnly, getReportCollectStatus } from '../../utils/api.js'
|
|
|
|
|
|
export default {
|
|
|
data() {
|
|
|
return {
|
|
|
memberId: null,
|
|
|
uploading: false,
|
|
|
- selectedFile: null,
|
|
|
- photoPath: null,
|
|
|
agreedToTerms: false,
|
|
|
- currentMemberId: null,
|
|
|
- extractedMetrics: [],
|
|
|
- reportKind: '',
|
|
|
- danDimension: 'mind',
|
|
|
- danDimensions: DAN_DIMENSIONS,
|
|
|
- showKindSheet: false,
|
|
|
- pendingIsPhoto: false,
|
|
|
+ uploadingText: '正在上传文件...',
|
|
|
collectDraftId: null,
|
|
|
collectTimer: null,
|
|
|
collecting: false,
|
|
|
@@ -230,53 +138,13 @@ export default {
|
|
|
collectPollCount: 0
|
|
|
}
|
|
|
},
|
|
|
- computed: {
|
|
|
- tipText: function() {
|
|
|
- if (this.reportKind === 'dan') {
|
|
|
- return '上传 DAN 测评 PDF(A2/B4 等),解析确认后生成个性化成长方案'
|
|
|
- }
|
|
|
- if (this.reportKind === 'health') {
|
|
|
- return '上传体检/菌群/舌诊等健康报告,解析确认后生成个性化健康方案'
|
|
|
- }
|
|
|
- return '请先选择「健康报告」或「DAN测评」,再上传文件生成方案'
|
|
|
- },
|
|
|
- uploadingText: function() {
|
|
|
- return this.reportKind === 'dan'
|
|
|
- ? '正在解析 DAN 测评报告...'
|
|
|
- : '正在上传文件,即将进入分析页面...'
|
|
|
- }
|
|
|
- },
|
|
|
onLoad: function(options) {
|
|
|
this.memberId = options.memberId ? parseInt(options.memberId) : null
|
|
|
- if (options.reportKind === 'health' || options.reportKind === 'dan') {
|
|
|
- this.reportKind = options.reportKind
|
|
|
- }
|
|
|
- if (options.dimension) {
|
|
|
- var codes = DAN_DIMENSIONS.map(function(d) { return d.code })
|
|
|
- if (codes.indexOf(options.dimension) >= 0) {
|
|
|
- this.danDimension = options.dimension
|
|
|
- this.reportKind = 'dan'
|
|
|
- }
|
|
|
- }
|
|
|
- if (options.bodyFatMetrics) {
|
|
|
- try {
|
|
|
- this.extractedMetrics = JSON.parse(decodeURIComponent(options.bodyFatMetrics))
|
|
|
- } catch (e) {}
|
|
|
- }
|
|
|
},
|
|
|
onUnload: function() {
|
|
|
this.stopCollectPolling()
|
|
|
},
|
|
|
methods: {
|
|
|
- selectReportKind: function(kind) {
|
|
|
- this.reportKind = kind
|
|
|
- if (kind === 'dan' && !this.danDimension) {
|
|
|
- this.danDimension = 'mind'
|
|
|
- }
|
|
|
- },
|
|
|
- selectDanDimension: function(code) {
|
|
|
- this.danDimension = code
|
|
|
- },
|
|
|
toggleAgree: function() {
|
|
|
this.agreedToTerms = !this.agreedToTerms
|
|
|
},
|
|
|
@@ -299,115 +167,75 @@ export default {
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
- // 点击上传:未选类型时弹层;已选则直接走对应链路
|
|
|
- pickFile: function() {
|
|
|
+ pickFromChat: function() {
|
|
|
var self = this
|
|
|
this.ensureAgreed(function() {
|
|
|
- self.beginUpload(false)
|
|
|
+ uni.chooseMessageFile({
|
|
|
+ count: 1,
|
|
|
+ type: 'file',
|
|
|
+ extension: ['pdf'],
|
|
|
+ success: function(res) {
|
|
|
+ var files = res.tempFiles
|
|
|
+ if (files && files.length > 0) {
|
|
|
+ self.uploadReport(files[0].path, files[0].name || '聊天文件')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: function() {
|
|
|
+ // 用户取消或失败,静默处理
|
|
|
+ }
|
|
|
+ })
|
|
|
})
|
|
|
},
|
|
|
takePhoto: function() {
|
|
|
var self = this
|
|
|
this.ensureAgreed(function() {
|
|
|
- self.beginUpload(true)
|
|
|
- })
|
|
|
- },
|
|
|
- beginUpload: function(isPhoto) {
|
|
|
- if (!this.reportKind) {
|
|
|
- this.pendingIsPhoto = isPhoto
|
|
|
- this.showKindSheet = true
|
|
|
- return
|
|
|
- }
|
|
|
- if (this.reportKind === 'dan') {
|
|
|
- if (!this.danDimension) {
|
|
|
- uni.showToast({ title: '请选择 DAN 测评维度', icon: 'none' })
|
|
|
- return
|
|
|
- }
|
|
|
- this.startPickDan()
|
|
|
- return
|
|
|
- }
|
|
|
- this.startPickHealth(isPhoto)
|
|
|
- },
|
|
|
- closeKindSheet: function() {
|
|
|
- this.showKindSheet = false
|
|
|
- },
|
|
|
- onKindSheetPick: function(kind) {
|
|
|
- this.reportKind = kind
|
|
|
- this.showKindSheet = false
|
|
|
- var isPhoto = this.pendingIsPhoto
|
|
|
- this.pendingIsPhoto = false
|
|
|
- if (kind === 'dan') {
|
|
|
- if (isPhoto) {
|
|
|
- uni.showToast({ title: 'DAN 请上传 PDF 文件', icon: 'none' })
|
|
|
- }
|
|
|
- this.startPickDan()
|
|
|
- return
|
|
|
- }
|
|
|
- this.startPickHealth(isPhoto)
|
|
|
- },
|
|
|
- startPickHealth: function(isPhoto) {
|
|
|
- var self = this
|
|
|
- if (isPhoto) {
|
|
|
uni.chooseImage({
|
|
|
count: 1,
|
|
|
sourceType: ['camera', 'album'],
|
|
|
success: function(res) {
|
|
|
- self.photoPath = res.tempFilePaths[0]
|
|
|
- self.uploadHealthAndGoConfirm(self.photoPath, 'image')
|
|
|
+ if (res.tempFilePaths && res.tempFilePaths.length > 0) {
|
|
|
+ self.uploadReport(res.tempFilePaths[0], '照片')
|
|
|
+ }
|
|
|
}
|
|
|
})
|
|
|
- } else {
|
|
|
+ })
|
|
|
+ },
|
|
|
+ pickFromFolder: function() {
|
|
|
+ var self = this
|
|
|
+ this.ensureAgreed(function() {
|
|
|
uni.chooseMessageFile({
|
|
|
count: 1,
|
|
|
type: 'file',
|
|
|
- extension: ['pdf'],
|
|
|
success: function(res) {
|
|
|
var files = res.tempFiles
|
|
|
if (files && files.length > 0) {
|
|
|
- self.selectedFile = files[0]
|
|
|
- self.uploadHealthAndGoConfirm(files[0].path, '')
|
|
|
+ self.uploadReport(files[0].path, files[0].name || '本地文件')
|
|
|
}
|
|
|
},
|
|
|
- fail: function(e) {
|
|
|
- console.log('选择文件取消或失败', e)
|
|
|
+ fail: function() {
|
|
|
+ // 降级到相册
|
|
|
+ uni.chooseImage({
|
|
|
+ count: 1,
|
|
|
+ sourceType: ['album'],
|
|
|
+ success: function(res) {
|
|
|
+ if (res.tempFilePaths && res.tempFilePaths.length > 0) {
|
|
|
+ self.uploadReport(res.tempFilePaths[0], '相册文件')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
})
|
|
|
- }
|
|
|
- },
|
|
|
- startPickDan: function() {
|
|
|
- var self = this
|
|
|
- uni.chooseMessageFile({
|
|
|
- count: 1,
|
|
|
- type: 'file',
|
|
|
- extension: ['pdf'],
|
|
|
- success: function(res) {
|
|
|
- var files = res.tempFiles
|
|
|
- if (files && files.length > 0) {
|
|
|
- self.selectedFile = files[0]
|
|
|
- self.uploadDanAndGoPreview(files[0].path)
|
|
|
- }
|
|
|
- },
|
|
|
- fail: function() {
|
|
|
- uni.chooseImage({
|
|
|
- count: 1,
|
|
|
- success: function(res) {
|
|
|
- if (res.tempFiles && res.tempFiles.length > 0) {
|
|
|
- self.selectedFile = res.tempFiles[0]
|
|
|
- var path = res.tempFiles[0].path || (res.tempFilePaths && res.tempFilePaths[0])
|
|
|
- self.uploadDanAndGoPreview(path)
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
})
|
|
|
},
|
|
|
- // 健康报告:upload-only → 后台异步采集(指纹判定→脚本/opencode),完成后自动入库
|
|
|
- uploadHealthAndGoConfirm: function(filePath, type) {
|
|
|
+ uploadReport: function(filePath, fileName) {
|
|
|
if (!filePath) return
|
|
|
var self = this
|
|
|
self.uploading = true
|
|
|
+ self.uploadingText = '正在上传文件...'
|
|
|
uni.showLoading({ title: '上传中...' })
|
|
|
- uploadReportOnly(filePath, type).then(function(res) {
|
|
|
+
|
|
|
+ // 不传 type,让后端通过指纹自动判断报告类型
|
|
|
+ uploadReportOnly(filePath).then(function(res) {
|
|
|
uni.hideLoading()
|
|
|
self.uploading = false
|
|
|
var draftId = res.data && res.data.draftId
|
|
|
@@ -418,7 +246,7 @@ export default {
|
|
|
self.collectDraftId = draftId
|
|
|
self.collecting = true
|
|
|
self.collectError = ''
|
|
|
- self.collectFileName = (self.selectedFile && (self.selectedFile.name || self.selectedFile.path)) || '健康报告'
|
|
|
+ self.collectFileName = fileName || '报告文件'
|
|
|
self.startCollectPolling(draftId)
|
|
|
}).catch(function(err) {
|
|
|
uni.hideLoading()
|
|
|
@@ -433,7 +261,6 @@ export default {
|
|
|
this.collectTimer = null
|
|
|
}
|
|
|
},
|
|
|
- // 轮询采集状态:立即查一次,再每 4 秒查,完成后跳转详情/列表
|
|
|
startCollectPolling: function(draftId) {
|
|
|
var self = this
|
|
|
self.stopCollectPolling()
|
|
|
@@ -446,7 +273,7 @@ export default {
|
|
|
pollCollectStatus: function(draftId) {
|
|
|
var self = this
|
|
|
self.collectPollCount = (self.collectPollCount || 0) + 1
|
|
|
- // 约 6 分钟仍未完成:停轮询,提示去列表看进度(后台任务可能仍在跑)
|
|
|
+ // 约 6 分钟仍未完成:停轮询,提示去列表看进度
|
|
|
if (self.collectPollCount > 90) {
|
|
|
self.stopCollectPolling()
|
|
|
self.collectError = '解析耗时较长,可去报告列表查看进度,无需重复上传'
|
|
|
@@ -463,10 +290,12 @@ export default {
|
|
|
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 })
|
|
|
+ // 统一跳转到健康报告详情页(后端指纹识别后统一入库到 health_report 表)
|
|
|
+ if (reportType === 'gut_flora') {
|
|
|
+ uni.redirectTo({ url: '/pages/health/gut-flora-detail?reportId=' + reportId })
|
|
|
+ } else {
|
|
|
+ uni.redirectTo({ url: '/pages/health/report-detail?reportType=' + reportType + '&reportId=' + reportId })
|
|
|
+ }
|
|
|
} else {
|
|
|
uni.redirectTo({ url: '/pages/health/report-list' })
|
|
|
}
|
|
|
@@ -484,91 +313,12 @@ export default {
|
|
|
this.stopCollectPolling()
|
|
|
uni.redirectTo({ url: '/pages/health/report-list' })
|
|
|
},
|
|
|
- // DAN测评:parse-preview → 预览确认页
|
|
|
- uploadDanAndGoPreview: function(filePath) {
|
|
|
- if (!filePath) return
|
|
|
- var self = this
|
|
|
- var memberId = self.memberId
|
|
|
- || (self.$store.state && self.$store.state.currentChildId)
|
|
|
- || uni.getStorageSync('currentChildId')
|
|
|
- || uni.getStorageSync('currentMemberId')
|
|
|
- if (!memberId) {
|
|
|
- uni.showToast({ title: '请先选择家庭成员', icon: 'none' })
|
|
|
- return
|
|
|
- }
|
|
|
- self.uploading = true
|
|
|
- uni.showLoading({ title: '解析中...' })
|
|
|
- danParsePreview(filePath, self.danDimension, memberId).then(function(res) {
|
|
|
- uni.hideLoading()
|
|
|
- self.uploading = false
|
|
|
- if (!res || res.code !== 200 || !res.data) {
|
|
|
- uni.showToast({ title: (res && res.message) || '解析失败', icon: 'none' })
|
|
|
- return
|
|
|
- }
|
|
|
- try {
|
|
|
- uni.setStorageSync('danUploadPreview', {
|
|
|
- draftId: res.data.draftId || res.data.uploadId,
|
|
|
- previewData: res.data,
|
|
|
- dimension: self.danDimension,
|
|
|
- memberId: memberId
|
|
|
- })
|
|
|
- } catch (e) {}
|
|
|
- uni.redirectTo({
|
|
|
- url: '/pages/dan-assessment/report-upload?resume=1&dimension=' + self.danDimension
|
|
|
- })
|
|
|
- }).catch(function(err) {
|
|
|
- uni.hideLoading()
|
|
|
- self.uploading = false
|
|
|
- uni.showToast({ title: (err && err.message) || '上传失败', icon: 'none' })
|
|
|
- })
|
|
|
- },
|
|
|
- goBodyFatScale: function() {
|
|
|
- var self = this
|
|
|
- this.ensureAgreed(function() {
|
|
|
- self.reportKind = 'health'
|
|
|
- self.startBodyFatUpload()
|
|
|
- })
|
|
|
- },
|
|
|
- startBodyFatUpload: function() {
|
|
|
- var self = this
|
|
|
- uni.chooseImage({
|
|
|
- count: 1,
|
|
|
- sourceType: ['camera', 'album'],
|
|
|
- success: function(res) {
|
|
|
- self.photoPath = res.tempFilePaths[0]
|
|
|
- self.uploadBodyFat(self.photoPath)
|
|
|
- }
|
|
|
- })
|
|
|
- },
|
|
|
- uploadBodyFat: function(filePath) {
|
|
|
- var self = this
|
|
|
- self.uploading = true
|
|
|
- uni.showLoading({ title: 'AI 识别中...' })
|
|
|
- var token = uni.getStorageSync('token')
|
|
|
- uni.uploadFile({
|
|
|
- url: config.API_BASE_URL + '/api/health/report/bodyfat-upload',
|
|
|
- filePath: filePath,
|
|
|
- name: 'file',
|
|
|
- header: { 'Authorization': 'Bearer ' + token },
|
|
|
- success: function(uploadRes) {
|
|
|
- var data
|
|
|
- try { data = JSON.parse(uploadRes.data) } catch (e) { data = uploadRes.data }
|
|
|
- self.uploading = false
|
|
|
- uni.hideLoading()
|
|
|
- if (data && data.code === 200) {
|
|
|
- self.currentMemberId = data.data && data.data.memberId
|
|
|
- self.extractedMetrics = data.data && data.data.metrics || []
|
|
|
- uni.navigateTo({ url: '/pages/health/bodyfat-confirm' })
|
|
|
- } else {
|
|
|
- uni.showToast({ title: (data && data.message) || '上传失败', icon: 'none' })
|
|
|
- }
|
|
|
- },
|
|
|
- fail: function() {
|
|
|
- self.uploading = false
|
|
|
- uni.hideLoading()
|
|
|
- uni.showToast({ title: '网络错误', icon: 'none' })
|
|
|
- }
|
|
|
- })
|
|
|
+ cancelCollect: function() {
|
|
|
+ this.stopCollectPolling()
|
|
|
+ this.collecting = false
|
|
|
+ this.collectDraftId = null
|
|
|
+ this.collectFileName = ''
|
|
|
+ this.collectError = ''
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -578,6 +328,7 @@ export default {
|
|
|
.upload-container {
|
|
|
min-height: 100vh;
|
|
|
background: #F5F7FA;
|
|
|
+ padding-bottom: env(safe-area-inset-bottom);
|
|
|
}
|
|
|
|
|
|
.tip-banner {
|
|
|
@@ -617,140 +368,77 @@ export default {
|
|
|
margin-bottom: 16rpx;
|
|
|
}
|
|
|
|
|
|
-.category-row {
|
|
|
+/* 上传方式卡片 */
|
|
|
+.upload-methods {
|
|
|
display: flex;
|
|
|
flex-direction: row;
|
|
|
gap: 16rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
}
|
|
|
-.category-card {
|
|
|
+.upload-card {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
- padding: 28rpx 16rpx;
|
|
|
- border-radius: 16rpx;
|
|
|
- background: #F8FAFC;
|
|
|
- border: 2rpx solid #E2E8F0;
|
|
|
-}
|
|
|
-.category-active {
|
|
|
- background: #EFF6FF;
|
|
|
- border-color: #3B82F6;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 32rpx 12rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ text-align: center;
|
|
|
+ min-height: 200rpx;
|
|
|
}
|
|
|
-.category-dan.category-active {
|
|
|
- background: #F5F3FF;
|
|
|
- border-color: #8B5CF6;
|
|
|
+.upload-card:active {
|
|
|
+ opacity: 0.85;
|
|
|
}
|
|
|
-.category-icon {
|
|
|
+.upload-card-icon {
|
|
|
+ width: 80rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
font-size: 40rpx;
|
|
|
- margin-bottom: 10rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
}
|
|
|
-.category-title {
|
|
|
- font-size: 28rpx;
|
|
|
+.upload-card-title {
|
|
|
+ font-size: 26rpx;
|
|
|
font-weight: 600;
|
|
|
- color: #1E293B;
|
|
|
- margin-bottom: 6rpx;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
}
|
|
|
-.category-desc {
|
|
|
+.upload-card-desc {
|
|
|
font-size: 20rpx;
|
|
|
color: #94A3B8;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-
|
|
|
-.dim-grid {
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- flex-wrap: wrap;
|
|
|
-}
|
|
|
-.dim-chip {
|
|
|
- width: 23%;
|
|
|
- margin-right: 2%;
|
|
|
- margin-bottom: 12rpx;
|
|
|
- padding: 16rpx 0;
|
|
|
- text-align: center;
|
|
|
- border-radius: 12rpx;
|
|
|
- background: #F1F5F9;
|
|
|
- border: 2rpx solid transparent;
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
-.dim-active {
|
|
|
- background: #EDE9FE;
|
|
|
- border-color: #8B5CF6;
|
|
|
-}
|
|
|
-.dim-chip-text {
|
|
|
- font-size: 22rpx;
|
|
|
- color: #334155;
|
|
|
+ line-height: 1.5;
|
|
|
}
|
|
|
|
|
|
-.kind-hint {
|
|
|
- background: #FFFBEB;
|
|
|
- border-radius: 12rpx;
|
|
|
- padding: 20rpx;
|
|
|
- margin-bottom: 20rpx;
|
|
|
- border: 2rpx dashed #FCD34D;
|
|
|
+.card-chat {
|
|
|
+ background: #F0F7FF;
|
|
|
+ border: 2rpx dashed #93C5FD;
|
|
|
}
|
|
|
-.kind-hint-text {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #92400E;
|
|
|
+.card-chat .upload-card-icon {
|
|
|
+ background: linear-gradient(135deg, #3B82F6, #1D4ED8);
|
|
|
+ color: #fff;
|
|
|
}
|
|
|
|
|
|
-.analyzing-status {
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- align-items: center;
|
|
|
+.card-photo {
|
|
|
+ background: #FFF7ED;
|
|
|
+ border: 2rpx solid #FED7AA;
|
|
|
}
|
|
|
-.analyzing-text {
|
|
|
- font-size: 26rpx;
|
|
|
- color: #5B9BD5;
|
|
|
+.card-photo .upload-card-icon {
|
|
|
+ background: linear-gradient(135deg, #FB923C, #EA580C);
|
|
|
+ color: #fff;
|
|
|
}
|
|
|
|
|
|
-.disclaimer-box {
|
|
|
- background: #FFF8F0;
|
|
|
- border: 2rpx solid #FDE68A;
|
|
|
-}
|
|
|
-.disclaimer-check {
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 12rpx;
|
|
|
+.card-folder {
|
|
|
+ background: #F0FDF4;
|
|
|
+ border: 2rpx dashed #86EFAC;
|
|
|
}
|
|
|
-.disclaimer-checkbox {
|
|
|
- width: 36rpx;
|
|
|
- height: 36rpx;
|
|
|
- border-radius: 6rpx;
|
|
|
- border: 2rpx solid #CBD5E1;
|
|
|
- background: #fff;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- flex-shrink: 0;
|
|
|
- margin-right: 12rpx;
|
|
|
-}
|
|
|
-.disclaimer-checked {
|
|
|
- background: #5B9BD5;
|
|
|
- border-color: #5B9BD5;
|
|
|
-}
|
|
|
-.disclaimer-checkmark {
|
|
|
- font-size: 24rpx;
|
|
|
+.card-folder .upload-card-icon {
|
|
|
+ background: linear-gradient(135deg, #22C55E, #16A34A);
|
|
|
color: #fff;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-.disclaimer-label {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #333;
|
|
|
- font-weight: 500;
|
|
|
-}
|
|
|
-.disclaimer-content {
|
|
|
- background: #FFFDF5;
|
|
|
- border-radius: 10rpx;
|
|
|
- padding: 16rpx;
|
|
|
- margin-left: 48rpx;
|
|
|
-}
|
|
|
-.disclaimer-text {
|
|
|
- font-size: 22rpx;
|
|
|
- color: #92400E;
|
|
|
- line-height: 1.6;
|
|
|
}
|
|
|
|
|
|
+/* 采集中面板 */
|
|
|
.collecting-panel {
|
|
|
margin-bottom: 20rpx;
|
|
|
}
|
|
|
@@ -816,75 +504,95 @@ export default {
|
|
|
margin-top: 8rpx;
|
|
|
line-height: 1.5;
|
|
|
}
|
|
|
+.collecting-actions {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ gap: 16rpx;
|
|
|
+ margin-top: 16rpx;
|
|
|
+}
|
|
|
.collecting-btn {
|
|
|
- margin-top: 20rpx;
|
|
|
- height: 80rpx;
|
|
|
- line-height: 80rpx;
|
|
|
+ flex: 1;
|
|
|
+ height: 72rpx;
|
|
|
+ line-height: 72rpx;
|
|
|
text-align: center;
|
|
|
background: #5B9BD5;
|
|
|
color: #fff;
|
|
|
font-size: 28rpx;
|
|
|
border-radius: 12rpx;
|
|
|
}
|
|
|
+.collecting-cancel {
|
|
|
+ padding: 0 24rpx;
|
|
|
+ height: 72rpx;
|
|
|
+ line-height: 72rpx;
|
|
|
+ text-align: center;
|
|
|
+ background: #fff;
|
|
|
+ border: 1rpx solid #D1D5DB;
|
|
|
+ color: #666;
|
|
|
+ font-size: 28rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+}
|
|
|
|
|
|
-.upload-methods {
|
|
|
+/* 上传中状态 */
|
|
|
+.analyzing-status {
|
|
|
display: flex;
|
|
|
flex-direction: row;
|
|
|
- gap: 16rpx;
|
|
|
- margin-bottom: 20rpx;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
-.upload-card {
|
|
|
- flex: 1;
|
|
|
+.analyzing-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #5B9BD5;
|
|
|
+}
|
|
|
+
|
|
|
+/* 责任声明 */
|
|
|
+.disclaimer-box {
|
|
|
+ background: #FFF8F0;
|
|
|
+ border: 2rpx solid #FDE68A;
|
|
|
+}
|
|
|
+.disclaimer-check {
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
+ flex-direction: row;
|
|
|
align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 32rpx 12rpx;
|
|
|
- border-radius: 20rpx;
|
|
|
- text-align: center;
|
|
|
- min-height: 220rpx;
|
|
|
-}
|
|
|
-.upload-card:active {
|
|
|
- opacity: 0.85;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
}
|
|
|
-.upload-card-icon {
|
|
|
- width: 80rpx;
|
|
|
- height: 80rpx;
|
|
|
- border-radius: 20rpx;
|
|
|
- font-size: 40rpx;
|
|
|
+.disclaimer-checkbox {
|
|
|
+ width: 36rpx;
|
|
|
+ height: 36rpx;
|
|
|
+ border-radius: 6rpx;
|
|
|
+ border: 2rpx solid #CBD5E1;
|
|
|
+ background: #fff;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- margin-bottom: 16rpx;
|
|
|
-}
|
|
|
-.upload-card-title {
|
|
|
- font-size: 26rpx;
|
|
|
- font-weight: 600;
|
|
|
- color: #333;
|
|
|
- margin-bottom: 8rpx;
|
|
|
-}
|
|
|
-.upload-card-desc {
|
|
|
- font-size: 20rpx;
|
|
|
- color: #94A3B8;
|
|
|
- line-height: 1.5;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-right: 12rpx;
|
|
|
}
|
|
|
-.card-file {
|
|
|
- background: #F0F7FF;
|
|
|
- border: 2rpx dashed #93C5FD;
|
|
|
+.disclaimer-checked {
|
|
|
+ background: #5B9BD5;
|
|
|
+ border-color: #5B9BD5;
|
|
|
}
|
|
|
-.card-file .upload-card-icon {
|
|
|
- background: linear-gradient(135deg, #3B82F6, #1D4ED8);
|
|
|
+.disclaimer-checkmark {
|
|
|
+ font-size: 24rpx;
|
|
|
color: #fff;
|
|
|
+ font-weight: bold;
|
|
|
}
|
|
|
-.card-photo {
|
|
|
- background: #FFF7ED;
|
|
|
- border: 2rpx solid #FED7AA;
|
|
|
+.disclaimer-label {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #333;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
-.card-photo .upload-card-icon {
|
|
|
- background: linear-gradient(135deg, #FB923C, #EA580C);
|
|
|
- color: #fff;
|
|
|
+.disclaimer-content {
|
|
|
+ background: #FFFDF5;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ padding: 16rpx;
|
|
|
+ margin-left: 48rpx;
|
|
|
+}
|
|
|
+.disclaimer-text {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #92400E;
|
|
|
+ line-height: 1.6;
|
|
|
}
|
|
|
|
|
|
+/* 上传说明 */
|
|
|
.guide-section {
|
|
|
margin: 0 30rpx 30rpx;
|
|
|
background: #fff;
|
|
|
@@ -964,59 +672,4 @@ export default {
|
|
|
display: block;
|
|
|
line-height: 1.7;
|
|
|
}
|
|
|
-
|
|
|
-.sheet-mask {
|
|
|
- position: fixed;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- top: 0;
|
|
|
- bottom: 0;
|
|
|
- background: rgba(15, 23, 42, 0.45);
|
|
|
- z-index: 1000;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- justify-content: flex-end;
|
|
|
-}
|
|
|
-.sheet-panel {
|
|
|
- background: #fff;
|
|
|
- border-radius: 24rpx 24rpx 0 0;
|
|
|
- padding: 32rpx 28rpx calc(32rpx + env(safe-area-inset-bottom));
|
|
|
-}
|
|
|
-.sheet-title {
|
|
|
- font-size: 30rpx;
|
|
|
- font-weight: 600;
|
|
|
- color: #0F172A;
|
|
|
- display: block;
|
|
|
- text-align: center;
|
|
|
- margin-bottom: 24rpx;
|
|
|
-}
|
|
|
-.sheet-item {
|
|
|
- background: #F8FAFC;
|
|
|
- border-radius: 16rpx;
|
|
|
- padding: 28rpx 24rpx;
|
|
|
- margin-bottom: 16rpx;
|
|
|
-}
|
|
|
-.sheet-item:active {
|
|
|
- background: #EFF6FF;
|
|
|
-}
|
|
|
-.sheet-item-title {
|
|
|
- font-size: 28rpx;
|
|
|
- font-weight: 600;
|
|
|
- color: #1E293B;
|
|
|
- display: block;
|
|
|
- margin-bottom: 6rpx;
|
|
|
-}
|
|
|
-.sheet-item-desc {
|
|
|
- font-size: 22rpx;
|
|
|
- color: #94A3B8;
|
|
|
-}
|
|
|
-.sheet-cancel {
|
|
|
- margin-top: 8rpx;
|
|
|
- padding: 24rpx;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-.sheet-cancel-text {
|
|
|
- font-size: 28rpx;
|
|
|
- color: #64748B;
|
|
|
-}
|
|
|
</style>
|