index.vue 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. <template>
  2. <view class="container">
  3. <block v-if="!isLoggedIn">
  4. <!-- 品牌定位语 -->
  5. <view class="brand-strap"><text class="brand-strap-text">科学管理全家健康数据</text></view>
  6. <!-- 痛点卡 -->
  7. <view class="pain-card">
  8. <text class="pain-quote">指标正常 ≠ 健康</text>
  9. <text class="pain-desc">孩子反复生病,你扛了多少次了?</text>
  10. </view>
  11. <!-- 功能预览 -->
  12. <view class="guest-features">
  13. <view class="feat-card" @click="goPage('/pages/health/report-upload')">
  14. <text class="feat-icon">📋</text>
  15. <text class="feat-title">上传健康报告</text>
  16. <text class="feat-desc">体检/肠道/舌诊 · 解读</text>
  17. </view>
  18. <view class="feat-card" @click="goPage('/pages/body/detail')">
  19. <text class="feat-icon">🧠</text>
  20. <text class="feat-title">认知能力测评</text>
  21. <text class="feat-desc">记忆力·注意力·逻辑推理</text>
  22. </view>
  23. <view class="feat-card" @click="goPage('/pages/mind/index')">
  24. <text class="feat-icon">💖</text>
  25. <text class="feat-title">心理健康测评</text>
  26. <text class="feat-desc">情绪稳定·抗压能力</text>
  27. </view>
  28. <view class="feat-card" @click="goPlanSummary">
  29. <text class="feat-icon">📝</text>
  30. <text class="feat-title">健康方案</text>
  31. <text class="feat-desc">选维度·选成员·定目标</text>
  32. </view>
  33. <view class="feat-card" @click="goPage('/pages/health/health-status-form')">
  34. <text class="feat-icon">📋</text>
  35. <text class="feat-title">健康档案</text>
  36. <text class="feat-desc">身高体重·血压血糖·疾病史</text>
  37. </view>
  38. </view>
  39. <!-- 自测入口 -->
  40. <view class="self-test-card" @click="goSelfTest">
  41. <view class="self-test-head">
  42. <text class="self-test-icon">⚡</text>
  43. <view class="self-test-info">
  44. <text class="self-test-title">15题五维健康自检</text>
  45. <text class="self-test-sub">约20秒,了解家人健康概况</text>
  46. </view>
  47. <text class="self-test-arrow">›</text>
  48. </view>
  49. </view>
  50. <!-- 本期待填调研(按周期计算,服务端返回 pending 列表) -->
  51. <view v-for="item in pendingSurveys" :key="surveyKey(item)" class="self-test-card" @click="goSurveyFill(item)">
  52. <view class="self-test-head">
  53. <text class="self-test-icon">📋</text>
  54. <view class="self-test-info">
  55. <text class="self-test-title">{{ item.title }}</text>
  56. <text class="self-test-sub">{{ cycleLabel(item.cycleType) }} · {{ item.periodStart }} 至 {{ item.periodEnd }}</text>
  57. </view>
  58. <text class="survey-pending-tag">待填写</text>
  59. </view>
  60. </view>
  61. <RadarChart :dimensions="demoBodyDims" :scores="demoBodyScores" fillColor="#FF8C42" childName="示例" width="560" height="460" />
  62. <view class="demo-chart-title-row">
  63. <text class="demo-chart-name">🧠 认知雷达</text>
  64. <text class="demo-chart-tag">示例</text>
  65. </view>
  66. <RadarChart :dimensions="demoCogDims" :scores="demoCogScores" fillColor="#6366F1" childName="示例" width="560" height="460" />
  67. <!-- 五维健康体系 -->
  68. <view class="wuxing-section">
  69. <view class="wuxing-title">身·心·智·行·富 · 看得见的健康闭环</view>
  70. <view class="wuxing-desc">五行相生相克,从报告和测评里,真正读懂家人的身体</view>
  71. <view class="wuxing-relations">
  72. <view class="rel-group">
  73. <text class="rel-title">相生 → 系统前进</text>
  74. <view class="rel-chain">
  75. <text class="rel-item">🌏 身</text>
  76. <text class="rel-arrow">→</text>
  77. <text class="rel-item">⚡ 智</text>
  78. <text class="rel-arrow">→</text>
  79. <text class="rel-item">💧 富</text>
  80. <text class="rel-arrow">→</text>
  81. <text class="rel-item">🌿 行</text>
  82. <text class="rel-arrow">→</text>
  83. <text class="rel-item">🔥 心</text>
  84. <text class="rel-arrow">→</text>
  85. <text class="rel-item">🌏 身</text>
  86. </view>
  87. <text class="rel-hint">健康孕育智慧,智慧创造价值,价值滋养关系,关系反哺心灵,心灵守护健康</text>
  88. </view>
  89. <view class="rel-group">
  90. <text class="rel-title">相克 → 系统平衡</text>
  91. <view class="rel-chain">
  92. <text class="rel-item">🌏 身</text>
  93. <text class="rel-op">克</text>
  94. <text class="rel-item">💧 富</text>
  95. <text class="rel-dot">·</text>
  96. <text class="rel-item">⚡ 智</text>
  97. <text class="rel-op">克</text>
  98. <text class="rel-item">🌿 行</text>
  99. <text class="rel-dot">·</text>
  100. <text class="rel-item">💧 富</text>
  101. <text class="rel-op">克</text>
  102. <text class="rel-item">🔥 心</text>
  103. <text class="rel-dot">·</text>
  104. <text class="rel-item">🌿 行</text>
  105. <text class="rel-op">克</text>
  106. <text class="rel-item">🌏 身</text>
  107. <text class="rel-dot">·</text>
  108. <text class="rel-item">🔥 心</text>
  109. <text class="rel-op">克</text>
  110. <text class="rel-item">⚡ 智</text>
  111. </view>
  112. <text class="rel-hint">莫以健康换金钱,真诚胜过算计,财富服务家庭,关爱有度、大爱留白</text>
  113. </view>
  114. </view>
  115. <view class="wuxing-cards">
  116. <view class="wc-card wc-body" @click="goPage('/pages/body-detail/index')">
  117. <text class="wc-icon">🌏</text>
  118. <view class="wc-info">
  119. <text class="wc-name">身 · 主动健康</text>
  120. <text class="wc-text">读懂每一份报告,看见全家体质的变化</text>
  121. </view>
  122. </view>
  123. <view class="wc-card wc-wisdom" @click="goPage('/pages/wisdom-detail/index')">
  124. <text class="wc-icon">⚡</text>
  125. <view class="wc-info">
  126. <text class="wc-name">智 · 赋能未来</text>
  127. <text class="wc-text">一次测评,看见孩子真实的专注与潜能</text>
  128. </view>
  129. </view>
  130. <view class="wc-card wc-wealth" @click="goPage('/pages/wealth/index')">
  131. <text class="wc-icon">💧</text>
  132. <view class="wc-info">
  133. <text class="wc-name">富 · 利他创富</text>
  134. <text class="wc-text">看懂健康与财富的关系,明白身体是最大的本钱</text>
  135. </view>
  136. </view>
  137. <view class="wc-card wc-action" @click="goPage('/pages/action-detail/member-action-detail')">
  138. <text class="wc-icon">🌿</text>
  139. <view class="wc-info">
  140. <text class="wc-name">行 · 人际和谐</text>
  141. <text class="wc-text">看懂关系里的情绪,看见家人真实的需求</text>
  142. </view>
  143. </view>
  144. <view class="wc-card wc-mind" @click="goPage('/pages/mind-detail/index')">
  145. <text class="wc-icon">🔥</text>
  146. <view class="wc-info">
  147. <text class="wc-name">心 · 大爱相随</text>
  148. <text class="wc-text">读懂情绪的信号,听懂家人没说出口的话</text>
  149. </view>
  150. </view>
  151. </view>
  152. </view>
  153. <!-- 登录引导 -->
  154. <view class="login-guide-section">
  155. <LoginGuideCard
  156. title="解锁全家健康数据"
  157. :items="[
  158. '查看七维雷达图与健康报告解读',
  159. '完成测评获取个性化健康方案',
  160. '每日打卡追踪身体/情绪/认知趋势'
  161. ]" />
  162. </view>
  163. </block>
  164. <block v-else>
  165. <view class="tab-bar">
  166. <view v-for="tab in tabs" :key="tab.code" class="tab-item" :class="{ active: currentTab === tab.code }" @click="switchTab(tab.code)">
  167. <text class="tab-icon">{{ tab.icon }}</text>
  168. <text class="tab-label">{{ tab.label }}</text>
  169. <view v-if="currentTab === tab.code" class="tab-underline" :style="{ background: tab.color }"></view>
  170. </view>
  171. </view>
  172. <view class="section section-chart">
  173. <RadarChart :dimensions="currentDimensions" :scores="currentScores" :fillColor="currentColor" :childName="selectedMemberName" :avgScores="currentAvgScores" width="640" height="520" />
  174. <view class="chart-empty" v-if="chartIsEmpty">
  175. <text class="empty-text">{{ currentTabLabel }}数据待采集</text>
  176. <text class="empty-sub">完成测评或上传报告即可解锁{{ currentTabLabel }}数据</text>
  177. </view>
  178. </view>
  179. <view class="section section-dc-header">
  180. <view class="dc-title-row">
  181. <text class="dc-icon">🔍</text>
  182. <text class="dc-title">看见 · 健康数据中心</text>
  183. </view>
  184. </view>
  185. <view class="section section-data-collect">
  186. <ReportUploadCard
  187. title="上传报告"
  188. desc="体检报告 · 菌群检测 · 认知测评 · 心理测评 · 情绪打卡"
  189. :tags="['体检报告', '菌群检测', '认知测评', '心理测评', '情绪打卡']"
  190. @click="goPage('/pages/health/report-upload')" />
  191. <view class="data-card data-card-assessment">
  192. <view class="data-card-head">
  193. <text class="data-card-title">在线测评</text>
  194. <text class="data-card-subtitle">多维度自测评估</text>
  195. </view>
  196. <view v-for="quiz in quizzes" :key="quiz.code" class="quiz-item">
  197. <view class="quiz-info">
  198. <text class="quiz-icon">{{ quiz.icon }}</text>
  199. <text class="quiz-label">{{ quiz.label }}</text>
  200. </view>
  201. <view v-if="quiz.score" class="quiz-score">
  202. <text class="score-value">{{ quiz.score }}</text>
  203. <text class="score-unit">分</text>
  204. </view>
  205. <button v-else class="quiz-btn" @click.stop="goQuiz(quiz.code)">开始</button>
  206. </view>
  207. </view>
  208. </view>
  209. <view class="section section-data-view">
  210. <view class="section-header">
  211. <text class="section-title">最近记录</text>
  212. <text class="section-more" @click="goPage('/pages/health/report-list')">查看全部 ›</text>
  213. </view>
  214. <view v-if="reports.length > 0">
  215. <view class="report-card" v-for="(report, idx) in reports.slice(0, 3)" :key="idx" @click="goReportDetail(report)">
  216. <view class="report-type-badge" :class="'badge-' + _reportTypeClass(report.reportType)">{{ _reportTypeLabel(report.reportType) }}</view>
  217. <view class="report-info">
  218. <text class="report-name">{{ report.childName || report.personName || '健康报告' }}</text>
  219. <text class="report-meta">{{ _formatReportDate(report.reportDate) }}{{ report.gutType ? ' · ' + report.gutType : '' }}</text>
  220. </view>
  221. <view class="report-score-wrap">
  222. <text v-if="report.overallScore != null" class="report-score">{{ report.overallScore }}</text>
  223. <text class="report-status" :class="'status-' + _statusClass(report.status)">{{ report.status === 'resolved' ? '已解析' : '待确认' }}</text>
  224. </view>
  225. <text class="report-arrow">›</text>
  226. </view>
  227. </view>
  228. <view v-else class="empty-hint">
  229. <text class="empty-text">暂无报告和测评结果</text>
  230. <text class="empty-sub">上传报告或完成测评开启健康之旅</text>
  231. </view>
  232. <!-- 新增:查看测评方案入口 -->
  233. <view class="plan-entry" @click="goToAssessmentPlans">
  234. <text class="entry-icon">📋</text>
  235. <text class="entry-text">查看我的测评方案</text>
  236. <text class="entry-arrow">›</text>
  237. </view>
  238. </view>
  239. <view class="section section-plan">
  240. <view class="plan-card">
  241. <view class="plan-head">
  242. <text class="plan-title">📋 健康方案</text>
  243. <button class="plan-btn" @click="goPlanSummary">{{ lastPlan ? '查看方案' : '生成新方案' }}</button>
  244. </view>
  245. <text v-if="lastPlan" class="plan-goal">{{ lastPlan }}</text>
  246. <text v-else class="plan-hint">选维度 + 选成员 + 设定目标 → 生成</text>
  247. </view>
  248. </view>
  249. <ArticleBookshelf :articles="healthArticles" :isLoggedIn="true" @articleClick="goArticleDetail" @moreArticles="goMoreArticles" />
  250. </block>
  251. </view>
  252. </template>
  253. <script>
  254. import LoginGuideCard from '../../components/LoginGuideCard.vue'
  255. import RadarChart from '../../components/RadarChart.vue'
  256. import ArticleBookshelf from '../../components/ArticleBookshelf.vue'
  257. import ReportUploadCard from '../../components/report-upload-card.vue'
  258. import { parseDate } from '../../utils/format.js'
  259. export default {
  260. components: { LoginGuideCard, RadarChart, ArticleBookshelf, ReportUploadCard },
  261. data() {
  262. return {
  263. isLoggedIn: false,
  264. currentTab: 'body',
  265. selectedMemberName: '',
  266. selectedMemberId: '',
  267. reports: [],
  268. lastPlan: '',
  269. lastPlanId: null,
  270. healthArticles: [],
  271. hasAiQHistory: false,
  272. pendingSurveys: [],
  273. tabs: [
  274. { code: 'body', label: '健康', icon: '🟠', color: '#FF8C42' },
  275. { code: 'cognitive', label: '认知', icon: '🧠', color: '#6366F1' },
  276. { code: 'mental', label: '心理', icon: '💖', color: '#FF6B9D' },
  277. { code: 'relationship', label: '社会性', icon: '🤝', color: '#10B981' },
  278. { code: 'wealth', label: '财富', icon: '💧', color: '#F59E0B' }
  279. ],
  280. quizzes: [
  281. { code: 'cognitive', label: '认知能力测评', icon: '🧠', score: null },
  282. { code: 'mental', label: '心理健康测评', icon: '💖', score: null },
  283. { code: 'relationship', label: '关系质量测评', icon: '🤝', score: null }
  284. ],
  285. demoBodyDims: [
  286. { label: '生长发育', key: 'growth' },
  287. { label: '睡眠质量', key: 'sleep' },
  288. { label: '视力健康', key: 'vision' },
  289. { label: '免疫力', key: 'immunity' },
  290. { label: '营养均衡', key: 'nutrition' },
  291. { label: '肠胃健康', key: 'gut' },
  292. { label: '运动活力', key: 'exercise' }
  293. ],
  294. demoCogDims: [
  295. { label: '记忆力', key: 'memory' },
  296. { label: '注意力', key: 'attention' },
  297. { label: '逻辑推理', key: 'logic' },
  298. { label: '空间想象', key: 'spatial' },
  299. { label: '语言表达', key: 'language' }
  300. ],
  301. demoCogScores: [78, 72, 85, 68, 80],
  302. // 真实数据缓存
  303. bodyData: null,
  304. cognitiveData: null,
  305. cognitiveFamilyData: [],
  306. emiData: null,
  307. emiFamilyData: [],
  308. relationshipData: [],
  309. energySandbox: null,
  310. wealthDetail: null,
  311. childrenList: [],
  312. relationshipEmpty: false
  313. }
  314. },
  315. computed: {
  316. currentTabLabel: function() {
  317. var tab = this.tabs.filter(function(t) { return t.code === this.currentTab }.bind(this))[0]
  318. return tab ? tab.label : ''
  319. },
  320. currentColor: function() {
  321. var tab = this.tabs.filter(function(t) { return t.code === this.currentTab }.bind(this))[0]
  322. return tab ? tab.color : '#FF8C42'
  323. },
  324. currentDimensions: function() {
  325. if (this.currentTab === 'cognitive') {
  326. return [{ label:'记忆力',key:'memory'},{ label:'注意力',key:'attention'},{ label:'逻辑推理',key:'logic'},{ label:'空间想象',key:'spatial'},{ label:'感知能力',key:'perception'},{ label:'专注力',key:'focus'},{ label:'加工速度',key:'processingSpeed' }]
  327. }
  328. if (this.currentTab === 'mental') {
  329. return [{ label:'开放性',key:'openness'},{ label:'尽责性',key:'conscientiousness'},{ label:'外向性',key:'extraversion'},{ label:'宜人性',key:'agreeableness'},{ label:'神经质',key:'neuroticism'},{ label:'自主性',key:'driveAutonomy'},{ label:'胜任感',key:'driveCompetence'},{ label:'归属感',key:'driveRelatedness'},{ label:'情绪稳定性',key:'emotionStability'},{ label:'自我概念',key:'selfConceptOverall' }]
  330. }
  331. if (this.currentTab === 'relationship') {
  332. return [{ label:'亲子信任',key:'parentTrust'},{ label:'亲子亲密度',key:'parentIntimacy'},{ label:'沟通质量',key:'communication'},{ label:'关系健康度',key:'healthStatus'},{ label:'最近互动',key:'lastInteraction' }]
  333. }
  334. if (this.currentTab === 'wealth') {
  335. var isChild = !!uni.getStorageSync('currentChildId')
  336. if (isChild) {
  337. return [{ label:'学业能力',key:'skill'},{ label:'利他贡献',key:'altruism'},{ label:'积分积累',key:'income'},{ label:'财务素养',key:'fx' }]
  338. }
  339. return [{ label:'个人能力',key:'skill'},{ label:'利他贡献',key:'altruism'},{ label:'CF值积累',key:'income'},{ label:'财务素养',key:'fx' }]
  340. }
  341. return [{ label:'生长发育',key:'growth'},{ label:'睡眠质量',key:'sleep'},{ label:'视力健康',key:'vision'},{ label:'免疫力',key:'immunity'},{ label:'营养均衡',key:'nutrition'},{ label:'肠胃健康',key:'gut'},{ label:'运动活力',key:'exercise' }]
  342. },
  343. currentScores: function() {
  344. if (this.chartIsEmpty) {
  345. var dims = this.currentDimensions, scores = []
  346. for (var i = 0; i < dims.length; i++) scores.push(0)
  347. return scores
  348. }
  349. if (this.currentTab === 'cognitive') {
  350. return [
  351. this._cognitiveScore('memoryScore'),
  352. this._cognitiveScore('attentionScore'),
  353. this._cognitiveScore('logicScore'),
  354. this._cognitiveScore('spatialScore'),
  355. this._cognitiveScore('perceptionScore'),
  356. this._cognitiveScore('focusScore'),
  357. this._cognitiveScore('processingSpeedScore')
  358. ]
  359. }
  360. if (this.currentTab === 'mental') {
  361. return [
  362. this._emiScore('opennessScore'),
  363. this._emiScore('conscientiousnessScore'),
  364. this._emiScore('extraversionScore'),
  365. this._emiScore('agreeablenessScore'),
  366. this._emiScore('neuroticismScore'),
  367. this._emiScore('driveAutonomy'),
  368. this._emiScore('driveCompetence'),
  369. this._emiScore('driveRelatedness'),
  370. this._emiScore('emotionStability'),
  371. this._emiScore('selfConceptOverall')
  372. ]
  373. }
  374. if (this.currentTab === 'relationship') {
  375. return [
  376. this._relScore('trustScore'),
  377. this._relScore('intimacyScore'),
  378. this._relScore('communicationScore'),
  379. this._relScore('totalScore'),
  380. 0
  381. ]
  382. }
  383. if (this.currentTab === 'wealth') {
  384. var d = this.wealthDetail
  385. if (!d) return [0, 0, 0, 0]
  386. return [d.wealthSkill || 0, d.wealthAltruism || 0, d.wealthIncome || 0, d.wealthFx || 0]
  387. }
  388. // body: 从 API 真实维度数据取分
  389. if (this.bodyData && this.bodyData.dimensions && this.bodyData.dimensions.length > 0) {
  390. return this.bodyData.dimensions.map(function(d) { return Number(d.score) || 0 })
  391. }
  392. // body: fallback to demo
  393. if (this.reports.length > 0) {
  394. var latest = this.reports[0]
  395. if (latest.overallScore) return [72, 68, 75, 80, 70, 78, 82]
  396. }
  397. return [72, 68, 75, 80, 70, 78, 82]
  398. },
  399. currentAvgScores: function() {
  400. if (this.chartIsEmpty) return []
  401. if (this.currentTab === 'cognitive' && this.cognitiveFamilyData.length > 0) {
  402. var keys = ['memoryScore','attentionScore','logicScore','spatialScore','perceptionScore','focusScore','processingSpeedScore']
  403. var avgs = []
  404. for (var k = 0; k < keys.length; k++) {
  405. var sum = 0
  406. for (var i = 0; i < this.cognitiveFamilyData.length; i++) {
  407. var v = this.cognitiveFamilyData[i][keys[k]]
  408. if (typeof v === 'number' && v > 0) sum += v
  409. }
  410. avgs.push(Math.round(sum / this.cognitiveFamilyData.length))
  411. }
  412. return avgs
  413. }
  414. if (this.currentTab === 'mental' && this.emiFamilyData.length > 0) {
  415. var keys2 = ['opennessScore','conscientiousnessScore','extraversionScore','agreeablenessScore','neuroticismScore','driveAutonomy','driveCompetence','driveRelatedness','emotionStability','selfConceptOverall']
  416. var avgs2 = []
  417. for (var k2 = 0; k2 < keys2.length; k2++) {
  418. var sum2 = 0
  419. for (var i2 = 0; i2 < this.emiFamilyData.length; i2++) {
  420. var v2 = this.emiFamilyData[i2][keys2[k2]]
  421. if (typeof v2 === 'number' && v2 > 0) sum2 += v2
  422. }
  423. avgs2.push(Math.round(sum2 / this.emiFamilyData.length))
  424. }
  425. return avgs2
  426. }
  427. if (this.currentTab === 'relationship' && this.relationshipData.length > 0) {
  428. return [this._relScore('trustScore'), this._relScore('intimacyScore'), this._relScore('communicationScore'), this._relScore('totalScore'), 0]
  429. }
  430. if (this.currentTab === 'wealth' && this.wealthDetail) {
  431. var d = this.wealthDetail
  432. return [d.wealthSkill || 0, d.wealthAltruism || 0, d.wealthIncome || 0, d.wealthFx || 0]
  433. }
  434. return []
  435. },
  436. chartIsEmpty: function() {
  437. if (this.currentTab === 'body') return !this.bodyData || !this.bodyData.dimensions || this.bodyData.dimensions.length === 0
  438. if (this.currentTab === 'cognitive') return !this.cognitiveData || !this.cognitiveData.overallScore
  439. if (this.currentTab === 'mental') return !this.emiData || !this.emiData.overallScore
  440. if (this.currentTab === 'relationship') return !this.relationshipData || this.relationshipData.length === 0
  441. if (this.currentTab === 'wealth') return !this.wealthDetail
  442. var quiz = this.quizzes.filter(function(q) { return q.code === this.currentTab }.bind(this))[0]
  443. return !(quiz && quiz.score)
  444. }
  445. },
  446. onShow() {
  447. this.isLoggedIn = !!uni.getStorageSync('token')
  448. if (this.isLoggedIn) {
  449. var stored = uni.getStorageSync('currentChildId') || uni.getStorageSync('currentMemberId') || ''
  450. if (stored) {
  451. var n = parseInt(stored, 10)
  452. this.selectedMemberId = isNaN(n) ? stored : n
  453. this.selectedMemberName = uni.getStorageSync('currentChildName') || '成员'
  454. }
  455. this.loadHealthData()
  456. this.loadPlanList()
  457. this.loadPendingSurveys()
  458. } else {
  459. this.pendingSurveys = []
  460. }
  461. },
  462. methods: {
  463. _cognitiveScore: function(key) {
  464. if (!this.cognitiveData) return 0
  465. var v = this.cognitiveData[key]
  466. return (typeof v === 'number' && v > 0) ? v : 0
  467. },
  468. _emiScore: function(key) {
  469. if (!this.emiData) return 0
  470. var v = this.emiData[key]
  471. return (typeof v === 'number' && v > 0) ? v : 0
  472. },
  473. _relScore: function(key) {
  474. if (!this.relationshipData || this.relationshipData.length === 0) return 0
  475. var total = 0, count = 0
  476. for (var i = 0; i < this.relationshipData.length; i++) {
  477. var item = this.relationshipData[i]
  478. if (item[key] != null) { total += Number(item[key]); count++ }
  479. }
  480. return count > 0 ? Math.round(total / count) : 0
  481. },
  482. _wealthScore: function(key) {
  483. if (!this.energySandbox) return 0
  484. var v = this.energySandbox[key]
  485. return (typeof v === 'number' && v > 0) ? v : 0
  486. },
  487. switchTab: function(code) { this.currentTab = code },
  488. goPage: function(url) { uni.navigateTo({ url: url }) },
  489. goQuiz: function(code) {
  490. var url = '/pages/body-detail/dimension-questionnaire?dim=' + code
  491. if (this.selectedMemberId) url += '&memberId=' + this.selectedMemberId
  492. uni.navigateTo({ url: url })
  493. },
  494. goReportDetail: function(report) {
  495. if (!report || !report.id) return
  496. var type = report.reportType || 'gut_flora'
  497. var url
  498. if (type === 'dan') {
  499. url = '/pages/dan-assessment/report-result?reportId=' + report.id
  500. } else if (type === 'gut_flora') {
  501. url = '/pages/health/gut-flora-detail?reportId=' + report.id
  502. } else {
  503. url = '/pages/health/report-detail?reportType=' + type + '&reportId=' + report.id
  504. }
  505. uni.navigateTo({ url: url })
  506. },
  507. // 跳转到测评方案列表
  508. goToAssessmentPlans: function() {
  509. var familyId = this.familyId || uni.getStorageSync('familyId')
  510. if (!familyId) {
  511. uni.showToast({ title: '请先选择家庭', icon: 'none' })
  512. return
  513. }
  514. uni.navigateTo({ url: '/pages/assessment-plan/list?familyId=' + familyId })
  515. },
  516. _reportTypeLabel: function(type) {
  517. var map = { gut_flora: '肠道', physical_exam: '体检', tongue: '舌诊', blood: '血液' }
  518. return map[type] || '健康报告'
  519. },
  520. _reportTypeClass: function(type) {
  521. var map = { gut_flora: 'gut', physical_exam: 'exam', tongue: 'tongue', blood: 'blood' }
  522. return map[type] || 'default'
  523. },
  524. _statusClass: function(status) {
  525. return status === 'resolved' ? 'resolved' : 'pending'
  526. },
  527. goSelfTest: function() { uni.navigateTo({ url: '/pages/family/self-check' }) },
  528. // 拉取本期待填调研(服务端按 cycle_type 计算当前周期)
  529. loadPendingSurveys: function() {
  530. var self = this
  531. var api = require('../../utils/api.js')
  532. api.getSurveyStatus({}).then(function(res) {
  533. var list = (res && res.code === 200 && res.data) ? res.data : []
  534. var pending = []
  535. for (var i = 0; i < list.length; i++) {
  536. if (list[i] && list[i].status === 'pending') pending.push(list[i])
  537. }
  538. self.pendingSurveys = pending
  539. }).catch(function() { self.pendingSurveys = [] })
  540. },
  541. surveyKey: function(item) { return item && item.templateId ? item.templateId : Math.random() },
  542. cycleLabel: function(cycleType) {
  543. var map = { weekly: '每周调研', biweekly: '双周调研', monthly: '每月调研' }
  544. return map[cycleType] || '定期调研'
  545. },
  546. goSurveyFill: function(item) {
  547. if (!item || !item.templateId) return
  548. var url = '/pages/health/survey-questionnaire?templateId=' + item.templateId +
  549. '&templateTitle=' + encodeURIComponent(item.title || '定期调研') +
  550. '&templateDimension=' + encodeURIComponent(item.dimension || '') +
  551. '&periodStart=' + (item.periodStart || '') +
  552. '&periodEnd=' + (item.periodEnd || '')
  553. uni.navigateTo({ url: url })
  554. },
  555. goPlanSummary: function() {
  556. var url = '/pages/health/health-plan-summary'
  557. if (this.lastPlanId) {
  558. url += '?planId=' + this.lastPlanId
  559. }
  560. var mid = this.selectedMemberId
  561. if (mid) {
  562. url += (url.indexOf('?') >= 0 ? '&' : '?') + 'memberId=' + mid
  563. }
  564. uni.navigateTo({ url: url })
  565. },
  566. loadHealthData: function() {
  567. var self = this
  568. try {
  569. var api = require('../../utils/api.js')
  570. var memberId = uni.getStorageSync('currentChildId') || uni.getStorageSync('currentMemberId') || uni.getStorageSync('userId') || ''
  571. // 健康报告:不传 memberId,由后端返回当前家庭的全部报告(size=3 仅返回最近 3 条)
  572. api.getReportList(null, 3).then(function(res) {
  573. if (res.code === 200 && res.data) {
  574. var list = Array.isArray(res.data) ? res.data : (res.data.list || [])
  575. self.reports = list
  576. }
  577. }).catch(function() {})
  578. // 身体七维概览
  579. if (memberId) {
  580. api.getDimensionOverview({ memberId: memberId }).then(function(res) {
  581. if (res.code === 200 && res.data) self.bodyData = res.data
  582. }).catch(function() {})
  583. }
  584. // 文章
  585. api.getFeaturedArticles({ size: 3, dimensionCode: 'body' }).then(function(res) {
  586. if (res.code === 200 && res.data) {
  587. var list = Array.isArray(res.data) ? res.data : (res.data.records || [])
  588. self.healthArticles = list.slice(0, 3) || []
  589. }
  590. }).catch(function() {})
  591. // 认知测评得分
  592. if (memberId) {
  593. api.getCognitiveChildScores(memberId).then(function(res) {
  594. if (res.code === 200) self.cognitiveData = res.data || null
  595. }).catch(function() {})
  596. api.getCognitiveFamilyScores().then(function(res) {
  597. if (res.code === 200 && Array.isArray(res.data)) self.cognitiveFamilyData = res.data
  598. }).catch(function() {})
  599. }
  600. // EMI心理报告
  601. if (memberId) {
  602. api.getEmiReport(memberId).then(function(res) {
  603. if (res.code === 200) self.emiData = res.data || null
  604. }).catch(function() {})
  605. }
  606. // 关系质量评分
  607. api.getRelationshipScores().then(function(res) {
  608. if (res.code === 200 && Array.isArray(res.data) && res.data.length > 0) {
  609. self.relationshipData = res.data
  610. self.relationshipEmpty = false
  611. } else {
  612. self.relationshipEmpty = true
  613. }
  614. }).catch(function() { self.relationshipEmpty = true })
  615. // 财富子维度(富维度四子维度:能力/利他/财务/素养)
  616. if (memberId) {
  617. var memberType = uni.getStorageSync('currentChildId') ? 'child' : 'parent'
  618. api.getWealthDetail(memberId, memberType).then(function(res) {
  619. if (res.code === 200 && res.data) {
  620. self.wealthDetail = res.data
  621. }
  622. }).catch(function() {})
  623. }
  624. } catch (e) { console.error('加载健康数据失败', e) }
  625. },
  626. loadPlanList: function() {
  627. var self = this
  628. var api = require('../../utils/api.js')
  629. api.getHealthPlanList({}).then(function(res) {
  630. if (res && res.code === 200 && res.data) {
  631. var list = res.data.list || res.data
  632. var plans = Array.isArray(list) ? list : []
  633. if (plans.length > 0) {
  634. self.lastPlan = plans[0].goal || plans[0].memberName || '已有健康方案'
  635. self.lastPlanId = plans[0].id || null
  636. } else {
  637. self.lastPlan = ''
  638. self.lastPlanId = null
  639. }
  640. } else {
  641. self.lastPlan = ''
  642. self.lastPlanId = null
  643. }
  644. }).catch(function() {
  645. self.lastPlan = ''
  646. self.lastPlanId = null
  647. })
  648. },
  649. goArticleDetail: function(article) {
  650. var id = article && article.id || article
  651. uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id })
  652. },
  653. goMoreArticles: function() {
  654. uni.navigateTo({ url: '/pages/article-center/index?dimension=body' })
  655. },
  656. _formatReportDate: function(dateStr) {
  657. if (!dateStr) return ''
  658. // 后端返回 ISO 8601 (2026-08-15T14:30:00) 或 yyyy-MM-dd,统一截取前10位
  659. var s = String(dateStr)
  660. return s.length >= 10 ? s.substring(0, 10) : s
  661. },
  662. }
  663. }
  664. </script>
  665. <style scoped>
  666. .container { background: #F8F8F8; min-height: 100vh; padding-bottom: calc(160rpx + env(safe-area-inset-bottom)); }
  667. .section { margin: 16rpx 24rpx; }
  668. .tab-bar { display: flex; background: #fff; margin: 0 24rpx 16rpx; border-radius: 16rpx; padding: 8rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
  669. .tab-item { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 12rpx 0; position: relative; border-radius: 12rpx; }
  670. .tab-item.active { background: #FFF7ED; }
  671. .tab-icon { font-size: 32rpx; margin-bottom: 4rpx; }
  672. .tab-label { font-size: 26rpx; color: #666; font-weight: 500; }
  673. .tab-item.active .tab-label { color: #333; font-weight: bold; }
  674. .tab-underline { width: 40rpx; height: 4rpx; border-radius: 2rpx; margin-top: 6rpx; }
  675. .section-chart { position: relative; margin: 0 24rpx 16rpx; }
  676. .chart-empty { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; z-index: 3; background: rgba(255,255,255,0.85); border-radius: 12rpx; padding: 20rpx 30rpx; }
  677. .chart-empty .empty-text { font-size: 28rpx; color: #333; font-weight: 500; display: block; }
  678. .chart-empty .empty-sub { font-size: 22rpx; color: #999; display: block; margin-top: 4rpx; }
  679. .section-dc-header { margin: 20rpx 24rpx 8rpx; }
  680. .dc-title-row { display: flex; align-items: center; }
  681. .dc-icon { font-size: 32rpx; margin-right: 8rpx; }
  682. .dc-title { font-size: 32rpx; font-weight: bold; color: #333; }
  683. .section-data-collect { margin: 8rpx 24rpx; }
  684. .data-card { display: flex; align-items: center; background: #fff; border-radius: 20rpx; padding: 24rpx; margin-bottom: 12rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
  685. .data-card-icon { width: 88rpx; height: 88rpx; border-radius: 20rpx; display: flex; align-items: center; justify-content: center; margin-right: 20rpx; font-size: 40rpx; }
  686. .data-card-info { flex: 1; }
  687. .data-card-title { font-size: 28rpx; font-weight: bold; color: #333; display: block; margin-bottom: 6rpx; }
  688. .data-card-desc { font-size: 22rpx; color: #999; }
  689. .data-card-arrow { font-size: 36rpx; color: #ccc; }
  690. .data-card-assessment { flex-direction: column; align-items: stretch; padding: 24rpx; }
  691. .data-card-head { display: flex; align-items: center; margin-bottom: 16rpx; }
  692. .data-card-subtitle { font-size: 22rpx; color: #999; margin-left: 12rpx; }
  693. .quiz-item { display: flex; align-items: center; padding: 16rpx 0; border-top: 1rpx solid #f0f0f0; }
  694. .quiz-item:first-of-type { border-top: none; }
  695. .quiz-info { display: flex; align-items: center; flex: 1; }
  696. .quiz-icon { font-size: 36rpx; margin-right: 16rpx; }
  697. .quiz-label { font-size: 28rpx; color: #333; }
  698. .quiz-score { display: flex; align-items: baseline; margin-right: 16rpx; }
  699. .score-value { font-size: 36rpx; font-weight: bold; color: #F97316; }
  700. .score-unit { font-size: 22rpx; color: #999; margin-left: 4rpx; }
  701. /* ===== 测评方案入口 ===== */
  702. .plan-entry {
  703. background: linear-gradient(135deg, #60A5FA 0%, #3B82F6 100%);
  704. border-radius: 16rpx;
  705. padding: 28rpx 30rpx;
  706. margin-top: 24rpx;
  707. display: flex;
  708. flex-direction: row;
  709. align-items: center;
  710. justify-content: space-between;
  711. box-shadow: 0 4rpx 16rpx rgba(59, 130, 246, 0.3);
  712. }
  713. .entry-icon { font-size: 40rpx; margin-right: 16rpx; }
  714. .entry-text { font-size: 28rpx; color: #fff; font-weight: bold; flex: 1; }
  715. .entry-arrow { font-size: 36rpx; color: #fff; }
  716. .quiz-btn { background: #F97316; color: #fff; font-size: 24rpx; border: none; border-radius: 20rpx; padding: 10rpx 30rpx; height: 56rpx; line-height: 36rpx; margin: 0; }
  717. .section-data-view { margin: 16rpx 24rpx; }
  718. .section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12rpx; }
  719. .section-title { font-size: 28rpx; font-weight: bold; color: #333; }
  720. .section-more { font-size: 24rpx; color: #F97316; }
  721. .report-card { display: flex; align-items: center; background: #fff; border-radius: 16rpx; padding: 16rpx 20rpx; margin-bottom: 10rpx; }
  722. .report-type-badge { font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 8rpx; margin-right: 12rpx; flex-shrink: 0; font-weight: 600; }
  723. .report-type-badge.badge-gut { background: rgba(249,115,22,0.12); color: #F97316; }
  724. .report-type-badge.badge-exam { background: rgba(99,102,241,0.12); color: #6366F1; }
  725. .report-type-badge.badge-tongue { background: rgba(16,185,129,0.12); color: #10B981; }
  726. .report-type-badge.badge-blood { background: rgba(239,68,68,0.12); color: #EF4444; }
  727. .report-type-badge.badge-default { background: rgba(107,114,128,0.12); color: #6B7280; }
  728. .report-info { flex: 1; min-width: 0; }
  729. .report-name { font-size: 26rpx; color: #333; font-weight: 600; display: block; margin-bottom: 4rpx; }
  730. .report-meta { font-size: 20rpx; color: #999; display: block; }
  731. .report-score-wrap { display: flex; flex-direction: column; align-items: flex-end; margin-right: 8rpx; flex-shrink: 0; }
  732. .report-score { font-size: 32rpx; font-weight: bold; color: #F97316; line-height: 1; }
  733. .report-status { font-size: 20rpx; margin-top: 4rpx; }
  734. .report-status.status-resolved { color: #10B981; }
  735. .report-status.status-pending { color: #F59E0B; }
  736. .report-arrow { font-size: 28rpx; color: #ccc; }
  737. .empty-hint { text-align: center; padding: 30rpx 0; background: #fff; border-radius: 16rpx; }
  738. .empty-hint .empty-text { font-size: 26rpx; color: #999; display: block; }
  739. .empty-hint .empty-sub { font-size: 22rpx; color: #ccc; display: block; margin-top: 6rpx; }
  740. .section-plan { margin: 8rpx 24rpx 16rpx; }
  741. .plan-card { background: #fff; border-radius: 20rpx; padding: 24rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
  742. .plan-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12rpx; }
  743. .plan-title { font-size: 28rpx; font-weight: bold; color: #333; }
  744. .plan-btn { background: linear-gradient(135deg, #F97316, #FB923C); color: #fff; font-size: 24rpx; border: none; border-radius: 20rpx; padding: 10rpx 28rpx; height: 56rpx; line-height: 36rpx; margin: 0; }
  745. .plan-goal { font-size: 24rpx; color: #666; line-height: 1.5; display: block; margin-top: 12rpx; }
  746. .plan-hint { font-size: 22rpx; color: #999; display: block; margin-top: 12rpx; }
  747. /* ===== 游客态样式 ===== */
  748. .brand-strap { margin: 0 24rpx 16rpx; background: linear-gradient(135deg, #FFF7ED, rgba(249,115,22,0.08)); border-radius: 16rpx; padding: 20rpx 24rpx; }
  749. .brand-strap-text { font-size: 26rpx; color: #F97316; font-weight: 600; }
  750. .pain-card { margin: 0 24rpx 16rpx; background: #fff; border-radius: 20rpx; padding: 28rpx; border-left: 6rpx solid #F97316; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
  751. .pain-quote { font-size: 32rpx; font-weight: bold; color: #333; display: block; margin-bottom: 8rpx; }
  752. .pain-desc { font-size: 26rpx; color: #888; display: block; }
  753. .guest-features { display: flex; flex-wrap: wrap; justify-content: space-between; margin: 0 24rpx 16rpx; }
  754. .feat-card { width: 48.5%; box-sizing: border-box; background: #fff; border-radius: 20rpx; padding: 24rpx 20rpx; margin-bottom: 16rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
  755. .feat-icon { font-size: 44rpx; display: block; margin-bottom: 10rpx; }
  756. .feat-title { font-size: 26rpx; font-weight: 600; color: #333; display: block; margin-bottom: 4rpx; }
  757. .feat-desc { font-size: 22rpx; color: #999; display: block; }
  758. .self-test-card { margin: 0 24rpx 16rpx; background: linear-gradient(135deg, #667eea, #764ba2); border-radius: 20rpx; padding: 24rpx 28rpx; }
  759. .self-test-head { display: flex; align-items: center; }
  760. .self-test-icon { font-size: 40rpx; margin-right: 16rpx; }
  761. .self-test-info { flex: 1; }
  762. .self-test-title { font-size: 28rpx; font-weight: bold; color: #fff; display: block; }
  763. .self-test-sub { font-size: 22rpx; color: rgba(255,255,255,0.8); display: block; margin-top: 4rpx; }
  764. .ai-q-entry { margin: 0 24rpx 16rpx; background: linear-gradient(135deg, #F97316, #F59E0B); border-radius: 20rpx; padding: 24rpx 28rpx; }
  765. .reminder-icon { font-size: 40rpx; margin-right: 16rpx; flex-shrink: 0; }
  766. .reminder-body { flex: 1; min-width: 0; }
  767. .reminder-text { font-size: 26rpx; font-weight: 600; color: #333; display: block; }
  768. .reminder-sub { font-size: 22rpx; color: #999; margin-top: 4rpx; display: block; line-height: 1.4; }
  769. .reminder-arrow { font-size: 28rpx; color: #F97316; flex-shrink: 0; }
  770. .ai-q-head { display: flex; align-items: center; }
  771. .ai-q-icon { font-size: 40rpx; margin-right: 16rpx; }
  772. .ai-q-info { flex: 1; }
  773. .q-title { font-size: 28rpx; font-weight: bold; color: #fff; display: block; }
  774. .ai-q-sub { font-size: 22rpx; color: rgba(255,255,255,0.85); display: block; margin-top: 4rpx; }
  775. .self-test-arrow { font-size: 36rpx; color: rgba(255,255,255,0.7); }
  776. .demo-section { margin: 0 24rpx 16rpx; }
  777. .demo-section-head { margin-bottom: 8rpx; }
  778. .demo-section-title { font-size: 30rpx; font-weight: bold; color: #333; display: block; }
  779. .demo-section-sub { font-size: 22rpx; color: #999; display: block; margin-top: 4rpx; }
  780. .demo-chart-title-row { display: flex; align-items: center; justify-content: space-between; margin: 8rpx 8rpx 0; padding: 0 8rpx; }
  781. .demo-chart-name { font-size: 26rpx; font-weight: 600; color: #333; }
  782. .demo-chart-tag { font-size: 20rpx; color: #F97316; background: rgba(249,115,22,0.1); border-radius: 8rpx; padding: 4rpx 12rpx; }
  783. .login-guide-section { margin: 0 24rpx 24rpx; }
  784. /* ===== 五维闭环体系样式 ===== */
  785. .wuxing-section { margin: 0 24rpx 16rpx; background: #fff; border-radius: 20rpx; padding: 24rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
  786. .wuxing-title { font-size: 30rpx; font-weight: bold; color: #333; text-align: center; margin-bottom: 6rpx; }
  787. .wuxing-desc { font-size: 22rpx; color: #999; text-align: center; margin-bottom: 20rpx; }
  788. .wuxing-diagram { position: relative; height: 320rpx; margin: 0 auto 20rpx; }
  789. .wuxing-relations { margin-top: 8rpx; }
  790. .rel-group { margin-bottom: 16rpx; }
  791. .rel-title { font-size: 24rpx; font-weight: bold; color: #333; margin-bottom: 8rpx; display: block; }
  792. .rel-chain { display: flex; flex-wrap: wrap; align-items: center; gap: 4rpx; margin-bottom: 6rpx; }
  793. .rel-item { font-size: 22rpx; padding: 4rpx 10rpx; border-radius: 8rpx; background: #f7f7f7; color: #555; }
  794. .rel-arrow { font-size: 20rpx; color: #F97316; font-weight: bold; }
  795. .rel-dot { font-size: 20rpx; color: #ccc; }
  796. .rel-hint { font-size: 20rpx; color: #999; line-height: 1.5; display: block; }
  797. .wuxing-cards { display: flex; flex-direction: column; gap: 10rpx; margin-top: 16rpx; }
  798. .wc-card { display: flex; align-items: center; padding: 16rpx 20rpx; border-radius: 16rpx; border: 2rpx solid #f0f0f0; }
  799. .wc-card:active { opacity: 0.85; }
  800. .wc-icon { font-size: 36rpx; margin-right: 16rpx; flex-shrink: 0; }
  801. .wc-info { flex: 1; min-width: 0; display: flex; flex-direction: column; }
  802. .wc-name { font-size: 24rpx; font-weight: 600; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  803. .wc-text { font-size: 20rpx; color: #999; display: block; margin-top: 4rpx; white-space: normal; }
  804. .wc-body { border-color: rgba(255,140,66,0.3); background: rgba(255,140,66,0.04); border-left: 8rpx solid #FF8C42; }
  805. .wc-body .wc-name { color: #FF8C42; }
  806. .wc-wisdom { border-color: rgba(99,102,241,0.3); background: rgba(99,102,241,0.04); border-left: 8rpx solid #6366F1; }
  807. .wc-wisdom .wc-name { color: #6366F1; }
  808. .wc-wealth { border-color: rgba(245,158,11,0.3); background: rgba(245,158,11,0.04); border-left: 8rpx solid #F59E0B; }
  809. .wc-wealth .wc-name { color: #F59E0B; }
  810. .wc-action { border-color: rgba(16,185,129,0.3); background: rgba(16,185,129,0.04); border-left: 8rpx solid #10B981; }
  811. .wc-action .wc-name { color: #10B981; }
  812. .wc-mind { border-color: rgba(255,107,157,0.3); background: rgba(255,107,157,0.04); border-left: 8rpx solid #FF6B9D; }
  813. .wc-mind .wc-name { color: #FF6B9D; }
  814. .survey-pending-tag { flex-shrink: 0; font-size: 20rpx; color: #fff; background: #F97316; padding: 6rpx 16rpx; border-radius: 999rpx; }
  815. </style>