indicator-quicklook.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <template>
  2. <view class="page">
  3. <!-- 成员切换 -->
  4. <picker :range="memberNames" @change="onMemberChange">
  5. <view class="member-picker">{{ currentMemberName }} ▾</view>
  6. </picker>
  7. <!-- 分类 Tab -->
  8. <scroll-view scroll-x class="cat-scroll">
  9. <view class="cat-tab" :class="activeCategory === '' ? 'cat-active' : ''" @tap="onCatTap('')">全部</view>
  10. <view
  11. class="cat-tab"
  12. :class="activeCategory === c.name ? 'cat-active' : ''"
  13. v-for="c in categories"
  14. :key="getCatKey(c)"
  15. @tap="onCatTap(c.name)"
  16. >{{ c.name }}({{ c.total }})</view>
  17. </scroll-view>
  18. <!-- 指标列表 -->
  19. <view class="item-list" v-if="items.length > 0">
  20. <view class="ql-item" v-for="item in items" :key="getItemKey(item)" @tap="goCurve(getItemId(item))">
  21. <view class="ql-name-row">
  22. <text class="ql-name">{{ item.name }}</text>
  23. <text :class="'ql-trend ' + item._cssClass">{{ item._arrow }} {{ item._trendLabel }}</text>
  24. </view>
  25. <view class="ql-value-row">
  26. <text class="ql-value">{{ item.value }}{{ item.unit || '' }}</text>
  27. <text class="ql-ref">参考: {{ item.refRange || '--' }}</text>
  28. <text class="ql-status" :class="item._statusClass">{{ item.status || '' }}</text>
  29. </view>
  30. <text class="ql-date">{{ item._dateText }}</text>
  31. </view>
  32. </view>
  33. <view class="empty-tip" v-else>暂无数据</view>
  34. <!-- 分页 -->
  35. <view class="pager" v-if="totalPages > 1">
  36. <view class="pager-btn" :class="page <= 1 ? 'pager-disabled' : ''" @tap="onPrevPage">上一页</view>
  37. <text class="pager-info">{{ page }} / {{ totalPages }}</text>
  38. <view class="pager-btn" :class="page >= totalPages ? 'pager-disabled' : ''" @tap="onNextPage">下一页</view>
  39. </view>
  40. <!-- 五维/七维评分小节 -->
  41. <view class="dim-section" v-if="dimensionScores.length > 0">
  42. <view class="section-title">维度评分趋势</view>
  43. <view class="dim-list">
  44. <view class="dim-row" v-for="d in dimensionScores" :key="getDimKey(d)">
  45. <text class="dim-name">{{ d.name }}</text>
  46. <text class="dim-score">{{ d.score }}</text>
  47. <text :class="'dim-trend ' + d._cssClass">{{ d._arrow }}</text>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. </template>
  53. <script>
  54. import { getIndicatorQuickLookup } from '@/utils/api'
  55. import { getFamilyMemberList } from '@/utils/api'
  56. import { resolveChangeStyle, formatDelta, colorClassFor } from '@/utils/indicator-change'
  57. export default {
  58. data: function() { return { members: [], currentMemberId: null, categories: [], activeCategory: '', items: [], dimensionScores: [], page: 1, pageSize: 30, totalPages: 1, _onLoadFired: false, _loading: false } },
  59. computed: {
  60. memberNames: function() { return this.members.map(function(m) { return m.name || m.nickname || '' }) },
  61. currentMemberName: function() {
  62. var self = this
  63. var m = this.members.find(function(x) { return x.id === self.currentMemberId })
  64. return (m && (m.name || m.nickname)) || '选择成员'
  65. },
  66. categoriesComputed: function() {
  67. var self = this
  68. return this.categories || []
  69. }
  70. },
  71. methods: {
  72. onLoad: function() { this.loadMembers(); this._onLoadFired = true },
  73. onShow: function() { if (this._onLoadFired) { this._onLoadFired = false } else if (this.currentMemberId) { this.reload() } },
  74. goCurve: function(definitionId) {
  75. uni.navigateTo({ url: '/pages/health/indicator-curve?definitionId=' + definitionId })
  76. },
  77. loadMembers: function() {
  78. var self = this
  79. getFamilyMemberList({ visibleOnly: true }).then(function(res) {
  80. var arr = (res.data && res.data.list) || (res.data instanceof Array ? res.data : [])
  81. self.members = arr
  82. if (!self.currentMemberId && arr.length > 0) { self.currentMemberId = arr[0].id; self.reload() }
  83. })
  84. },
  85. reload: function() { this.page = 1; this.loadData() },
  86. loadData: function() {
  87. var self = this
  88. if (!this.currentMemberId || this._loading) return
  89. this._loading = true
  90. getIndicatorQuickLookup({ subjectId: this.currentMemberId, category: this.activeCategory || undefined, page: this.page, pageSize: this.pageSize }).then(function(res) {
  91. self._loading = false
  92. var data = res.data || {}
  93. // 预计算展示字段,避免小程序 :class 中调用方法(微信模板编译器不支持带参方法调用)
  94. self.rankItems = (data && data.items) || []
  95. self.rankItems.forEach(function(it) {
  96. var st = resolveChangeStyle(it.goodDirection, it.movement || 'flat')
  97. it._cssClass = colorClassFor(st.cssClass)
  98. it._arrow = st.arrow
  99. it._trendLabel = st.trendLabel
  100. it._statusClass = 'status-' + (it._cssClass || 'normal')
  101. it._dateText = it.latestReportDate ? String(it.latestReportDate).slice(0, 10) : '--'
  102. })
  103. self.categories = data.categories || []
  104. self.items = data.items || []
  105. self.dimensionScores = data.dimensionScores || []
  106. var total = data.total !== undefined ? data.total : self.items.length
  107. self.totalPages = Math.max(1, Math.ceil(total / self.pageSize))
  108. }).catch(function() { self._loading = false })
  109. },
  110. onCatTap: function(name) { this.activeCategory = name; this.reload() },
  111. onPrevPage: function() { if (this.page > 1) { this.page--; this.loadData() } },
  112. onNextPage: function() { if (this.page < this.totalPages) { this.page++; this.loadData() } },
  113. formatDate: function(s) { if (!s) return '--'; return String(s).slice(0, 10) },
  114. getCatKey: function(c) { return c.name },
  115. getItemKey: function(item) { return item.definitionId },
  116. getItemId: function(item) { return item.definitionId },
  117. getDimKey: function(d) { return d.name }
  118. }
  119. }
  120. </script>
  121. <style scoped>
  122. .member-picker { font-size: 24rpx; color: #666; }
  123. .cat-scroll { height: 40rpx; line-height: 40rpx; overflow-x: scroll; }
  124. .cat-tab { float: left; margin-right: 20rpx; padding: 0 12rpx; height: 32rpx; line-height: 32rpx; font-size: 22rpx; color: #999; }
  125. .cat-tab.cat-active { color: #4A9BD7; border-bottom: 2rpx solid #4A9BD7; }
  126. .item-list { padding: 20rpx; }
  127. .ql-item { margin-bottom: 20rpx; }
  128. .ql-name-row { display: flex; justify-content: space-between; margin-bottom: 8rpx; }
  129. .ql-name { font-size: 26rpx; }
  130. .ql-trend { font-size: 20rpx; color: #666; }
  131. .ql-value-row { display: flex; justify-content: space-between; margin-bottom: 8rpx; }
  132. .ql-value { font-size: 24rpx; }
  133. .ql-ref { font-size: 16rpx; color: #999; }
  134. .ql-status { font-size: 20rpx; }
  135. .ql-date { font-size: 16rpx; color: #999; margin-top: 4rpx; }
  136. .pager { height: 40rpx; line-height: 40rpx; padding: 0 20rpx; font-size: 20rpx; }
  137. .pager-btn { float: left; margin-right: 10rpx; padding: 0 12rpx; height: 32rpx; line-height: 32rpx; font-size: 20rpx; color: #999; }
  138. .pager-btn.pager-disabled { color: #ccc; }
  139. .pager-info { float: left; margin: 0 20rpx; }
  140. .dim-section { padding: 20rpx; }
  141. .section-title { font-size: 26rpx; margin-bottom: 12rpx; }
  142. .dim-list { display: flex; flex-wrap: wrap; }
  143. .dim-row { margin-bottom: 12rpx; }
  144. .dim-name { font-size: 22rpx; width: 60rpx; }
  145. .dim-score { font-size: 22rpx; color: #666; }
  146. .dim-trend { font-size: 18rpx; color: #999; }
  147. </style>