report-survey.vue 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. <template>
  2. <view class="survey-container">
  3. <!-- 导航 -->
  4. <view class="nav-bar">
  5. <text class="nav-back" @click="goBack">‹ 返回</text>
  6. <text class="nav-title">健康调研问卷</text>
  7. <view class="nav-placeholder"></view>
  8. </view>
  9. <!-- 进度条 -->
  10. <view class="progress-bar">
  11. <view class="progress-fill" :style="{ width: progressPercent + '%' }"></view>
  12. </view>
  13. <!-- 提示说明 -->
  14. <view class="tip-banner">
  15. <text class="tip-icon">💡</text>
  16. <text class="tip-text">请根据孩子和家庭的实际情况填写,帮助AI更准确地解读报告</text>
  17. </view>
  18. <!-- 表单 -->
  19. <view class="form-section">
  20. <!-- ===================== 第一部分:生活习惯 ===================== -->
  21. <view class="section-header">
  22. <text class="section-icon">🍚</text>
  23. <text class="section-title">生活习惯</text>
  24. </view>
  25. <!-- Q1: 饮食结构 -->
  26. <view class="question-card">
  27. <text class="q-number">1/12</text>
  28. <text class="q-title">孩子平时的饮食结构是怎样的?</text>
  29. <view class="q-options">
  30. <view class="q-option" :class="{ 'q-selected': survey.diet === 'balanced' }" @click="survey.diet = 'balanced'">
  31. <text class="q-icon">🥗</text>
  32. <text class="q-text">均衡饮食,荤素搭配</text>
  33. </view>
  34. <view class="q-option" :class="{ 'q-selected': survey.diet === 'meat' }" @click="survey.diet = 'meat'">
  35. <text class="q-icon">🥩</text>
  36. <text class="q-text">偏荤食,爱吃肉</text>
  37. </view>
  38. <view class="q-option" :class="{ 'q-selected': survey.diet === 'veggie' }" @click="survey.diet = 'veggie'">
  39. <text class="q-icon">🥬</text>
  40. <text class="q-text">偏素食,不爱吃肉</text>
  41. </view>
  42. <view class="q-option" :class="{ 'q-selected': survey.diet === 'junk' }" @click="survey.diet = 'junk'">
  43. <text class="q-icon">🍟</text>
  44. <text class="q-text">偏好零食/快餐</text>
  45. </view>
  46. </view>
  47. </view>
  48. <!-- Q2: 消化状况 -->
  49. <view class="question-card">
  50. <text class="q-number">2/12</text>
  51. <text class="q-title">孩子近期消化状况如何?</text>
  52. <view class="q-options">
  53. <view class="q-option" :class="{ 'q-selected': survey.digestion === 'good' }" @click="survey.digestion = 'good'">
  54. <text>😊</text>
  55. <text class="q-text">正常,消化良好</text>
  56. </view>
  57. <view class="q-option" :class="{ 'q-selected': survey.digestion === 'constipation' }" @click="survey.digestion = 'constipation'">
  58. <text>😣</text>
  59. <text class="q-text">容易便秘</text>
  60. </view>
  61. <view class="q-option" :class="{ 'q-selected': survey.digestion === 'diarrhea' }" @click="survey.digestion = 'diarrhea'">
  62. <text>😟</text>
  63. <text class="q-text">容易腹泻</text>
  64. </view>
  65. <view class="q-option" :class="{ 'q-selected': survey.digestion === 'irregular' }" @click="survey.digestion = 'irregular'">
  66. <text>🤔</text>
  67. <text class="q-text">不太规律</text>
  68. </view>
  69. </view>
  70. </view>
  71. <!-- Q3: 睡眠质量 -->
  72. <view class="question-card">
  73. <text class="q-number">3/12</text>
  74. <text class="q-title">孩子近期的睡眠质量如何?</text>
  75. <view class="q-options">
  76. <view class="q-option" :class="{ 'q-selected': survey.sleep === 'good' }" @click="survey.sleep = 'good'">
  77. <text>😴</text>
  78. <text class="q-text">睡得好,作息规律</text>
  79. </view>
  80. <view class="q-option" :class="{ 'q-selected': survey.sleep === 'late' }" @click="survey.sleep = 'late'">
  81. <text>🦉</text>
  82. <text class="q-text">睡得太晚</text>
  83. </view>
  84. <view class="q-option" :class="{ 'q-selected': survey.sleep === 'restless' }" @click="survey.sleep = 'restless'">
  85. <text>😰</text>
  86. <text class="q-text">翻来覆去睡不安稳</text>
  87. </view>
  88. <view class="q-option" :class="{ 'q-selected': survey.sleep === 'short' }" @click="survey.sleep = 'short'">
  89. <text>⏰</text>
  90. <text class="q-text">睡眠时间不足</text>
  91. </view>
  92. </view>
  93. </view>
  94. <!-- Q4: 运动习惯 -->
  95. <view class="question-card">
  96. <text class="q-number">4/12</text>
  97. <text class="q-title">孩子每周运动情况?</text>
  98. <view class="q-options">
  99. <view class="q-option" :class="{ 'q-selected': survey.exercise === 'frequent' }" @click="survey.exercise = 'frequent'">
  100. <text>🏃</text>
  101. <text class="q-text">经常运动(3次以上/周)</text>
  102. </view>
  103. <view class="q-option" :class="{ 'q-selected': survey.exercise === 'moderate' }" @click="survey.exercise = 'moderate'">
  104. <text>🚶</text>
  105. <text class="q-text">偶尔运动(1-2次/周)</text>
  106. </view>
  107. <view class="q-option" :class="{ 'q-selected': survey.exercise === 'rare' }" @click="survey.exercise = 'rare'">
  108. <text>🪑</text>
  109. <text class="q-text">很少运动</text>
  110. </view>
  111. </view>
  112. </view>
  113. <!-- Q5: 饮水习惯 -->
  114. <view class="question-card">
  115. <text class="q-number">5/12</text>
  116. <text class="q-title">孩子每日饮水量如何?</text>
  117. <view class="q-options">
  118. <view class="q-option" :class="{ 'q-selected': survey.water === 'enough' }" @click="survey.water = 'enough'">
  119. <text>💧</text>
  120. <text class="q-text">充足(>1500ml)</text>
  121. </view>
  122. <view class="q-option" :class="{ 'q-selected': survey.water === 'moderate' }" @click="survey.water = 'moderate'">
  123. <text>🥤</text>
  124. <text class="q-text">一般(500-1500ml)</text>
  125. </view>
  126. <view class="q-option" :class="{ 'q-selected': survey.water === 'little' }" @click="survey.water = 'little'">
  127. <text>😥</text>
  128. <text class="q-text">偏少(<500ml)</text>
  129. </view>
  130. </view>
  131. </view>
  132. <!-- Q6: 用药情况 -->
  133. <view class="question-card">
  134. <text class="q-number">6/12</text>
  135. <text class="q-title">孩子近期是否有以下用药情况?(可多选)</text>
  136. <view class="q-options multi">
  137. <view class="q-option" :class="{ 'q-selected': hasMedication('antibiotic') }" @click="toggleMedication('antibiotic')">
  138. <text class="q-text">抗生素(近3个月内使用过)</text>
  139. </view>
  140. <view class="q-option" :class="{ 'q-selected': hasMedication('probiotic') }" @click="toggleMedication('probiotic')">
  141. <text class="q-text">益生菌/益生元</text>
  142. </view>
  143. <view class="q-option" :class="{ 'q-selected': hasMedication('cold') }" @click="toggleMedication('cold')">
  144. <text class="q-text">感冒药/退烧药</text>
  145. </view>
  146. <view class="q-option" :class="{ 'q-selected': hasMedication('stomach') }" @click="toggleMedication('stomach')">
  147. <text class="q-text">肠胃药</text>
  148. </view>
  149. <view class="q-option" :class="{ 'q-selected': hasMedication('none') }" @click="toggleMedication('none')">
  150. <text class="q-text">无特殊用药</text>
  151. </view>
  152. </view>
  153. </view>
  154. <!-- ===================== 第二部分:疾病史 ===================== -->
  155. <view class="section-header">
  156. <text class="section-icon">🏥</text>
  157. <text class="section-title">疾病史</text>
  158. </view>
  159. <!-- Q7: 慢性病/系统性疾病 -->
  160. <view class="question-card">
  161. <text class="q-number">7/12</text>
  162. <text class="q-title">孩子是否有以下慢性或系统性疾病?(可多选)</text>
  163. <view class="q-options multi">
  164. <view class="q-option" :class="{ 'q-selected': hasChronic('none') }" @click="toggleChronic('none')">
  165. <text class="q-text">无已知疾病</text>
  166. </view>
  167. <view class="q-option" :class="{ 'q-selected': hasChronic('asthma') }" @click="toggleChronic('asthma')">
  168. <text class="q-text">哮喘/过敏性鼻炎</text>
  169. </view>
  170. <view class="q-option" :class="{ 'q-selected': hasChronic('eczema') }" @click="toggleChronic('eczema')">
  171. <text class="q-text">湿疹/特应性皮炎</text>
  172. </view>
  173. <view class="q-option" :class="{ 'q-selected': hasChronic('anemia') }" @click="toggleChronic('anemia')">
  174. <text class="q-text">贫血</text>
  175. </view>
  176. <view class="q-option" :class="{ 'q-selected': hasChronic('obesity') }" @click="toggleChronic('obesity')">
  177. <text class="q-text">超重/肥胖</text>
  178. </view>
  179. <view class="q-option" :class="{ 'q-selected': hasChronic('underweight') }" @click="toggleChronic('underweight')">
  180. <text class="q-text">偏瘦/营养不良</text>
  181. </view>
  182. <view class="q-option" :class="{ 'q-selected': hasChronic('thyroid') }" @click="toggleChronic('thyroid')">
  183. <text class="q-text">甲状腺问题</text>
  184. </view>
  185. <view class="q-option" :class="{ 'q-selected': hasChronic('digestive') }" @click="toggleChronic('digestive')">
  186. <text class="q-text">消化系统疾病(胃炎/肠炎等)</text>
  187. </view>
  188. <view class="q-option" :class="{ 'q-selected': hasChronic('other') }" @click="toggleChronic('other')">
  189. <text class="q-text">其他(请在备注说明)</text>
  190. </view>
  191. </view>
  192. <!-- 其他疾病描述 -->
  193. <textarea v-if="hasChronic('other')" class="extra-input" v-model="survey.diseaseHistory.otherDesc" placeholder="请描述其他疾病情况..." maxlength="200" />
  194. </view>
  195. <!-- Q8: 过敏史 -->
  196. <view class="question-card">
  197. <text class="q-number">8/12</text>
  198. <text class="q-title">孩子是否有以下过敏情况?(可多选)</text>
  199. <view class="q-options multi">
  200. <view class="q-option" :class="{ 'q-selected': survey.allergies.indexOf('none') !== -1 }" @click="toggleAllergy('none')">
  201. <text class="q-text">无明显过敏</text>
  202. </view>
  203. <view class="q-option" :class="{ 'q-selected': survey.allergies.indexOf('food') !== -1 }" @click="toggleAllergy('food')">
  204. <text class="q-text">食物过敏(牛奶/鸡蛋/海鲜等)</text>
  205. </view>
  206. <view class="q-option" :class="{ 'q-selected': survey.allergies.indexOf('drug') !== -1 }" @click="toggleAllergy('drug')">
  207. <text class="q-text">药物过敏</text>
  208. </view>
  209. <view class="q-option" :class="{ 'q-selected': survey.allergies.indexOf('pollen') !== -1 }" @click="toggleAllergy('pollen')">
  210. <text class="q-text">花粉/尘螨过敏</text>
  211. </view>
  212. <view class="q-option" :class="{ 'q-selected': survey.allergies.indexOf('skin') !== -1 }" @click="toggleAllergy('skin')">
  213. <text class="q-text">皮肤过敏/荨麻疹</text>
  214. </view>
  215. </view>
  216. <!-- 过敏详情 -->
  217. <textarea v-if="survey.allergies.length > 0 && survey.allergies.indexOf('none') === -1" class="extra-input" v-model="survey.allergyDetail" placeholder="请补充过敏详情(过敏原、症状等)..." maxlength="200" />
  218. </view>
  219. <!-- Q9: 手术/住院史 -->
  220. <view class="question-card">
  221. <text class="q-number">9/12</text>
  222. <text class="q-title">孩子是否有手术或住院史?</text>
  223. <view class="q-options">
  224. <view class="q-option" :class="{ 'q-selected': survey.surgery === 'none' }" @click="survey.surgery = 'none'">
  225. <text class="q-text">无</text>
  226. </view>
  227. <view class="q-option" :class="{ 'q-selected': survey.surgery === 'yes' }" @click="survey.surgery = 'yes'">
  228. <text class="q-text">有</text>
  229. </view>
  230. </view>
  231. <textarea v-if="survey.surgery === 'yes'" class="extra-input" v-model="survey.surgeryDetail" placeholder="请描述手术/住院原因和时间..." maxlength="200" />
  232. </view>
  233. <!-- ===================== 第三部分:家族史 ===================== -->
  234. <view class="section-header">
  235. <text class="section-icon">🧬</text>
  236. <text class="section-title">家族病史</text>
  237. </view>
  238. <!-- Q10: 家族病史 -->
  239. <view class="question-card">
  240. <text class="q-number">10/12</text>
  241. <text class="q-title">直系亲属是否有以下疾病史?(可多选)</text>
  242. <view class="family-grid">
  243. <view class="family-col">
  244. <text class="family-role">父亲</text>
  245. <view class="family-options">
  246. <view v-for="opt in familyDiseaseOptions" :key="opt.value"
  247. class="family-tag" :class="{ 'tag-selected': hasFamilyDisease('father', opt.value) }"
  248. @click="toggleFamilyDisease('father', opt.value)">
  249. <text>{{ opt.label }}</text>
  250. </view>
  251. <view class="family-tag" :class="{ 'tag-selected': hasFamilyDisease('father', 'other') }"
  252. @click="toggleFamilyDisease('father', 'other')">
  253. <text>其他</text>
  254. </view>
  255. </view>
  256. </view>
  257. <view class="family-col">
  258. <text class="family-role">母亲</text>
  259. <view class="family-options">
  260. <view v-for="opt in familyDiseaseOptions" :key="opt.value"
  261. class="family-tag" :class="{ 'tag-selected': hasFamilyDisease('mother', opt.value) }"
  262. @click="toggleFamilyDisease('mother', opt.value)">
  263. <text>{{ opt.label }}</text>
  264. </view>
  265. <view class="family-tag" :class="{ 'tag-selected': hasFamilyDisease('mother', 'other') }"
  266. @click="toggleFamilyDisease('mother', 'other')">
  267. <text>其他</text>
  268. </view>
  269. </view>
  270. </view>
  271. <view class="family-col">
  272. <text class="family-role">兄弟姐妹</text>
  273. <view class="family-options">
  274. <view v-for="opt in familyDiseaseOptions" :key="opt.value"
  275. class="family-tag" :class="{ 'tag-selected': hasFamilyDisease('sibling', opt.value) }"
  276. @click="toggleFamilyDisease('sibling', opt.value)">
  277. <text>{{ opt.label }}</text>
  278. </view>
  279. <view class="family-tag" :class="{ 'tag-selected': hasFamilyDisease('sibling', 'other') }"
  280. @click="toggleFamilyDisease('sibling', 'other')">
  281. <text>其他</text>
  282. </view>
  283. </view>
  284. </view>
  285. </view>
  286. </view>
  287. <!-- Q11: 祖父母病史 -->
  288. <view class="question-card">
  289. <text class="q-number">11/12</text>
  290. <text class="q-title">祖父母/外祖父母是否有以下疾病史?(可多选)</text>
  291. <view class="q-options multi">
  292. <view class="q-option" :class="{ 'q-selected': survey.grandparentHistory.indexOf('unknown') !== -1 }" @click="toggleGrandparent('unknown')">
  293. <text class="q-text">不清楚</text>
  294. </view>
  295. <view class="q-option" :class="{ 'q-selected': survey.grandparentHistory.indexOf('hypertension') !== -1 }" @click="toggleGrandparent('hypertension')">
  296. <text class="q-text">高血压</text>
  297. </view>
  298. <view class="q-option" :class="{ 'q-selected': survey.grandparentHistory.indexOf('diabetes') !== -1 }" @click="toggleGrandparent('diabetes')">
  299. <text class="q-text">糖尿病</text>
  300. </view>
  301. <view class="q-option" :class="{ 'q-selected': survey.grandparentHistory.indexOf('heart') !== -1 }" @click="toggleGrandparent('heart')">
  302. <text class="q-text">心脏病</text>
  303. </view>
  304. <view class="q-option" :class="{ 'q-selected': survey.grandparentHistory.indexOf('stroke') !== -1 }" @click="toggleGrandparent('stroke')">
  305. <text class="q-text">脑卒中</text>
  306. </view>
  307. <view class="q-option" :class="{ 'q-selected': survey.grandparentHistory.indexOf('cancer') !== -1 }" @click="toggleGrandparent('cancer')">
  308. <text class="q-text">癌症</text>
  309. </view>
  310. <view class="q-option" :class="{ 'q-selected': survey.grandparentHistory.indexOf('autoimmune') !== -1 }" @click="toggleGrandparent('autoimmune')">
  311. <text class="q-text">自身免疫病</text>
  312. </view>
  313. <view class="q-option" :class="{ 'q-selected': survey.grandparentHistory.indexOf('none') !== -1 }" @click="toggleGrandparent('none')">
  314. <text class="q-text">无明显疾病</text>
  315. </view>
  316. </view>
  317. </view>
  318. <!-- ===================== 第四部分:健康目标 ===================== -->
  319. <view class="section-header">
  320. <text class="section-icon">🎯</text>
  321. <text class="section-title">健康目标</text>
  322. </view>
  323. <!-- Q12: 健康目标 -->
  324. <view class="question-card">
  325. <text class="q-number">12/12</text>
  326. <text class="q-title">您希望通过本次健康管理改善什么?(可多选)</text>
  327. <view class="q-options multi">
  328. <view class="q-option" :class="{ 'q-selected': survey.goals.indexOf('immunity') !== -1 }" @click="toggleGoal('immunity')">
  329. <text>🛡️</text>
  330. <text class="q-text">增强免疫力</text>
  331. </view>
  332. <view class="q-option" :class="{ 'q-selected': survey.goals.indexOf('digestion') !== -1 }" @click="toggleGoal('digestion')">
  333. <text>🌿</text>
  334. <text class="q-text">改善消化</text>
  335. </view>
  336. <view class="q-option" :class="{ 'q-selected': survey.goals.indexOf('growth') !== -1 }" @click="toggleGoal('growth')">
  337. <text>📈</text>
  338. <text class="q-text">促进生长发育</text>
  339. </view>
  340. <view class="q-option" :class="{ 'q-selected': survey.goals.indexOf('focus') !== -1 }" @click="toggleGoal('focus')">
  341. <text>🎯</text>
  342. <text class="q-text">提升专注力</text>
  343. </view>
  344. <view class="q-option" :class="{ 'q-selected': survey.goals.indexOf('sleep') !== -1 }" @click="toggleGoal('sleep')">
  345. <text>😴</text>
  346. <text class="q-text">改善睡眠</text>
  347. </view>
  348. <view class="q-option" :class="{ 'q-selected': survey.goals.indexOf('weight') !== -1 }" @click="toggleGoal('weight')">
  349. <text>⚖️</text>
  350. <text class="q-text">体重管理</text>
  351. </view>
  352. <view class="q-option" :class="{ 'q-selected': survey.goals.indexOf('allergy') !== -1 }" @click="toggleGoal('allergy')">
  353. <text>🌸</text>
  354. <text class="q-text">改善过敏</text>
  355. </view>
  356. <view class="q-option" :class="{ 'q-selected': survey.goals.indexOf('mood') !== -1 }" @click="toggleGoal('mood')">
  357. <text>😊</text>
  358. <text class="q-text">改善情绪</text>
  359. </view>
  360. </view>
  361. </view>
  362. <!-- 提交按钮 -->
  363. <view class="submit-btn" :class="{ 'btn-disabled': !canSubmit }" @click="doSubmit">
  364. <text v-if="submitting">提交中...</text>
  365. <text v-else>提交并进入 AI 解读</text>
  366. </view>
  367. </view>
  368. <view class="bottom-spacer"></view>
  369. </view>
  370. </template>
  371. <script>
  372. import { createReportSurvey, submitReportSurvey, getSurveyStatus } from '../../utils/api.js'
  373. export default {
  374. data() {
  375. return {
  376. reportId: null,
  377. childId: null,
  378. surveyId: null,
  379. survey: {
  380. // 生活习惯
  381. diet: '',
  382. digestion: '',
  383. sleep: '',
  384. exercise: '',
  385. water: '',
  386. medications: [],
  387. // 疾病史
  388. diseaseHistory: {
  389. chronic: [],
  390. otherDesc: ''
  391. },
  392. allergies: [],
  393. allergyDetail: '',
  394. surgery: '',
  395. surgeryDetail: '',
  396. // 家族史
  397. familyHistory: {
  398. father: [],
  399. mother: [],
  400. sibling: []
  401. },
  402. grandparentHistory: [],
  403. // 健康目标
  404. goals: []
  405. },
  406. familyDiseaseOptions: [
  407. { value: 'none', label: '无' },
  408. { value: 'hypertension', label: '高血压' },
  409. { value: 'diabetes', label: '糖尿病' },
  410. { value: 'heart', label: '心脏病' },
  411. { value: 'stroke', label: '脑卒中' },
  412. { value: 'cancer', label: '癌症' },
  413. { value: 'allergy', label: '过敏性疾病' },
  414. { value: 'autoimmune', label: '自身免疫病' },
  415. { value: 'mental', label: '精神/心理疾病' },
  416. { value: 'obesity', label: '肥胖' },
  417. ],
  418. submitting: false
  419. }
  420. },
  421. computed: {
  422. progressPercent: function() {
  423. var answered = 0
  424. var total = 12
  425. if (this.survey.diet) answered++
  426. if (this.survey.digestion) answered++
  427. if (this.survey.sleep) answered++
  428. if (this.survey.exercise) answered++
  429. if (this.survey.water) answered++
  430. if (this.survey.medications.length > 0) answered++
  431. if (this.survey.diseaseHistory.chronic.length > 0) answered++
  432. if (this.survey.allergies.length > 0) answered++
  433. if (this.survey.surgery) answered++
  434. // 家族史:至少填了父亲或母亲或兄弟姐妹或祖父母之一
  435. if (this.survey.familyHistory.father.length > 0
  436. || this.survey.familyHistory.mother.length > 0
  437. || this.survey.familyHistory.sibling.length > 0) answered++
  438. if (this.survey.grandparentHistory.length > 0) answered++
  439. if (this.survey.goals.length > 0) answered++
  440. return Math.round((answered / total) * 100)
  441. },
  442. canSubmit: function() {
  443. return this.survey.diet && this.survey.sleep && this.survey.exercise
  444. && this.survey.diseaseHistory.chronic.length > 0
  445. && this.survey.allergies.length > 0
  446. && this.survey.goals.length > 0
  447. }
  448. },
  449. onLoad: function(options) {
  450. this.reportId = options.reportId ? parseInt(options.reportId) : null
  451. this.childId = options.childId ? parseInt(options.childId) : null
  452. this.initSurvey()
  453. },
  454. methods: {
  455. initSurvey: function() {
  456. var self = this
  457. if (!self.reportId) return
  458. getSurveyStatus(self.reportId).then(function(res) {
  459. if (res.code === 200 && res.data) {
  460. if (res.data.completed) {
  461. uni.showToast({ title: '该报告问卷已提交', icon: 'none' })
  462. return
  463. }
  464. if (res.data.pendingSurveyId) {
  465. self.surveyId = res.data.pendingSurveyId
  466. return
  467. }
  468. }
  469. return createReportSurvey(self.reportId, self.childId || 0)
  470. }).then(function(res) {
  471. if (res && res.code === 200 && res.data && res.data.id) {
  472. self.surveyId = res.data.id
  473. }
  474. }).catch(function(e) {
  475. console.log('初始化问卷失败', e)
  476. })
  477. },
  478. // === 用药多选 ===
  479. hasMedication: function(val) {
  480. return this.survey.medications.indexOf(val) !== -1
  481. },
  482. toggleMedication: function(val) {
  483. var idx = this.survey.medications.indexOf(val)
  484. if (val === 'none') {
  485. this.survey.medications = ['none']
  486. } else {
  487. var noneIdx = this.survey.medications.indexOf('none')
  488. if (noneIdx !== -1) this.survey.medications.splice(noneIdx, 1)
  489. if (idx === -1) {
  490. this.survey.medications.push(val)
  491. } else {
  492. this.survey.medications.splice(idx, 1)
  493. }
  494. if (this.survey.medications.length === 0) {
  495. this.survey.medications.push('none')
  496. }
  497. }
  498. },
  499. // === 慢性病多选 ===
  500. hasChronic: function(val) {
  501. return this.survey.diseaseHistory.chronic.indexOf(val) !== -1
  502. },
  503. toggleChronic: function(val) {
  504. var arr = this.survey.diseaseHistory.chronic
  505. var idx = arr.indexOf(val)
  506. if (val === 'none') {
  507. this.survey.diseaseHistory.chronic = ['none']
  508. } else {
  509. var noneIdx = arr.indexOf('none')
  510. if (noneIdx !== -1) arr.splice(noneIdx, 1)
  511. if (idx === -1) {
  512. arr.push(val)
  513. } else {
  514. arr.splice(idx, 1)
  515. }
  516. if (arr.length === 0) {
  517. arr.push('none')
  518. }
  519. }
  520. },
  521. // === 过敏多选 ===
  522. toggleAllergy: function(val) {
  523. var idx = this.survey.allergies.indexOf(val)
  524. if (val === 'none') {
  525. this.survey.allergies = ['none']
  526. } else {
  527. var noneIdx = this.survey.allergies.indexOf('none')
  528. if (noneIdx !== -1) this.survey.allergies.splice(noneIdx, 1)
  529. if (idx === -1) {
  530. this.survey.allergies.push(val)
  531. } else {
  532. this.survey.allergies.splice(idx, 1)
  533. }
  534. if (this.survey.allergies.length === 0) {
  535. this.survey.allergies.push('none')
  536. }
  537. }
  538. },
  539. // === 家族病史 ===
  540. hasFamilyDisease: function(role, val) {
  541. return this.survey.familyHistory[role].indexOf(val) !== -1
  542. },
  543. toggleFamilyDisease: function(role, val) {
  544. var arr = this.survey.familyHistory[role]
  545. var idx = arr.indexOf(val)
  546. if (val === 'none') {
  547. this.survey.familyHistory[role] = ['none']
  548. } else {
  549. var noneIdx = arr.indexOf('none')
  550. if (noneIdx !== -1) arr.splice(noneIdx, 1)
  551. if (idx === -1) {
  552. arr.push(val)
  553. } else {
  554. arr.splice(idx, 1)
  555. }
  556. if (arr.length === 0) {
  557. arr.push('none')
  558. }
  559. }
  560. },
  561. // === 祖父母病史 ===
  562. toggleGrandparent: function(val) {
  563. var idx = this.survey.grandparentHistory.indexOf(val)
  564. if (val === 'unknown') {
  565. this.survey.grandparentHistory = ['unknown']
  566. } else {
  567. var unkIdx = this.survey.grandparentHistory.indexOf('unknown')
  568. if (unkIdx !== -1) this.survey.grandparentHistory.splice(unkIdx, 1)
  569. if (idx === -1) {
  570. this.survey.grandparentHistory.push(val)
  571. } else {
  572. this.survey.grandparentHistory.splice(idx, 1)
  573. }
  574. if (this.survey.grandparentHistory.length === 0) {
  575. this.survey.grandparentHistory.push('unknown')
  576. }
  577. }
  578. },
  579. // === 健康目标 ===
  580. toggleGoal: function(val) {
  581. var idx = this.survey.goals.indexOf(val)
  582. if (idx === -1) {
  583. this.survey.goals.push(val)
  584. } else {
  585. this.survey.goals.splice(idx, 1)
  586. }
  587. },
  588. goBack: function() {
  589. uni.navigateBack()
  590. },
  591. doSubmit: function() {
  592. if (!this.canSubmit || this.submitting) return
  593. var self = this
  594. self.submitting = true
  595. uni.showLoading({ title: '提交中...' })
  596. var doSubmit = function() {
  597. submitReportSurvey(self.surveyId, JSON.stringify(self.survey)).then(function(res) {
  598. uni.hideLoading()
  599. if (res.code === 200) {
  600. uni.showToast({ title: '提交成功', icon: 'success' })
  601. // AI问答功能已屏蔽
  602. // setTimeout(function() {
  603. // var params = 'reportId=' + self.reportId + '&surveyId=' + self.surveyId + '&firstMessage=' + encodeURIComponent('请根据报告和问卷信息,提供个性化的健康建议')
  604. // uni.redirectTo({ url: '/pages/ai/chat?' + params })
  605. // }, 500)
  606. } else {
  607. uni.showToast({ title: res.message || '提交失败', icon: 'none' })
  608. self.submitting = false
  609. }
  610. }).catch(function(e) {
  611. uni.hideLoading()
  612. uni.showToast({ title: '提交失败,请重试', icon: 'none' })
  613. console.log('提交问卷失败', e)
  614. self.submitting = false
  615. })
  616. }
  617. if (this.surveyId) {
  618. doSubmit()
  619. } else {
  620. createReportSurvey(this.reportId, this.childId || 0).then(function(res) {
  621. if (res.code === 200 && res.data && res.data.id) {
  622. self.surveyId = res.data.id
  623. doSubmit()
  624. } else {
  625. uni.hideLoading()
  626. uni.showToast({ title: '创建问卷失败', icon: 'none' })
  627. self.submitting = false
  628. }
  629. }).catch(function(e) {
  630. uni.hideLoading()
  631. uni.showToast({ title: '创建问卷失败', icon: 'none' })
  632. self.submitting = false
  633. console.log('创建问卷失败', e)
  634. })
  635. }
  636. }
  637. }
  638. }
  639. </script>
  640. <style scoped>
  641. .survey-container {
  642. min-height: 100vh;
  643. background: #F3F7FA;
  644. }
  645. .nav-bar {
  646. position: sticky;
  647. top: 0;
  648. background: #fff;
  649. display: flex;
  650. flex-direction: row;
  651. align-items: center;
  652. justify-content: space-between;
  653. padding: 20rpx 30rpx;
  654. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06);
  655. z-index: 100;
  656. }
  657. .nav-back { font-size: 32rpx; color: #5B9BD5; }
  658. .nav-title { font-size: 32rpx; font-weight: bold; color: #333; }
  659. .nav-placeholder { width: 80rpx; }
  660. .progress-bar {
  661. height: 6rpx;
  662. background: #E2E8F0;
  663. margin: 0 30rpx;
  664. border-radius: 3rpx;
  665. overflow: hidden;
  666. }
  667. .progress-fill {
  668. height: 100%;
  669. background: linear-gradient(90deg, #66BB6A, #43A047);
  670. border-radius: 3rpx;
  671. transition: width 0.3s;
  672. }
  673. .tip-banner {
  674. display: flex;
  675. flex-direction: row;
  676. align-items: center;
  677. background: #FFF8E1;
  678. margin: 16rpx 30rpx;
  679. padding: 16rpx 20rpx;
  680. border-radius: 12rpx;
  681. }
  682. .tip-icon { font-size: 28rpx; margin-right: 12rpx; flex-shrink: 0; }
  683. .tip-text { font-size: 22rpx; color: #F57F17; line-height: 1.5; }
  684. .form-section { margin: 10rpx 30rpx 30rpx; }
  685. /* 分段标题 */
  686. .section-header {
  687. display: flex;
  688. flex-direction: row;
  689. align-items: center;
  690. margin: 30rpx 0 16rpx;
  691. padding-left: 8rpx;
  692. }
  693. .section-icon { font-size: 36rpx; margin-right: 12rpx; }
  694. .section-title {
  695. font-size: 32rpx;
  696. font-weight: bold;
  697. color: #333;
  698. }
  699. .question-card {
  700. background: #fff;
  701. border-radius: 20rpx;
  702. padding: 28rpx 24rpx;
  703. margin-bottom: 16rpx;
  704. box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
  705. }
  706. .q-number {
  707. font-size: 20rpx;
  708. color: #66BB6A;
  709. font-weight: bold;
  710. display: block;
  711. margin-bottom: 8rpx;
  712. }
  713. .q-title {
  714. font-size: 28rpx;
  715. font-weight: bold;
  716. color: #333;
  717. display: block;
  718. margin-bottom: 16rpx;
  719. }
  720. .q-options {
  721. display: flex;
  722. flex-direction: column;
  723. gap: 12rpx;
  724. }
  725. .q-options.multi {
  726. gap: 10rpx;
  727. }
  728. .q-option {
  729. display: flex;
  730. flex-direction: row;
  731. align-items: center;
  732. gap: 12rpx;
  733. padding: 16rpx 18rpx;
  734. border-radius: 14rpx;
  735. background: #F5F7FA;
  736. border: 2rpx solid transparent;
  737. }
  738. .q-selected {
  739. background: #E8F5E9;
  740. border-color: #66BB6A;
  741. }
  742. .q-option:active { opacity: 0.7; }
  743. .q-icon { font-size: 32rpx; flex-shrink: 0; }
  744. .q-text { font-size: 26rpx; color: #333; }
  745. /* 家族史网格 */
  746. .family-grid {
  747. display: flex;
  748. flex-direction: column;
  749. gap: 20rpx;
  750. }
  751. .family-col {
  752. background: #F5F7FA;
  753. border-radius: 14rpx;
  754. padding: 16rpx;
  755. }
  756. .family-role {
  757. font-size: 26rpx;
  758. font-weight: bold;
  759. color: #5B9BD5;
  760. display: block;
  761. margin-bottom: 12rpx;
  762. }
  763. .family-options {
  764. display: flex;
  765. flex-direction: row;
  766. flex-wrap: wrap;
  767. gap: 8rpx;
  768. }
  769. .family-tag {
  770. padding: 8rpx 16rpx;
  771. border-radius: 20rpx;
  772. font-size: 22rpx;
  773. color: #666;
  774. background: #fff;
  775. border: 2rpx solid #E2E8F0;
  776. }
  777. .family-tag:active { opacity: 0.7; }
  778. .tag-selected {
  779. background: #E3F2FD;
  780. border-color: #5B9BD5;
  781. color: #1565C0;
  782. }
  783. /* 额外文本输入 */
  784. .extra-input {
  785. width: 100%;
  786. min-height: 100rpx;
  787. background: #F5F7FA;
  788. border-radius: 12rpx;
  789. padding: 16rpx 20rpx;
  790. font-size: 24rpx;
  791. color: #333;
  792. margin-top: 16rpx;
  793. box-sizing: border-box;
  794. }
  795. .submit-btn {
  796. background: linear-gradient(135deg, #43A047, #2E7D32);
  797. color: #fff;
  798. font-size: 30rpx;
  799. font-weight: bold;
  800. text-align: center;
  801. padding: 28rpx;
  802. border-radius: 16rpx;
  803. margin-top: 20rpx;
  804. }
  805. .submit-btn:active { opacity: 0.85; }
  806. .btn-disabled { opacity: 0.5; }
  807. .bottom-spacer { height: 60rpx; }
  808. </style>