ProfileGrowth.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <template>
  2. <view class="section">
  3. <view class="section-header">
  4. <text class="section-title">📈 成长报告</text>
  5. <text class="section-more" @click="goGrowthReport">查看 ›</text>
  6. </view>
  7. <view class="report-card" @click="goGrowthReport">
  8. <view class="report-stat-item">
  9. <text class="report-stat">{{ growthReport.monthActiveDays || 0 }}天</text>
  10. <text class="report-label">本月活跃</text>
  11. </view>
  12. <view class="report-divider"></view>
  13. <view class="report-stat-item">
  14. <text class="report-stat">{{ growthReport.totalTasks || 0 }}</text>
  15. <text class="report-label">累计任务</text>
  16. </view>
  17. <view class="report-divider"></view>
  18. <view class="report-stat-item">
  19. <text class="report-stat">{{ growthReport.completionRate || 0 }}%</text>
  20. <text class="report-label">完成率</text>
  21. </view>
  22. </view>
  23. </view>
  24. </template>
  25. <script>
  26. import { getGrowthReport } from '../../../utils/api.js'
  27. export default {
  28. name: 'ProfileGrowth',
  29. data() {
  30. return {
  31. growthReport: {
  32. monthActiveDays: 0,
  33. totalTasks: 0,
  34. completionRate: 0
  35. }
  36. }
  37. },
  38. onShow() {
  39. if (!uni.getStorageSync('token')) return
  40. this.loadGrowthReport()
  41. },
  42. methods: {
  43. loadGrowthReport() {
  44. let memberId = uni.getStorageSync('currentChildId') || null
  45. if (!memberId) {
  46. const children = uni.getStorageSync('childrenList')
  47. if (children && children.length > 0) {
  48. memberId = children[0].id
  49. }
  50. }
  51. if (!memberId) {
  52. this.loadGrowthReportLocal()
  53. return
  54. }
  55. getGrowthReport(memberId).then((res) => {
  56. if (res.code === 200 && res.data) {
  57. const d = res.data
  58. this.growthReport.monthActiveDays = d.monthActiveDays || d.activeDays || 0
  59. this.growthReport.totalTasks = (d.taskStats && d.taskStats.total) || d.totalTasks || 0
  60. this.growthReport.completionRate = (d.taskStats && d.taskStats.completionRate) || d.completionRate || 0
  61. } else {
  62. this.loadGrowthReportLocal()
  63. }
  64. }).catch(() => {
  65. this.loadGrowthReportLocal()
  66. })
  67. },
  68. loadGrowthReportLocal() {
  69. const streakDays = parseInt(uni.getStorageSync('streakDays') || 0)
  70. const completedTasks = parseInt(uni.getStorageSync('completedTasks') || 0)
  71. this.growthReport.monthActiveDays = streakDays > 0 ? Math.min(streakDays, 30) : 0
  72. this.growthReport.totalTasks = completedTasks || 0
  73. this.growthReport.completionRate = 85
  74. },
  75. goGrowthReport() {
  76. const memberId = uni.getStorageSync('currentChildId') || ''
  77. uni.navigateTo({ url: '/pages/growth/report?memberId=' + memberId })
  78. }
  79. }
  80. }
  81. </script>
  82. <style scoped>
  83. .section {
  84. margin: 20rpx 30rpx;
  85. }
  86. .section-header {
  87. display: flex;
  88. justify-content: space-between;
  89. align-items: center;
  90. margin-bottom: 20rpx;
  91. }
  92. .section-title {
  93. font-size: 30rpx;
  94. font-weight: bold;
  95. color: #333;
  96. }
  97. .section-more {
  98. font-size: 24rpx;
  99. color: #999;
  100. }
  101. .report-card {
  102. background: #fff;
  103. border-radius: 20rpx;
  104. padding: 30rpx;
  105. display: flex;
  106. align-items: center;
  107. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  108. }
  109. .report-stat-item {
  110. flex: 1;
  111. display: flex;
  112. flex-direction: column;
  113. align-items: center;
  114. }
  115. .report-stat {
  116. font-size: 40rpx;
  117. font-weight: bold;
  118. color: #667eea;
  119. }
  120. .report-label {
  121. font-size: 24rpx;
  122. color: #999;
  123. margin-top: 8rpx;
  124. }
  125. .report-divider {
  126. width: 1rpx;
  127. height: 60rpx;
  128. background: #f0f0f0;
  129. }
  130. </style>