report-result.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <template>
  2. <view class="container">
  3. <!-- 报告头部 -->
  4. <view class="report-head" v-if="headInfo">
  5. <text class="head-name">{{ headInfo.personName || headInfo.childName || 'DAN 测评报告' }}</text>
  6. <text class="head-date">{{ headInfo.dateText }}</text>
  7. <text class="head-dim" v-if="dimensionLabel">{{ dimensionLabel }}</text>
  8. </view>
  9. <view class="loading-wrap" v-if="loading">
  10. <text class="loading-text">加载中...</text>
  11. </view>
  12. <template v-else-if="result">
  13. <!-- 综合得分 -->
  14. <view class="section overview-card">
  15. <view class="overview-header">
  16. <text class="overview-title">综合评估</text>
  17. <text class="overview-score">{{ result.overallScore || '--' }}</text>
  18. </view>
  19. <view class="overview-desc" v-if="result.analysisReport">
  20. <text>{{ result.analysisReport }}</text>
  21. </view>
  22. </view>
  23. <!-- 认知七维雷达图 -->
  24. <view class="section radar-section">
  25. <view class="section-header">
  26. <text class="section-title">🧠 认知能力</text>
  27. </view>
  28. <RadarChart
  29. :dimensions="cognitiveDimensions"
  30. :scores="cognitiveScores"
  31. fillColor="#6366F1"
  32. gridColor="#E0E7FF"
  33. labelColor="#3730A3"
  34. :width="560"
  35. :height="460" />
  36. <view class="score-row" v-for="(dim, i) in cognitiveDimensions" :key="i">
  37. <text class="score-label">{{ dim.label }}</text>
  38. <view class="score-bar-bg">
  39. <view class="score-bar-fill" :style="'width:' + Math.min(100, result[dim.key] || 0) + '%;background:' + dim.color"></view>
  40. </view>
  41. <text class="score-num">{{ result[dim.key] || 0 }}</text>
  42. </view>
  43. </view>
  44. <!-- EMI 心理维度 -->
  45. <view class="section">
  46. <view class="section-header">
  47. <text class="section-title">💖 心理素养</text>
  48. </view>
  49. <view class="score-row" v-for="(dim, i) in emiDimensions" :key="i">
  50. <text class="score-label">{{ dim.label }}</text>
  51. <view class="score-bar-bg">
  52. <view class="score-bar-fill" :style="'width:' + Math.min(100, result[dim.key] || 0) + '%;background:' + dim.color"></view>
  53. </view>
  54. <text class="score-num">{{ result[dim.key] || 0 }}</text>
  55. </view>
  56. </view>
  57. <!-- 大五人格 -->
  58. <view class="section">
  59. <view class="section-header">
  60. <text class="section-title">🌈 人格特质</text>
  61. </view>
  62. <view class="score-row" v-for="(dim, i) in bigFiveDimensions" :key="i">
  63. <text class="score-label">{{ dim.label }}</text>
  64. <view class="score-bar-bg">
  65. <view class="score-bar-fill" :style="'width:' + Math.min(100, result[dim.key] || 0) + '%;background:' + dim.color"></view>
  66. </view>
  67. <text class="score-num">{{ result[dim.key] || 0 }}</text>
  68. </view>
  69. <view class="bigfive-total" v-if="result.bigFiveOverallScore != null">
  70. <text>大五综合分:</text>
  71. <text class="bigfive-val">{{ result.bigFiveOverallScore }}</text>
  72. </view>
  73. </view>
  74. <!-- 成长建议 -->
  75. <view class="section suggestion-card" v-if="result.growthSuggestions">
  76. <view class="section-title">🌱 成长建议</view>
  77. <text class="suggestion-text">{{ result.growthSuggestions }}</text>
  78. </view>
  79. <!-- 报告内容块 -->
  80. <view class="section" v-if="blocks && blocks.length > 0">
  81. <view class="section-header">
  82. <text class="section-title">📋 报告内容</text>
  83. </view>
  84. <view class="block-item" v-for="(block, i) in blocks" :key="i">
  85. <text class="block-title">{{ block.title || '' }}</text>
  86. <text class="block-content">{{ block.content || '' }}</text>
  87. </view>
  88. </view>
  89. </template>
  90. <view class="empty-wrap" v-else>
  91. <text class="empty-text">暂无数据</text>
  92. </view>
  93. <view class="bottom-spacer"></view>
  94. </view>
  95. </template>
  96. <script>
  97. import RadarChart from '../../components/RadarChart.vue'
  98. import { getDanReportDetail } from '../../utils/api.js'
  99. export default {
  100. components: { RadarChart },
  101. data() {
  102. return {
  103. reportId: null,
  104. loading: true,
  105. headInfo: null,
  106. result: null,
  107. blocks: [],
  108. cognitiveDimensions: [
  109. { key: 'attentionScore', label: '注意力', color: '#6366F1' },
  110. { key: 'focusScore', label: '专注力', color: '#818CF8' },
  111. { key: 'memoryScore', label: '记忆力', color: '#A5B4FC' },
  112. { key: 'logicScore', label: '逻辑思维', color: '#C7D2FE' },
  113. { key: 'perceptionScore', label: '感知能力', color: '#6366F1' },
  114. { key: 'spatialScore', label: '空间思维', color: '#818CF8' },
  115. { key: 'processingSpeedScore', label: '加工速度', color: '#A5B4FC' }
  116. ],
  117. emiDimensions: [
  118. { key: 'emotionScore', label: '情绪商数', color: '#FF6B9D' },
  119. { key: 'resilienceScore', label: '心理韧性', color: '#F472B6' },
  120. { key: 'stressCopingScore', label: '压力应对', color: '#EC4899' },
  121. { key: 'selfAwarenessScore', label: '自我认知', color: '#DB2777' }
  122. ],
  123. bigFiveDimensions: [
  124. { key: 'opennessScore', label: '开放性', color: '#F59E0B' },
  125. { key: 'conscientiousnessScore', label: '尽责性', color: '#FBBF24' },
  126. { key: 'extraversionScore', label: '外向性', color: '#FCD34D' },
  127. { key: 'agreeablenessScore', label: '宜人性', color: '#FDE68A' },
  128. { key: 'neuroticismScore', label: '神经质', color: '#F59E0B' }
  129. ]
  130. }
  131. },
  132. computed: {
  133. dimensionLabel() {
  134. if (!this.result) return ''
  135. var dim = this.result.dimension
  136. return dim === 'mind' ? '心维度 (A2)' : dim === 'wisdom' ? '智维度 (B4)' : ''
  137. }
  138. },
  139. onLoad(options) {
  140. this.reportId = options.reportId ? parseInt(options.reportId) : null
  141. if (this.reportId) this.loadData()
  142. },
  143. methods: {
  144. loadData() {
  145. var self = this
  146. this.loading = true
  147. getDanReportDetail(this.reportId).then(function(res) {
  148. self.loading = false
  149. if (res.code !== 200 || !res.data) {
  150. uni.showToast({ title: res.message || '加载失败', icon: 'none' })
  151. return
  152. }
  153. var data = res.data
  154. // head info
  155. self.headInfo = {
  156. personName: data.personName || data.childName || '',
  157. dateText: data.assessmentDate ? data.assessmentDate.substring(0, 10) : (data.confirmedAt ? data.confirmedAt.substring(0, 10) : ''),
  158. dimension: data.dimension
  159. }
  160. // linked result scores
  161. self.result = data.result || null
  162. // blocks
  163. self.blocks = (data.blocks || []).filter(function(b) { return b.title || b.content })
  164. }).catch(function(e) {
  165. self.loading = false
  166. uni.showToast({ title: '加载异常', icon: 'none' })
  167. })
  168. }
  169. }
  170. }
  171. </script>
  172. <style scoped>
  173. .container { min-height: 100vh; background: #F8F8F8; padding-bottom: 40rpx; }
  174. .loading-wrap { display: flex; justify-content: center; padding: 120rpx 0; }
  175. .loading-text { font-size: 28rpx; color: #999; }
  176. .empty-wrap { display: flex; justify-content: center; padding: 120rpx 0; }
  177. .empty-text { font-size: 28rpx; color: #999; }
  178. .report-head { background: linear-gradient(135deg, #6366F1, #8B5CF6); padding: 32rpx 28rpx 28rpx; color: #fff; }
  179. .head-name { font-size: 36rpx; font-weight: bold; display: block; }
  180. .head-date { font-size: 24rpx; opacity: 0.85; display: block; margin-top: 8rpx; }
  181. .head-dim { font-size: 22rpx; background: rgba(255,255,255,0.2); border-radius: 20rpx; padding: 4rpx 16rpx; margin-top: 12rpx; display: inline-block; }
  182. .section { margin: 20rpx 24rpx; background: #fff; border-radius: 20rpx; padding: 24rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
  183. .section-header { display: flex; align-items: center; margin-bottom: 20rpx; }
  184. .section-title { font-size: 30rpx; font-weight: bold; color: #333; }
  185. .overview-card { text-align: center; }
  186. .overview-header { display: flex; align-items: baseline; justify-content: center; gap: 12rpx; margin-bottom: 16rpx; }
  187. .overview-title { font-size: 28rpx; color: #666; }
  188. .overview-score { font-size: 56rpx; font-weight: bold; color: #6366F1; }
  189. .overview-desc { font-size: 26rpx; color: #666; line-height: 1.6; }
  190. .radar-section { padding-bottom: 12rpx; }
  191. .score-row { display: flex; align-items: center; margin-bottom: 16rpx; }
  192. .score-label { font-size: 24rpx; color: #555; width: 140rpx; flex-shrink: 0; }
  193. .score-bar-bg { flex: 1; height: 16rpx; background: #F0F0F0; border-radius: 8rpx; margin: 0 16rpx; overflow: hidden; }
  194. .score-bar-fill { height: 100%; border-radius: 8rpx; transition: width 0.3s; }
  195. .score-num { font-size: 24rpx; color: #666; width: 60rpx; text-align: right; flex-shrink: 0; }
  196. .bigfive-total { margin-top: 16rpx; padding-top: 16rpx; border-top: 1rpx solid #F0F0F0; font-size: 26rpx; color: #666; }
  197. .bigfive-val { font-size: 32rpx; font-weight: bold; color: #F59E0B; margin-left: 8rpx; }
  198. .suggestion-card { background: linear-gradient(135deg, #FFF7ED, #FEF3C7); }
  199. .suggestion-card .section-title { margin-bottom: 16rpx; }
  200. .suggestion-text { font-size: 26rpx; color: #92400E; line-height: 1.8; }
  201. .block-item { padding: 20rpx 0; border-bottom: 1rpx solid #F5F5F5; }
  202. .block-item:last-child { border-bottom: none; }
  203. .block-title { font-size: 28rpx; font-weight: 600; color: #333; display: block; margin-bottom: 8rpx; }
  204. .block-content { font-size: 26rpx; color: #666; line-height: 1.6; }
  205. .bottom-spacer { height: 40rpx; }
  206. </style>