index.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <template>
  2. <CustomNav title="健康数据" leftType="none" />
  3. <view class="content">
  4. <view class="menu-card">
  5. <view class="menu-list">
  6. <view class="menu-item" @click="openDetail('physical','height')">
  7. <image src="/static/icons/remixicon/height.svg" class="menu-icon" mode="widthFix" />
  8. <text class="menu-text">身高</text>
  9. <text class="menu-value">{{ height !== null ? height + 'cm' : '--' }}</text>
  10. <uni-icons class="menu-arrow" type="arrowright" size="20" color="#c0c0c0" />
  11. </view>
  12. <view class="menu-item" @click="openDetail('physical','weight')">
  13. <image src="/static/icons/remixicon/weight.svg" class="menu-icon" mode="widthFix" />
  14. <text class="menu-text">体重</text>
  15. <text class="menu-value">{{ weight !== null ? weight + 'kg' : '--' }}</text>
  16. <uni-icons class="menu-arrow" type="arrowright" size="20" color="#c0c0c0" />
  17. </view>
  18. <view class="menu-item" @click="openDetail('physical','bmi')">
  19. <image src="/static/icons/remixicon/bmi.svg" class="menu-icon" mode="widthFix" />
  20. <text class="menu-text">BMI</text>
  21. <text class="menu-value">{{ bmi !== null ? (Number.isFinite(Number(bmi)) ? Number(bmi).toFixed(1) : bmi) : '--' }}</text>
  22. <uni-icons class="menu-arrow" type="arrowright" size="20" color="#c0c0c0" />
  23. </view>
  24. <view class="menu-item" @click="openDetail('blood-pressure')"><image src="/static/icons/remixicon/scan-line.svg" class="menu-icon" mode="widthFix" />
  25. <text class="menu-text">血压</text>
  26. <text class="menu-value">{{ systolic !== null && diastolic !== null ? systolic + '/' + diastolic : '--' }}</text>
  27. <uni-icons class="menu-arrow" type="arrowright" size="20" color="#c0c0c0" />
  28. </view>
  29. <view class="menu-item" @click="openDetail('blood-glucose')"><image src="/static/icons/remixicon/contrast-drop-2-line.svg" class="menu-icon" mode="widthFix" />
  30. <text class="menu-text">血糖</text>
  31. <text class="menu-value">{{ bloodGlucose !== null ? (bloodGlucoseType ? bloodGlucoseType + ' ' + bloodGlucose : String(bloodGlucose)) : '--' }}</text>
  32. <uni-icons class="menu-arrow" type="arrowright" size="20" color="#c0c0c0" />
  33. </view>
  34. <view class="menu-item" @click="openDetail('heart-rate')">
  35. <image src="/static/icons/remixicon/heart-pulse.svg" class="menu-icon" mode="widthFix" />
  36. <text class="menu-text">心率</text>
  37. <text class="menu-value">{{ heartRate !== null ? heartRate + ' bpm' : '--' }}</text>
  38. <uni-icons class="menu-arrow" type="arrowright" size="20" color="#c0c0c0" />
  39. </view>
  40. </view>
  41. </view>
  42. <view class="reminder-card">
  43. <view class="reminder-button" @click="openReminder">
  44. <image src="/static/icons/remixicon/alarm-line.svg" class="reminder-icon" mode="widthFix" />
  45. <text class="reminder-text">健康提醒</text>
  46. <uni-icons class="reminder-arrow" type="arrowright" size="20" color="#c0c0c0" />
  47. </view>
  48. </view>
  49. </view>
  50. <TabBar />
  51. </template>
  52. <script setup lang="ts">
  53. import { ref } from 'vue'
  54. import { onShow } from '@dcloudio/uni-app'
  55. import { getLatestOverview } from '@/api/patientData'
  56. import CustomNav from '@/components/custom-nav.vue'
  57. import TabBar from '@/components/tab-bar.vue'
  58. const title = ref('健康数据')
  59. const height = ref<number | null>(null)
  60. const weight = ref<number | null>(null)
  61. const bmi = ref<number | null>(null)
  62. const systolic = ref<number | null>(null)
  63. const diastolic = ref<number | null>(null)
  64. const bloodGlucose = ref<number | null>(null)
  65. const bloodGlucoseType = ref<string | null>(null)
  66. const heartRate = ref<number | null>(null)
  67. async function loadOverview() {
  68. try {
  69. console.log('[patient-data] loadOverview start')
  70. const res: any = await getLatestOverview()
  71. // `request()` 返回的 res 包含 data 字段,data 字段里才是后端返回的 { code, message, data }
  72. // 为了兼容其他实现,支持两类响应结构:
  73. // 1) res.data === { code, message, data }
  74. // 2) res === { code, message, data }
  75. let payload: any = null
  76. if (res && res.data && res.data.code === 200 && res.data.data) {
  77. payload = res.data.data
  78. } else if (res && res.code === 200 && res.data) {
  79. payload = res.data
  80. }
  81. if (payload) {
  82. const data = payload
  83. console.log('[patient-data] response data:', data)
  84. height.value = data.height ?? null
  85. weight.value = data.weight ?? null
  86. bmi.value = data.bmi ?? null
  87. systolic.value = data.systolicPressure ?? null
  88. diastolic.value = data.diastolicPressure ?? null
  89. bloodGlucose.value = data.bloodGlucose ?? null
  90. bloodGlucoseType.value = data.bloodGlucoseType ?? null
  91. heartRate.value = data.heartRate ?? null
  92. console.log('[patient-data] height,weight,bmi:', height.value, weight.value, bmi.value)
  93. }
  94. } catch (e) {
  95. console.error('[patient-data] loadOverview error', e)
  96. }
  97. }
  98. onShow(() => {
  99. loadOverview()
  100. })
  101. const openDetail = (type: string, metric?: string) => {
  102. const url = metric ? `details/${type}?metric=${metric}` : `details/${type}`
  103. uni.navigateTo({ url })
  104. }
  105. const openReminder = () => {
  106. uni.navigateTo({ url: 'reminder' })
  107. }
  108. </script>
  109. <style scoped>
  110. .content {
  111. padding-top: calc(var(--status-bar-height) + 44px);
  112. min-height: 100vh;
  113. background-color: #f5f5f5;
  114. box-sizing: border-box;
  115. }
  116. .text-area {
  117. display: flex;
  118. justify-content: center;
  119. }
  120. .title {
  121. font-size: 36rpx;
  122. color: #8f8f94;
  123. }
  124. .menu-card {
  125. padding: 50rpx 0rpx;
  126. }
  127. .menu-list {
  128. background-color: #fff;
  129. border-radius: 12rpx;
  130. overflow: hidden;
  131. }
  132. .menu-item {
  133. display: flex;
  134. justify-content: flex-start;
  135. align-items: center;
  136. padding: 30rpx 40rpx;
  137. border-bottom: 1rpx solid #eee;
  138. }
  139. .menu-item:last-child {
  140. border-bottom: none
  141. }
  142. .menu-text {
  143. font-size: 32rpx;
  144. color: #000000;
  145. flex: 1;
  146. /* 字符间距,调整数值以获得所需视觉效果 */
  147. letter-spacing: 1rpx;
  148. }
  149. .menu-value {
  150. font-size: 28rpx;
  151. color: #5a5a5a;
  152. margin-right: 10rpx
  153. }
  154. .menu-arrow {
  155. display: inline-flex;
  156. align-items: center;
  157. justify-content: center;
  158. width: 44rpx;
  159. height: 44rpx;
  160. }
  161. .menu-icon {
  162. width: 40rpx;
  163. height: 40rpx;
  164. margin-right: 30rpx;
  165. display: inline-block;
  166. }
  167. .reminder-card {
  168. margin-top: 20rpx;
  169. padding: 50rpx 0rpx;
  170. }
  171. .reminder-button {
  172. display: flex;
  173. justify-content: flex-start;
  174. align-items: center;
  175. padding: 30rpx 40rpx;
  176. background-color: #fff;
  177. border-radius: 12rpx;
  178. }
  179. .reminder-text {
  180. font-size: 32rpx;
  181. color: #000000;
  182. flex: 1;
  183. letter-spacing: 1rpx;
  184. }
  185. .reminder-arrow {
  186. display: inline-flex;
  187. align-items: center;
  188. justify-content: center;
  189. width: 44rpx;
  190. height: 44rpx;
  191. }
  192. .reminder-icon {
  193. width: 40rpx;
  194. height: 40rpx;
  195. margin-right: 30rpx;
  196. display: inline-block;
  197. }
  198. </style>