FamilyEnergyBar.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <template>
  2. <view class="family-energy-bar">
  3. <view class="bar-header">
  4. <text class="bar-icon">{{ dimensionIcon }}</text>
  5. <text class="bar-title">{{ dimensionName }}能量</text>
  6. <text class="bar-total-score">{{ familyScore }}</text>
  7. </view>
  8. <view class="bar-list">
  9. <view class="bar-row bar-row-family">
  10. <text class="bar-label">全家</text>
  11. <view class="bar-track">
  12. <view class="bar-fill" :style="{ width: familyScore + '%', background: dimensionColor }"></view>
  13. </view>
  14. <text class="bar-value">{{ familyScore }}</text>
  15. </view>
  16. <view
  17. class="bar-row bar-row-member"
  18. v-for="member in members"
  19. :key="member.memberId"
  20. @click="onMemberClick(member)"
  21. >
  22. <text class="bar-label">{{ member.name }}</text>
  23. <view class="bar-track">
  24. <view class="bar-fill" :style="{ width: getMemberScore(member) + '%', background: memberColor(member) }"></view>
  25. </view>
  26. <text class="bar-value">{{ getMemberScore(member) }}</text>
  27. <text class="bar-arrow">›</text>
  28. </view>
  29. </view>
  30. </view>
  31. </template>
  32. <script>
  33. export default {
  34. props: {
  35. dimensionCode: { type: String, required: true },
  36. sandboxData: { type: Object, default: null },
  37. dualDimension: { type: String, default: '' }
  38. },
  39. computed: {
  40. dimensionConfig: function() {
  41. var maps = {
  42. body: { name: '身体', icon: '\u{1F3C3}', color: '#10B981' },
  43. mind: { name: '心', icon: '\u2764', color: '#8B5CF6' },
  44. wisdom: { name: '智', icon: '\u{1F9E0}', color: '#3B82F6' },
  45. action: { name: '行动', icon: '\u{1F3CB}', color: '#F97316' },
  46. wealth: { name: '富', icon: '\u{1F4B0}', color: '#F59E0B' }
  47. }
  48. return maps[this.dimensionCode] || { name: '', icon: '', color: '#999' }
  49. },
  50. dimensionIcon: function() { return this.dimensionConfig.icon },
  51. dimensionName: function() { return this.dimensionConfig.name },
  52. dimensionColor: function() { return this.dimensionConfig.color },
  53. familyScore: function() {
  54. if (!this.sandboxData) return 0
  55. return this.sandboxData[this.dimensionCode + 'Score'] || 0
  56. },
  57. members: function() {
  58. return this.sandboxData && this.sandboxData.members ? this.sandboxData.members : []
  59. }
  60. },
  61. methods: {
  62. getMemberScore: function(member) {
  63. return member[this.dimensionCode + 'Score'] || 0
  64. },
  65. memberColor: function(member) {
  66. var score = this.getMemberScore(member)
  67. if (score >= 80) return '#10B981'
  68. if (score >= 60) return '#3B82F6'
  69. if (score >= 40) return '#F97316'
  70. return '#EF4444'
  71. },
  72. onMemberClick: function(member) {
  73. var detailPages = {
  74. body: '/pages/body/member-body-detail',
  75. mind: '/pages/mind/member-mind-detail',
  76. wisdom: '/pages/mind/member-mind-detail',
  77. action: '/pages/action/member-action-detail'
  78. }
  79. var page = detailPages[this.dimensionCode]
  80. if (page) {
  81. uni.navigateTo({
  82. url: page + '?childId=' + member.memberId + '&memberName=' + encodeURIComponent(member.name) + '&dimensionCode=' + this.dimensionCode
  83. })
  84. }
  85. }
  86. }
  87. }
  88. </script>
  89. <style scoped>
  90. .family-energy-bar {
  91. margin: 20rpx 30rpx;
  92. background: #fff;
  93. border-radius: 24rpx;
  94. padding: 28rpx 24rpx;
  95. box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.06);
  96. }
  97. .bar-header {
  98. display: flex;
  99. flex-direction: row;
  100. align-items: center;
  101. margin-bottom: 20rpx;
  102. }
  103. .bar-icon { font-size: 32rpx; margin-right: 8rpx; }
  104. .bar-title { font-size: 28rpx; font-weight: bold; color: #333; flex: 1; }
  105. .bar-total-score { font-size: 40rpx; font-weight: bold; color: #F97316; }
  106. .bar-row {
  107. display: flex;
  108. flex-direction: row;
  109. align-items: center;
  110. margin-bottom: 16rpx;
  111. padding: 8rpx 0;
  112. }
  113. .bar-row:last-child { margin-bottom: 0; }
  114. .bar-row-member:active { opacity: 0.6; }
  115. .bar-label {
  116. font-size: 24rpx;
  117. color: #666;
  118. width: 80rpx;
  119. flex-shrink: 0;
  120. }
  121. .bar-track {
  122. flex: 1;
  123. height: 24rpx;
  124. background: #f0f0f0;
  125. border-radius: 12rpx;
  126. overflow: hidden;
  127. margin: 0 12rpx;
  128. }
  129. .bar-fill {
  130. height: 100%;
  131. border-radius: 12rpx;
  132. transition: width 0.5s ease;
  133. }
  134. .bar-value {
  135. font-size: 26rpx;
  136. font-weight: bold;
  137. color: #333;
  138. width: 60rpx;
  139. text-align: right;
  140. flex-shrink: 0;
  141. }
  142. .bar-arrow {
  143. font-size: 28rpx;
  144. color: #ccc;
  145. margin-left: 8rpx;
  146. }
  147. .bar-row-family .bar-fill {
  148. background: linear-gradient(90deg, #F97316, #FB923C);
  149. }
  150. </style>