|
|
@@ -51,106 +51,22 @@
|
|
|
<text class="form-member-save">每个成员独立保存,切换后自动保留</text>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 基础体征 -->
|
|
|
- <view class="form-section">
|
|
|
- <view class="form-title">基础体征</view>
|
|
|
- <view class="form-row">
|
|
|
- <text class="form-label">身高 (cm)</text>
|
|
|
- <input class="form-input" type="digit" v-model="form.heightCm" placeholder="如 170" />
|
|
|
- </view>
|
|
|
- <view class="form-row">
|
|
|
- <text class="form-label">体重 (kg)</text>
|
|
|
- <input class="form-input" type="digit" v-model="form.weightKg" placeholder="如 60" />
|
|
|
- </view>
|
|
|
- <view class="form-row">
|
|
|
- <text class="form-label">血压</text>
|
|
|
- <input class="form-input" type="text" v-model="form.bloodPressure" placeholder="如 120/80" />
|
|
|
- </view>
|
|
|
- <view class="form-row">
|
|
|
- <text class="form-label">空腹血糖 (mmol/L)</text>
|
|
|
- <input class="form-input" type="digit" v-model="form.bloodGlucose" placeholder="如 5.6" />
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 血脂 -->
|
|
|
- <view class="form-section">
|
|
|
- <view class="form-title">血脂</view>
|
|
|
- <view class="form-row">
|
|
|
- <text class="form-label">总胆固醇 (mmol/L)</text>
|
|
|
- <input class="form-input" type="digit" v-model="lipidCholesterol" placeholder="如 4.5" />
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 疾病史 -->
|
|
|
- <view class="form-section">
|
|
|
- <view class="form-title">疾病史</view>
|
|
|
- <view v-for="(group, gi) in diseaseGroups" :key="group.key" class="disease-group">
|
|
|
- <view class="group-head" @click="toggleGroup(group.key)">
|
|
|
- <text class="group-title">{{ group.title }}</text>
|
|
|
- <text class="group-arrow">{{ expandedGroups.indexOf(group.key) >= 0 ? '收起' : '展开' }}</text>
|
|
|
- </view>
|
|
|
- <view v-if="expandedGroups.indexOf(group.key) >= 0" class="tag-wrap">
|
|
|
- <view
|
|
|
- v-for="(item, ii) in group.items"
|
|
|
- :key="item.name"
|
|
|
- class="tag-item"
|
|
|
- :class="{ 'tag-active': selectedNames.indexOf(item.name) >= 0 }"
|
|
|
- @click="toggleDisease(item.name)">
|
|
|
- <text>{{ item.name }}</text>
|
|
|
- <text v-if="item.risk" class="risk-badge" @click.stop="showRiskTip(item.name)">★</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="custom-row">
|
|
|
- <input class="custom-input" type="text" v-model="diseaseInput" placeholder="输入其他疾病" />
|
|
|
- <text class="add-link" @click="addCustomDisease">添加</text>
|
|
|
- </view>
|
|
|
- <view v-if="selectedDiseases.length > 0" class="selected-area">
|
|
|
- <view class="selected-title">已选疾病({{ selectedDiseases.length }})</view>
|
|
|
- <view v-for="(item, si) in selectedDiseases" :key="getSelKey(si)" class="sel-row">
|
|
|
- <text class="sel-name">{{ item.name }}</text>
|
|
|
- <picker mode="date" fields="month" :value="item.diagnosedAt || currentMonth" :end="monthEnd" @change="onDiagChange(si, $event)">
|
|
|
- <view class="sel-diag">{{ item.diagnosedAt ? item.diagnosedAt : '设确诊时间' }}</view>
|
|
|
- </picker>
|
|
|
- <text class="sel-del" @click="removeSelected(si)">×</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 在服药物/治疗 -->
|
|
|
- <view class="form-section">
|
|
|
- <view class="form-title">在服药物/治疗</view>
|
|
|
- <view v-for="(med, idx) in medRows" :key="idx" class="med-row">
|
|
|
- <view class="med-line">
|
|
|
- <input class="med-name" type="text" v-model="med.name" placeholder="药物品牌,如 立普妥" />
|
|
|
- <text class="med-del" @click="removeMed(idx)">删除</text>
|
|
|
- </view>
|
|
|
- <view class="med-line">
|
|
|
- <picker mode="date" fields="month" :value="med.startDate || currentMonth" :end="monthEnd" @change="onMedStartChange(idx, $event)">
|
|
|
- <view class="med-picker">{{ med.startDate ? med.startDate : '选择开始日期' }}</view>
|
|
|
- </picker>
|
|
|
- <text class="med-forget" @click="onForgetClick(idx)">记不清</text>
|
|
|
- </view>
|
|
|
- <view class="med-line" v-if="med.durationText">
|
|
|
- <text class="med-duration">已服时长:{{ med.durationText }}</text>
|
|
|
- </view>
|
|
|
- <view class="med-line">
|
|
|
- <input class="med-time" type="text" v-model="med.time" placeholder="服药时间,如 早饭后一次" />
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <text class="add-link" @click="addMed">+ 添加药物/治疗</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 其他补充 -->
|
|
|
- <view class="form-section">
|
|
|
- <view class="form-title">其他补充</view>
|
|
|
- <textarea class="notes-area" v-model="form.notes" placeholder="其他想补充的健康信息(选填)" :maxlength="500" />
|
|
|
- </view>
|
|
|
+ <!-- 分步问卷向导(体征 / 疾病史 / 饮食习惯 / 确认) -->
|
|
|
+ <health-questionnaire-wizard
|
|
|
+ ref="wizard"
|
|
|
+ :member-form-map="memberFormMap"
|
|
|
+ :diet-map="memberDietMap"
|
|
|
+ :active-form-member-id="activeFormMemberId"
|
|
|
+ :submitting="loading"
|
|
|
+ @update-vitals="onWizardVitals"
|
|
|
+ @update-medical="onWizardMedical"
|
|
|
+ @update-diet="onWizardDiet"
|
|
|
+ @submit="onWizardSubmit"
|
|
|
+ />
|
|
|
|
|
|
<!-- 底部按钮 -->
|
|
|
<view class="btn-pair">
|
|
|
- <button class="btn-skip" @click="skipToGenerate">跳过</button>
|
|
|
- <button class="btn-generate" :disabled="loading" @click="saveAndGenerate">{{ loading ? '生成中...' : '保存并生成' }}</button>
|
|
|
+ <button class="btn-skip" @click="skipToGenerate">跳过问卷,直接生成</button>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
@@ -267,85 +183,12 @@
|
|
|
|
|
|
<script>
|
|
|
import { generateHealthPlan, regenerateSection, confirmPlan, saveHealthPlan, getHealthPlanDetail, approvePlan } from '../../utils/api'
|
|
|
-import { getHealthStatus, saveHealthStatus } from '../../utils/api'
|
|
|
+import { getHealthStatus, saveHealthStatus, getDietPreferences, saveDietPreferences, getMyMembership } from '../../utils/api'
|
|
|
import MemberChipPicker from '@/pages/health/components/MemberChipPicker.vue'
|
|
|
-
|
|
|
-// v2: 预置疾病清单(菌群报告病症风险 ★ + 互联网统计常见病 两源合并去重,8 组 54 项)
|
|
|
-var DISEASE_GROUPS = [
|
|
|
- { key: 'cardio', title: '心血管代谢', items: [
|
|
|
- { name: '高血压', risk: false },
|
|
|
- { name: '糖尿病', risk: false },
|
|
|
- { name: '血脂异常', risk: false },
|
|
|
- { name: '冠心病', risk: false },
|
|
|
- { name: '脑卒中', risk: false },
|
|
|
- { name: '心力衰竭', risk: false },
|
|
|
- { name: '心房颤动', risk: false },
|
|
|
- { name: '慢阻肺', risk: false },
|
|
|
- { name: '心脑血管疾病', risk: true },
|
|
|
- { name: 'II型糖尿病', risk: true },
|
|
|
- { name: '肥胖', risk: true },
|
|
|
- { name: '超重', risk: false },
|
|
|
- { name: '高尿酸血症', risk: false },
|
|
|
- { name: '骨质疏松', risk: false }
|
|
|
- ]},
|
|
|
- { key: 'digest', title: '消化系统', items: [
|
|
|
- { name: '幽门螺杆菌感染', risk: false },
|
|
|
- { name: '脂肪肝', risk: false },
|
|
|
- { name: '慢性胃炎', risk: false },
|
|
|
- { name: '胃食管反流', risk: false },
|
|
|
- { name: '肠易激综合征', risk: true },
|
|
|
- { name: '炎症性肠炎', risk: true },
|
|
|
- { name: '慢性便秘', risk: true },
|
|
|
- { name: '感染性腹泻', risk: true },
|
|
|
- { name: '胆结石', risk: false },
|
|
|
- { name: '炎症性肠病', risk: false },
|
|
|
- { name: '肝病', risk: true },
|
|
|
- { name: '胃病', risk: true },
|
|
|
- { name: '胆病', risk: true },
|
|
|
- { name: '肾病', risk: true },
|
|
|
- { name: '腹胀', risk: true }
|
|
|
- ]},
|
|
|
- { key: 'immune', title: '过敏免疫', items: [
|
|
|
- { name: '过敏性鼻炎', risk: true },
|
|
|
- { name: '哮喘', risk: false },
|
|
|
- { name: '湿疹', risk: false },
|
|
|
- { name: '食物过敏', risk: false },
|
|
|
- { name: '自体免疫病', risk: true }
|
|
|
- ]},
|
|
|
- { key: 'neuro', title: '精神神经', items: [
|
|
|
- { name: '抑郁症', risk: true },
|
|
|
- { name: '失眠', risk: true },
|
|
|
- { name: '焦虑障碍', risk: false },
|
|
|
- { name: '偏头痛', risk: false },
|
|
|
- { name: '自闭症', risk: true }
|
|
|
- ]},
|
|
|
- { key: 'resp', title: '呼吸系统', items: [
|
|
|
- { name: '肺部感染或疾病', risk: true },
|
|
|
- { name: '肺部疾病', risk: true }
|
|
|
- ]},
|
|
|
- { key: 'tumor', title: '肿瘤', items: [
|
|
|
- { name: '结直肠癌', risk: true },
|
|
|
- { name: '肺癌', risk: false },
|
|
|
- { name: '甲状腺癌', risk: false },
|
|
|
- { name: '肝癌', risk: false },
|
|
|
- { name: '胃癌', risk: false },
|
|
|
- { name: '乳腺癌', risk: false },
|
|
|
- { name: '食管癌', risk: false }
|
|
|
- ]},
|
|
|
- { key: 'child', title: '儿童青少年', items: [
|
|
|
- { name: '近视', risk: false },
|
|
|
- { name: '龋齿', risk: false },
|
|
|
- { name: '注意缺陷多动障碍', risk: false },
|
|
|
- { name: '甲状腺疾病', risk: true }
|
|
|
- ]},
|
|
|
- { key: 'other', title: '其他', items: [
|
|
|
- { name: '缺铁性贫血', risk: false },
|
|
|
- { name: '贫血', risk: false }
|
|
|
- ]}
|
|
|
-]
|
|
|
+import HealthQuestionnaireWizard from '@/pages/health/components/HealthQuestionnaireWizard.vue'
|
|
|
|
|
|
export default {
|
|
|
- components: { MemberChipPicker },
|
|
|
+ components: { MemberChipPicker, HealthQuestionnaireWizard },
|
|
|
data() {
|
|
|
return {
|
|
|
// 步骤控制
|
|
|
@@ -357,24 +200,10 @@ export default {
|
|
|
// 目标
|
|
|
userGoal: '',
|
|
|
goalLen: 0,
|
|
|
- // 健康问卷表单
|
|
|
- form: {
|
|
|
- heightCm: '',
|
|
|
- weightKg: '',
|
|
|
- bloodPressure: '',
|
|
|
- bloodGlucose: '',
|
|
|
- notes: ''
|
|
|
- },
|
|
|
- lipidCholesterol: '',
|
|
|
- // 疾病清单很大,不放进首屏 data,避免微信 setData 超限导致成员列表无法渲染
|
|
|
- expandedGroups: [],
|
|
|
- selectedDiseases: [],
|
|
|
- diseaseInput: '',
|
|
|
- medRows: [{ name: '', startDate: '', durationText: '', time: '' }],
|
|
|
- currentMonth: '',
|
|
|
- monthEnd: '',
|
|
|
- // 多成员分别填写:memberId → 各自的表单快照 { form, lipidCholesterol, selectedDiseases, medRows }
|
|
|
+ // 多成员分别填写:memberId → 各自的表单快照 { form, lipidCholesterol, selectedDiseases, medRows, noMedication }
|
|
|
memberFormMap: {},
|
|
|
+ // 多成员饮食习惯:memberId → dietPreferences 对象
|
|
|
+ memberDietMap: {},
|
|
|
activeFormMemberId: '',
|
|
|
// 方案数据
|
|
|
planData: {},
|
|
|
@@ -396,10 +225,6 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
- // 仅在问卷步骤暴露疾病清单,减小 step1 的 setData 体积
|
|
|
- diseaseGroups: function() {
|
|
|
- return this.step >= 2 ? DISEASE_GROUPS : []
|
|
|
- },
|
|
|
canGenerate: function() {
|
|
|
return this.selectedMemberIds.length > 0 && this.goalLen > 0 && !this.loading
|
|
|
},
|
|
|
@@ -430,9 +255,6 @@ export default {
|
|
|
var idx = this.step - 3
|
|
|
return this.sectionHints[idx] || ''
|
|
|
},
|
|
|
- selectedNames: function() {
|
|
|
- return this.selectedDiseases.map(function(d) { return d.name })
|
|
|
- },
|
|
|
selectedMembers: function() {
|
|
|
var self = this
|
|
|
var out = []
|
|
|
@@ -476,15 +298,10 @@ selectedMembers: function() {
|
|
|
this.viewMode = true
|
|
|
this.loadPlanDetail()
|
|
|
}
|
|
|
- // 初始化健康问卷时间
|
|
|
- var now = new Date()
|
|
|
- var y = now.getFullYear()
|
|
|
- var m = now.getMonth() + 1
|
|
|
- var mStr = m < 10 ? '0' + m : '' + m
|
|
|
- this.currentMonth = y + '-' + mStr
|
|
|
- var lastDay = new Date(y, m, 0).getDate()
|
|
|
- this.monthEnd = y + '-' + mStr + '-' + (lastDay < 10 ? '0' + lastDay : '' + lastDay)
|
|
|
// 健康问卷数据在成员选择组件 loaded 后按成员异步加载
|
|
|
+ if (!this.viewMode) {
|
|
|
+ this.checkQuestionnaireGate()
|
|
|
+ }
|
|
|
// 自动执行
|
|
|
if (options.autoExecute === '1') {
|
|
|
setTimeout(function() { self.doAutoExecute() }, 1500)
|
|
|
@@ -524,7 +341,7 @@ selectedMembers: function() {
|
|
|
if (formId) {
|
|
|
this.activeFormMemberId = String(formId)
|
|
|
var self = this
|
|
|
- setTimeout(function() { self.loadHealthForm(formId) }, 100)
|
|
|
+ setTimeout(function() { self.loadHealthForm(formId); self.loadDietForm(formId) }, 100)
|
|
|
}
|
|
|
},
|
|
|
onAddMember: function() {
|
|
|
@@ -540,14 +357,11 @@ selectedMembers: function() {
|
|
|
|
|
|
// ===== 步骤导航 =====
|
|
|
goToStep2: function() {
|
|
|
- if (this.expandedGroups.length === 0) {
|
|
|
- this.expandedGroups = DISEASE_GROUPS.slice(0, 3).map(function(g) { return g.key })
|
|
|
- }
|
|
|
- // 多成员调研:确保 activeFormMemberId 指向第一个选中成员,并加载其表单
|
|
|
+ // 多成员调研:确保 activeFormMemberId 指向第一个选中成员,并加载其表单与饮食习惯
|
|
|
if (!this.activeFormMemberId && this.selectedMemberIds.length > 0) {
|
|
|
this.activeFormMemberId = String(this.selectedMemberIds[0])
|
|
|
var self = this
|
|
|
- setTimeout(function() { self.loadHealthForm(self.activeFormMemberId) }, 100)
|
|
|
+ setTimeout(function() { self.loadHealthForm(self.activeFormMemberId); self.loadDietForm(self.activeFormMemberId) }, 100)
|
|
|
}
|
|
|
this.step = 2
|
|
|
},
|
|
|
@@ -556,19 +370,17 @@ selectedMembers: function() {
|
|
|
this.generatePlan()
|
|
|
},
|
|
|
|
|
|
- // ===== 健康问卷方法 (从 health-status-form.vue 移植,支持按成员加载) =====
|
|
|
+ // ===== 健康问卷方法:按成员从服务端加载到 memberFormMap 快照 =====
|
|
|
loadHealthForm: function(memberId) {
|
|
|
var self = this
|
|
|
var mid = memberId || self.activeFormMemberId || ''
|
|
|
- // 已有该成员的本地快照 → 直接恢复
|
|
|
- if (mid && self.memberFormMap[mid]) {
|
|
|
- self.applyFormSnapshot(self.memberFormMap[mid])
|
|
|
- return
|
|
|
- }
|
|
|
+ var key = String(mid || '__account')
|
|
|
+ // 本地已有该成员快照 → 无需重复请求
|
|
|
+ if (self.memberFormMap[key]) return
|
|
|
getHealthStatus(mid || undefined).then(function(res) {
|
|
|
if (res && res.code === 200 && res.data) {
|
|
|
var d = res.data
|
|
|
- var snapshot = {
|
|
|
+ self.$set(self.memberFormMap, key, {
|
|
|
form: {
|
|
|
heightCm: d.heightCm || '',
|
|
|
weightKg: d.weightKg || '',
|
|
|
@@ -577,59 +389,63 @@ selectedMembers: function() {
|
|
|
notes: d.notes || ''
|
|
|
},
|
|
|
lipidCholesterol: self.parseLipidCholesterol(d.bloodLipids),
|
|
|
- selectedDiseases: [],
|
|
|
- medRows: self.parseMeds(d.medications)
|
|
|
- }
|
|
|
- self.memberFormMap[mid || '__account'] = snapshot
|
|
|
- self.loadDiseasesInto(snapshot.selectedDiseases, d.diseaseHistory)
|
|
|
- if (mid) self.applyFormSnapshot(snapshot)
|
|
|
- else self.applyFormSnapshot({
|
|
|
- form: snapshot.form,
|
|
|
- lipidCholesterol: snapshot.lipidCholesterol,
|
|
|
- selectedDiseases: snapshot.selectedDiseases,
|
|
|
- medRows: snapshot.medRows
|
|
|
+ selectedDiseases: self.parseDiseases(d.diseaseHistory),
|
|
|
+ medRows: self.parseMeds(d.medications),
|
|
|
+ noMedication: false
|
|
|
})
|
|
|
}
|
|
|
}).catch(function() {})
|
|
|
},
|
|
|
- // 切换成员时先保存当前编辑内容,再加载目标成员快照
|
|
|
- switchMember: function(memberId) {
|
|
|
+ // 按成员加载饮食习惯到 memberDietMap
|
|
|
+ loadDietForm: function(memberId) {
|
|
|
var self = this
|
|
|
- if (String(memberId) === String(self.activeFormMemberId)) return
|
|
|
- // 保存当前成员到快照
|
|
|
- self.memberFormMap[self.activeFormMemberId || '__account'] = {
|
|
|
- form: JSON.parse(JSON.stringify(self.form)),
|
|
|
- lipidCholesterol: self.lipidCholesterol,
|
|
|
- selectedDiseases: JSON.parse(JSON.stringify(self.selectedDiseases)),
|
|
|
- medRows: JSON.parse(JSON.stringify(self.medRows))
|
|
|
+ var mid = memberId || self.activeFormMemberId || ''
|
|
|
+ var key = String(mid || '__account')
|
|
|
+ if (self.memberDietMap[key]) return
|
|
|
+ getDietPreferences({ memberId: mid }).then(function(res) {
|
|
|
+ var d = (res && res.code === 200 && res.data) ? res.data : null
|
|
|
+ self.$set(self.memberDietMap, key, self.normalizeDiet(d))
|
|
|
+ }).catch(function() {
|
|
|
+ self.$set(self.memberDietMap, key, self.normalizeDiet(null))
|
|
|
+ })
|
|
|
+ },
|
|
|
+ normalizeDiet: function(d) {
|
|
|
+ return {
|
|
|
+ allergies: (d && d.allergies) || [],
|
|
|
+ absoluteAvoid: (d && d.absoluteAvoid) || [],
|
|
|
+ mustEat: (d && d.mustEat) || [],
|
|
|
+ religiousDiet: (d && d.religiousDiet) || 'none',
|
|
|
+ spiceLevel: (d && d.spiceLevel) || 0,
|
|
|
+ flavorPref: (d && d.flavorPref) || [],
|
|
|
+ cuisinePref: (d && d.cuisinePref) || [],
|
|
|
+ cookingMethods: (d && d.cookingMethods) || [],
|
|
|
+ healthGoals: (d && d.healthGoals) || [],
|
|
|
+ noPreference: !!(d && d.noPreference)
|
|
|
}
|
|
|
- self.activeFormMemberId = String(memberId)
|
|
|
- // 目标成员已有快照 → 恢复;无则按该成员从服务端加载
|
|
|
- if (self.memberFormMap[self.activeFormMemberId]) {
|
|
|
- self.applyFormSnapshot(self.memberFormMap[self.activeFormMemberId])
|
|
|
- } else {
|
|
|
- self.resetFormFields()
|
|
|
- self.loadHealthForm(self.activeFormMemberId)
|
|
|
+ },
|
|
|
+ hasDietContent: function(diet) {
|
|
|
+ if (!diet) return false
|
|
|
+ var arrs = [diet.allergies, diet.absoluteAvoid, diet.mustEat, diet.flavorPref, diet.cuisinePref, diet.cookingMethods, diet.healthGoals]
|
|
|
+ for (var i = 0; i < arrs.length; i++) {
|
|
|
+ if (arrs[i] && arrs[i].length > 0) return true
|
|
|
}
|
|
|
+ if (diet.spiceLevel && Number(diet.spiceLevel) > 0) return true
|
|
|
+ if (diet.religiousDiet && diet.religiousDiet !== 'none') return true
|
|
|
+ return false
|
|
|
},
|
|
|
- applyFormSnapshot: function(snapshot) {
|
|
|
- if (!snapshot) return
|
|
|
- this.form = JSON.parse(JSON.stringify(snapshot.form || {}))
|
|
|
- this.lipidCholesterol = snapshot.lipidCholesterol || ''
|
|
|
- this.selectedDiseases = JSON.parse(JSON.stringify(snapshot.selectedDiseases || []))
|
|
|
- this.medRows = snapshot.medRows && snapshot.medRows.length > 0 ? JSON.parse(JSON.stringify(snapshot.medRows)) : [{ name: '', startDate: '', durationText: '', time: '' }]
|
|
|
- var self = this
|
|
|
- this.selectedDiseases.forEach(function(item) {
|
|
|
- var gk = self.findGroupKey(item.name)
|
|
|
- if (gk && self.expandedGroups.indexOf(gk) < 0) self.expandedGroups.push(gk)
|
|
|
- })
|
|
|
+ // 保存用饮食对象:noPreference 为前端标记,但随表单落库(后端 diet_preferences.no_preference 持久化)
|
|
|
+ dietForSave: function(diet) {
|
|
|
+ var out = {}
|
|
|
+ var keys = ['allergies', 'absoluteAvoid', 'mustEat', 'religiousDiet', 'spiceLevel', 'flavorPref', 'cuisinePref', 'cookingMethods', 'healthGoals', 'noPreference']
|
|
|
+ keys.forEach(function(k) { out[k] = diet[k] })
|
|
|
+ return out
|
|
|
},
|
|
|
- resetFormFields: function() {
|
|
|
- this.form = { heightCm: '', weightKg: '', bloodPressure: '', bloodGlucose: '', notes: '' }
|
|
|
- this.lipidCholesterol = ''
|
|
|
- this.selectedDiseases = []
|
|
|
- this.medRows = [{ name: '', startDate: '', durationText: '', time: '' }]
|
|
|
- this.diseaseInput = ''
|
|
|
+ // 切换成员:仅切换当前填写对象(数据已按成员写入快照,无需手动保存)
|
|
|
+ switchMember: function(memberId) {
|
|
|
+ if (String(memberId) === String(this.activeFormMemberId)) return
|
|
|
+ this.activeFormMemberId = String(memberId)
|
|
|
+ this.loadHealthForm(this.activeFormMemberId)
|
|
|
+ this.loadDietForm(this.activeFormMemberId)
|
|
|
},
|
|
|
parseLipidCholesterol: function(json) {
|
|
|
try {
|
|
|
@@ -640,26 +456,17 @@ selectedMembers: function() {
|
|
|
} catch (e) {}
|
|
|
return ''
|
|
|
},
|
|
|
- loadDiseasesInto: function(targetList, json) {
|
|
|
- var self = this
|
|
|
+ parseDiseases: function(json) {
|
|
|
+ var list = []
|
|
|
try {
|
|
|
var arr = JSON.parse(json || '[]')
|
|
|
if (arr instanceof Array) {
|
|
|
arr.forEach(function(item) {
|
|
|
- if (item.name && self.selectedNames.indexOf(item.name) < 0) {
|
|
|
- targetList.push({
|
|
|
- name: item.name,
|
|
|
- diagnosedAt: item.diagnosedAt || '',
|
|
|
- custom: false
|
|
|
- })
|
|
|
- var gk = self.findGroupKey(item.name)
|
|
|
- if (gk && self.expandedGroups.indexOf(gk) < 0) {
|
|
|
- self.expandedGroups.push(gk)
|
|
|
- }
|
|
|
- }
|
|
|
+ if (item.name) list.push({ name: item.name, diagnosedAt: item.diagnosedAt || '', custom: false })
|
|
|
})
|
|
|
}
|
|
|
} catch (e) {}
|
|
|
+ return list
|
|
|
},
|
|
|
parseMeds: function(json) {
|
|
|
var list = []
|
|
|
@@ -676,103 +483,44 @@ selectedMembers: function() {
|
|
|
})
|
|
|
}
|
|
|
} catch (e) {}
|
|
|
- if (list.length === 0) list.push({ name: '', startDate: '', durationText: '', time: '' })
|
|
|
return list
|
|
|
},
|
|
|
- toggleGroup: function(key) {
|
|
|
- var idx = this.expandedGroups.indexOf(key)
|
|
|
- if (idx >= 0) this.expandedGroups.splice(idx, 1)
|
|
|
- else this.expandedGroups.push(key)
|
|
|
- },
|
|
|
- findGroupKey: function(name) {
|
|
|
- for (var i = 0; i < DISEASE_GROUPS.length; i++) {
|
|
|
- var items = DISEASE_GROUPS[i].items
|
|
|
- for (var j = 0; j < items.length; j++) {
|
|
|
- if (items[j].name === name) return DISEASE_GROUPS[i].key
|
|
|
- }
|
|
|
- }
|
|
|
- return ''
|
|
|
- },
|
|
|
- toggleDisease: function(name) {
|
|
|
- var idx = -1
|
|
|
- for (var i = 0; i < this.selectedDiseases.length; i++) {
|
|
|
- if (this.selectedDiseases[i].name === name) { idx = i; break }
|
|
|
- }
|
|
|
- if (idx >= 0) {
|
|
|
- this.selectedDiseases.splice(idx, 1)
|
|
|
- } else {
|
|
|
- this.selectedDiseases.push({ name: name, diagnosedAt: '', custom: false })
|
|
|
- var gk = this.findGroupKey(name)
|
|
|
- if (gk && this.expandedGroups.indexOf(gk) < 0) {
|
|
|
- this.expandedGroups.push(gk)
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- showRiskTip: function(name) {
|
|
|
- uni.showModal({
|
|
|
- title: '菌群报告关联',
|
|
|
- content: '「' + name + '」与肠道菌群报告相关,勾选后出方案时可结合菌群报告风险值评估。',
|
|
|
- showCancel: false
|
|
|
- })
|
|
|
- },
|
|
|
- addCustomDisease: function() {
|
|
|
- var name = (this.diseaseInput || '').trim()
|
|
|
- if (!name) return
|
|
|
- if (this.selectedNames.indexOf(name) < 0) {
|
|
|
- this.selectedDiseases.push({ name: name, diagnosedAt: '', custom: true })
|
|
|
- }
|
|
|
- this.diseaseInput = ''
|
|
|
- },
|
|
|
- getSelKey: function(i) { return 's' + i },
|
|
|
- removeSelected: function(idx) {
|
|
|
- this.selectedDiseases.splice(idx, 1)
|
|
|
+ // ===== 向导事件:按当前成员写回快照 =====
|
|
|
+ onWizardVitals: function(flat) {
|
|
|
+ this.mergeWizardForm(flat)
|
|
|
},
|
|
|
- onDiagChange: function(idx, e) {
|
|
|
- this.selectedDiseases[idx].diagnosedAt = e.detail.value
|
|
|
+ onWizardMedical: function(flat) {
|
|
|
+ this.mergeWizardForm(flat)
|
|
|
},
|
|
|
- addMed: function() {
|
|
|
- this.medRows.push({ name: '', startDate: '', durationText: '', time: '' })
|
|
|
+ onWizardDiet: function(diet) {
|
|
|
+ var key = String(this.activeFormMemberId || '__account')
|
|
|
+ this.$set(this.memberDietMap, key, diet)
|
|
|
},
|
|
|
- onMedStartChange: function(idx, e) {
|
|
|
- var start = e.detail.value
|
|
|
- this.medRows[idx].startDate = start
|
|
|
- this.medRows[idx].durationText = this.calcDuration(start)
|
|
|
+ onWizardSubmit: function() {
|
|
|
+ this.saveAndGenerate()
|
|
|
},
|
|
|
- onForgetClick: function(idx) {
|
|
|
- var self = this
|
|
|
- uni.showModal({
|
|
|
- title: '记不清开始日期',
|
|
|
- editable: true,
|
|
|
- placeholderText: '如:约 3 个月',
|
|
|
- success: function(res) {
|
|
|
- if (res.confirm && res.content) {
|
|
|
- self.medRows[idx].durationText = res.content.trim()
|
|
|
- }
|
|
|
- }
|
|
|
+ // 合并向导推送的扁平体征/疾病数据到当前成员快照
|
|
|
+ mergeWizardForm: function(flat) {
|
|
|
+ if (!flat) return
|
|
|
+ var key = String(this.activeFormMemberId || '__account')
|
|
|
+ var prev = this.memberFormMap[key] || {}
|
|
|
+ var pf = prev.form || {}
|
|
|
+ this.$set(this.memberFormMap, key, {
|
|
|
+ form: {
|
|
|
+ heightCm: flat.heightCm != null ? flat.heightCm : (pf.heightCm || ''),
|
|
|
+ weightKg: flat.weightKg != null ? flat.weightKg : (pf.weightKg || ''),
|
|
|
+ bloodPressure: flat.bloodPressure != null ? flat.bloodPressure : (pf.bloodPressure || ''),
|
|
|
+ bloodGlucose: flat.bloodGlucose != null ? flat.bloodGlucose : (pf.bloodGlucose || ''),
|
|
|
+ notes: flat.notes != null ? flat.notes : (pf.notes || '')
|
|
|
+ },
|
|
|
+ lipidCholesterol: flat.lipidCholesterol != null ? flat.lipidCholesterol : (prev.lipidCholesterol || ''),
|
|
|
+ selectedDiseases: flat.selectedDiseases != null ? flat.selectedDiseases : (prev.selectedDiseases || []),
|
|
|
+ medRows: flat.medRows != null ? flat.medRows : (prev.medRows || []),
|
|
|
+ noMedication: flat.noMedication != null ? flat.noMedication : (prev.noMedication || false)
|
|
|
})
|
|
|
},
|
|
|
- calcDuration: function(startDate) {
|
|
|
- if (!startDate) return ''
|
|
|
- var parts = startDate.split('-')
|
|
|
- if (parts.length !== 2) return ''
|
|
|
- var sy = parseInt(parts[0], 10)
|
|
|
- var sm = parseInt(parts[1], 10)
|
|
|
- var now = new Date()
|
|
|
- var months = (now.getFullYear() - sy) * 12 + (now.getMonth() + 1 - sm)
|
|
|
- if (months < 1) months = 1
|
|
|
- if (months < 12) return '已服 ' + months + ' 个月'
|
|
|
- return '已服 ' + Math.floor(months / 12) + ' 年'
|
|
|
- },
|
|
|
- removeMed: function(idx) {
|
|
|
- if (this.medRows.length > 1) this.medRows.splice(idx, 1)
|
|
|
- },
|
|
|
buildHealthPayload: function(snapshot) {
|
|
|
- var s = snapshot || {
|
|
|
- form: this.form,
|
|
|
- lipidCholesterol: this.lipidCholesterol,
|
|
|
- selectedDiseases: this.selectedDiseases,
|
|
|
- medRows: this.medRows
|
|
|
- }
|
|
|
+ var s = snapshot || {}
|
|
|
var lipids = []
|
|
|
if (s.lipidCholesterol) {
|
|
|
lipids.push({ name: '总胆固醇', value: parseFloat(s.lipidCholesterol), unit: 'mmol/L', note: '' })
|
|
|
@@ -804,39 +552,21 @@ selectedMembers: function() {
|
|
|
if (s.form.notes) payload.notes = s.form.notes
|
|
|
return payload
|
|
|
},
|
|
|
- // 当前成员快照(无改动数据时返回 null)
|
|
|
+ // 当前成员快照(无数据时返回 null)
|
|
|
snapshotForMember: function(memberId) {
|
|
|
- var key = String(memberId)
|
|
|
- // 优先用已保存的成员快照,其次当前活动表单
|
|
|
- if (this.memberFormMap[key]) {
|
|
|
- var s = this.memberFormMap[key]
|
|
|
- var p = this.buildHealthPayload(s)
|
|
|
- return this.hasPayload(p) ? p : null
|
|
|
- }
|
|
|
- // 活动成员直接用当前表单
|
|
|
- if (key === String(this.activeFormMemberId)) {
|
|
|
- var activePayload = this.buildHealthPayload()
|
|
|
- return this.hasPayload(activePayload) ? activePayload : null
|
|
|
- }
|
|
|
- return null
|
|
|
+ var s = this.memberFormMap[String(memberId)]
|
|
|
+ if (!s) return null
|
|
|
+ var p = this.buildHealthPayload(s)
|
|
|
+ return this.hasPayload(p) ? p : null
|
|
|
},
|
|
|
hasPayload: function(payload) {
|
|
|
if (!payload) return false
|
|
|
return payload.heightCm || payload.weightKg || payload.bloodPressure || payload.bloodGlucose ||
|
|
|
payload.bloodLipids || payload.diseaseHistory || payload.medications || payload.notes
|
|
|
},
|
|
|
- // 先保存当前活动成员的编辑内容到快照,再逐个成员保存健康档案,最后生成方案
|
|
|
+ // 逐个成员保存健康档案 + 饮食习惯,最后生成方案
|
|
|
saveAndGenerate: function() {
|
|
|
var self = this
|
|
|
- // 保存当前活动成员到快照
|
|
|
- if (self.activeFormMemberId) {
|
|
|
- self.memberFormMap[self.activeFormMemberId] = {
|
|
|
- form: JSON.parse(JSON.stringify(self.form)),
|
|
|
- lipidCholesterol: self.lipidCholesterol,
|
|
|
- selectedDiseases: JSON.parse(JSON.stringify(self.selectedDiseases)),
|
|
|
- medRows: JSON.parse(JSON.stringify(self.medRows))
|
|
|
- }
|
|
|
- }
|
|
|
// 血压格式校验(检查所有成员)
|
|
|
var members = self.selectedMemberIds.slice()
|
|
|
for (var i = 0; i < members.length; i++) {
|
|
|
@@ -850,18 +580,25 @@ selectedMembers: function() {
|
|
|
var saveTasks = []
|
|
|
members.forEach(function(mid) {
|
|
|
var payload = self.snapshotForMember(mid)
|
|
|
- if (!payload) return
|
|
|
- payload.memberId = mid
|
|
|
- saveTasks.push(saveHealthStatus(payload))
|
|
|
+ if (payload) {
|
|
|
+ payload.memberId = mid
|
|
|
+ saveTasks.push(saveHealthStatus(payload))
|
|
|
+ }
|
|
|
+ var diet = self.memberDietMap[String(mid)]
|
|
|
+ if (diet && (self.hasDietContent(diet) || diet.noPreference)) {
|
|
|
+ var dietPayload = self.dietForSave(diet)
|
|
|
+ dietPayload.familyMemberId = mid
|
|
|
+ saveTasks.push(saveDietPreferences(dietPayload))
|
|
|
+ }
|
|
|
})
|
|
|
if (saveTasks.length === 0) {
|
|
|
- // 无健康数据,直接生成方案
|
|
|
+ // 无问卷数据,直接生成方案
|
|
|
self.loading = false
|
|
|
self.generatePlan()
|
|
|
return
|
|
|
}
|
|
|
Promise.all(saveTasks).then(function() {
|
|
|
- uni.showToast({ title: '健康信息已保存', icon: 'success' })
|
|
|
+ uni.showToast({ title: '信息已保存', icon: 'success' })
|
|
|
self.loading = false
|
|
|
self.generatePlan()
|
|
|
}).catch(function() {
|
|
|
@@ -918,6 +655,27 @@ selectedMembers: function() {
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
+ checkQuestionnaireGate: function() {
|
|
|
+ var self = this
|
|
|
+ getMyMembership().then(function(res) {
|
|
|
+ var m = (res && res.data) || {}
|
|
|
+ var level = m.memberLevel || m.levelCode || ''
|
|
|
+ if (level && level !== 'FREE') return
|
|
|
+ uni.showModal({
|
|
|
+ title: '开通 9.9 元/月健康会员',
|
|
|
+ content: '填写健康自检问卷需先开通月度健康会员(9.9 元/月),开通后可填写问卷并生成个性化健康方案。',
|
|
|
+ confirmText: '去开通',
|
|
|
+ cancelText: '暂不',
|
|
|
+ success: function(r) {
|
|
|
+ if (r.confirm) {
|
|
|
+ uni.navigateTo({ url: '/pages/membership/pay?levelCode=LITE&period=monthly' })
|
|
|
+ } else {
|
|
|
+ uni.navigateBack({ delta: 1 })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }).catch(function() {})
|
|
|
+ },
|
|
|
// 付费墙引导:三选一(购买家庭会员 / 购买健康启航计划 / 取消)
|
|
|
showPaywallSheet: function() {
|
|
|
uni.showActionSheet({
|
|
|
@@ -1175,13 +933,8 @@ selectedMembers: function() {
|
|
|
exercise: { content: '', confirmed: false }
|
|
|
}
|
|
|
// 重置健康问卷
|
|
|
- this.form = { heightCm: '', weightKg: '', bloodPressure: '', bloodGlucose: '', notes: '' }
|
|
|
- this.lipidCholesterol = ''
|
|
|
- this.selectedDiseases = []
|
|
|
- this.diseaseInput = ''
|
|
|
- this.medRows = [{ name: '', startDate: '', durationText: '', time: '' }]
|
|
|
- this.expandedGroups = DISEASE_GROUPS.slice(0, 3).map(function(g) { return g.key })
|
|
|
this.memberFormMap = {}
|
|
|
+ this.memberDietMap = {}
|
|
|
this.activeFormMemberId = ''
|
|
|
this.pickerMembers = []
|
|
|
this.goalLen = 0
|