detail.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <view class="container">
  3. <!-- 头部:维度信息 -->
  4. <view class="dim-header" v-if="dimInfo">
  5. <view class="dim-icon-wrap" :class="'dim-icon--' + elementColor">
  6. <text class="dim-icon">{{ dimInfo.icon }}</text>
  7. </view>
  8. <text class="dim-name">{{ dimInfo.name }}</text>
  9. <text class="dim-element">{{ dimInfo.element }} · {{ dimInfo.code }}</text>
  10. <view class="dim-energy">
  11. <text class="dim-energy-value">{{ dimEnergy }}</text>
  12. <text class="dim-energy-label">能量值</text>
  13. </view>
  14. </view>
  15. <!-- 加载状态 -->
  16. <BaseLoading :loading="loading" text="加载中..." />
  17. <!-- 流水列表 -->
  18. <view class="logs-section" v-if="!loading">
  19. <view class="section-header">
  20. <text class="section-title">📋 能量流水</text>
  21. </view>
  22. <view class="log-item" v-for="(log, idx) in logs" :key="idx" v-if="logs.length > 0">
  23. <view class="log-left">
  24. <text :class="log.amount > 0 ? 'log-amount earn' : 'log-amount spend'">
  25. {{ log.amount > 0 ? '+' : '' }}{{ log.amount }}
  26. </text>
  27. <text class="log-desc">{{ log.description || '能量变动' }}</text>
  28. </view>
  29. <view class="log-right">
  30. <text class="log-balance">余额 {{ log.balanceAfter }}</text>
  31. <text class="log-time">{{ formatTime(log.createdAt) }}</text>
  32. </view>
  33. </view>
  34. <BaseEmpty v-if="logs.length === 0" icon="💧" title="暂无能量流水" description="完成任务可以获取能量值" />
  35. <view class="load-more" v-if="hasMore" @click="loadMore">
  36. <text>加载更多...</text>
  37. </view>
  38. </view>
  39. </view>
  40. </template>
  41. <script>
  42. import { getEnergyLogs } from '../../utils/api.js'
  43. import BaseLoading from '../../components/BaseLoading.vue'
  44. import BaseEmpty from '../../components/BaseEmpty.vue'
  45. var ELEMENT_MAP = {
  46. 'mind': 'fire', 'body': 'earth', 'wisdom': 'metal',
  47. 'action': 'wood', 'wealth': 'water'
  48. }
  49. export default {
  50. components: { BaseLoading, BaseEmpty },
  51. data() {
  52. return {
  53. childId: '',
  54. code: '',
  55. dimInfo: null,
  56. dimEnergy: 0,
  57. loading: true,
  58. logs: [],
  59. page: 1,
  60. pageSize: 20,
  61. hasMore: true,
  62. elementColor: 'fire'
  63. }
  64. },
  65. onLoad(options) {
  66. if (options.childId) this.childId = options.childId
  67. if (options.code) {
  68. this.code = options.code
  69. this.elementColor = ELEMENT_MAP[options.code] || 'fire'
  70. }
  71. // 如果有传入 dimData(URL编码的JSON),解析维度信息
  72. if (options.dimData) {
  73. try {
  74. var parsed = JSON.parse(decodeURIComponent(options.dimData))
  75. if (parsed) {
  76. this.dimInfo = parsed
  77. this.dimEnergy = parsed.energy || 0
  78. }
  79. } catch (e) { /* ignore */ }
  80. }
  81. this.loadLogs()
  82. },
  83. methods: {
  84. async loadLogs() {
  85. this.loading = true
  86. try {
  87. var res = await getEnergyLogs(this.childId, this.code, this.page, this.pageSize)
  88. if (res && res.data) {
  89. var records = res.data.records || []
  90. if (this.page === 1) {
  91. this.logs = records
  92. } else {
  93. this.logs = this.logs.concat(records)
  94. }
  95. this.hasMore = records.length >= this.pageSize
  96. }
  97. } catch (e) {
  98. console.log('获取能量流水失败', e)
  99. } finally {
  100. this.loading = false
  101. }
  102. },
  103. loadMore() {
  104. this.page++
  105. this.loadLogs()
  106. },
  107. formatTime(dateStr) {
  108. if (!dateStr) return ''
  109. var d = new Date(dateStr)
  110. var month = d.getMonth() + 1
  111. var day = d.getDate()
  112. var hour = d.getHours()
  113. var min = d.getMinutes()
  114. if (month < 10) month = '0' + month
  115. if (day < 10) day = '0' + day
  116. if (hour < 10) hour = '0' + hour
  117. if (min < 10) min = '0' + min
  118. return month + '-' + day + ' ' + hour + ':' + min
  119. }
  120. }
  121. }
  122. </script>
  123. <style scoped>
  124. .container {
  125. min-height: 100vh;
  126. background: #0F1B2D;
  127. padding-bottom: 40rpx;
  128. }
  129. /* ---- 头部 ---- */
  130. .dim-header {
  131. display: flex;
  132. flex-direction: column;
  133. align-items: center;
  134. padding: 60rpx 0 40rpx;
  135. position: relative;
  136. }
  137. .dim-header::after {
  138. content: '';
  139. position: absolute;
  140. bottom: 0;
  141. left: 10%;
  142. width: 80%;
  143. height: 1rpx;
  144. background: linear-gradient(90deg, transparent, rgba(143,197,232,0.2), transparent);
  145. }
  146. .dim-icon-wrap {
  147. width: 100rpx;
  148. height: 100rpx;
  149. border-radius: 50%;
  150. display: flex;
  151. align-items: center;
  152. justify-content: center;
  153. margin-bottom: 16rpx;
  154. box-shadow: 0 0 40rpx rgba(255,255,255,0.15);
  155. }
  156. .dim-icon--fire { background: linear-gradient(135deg, #FF6B35, #E65100); }
  157. .dim-icon--water { background: linear-gradient(135deg, #42A5F5, #1565C0); }
  158. .dim-icon--earth { background: linear-gradient(135deg, #8D6E63, #5D4037); }
  159. .dim-icon--metal { background: linear-gradient(135deg, #FFD700, #FF8F00); }
  160. .dim-icon--wood { background: linear-gradient(135deg, #4CAF50, #2E7D32); }
  161. .dim-icon { font-size: 44rpx; }
  162. .dim-name { font-size: 36rpx; font-weight: bold; color: #FFFFFF; }
  163. .dim-element { font-size: 22rpx; color: rgba(143,197,232,0.5); margin-top: 6rpx; }
  164. .dim-energy {
  165. display: flex;
  166. flex-direction: column;
  167. align-items: center;
  168. margin-top: 20rpx;
  169. }
  170. .dim-energy-value { font-size: 56rpx; font-weight: bold; color: #F97316; }
  171. .dim-energy-label { font-size: 20rpx; color: rgba(143,197,232,0.4); }
  172. /* ---- 流水 ---- */
  173. .logs-section {
  174. padding: 30rpx 30rpx 0;
  175. }
  176. .section-header { margin-bottom: 20rpx; }
  177. .section-title { font-size: 28rpx; font-weight: bold; color: #8FC5E8; }
  178. .log-item {
  179. display: flex;
  180. justify-content: space-between;
  181. align-items: center;
  182. padding: 24rpx 20rpx;
  183. background: rgba(255,255,255,0.04);
  184. border-radius: 16rpx;
  185. margin-bottom: 12rpx;
  186. }
  187. .log-left { display: flex; flex-direction: column; }
  188. .log-amount { font-size: 32rpx; font-weight: bold; }
  189. .log-amount.earn { color: #4CAF50; }
  190. .log-amount.spend { color: #FF6B35; }
  191. .log-desc { font-size: 22rpx; color: rgba(255,255,255,0.5); margin-top: 4rpx; }
  192. .log-right { display: flex; flex-direction: column; align-items: flex-end; }
  193. .log-balance { font-size: 22rpx; color: rgba(255,255,255,0.4); }
  194. .log-time { font-size: 20rpx; color: rgba(255,255,255,0.25); margin-top: 4rpx; }
  195. .load-more {
  196. text-align: center;
  197. padding: 24rpx;
  198. color: rgba(143,197,232,0.4);
  199. font-size: 24rpx;
  200. }
  201. </style>