BasicVitalsStep.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <template>
  2. <view class="vitals-step">
  3. <view class="step-title-row">
  4. <text class="step-title">基础体征</text>
  5. <text class="step-sub">填写身高、体重、血压、血糖等基础指标</text>
  6. </view>
  7. <!-- 身高 -->
  8. <view class="form-card">
  9. <view class="card-head">
  10. <text class="card-title">身高 (cm)</text>
  11. <view class="quick-chips">
  12. <view
  13. class="quick-chip"
  14. :class="{ 'quick-chip-on': heightQuick === 'normal' }"
  15. @click="setHeightQuick('normal')"
  16. ><text>正常</text></view>
  17. <view
  18. class="quick-chip"
  19. :class="{ 'quick-chip-on': heightQuick === 'high' }"
  20. @click="setHeightQuick('high')"
  21. ><text>偏高</text></view>
  22. <view
  23. class="quick-chip"
  24. :class="{ 'quick-chip-on': heightQuick === 'low' }"
  25. @click="setHeightQuick('low')"
  26. ><text>偏低</text></view>
  27. </view>
  28. </view>
  29. <input class="num-input" type="digit" v-model="inner.heightCm" placeholder="如 170"
  30. @input="onInput" />
  31. <text class="unit-hint">单位:厘米</text>
  32. </view>
  33. <!-- 体重 -->
  34. <view class="form-card">
  35. <view class="card-head">
  36. <text class="card-title">体重 (kg)</text>
  37. <view class="quick-chips">
  38. <view
  39. class="quick-chip"
  40. :class="{ 'quick-chip-on': weightQuick === 'normal' }"
  41. @click="setWeightQuick('normal')"
  42. ><text>正常</text></view>
  43. <view
  44. class="quick-chip"
  45. :class="{ 'quick-chip-on': weightQuick === 'high' }"
  46. @click="setWeightQuick('high')"
  47. ><text>偏重</text></view>
  48. <view
  49. class="quick-chip"
  50. :class="{ 'quick-chip-on': weightQuick === 'low' }"
  51. @click="setWeightQuick('low')"
  52. ><text>偏轻</text></view>
  53. </view>
  54. </view>
  55. <input class="num-input" type="digit" v-model="inner.weightKg" placeholder="如 60"
  56. @input="onInput" />
  57. <text class="unit-hint">单位:公斤</text>
  58. </view>
  59. <!-- 血压 -->
  60. <view class="form-card">
  61. <view class="card-head">
  62. <text class="card-title">血压</text>
  63. <view class="quick-chips">
  64. <view
  65. class="quick-chip"
  66. :class="{ 'quick-chip-on': bpQuick === 'normal' }"
  67. @click="setBpQuick('normal')"
  68. ><text>正常</text></view>
  69. <view
  70. class="quick-chip"
  71. :class="{ 'quick-chip-on': bpQuick === 'high' }"
  72. @click="setBpQuick('high')"
  73. ><text>偏高</text></view>
  74. <view
  75. class="quick-chip"
  76. :class="{ 'quick-chip-on': bpQuick === 'low' }"
  77. @click="setBpQuick('low')"
  78. ><text>偏低</text></view>
  79. </view>
  80. </view>
  81. <input class="num-input" type="text" v-model="inner.bloodPressure" placeholder="如 120/80"
  82. @input="onInput" />
  83. <text class="unit-hint">格式:收缩压/舒张压 (mmHg)</text>
  84. </view>
  85. <!-- 血糖 -->
  86. <view class="form-card">
  87. <view class="card-head">
  88. <text class="card-title">空腹血糖 (mmol/L)</text>
  89. <view class="quick-chips">
  90. <view
  91. class="quick-chip"
  92. :class="{ 'quick-chip-on': glucoseQuick === 'normal' }"
  93. @click="setGlucoseQuick('normal')"
  94. ><text>正常</text></view>
  95. <view
  96. class="quick-chip"
  97. :class="{ 'quick-chip-on': glucoseQuick === 'high' }"
  98. @click="setGlucoseQuick('high')"
  99. ><text>偏高</text></view>
  100. <view
  101. class="quick-chip"
  102. :class="{ 'quick-chip-on': glucoseQuick === 'low' }"
  103. @click="setGlucoseQuick('low')"
  104. ><text>偏低</text></view>
  105. </view>
  106. </view>
  107. <input class="num-input" type="digit" v-model="inner.bloodGlucose" placeholder="如 5.6"
  108. @input="onInput" />
  109. </view>
  110. <!-- 血脂 -->
  111. <view class="form-card">
  112. <view class="card-head">
  113. <text class="card-title">总胆固醇 (mmol/L)</text>
  114. <view class="quick-chips">
  115. <view
  116. class="quick-chip"
  117. :class="{ 'quick-chip-on': lipidQuick === 'normal' }"
  118. @click="setLipidQuick('normal')"
  119. ><text>正常</text></view>
  120. <view
  121. class="quick-chip"
  122. :class="{ 'quick-chip-on': lipidQuick === 'high' }"
  123. @click="setLipidQuick('high')"
  124. ><text>偏高</text></view>
  125. </view>
  126. </view>
  127. <input class="num-input" type="digit" v-model="inner.lipidCholesterol" placeholder="如 4.5"
  128. @input="onInput" />
  129. </view>
  130. <!-- 其他补充 -->
  131. <view class="form-card">
  132. <view class="card-head">
  133. <text class="card-title">其他补充(选填)</text>
  134. </view>
  135. <textarea class="notes-area" v-model="inner.notes" placeholder="其他想补充的健康信息"
  136. :maxlength="500" @input="onInput" />
  137. </view>
  138. </view>
  139. </template>
  140. <script>
  141. // 快捷标签 → 参考数值(近似参考值,点击后填入输入框,用户可继续手改)
  142. var QUICK_VALUES = {
  143. height: { normal: '170', high: '185', low: '155' },
  144. weight: { normal: '60', high: '80', low: '45' },
  145. bloodPressure: { normal: '120/80', high: '140/90', low: '90/60' },
  146. bloodGlucose: { normal: '5.0', high: '7.0', low: '3.5' },
  147. lipid: { normal: '4.5', high: '6.2' }
  148. }
  149. function matchQuick(map, val) {
  150. if (val === '' || val === null || val === undefined) return ''
  151. var v = String(val)
  152. for (var k in map) {
  153. if (Object.prototype.hasOwnProperty.call(map, k) && map[k] === v) return k
  154. }
  155. return ''
  156. }
  157. export default {
  158. name: 'BasicVitalsStep',
  159. props: {
  160. value: {
  161. type: Object,
  162. default: function() { return {} }
  163. }
  164. },
  165. data() {
  166. return {
  167. inner: {
  168. heightCm: '',
  169. weightKg: '',
  170. bloodPressure: '',
  171. bloodGlucose: '',
  172. lipidCholesterol: '',
  173. notes: ''
  174. }
  175. }
  176. },
  177. computed: {
  178. heightQuick: function() { return matchQuick(QUICK_VALUES.height, this.inner.heightCm) },
  179. weightQuick: function() { return matchQuick(QUICK_VALUES.weight, this.inner.weightKg) },
  180. bpQuick: function() { return matchQuick(QUICK_VALUES.bloodPressure, this.inner.bloodPressure) },
  181. glucoseQuick: function() { return matchQuick(QUICK_VALUES.bloodGlucose, this.inner.bloodGlucose) },
  182. lipidQuick: function() { return matchQuick(QUICK_VALUES.lipid, this.inner.lipidCholesterol) }
  183. },
  184. watch: {
  185. value: {
  186. deep: true,
  187. handler: function(val) {
  188. this.syncFromValue(val)
  189. }
  190. }
  191. },
  192. created: function() {
  193. this.syncFromValue(this.value)
  194. },
  195. methods: {
  196. syncFromValue: function(val) {
  197. if (!val) return
  198. this.inner.heightCm = val.heightCm != null ? String(val.heightCm) : ''
  199. this.inner.weightKg = val.weightKg != null ? String(val.weightKg) : ''
  200. this.inner.bloodPressure = val.bloodPressure != null ? String(val.bloodPressure) : ''
  201. this.inner.bloodGlucose = val.bloodGlucose != null ? String(val.bloodGlucose) : ''
  202. this.inner.lipidCholesterol = val.lipidCholesterol != null ? String(val.lipidCholesterol) : ''
  203. this.inner.notes = val.notes != null ? String(val.notes) : ''
  204. },
  205. onInput: function() {
  206. var payload = {
  207. heightCm: this.inner.heightCm,
  208. weightKg: this.inner.weightKg,
  209. bloodPressure: this.inner.bloodPressure,
  210. bloodGlucose: this.inner.bloodGlucose,
  211. lipidCholesterol: this.inner.lipidCholesterol,
  212. notes: this.inner.notes
  213. }
  214. this.$emit('input', payload)
  215. },
  216. // 快捷选择:点击标签把对应参考数值填入输入框(用户可继续手改)
  217. setHeightQuick: function(k) {
  218. this.inner.heightCm = QUICK_VALUES.height[k] || ''
  219. this.onInput()
  220. },
  221. setWeightQuick: function(k) {
  222. this.inner.weightKg = QUICK_VALUES.weight[k] || ''
  223. this.onInput()
  224. },
  225. setBpQuick: function(k) {
  226. this.inner.bloodPressure = QUICK_VALUES.bloodPressure[k] || ''
  227. this.onInput()
  228. },
  229. setGlucoseQuick: function(k) {
  230. this.inner.bloodGlucose = QUICK_VALUES.bloodGlucose[k] || ''
  231. this.onInput()
  232. },
  233. setLipidQuick: function(k) {
  234. this.inner.lipidCholesterol = QUICK_VALUES.lipid[k] || ''
  235. this.onInput()
  236. }
  237. }
  238. }
  239. </script>
  240. <style scoped>
  241. .vitals-step {
  242. padding: 10rpx 0 30rpx;
  243. }
  244. .step-title-row {
  245. margin-bottom: 20rpx;
  246. }
  247. .step-title {
  248. font-size: 34rpx;
  249. font-weight: 700;
  250. color: #333;
  251. }
  252. .step-sub {
  253. display: block;
  254. font-size: 24rpx;
  255. color: #999;
  256. margin-top: 8rpx;
  257. }
  258. .form-card {
  259. background: #fff;
  260. border-radius: 20rpx;
  261. padding: 24rpx;
  262. margin-bottom: 20rpx;
  263. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
  264. }
  265. .card-head {
  266. display: flex;
  267. align-items: center;
  268. justify-content: space-between;
  269. margin-bottom: 16rpx;
  270. }
  271. .card-title {
  272. font-size: 28rpx;
  273. font-weight: 600;
  274. color: #333;
  275. }
  276. .quick-chips {
  277. display: flex;
  278. flex-wrap: wrap;
  279. }
  280. .quick-chip {
  281. padding: 8rpx 20rpx;
  282. border-radius: 999rpx;
  283. background: #F1F5F9;
  284. font-size: 22rpx;
  285. color: #64748B;
  286. margin-left: 10rpx;
  287. margin-bottom: 6rpx;
  288. }
  289. .quick-chip-on {
  290. background: #FFF3E0;
  291. color: #F97316;
  292. font-weight: 600;
  293. }
  294. .num-input {
  295. height: 80rpx;
  296. border: 2rpx solid #E2E8F0;
  297. border-radius: 12rpx;
  298. padding: 0 20rpx;
  299. font-size: 28rpx;
  300. color: #333;
  301. background: #F8FAFC;
  302. }
  303. .unit-hint {
  304. display: block;
  305. font-size: 22rpx;
  306. color: #999;
  307. margin-top: 10rpx;
  308. }
  309. .notes-area {
  310. width: 100%;
  311. min-height: 160rpx;
  312. background: #F8FAFC;
  313. border: 2rpx solid #E2E8F0;
  314. border-radius: 12rpx;
  315. padding: 16rpx;
  316. font-size: 26rpx;
  317. color: #333;
  318. }
  319. </style>