detail.vue 6.3 KB

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