|
|
@@ -8,6 +8,16 @@
|
|
|
<view class="head-meta">
|
|
|
<text class="type-badge">{{ typeLabel }}</text>
|
|
|
<text class="head-date">{{ headInfo.reportDateText || '' }}</text>
|
|
|
+ <!-- 报告日期修改入口(view 模式;DAN 报告走独立存储与接口,不在本页编辑范围) -->
|
|
|
+ <text class="head-date-edit" v-if="pageMode==='view' && headInfo.reportDate && reportType !== 'dan'" @tap="startEditDate">修改</text>
|
|
|
+ </view>
|
|
|
+ <!-- 日期编辑行(仅查看态入口,复用 /report/edit 接口) -->
|
|
|
+ <view class="head-date-editor" v-if="dateEditing">
|
|
|
+ <input class="head-date-input" type="text" v-model="dateInput" placeholder="yyyy-MM-dd" />
|
|
|
+ <view class="head-date-actions">
|
|
|
+ <text class="head-date-btn head-date-cancel" @tap="cancelEditDate">取消</text>
|
|
|
+ <text class="head-date-btn head-date-save" @tap="submitDateChange">保存</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
@@ -409,7 +419,7 @@ import ReportBlocksRenderer from './report-blocks-renderer.vue'
|
|
|
import FeedbackPopup from '@/pages/health/components/feedback-popup.vue'
|
|
|
import { normalizeMembers, memberIdOf } from '../../utils/memberNormalize.js'
|
|
|
import { getReportDetail, getDanReportDetail, getReportPayload, editHealthReport, parseReportDraft, confirmReportPreview, discardReportDraft, confirmTongue, discardTongue, getFamilyMemberList, addFamilyMember, queryIndicatorKnowledge, queryBacteriaKnowledge } from '../../utils/api.js'
|
|
|
-import { parseDate } from '../../utils/format.js'
|
|
|
+import { formatDate } from '../../utils/format.js'
|
|
|
import fontScaleMixin from '@/mixins/font-scale.js'
|
|
|
|
|
|
export default {
|
|
|
@@ -470,7 +480,11 @@ export default {
|
|
|
showHelpPopup: false,
|
|
|
helpData: {},
|
|
|
_kbCache: {},
|
|
|
- feedbackVisible: false
|
|
|
+ feedbackVisible: false,
|
|
|
+ // view 模式报告日期修改(仅日期,走 /report/edit 复用现有接口)
|
|
|
+ dateEditing: false,
|
|
|
+ dateInput: '',
|
|
|
+ lastDetail: null
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -614,10 +628,13 @@ export default {
|
|
|
uni.hideLoading()
|
|
|
if (res.code === 200) {
|
|
|
var report = res.data.report || res.data
|
|
|
+ self.lastDetail = res.data
|
|
|
var head = {}
|
|
|
head.personName = report.personName || report.childName || ''
|
|
|
head.childName = report.childName || ''
|
|
|
- head.reportDateText = report.reportDate ? parseDate(report.reportDate) : ''
|
|
|
+ // 仅日期场景统一 yyyy-MM-dd(禁止渲染 Date 对象/ISO 串)
|
|
|
+ head.reportDate = report.reportDate ? formatDate(report.reportDate) : ''
|
|
|
+ head.reportDateText = head.reportDate
|
|
|
self.headInfo = head
|
|
|
var backendBlocks = (res.data && res.data.blocks) || report.blocks || []
|
|
|
if (res.data.payload) {
|
|
|
@@ -1097,9 +1114,61 @@ export default {
|
|
|
} else {
|
|
|
uni.showToast({ title: res.message || '保存失败', icon: 'none' })
|
|
|
}
|
|
|
- }).catch(function() {
|
|
|
+ }).catch(function(err) {
|
|
|
+ // 与 submitDateChange 同理:后端明确原因以 err.message 为准。封装层已弹过该文案,
|
|
|
+ // 但微信小程序 showToast 与 showLoading 共用同一组件,hideLoading 会把它一并隐藏,
|
|
|
+ // 故 hideLoading 后重放同一条原因;仅非业务错误(无 message)才兜底弹通用提示。
|
|
|
+ uni.hideLoading()
|
|
|
+ var reason = (err && err.message) ? err.message : ''
|
|
|
+ uni.showToast({ title: reason || '保存异常', icon: 'none' })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // ===== view 模式:报告日期修改(复用 /report/edit,只改 summary.reportDate)=====
|
|
|
+ startEditDate() {
|
|
|
+ this.dateInput = this.headInfo && this.headInfo.reportDate ? this.headInfo.reportDate : ''
|
|
|
+ this.dateEditing = true
|
|
|
+ },
|
|
|
+ cancelEditDate() {
|
|
|
+ this.dateEditing = false
|
|
|
+ this.dateInput = ''
|
|
|
+ },
|
|
|
+ submitDateChange() {
|
|
|
+ var self = this
|
|
|
+ var val = (self.dateInput || '').trim()
|
|
|
+ if (!val) {
|
|
|
+ uni.showToast({ title: '请输入报告日期', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 日期专用最小 payload:只带 summary(沿用现有分数等值,仅覆盖 reportDate)。
|
|
|
+ // 刻意不带 indicators/gutFlora/diseaseRisks —— 后端 updateReportFromPayload 对缺失键
|
|
|
+ // 已有 instanceof List 保护,缺键即跳过整表「先删后插」,避免误清 collectionDate /
|
|
|
+ // description / relatedBacteria 等 payload 快照不含的列(若回填这三张表,insert 不会
|
|
|
+ // 写这些列 → 存量数据被永久清掉)。
|
|
|
+ var srcSummary = (self.payload && self.payload.summary) ? self.payload.summary : {}
|
|
|
+ // 复制一份再改:payload.summary 与编辑态日期输入框 v-model 双向绑定,直接改会把
|
|
|
+ // 未保存的日期写进组件状态,保存失败后编辑态会带出错误日期。
|
|
|
+ var summary = Object.assign({}, srcSummary)
|
|
|
+ summary.reportDate = val
|
|
|
+ var dateOnlyPayload = { type: self.payload.type || 'gut_flora', summary: summary }
|
|
|
+ var subjectId = self.selectedMemberId || self.createdMemberId || null
|
|
|
+ uni.showLoading({ title: '保存中...' })
|
|
|
+ editHealthReport(self.reportId, dateOnlyPayload, subjectId).then(function(res) {
|
|
|
+ uni.hideLoading()
|
|
|
+ if (res.code === 200) {
|
|
|
+ self.dateEditing = false
|
|
|
+ uni.showToast({ title: '已保存', icon: 'success' })
|
|
|
+ setTimeout(function() { self.loadData() }, 600)
|
|
|
+ }
|
|
|
+ // 非 200 不在此处理:api.js 封装层对 code!==200 会先弹后端明确原因再 reject,
|
|
|
+ // .then 只会拿到 200(/report/edit 不返回 5001),此处再弹一次只会覆盖具体原因。
|
|
|
+ }).catch(function(err) {
|
|
|
+ // err.message 即后端原文(如「报告日期不能晚于今天,当前值:2099-01-01」)。
|
|
|
+ // 注意:微信小程序 showToast 与 showLoading 共用同一组件,hideLoading 会把封装层
|
|
|
+ // 刚弹的那条提示一并隐藏,所以这里 hideLoading 后重放同一条原因,保证不吞错;
|
|
|
+ // 只有非业务错误对象(无 message)才兜底弹一次通用提示。
|
|
|
uni.hideLoading()
|
|
|
- uni.showToast({ title: '保存异常', icon: 'none' })
|
|
|
+ var reason = (err && err.message) ? err.message : ''
|
|
|
+ uni.showToast({ title: reason || '保存失败', icon: 'none' })
|
|
|
})
|
|
|
},
|
|
|
/** 从 blocks 中过滤掉"食物推荐/饮食推荐"块(报告详情不展示饮食推荐) */
|
|
|
@@ -1358,6 +1427,50 @@ $c-rptd-orange-line: #FFD4A8; // 暖橙描边
|
|
|
font-size: calc(24rpx * var(--font-scale, 1));
|
|
|
color: $facade-text-muted;
|
|
|
}
|
|
|
+.head-date-edit {
|
|
|
+ font-size: calc(22rpx * var(--font-scale, 1));
|
|
|
+ color: $c-rptd-blue;
|
|
|
+ background: $c-rptd-blue-bg;
|
|
|
+ padding: 4rpx 14rpx;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ margin-left: 4rpx;
|
|
|
+}
|
|
|
+.head-date-edit:active { opacity: 0.7; }
|
|
|
+.head-date-editor {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12rpx;
|
|
|
+ margin-top: 12rpx;
|
|
|
+}
|
|
|
+.head-date-input {
|
|
|
+ flex: 1;
|
|
|
+ font-size: calc(26rpx * var(--font-scale, 1));
|
|
|
+ color: $facade-text-strong;
|
|
|
+ padding: 10rpx 16rpx;
|
|
|
+ background: $app-bg;
|
|
|
+ border-radius: 8rpx;
|
|
|
+}
|
|
|
+.head-date-actions {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ gap: 12rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.head-date-btn {
|
|
|
+ font-size: calc(24rpx * var(--font-scale, 1));
|
|
|
+ padding: 10rpx 24rpx;
|
|
|
+ border-radius: 8rpx;
|
|
|
+}
|
|
|
+.head-date-btn:active { opacity: 0.7; }
|
|
|
+.head-date-cancel {
|
|
|
+ color: $facade-text-muted;
|
|
|
+ background: $facade-fill-slate;
|
|
|
+}
|
|
|
+.head-date-save {
|
|
|
+ color: $app-surface;
|
|
|
+ background: $c-rptd-blue;
|
|
|
+}
|
|
|
.empty-hint {
|
|
|
text-align: center;
|
|
|
color: $facade-text-muted;
|