OnboardingProgressBar.vue 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. <template>
  2. <view class="opb-card" v-if="visible" @click="goOnboarding">
  3. <view class="opb-head">
  4. <text class="opb-title">🎁 新手成长礼包</text>
  5. <text class="opb-count">{{ completed }}/{{ total }} 已完成</text>
  6. </view>
  7. <view class="opb-bar">
  8. <view class="opb-bar-fill" :style="{ width: percent + '%' }"></view>
  9. </view>
  10. <view class="opb-tip">完成新手任务,赢取积分与五维能量 →</view>
  11. </view>
  12. </template>
  13. <script>
  14. import { getOnboardingProgress } from '../utils/api.js'
  15. export default {
  16. name: 'OnboardingProgressBar',
  17. data() {
  18. return {
  19. taskList: []
  20. }
  21. },
  22. computed: {
  23. total() {
  24. return this.taskList.length
  25. },
  26. completed() {
  27. var count = 0
  28. for (var i = 0; i < this.taskList.length; i++) {
  29. var st = this.taskList[i].status
  30. if (st === 'COMPLETED' || st === 'CLAIMED') {
  31. count++
  32. }
  33. }
  34. return count
  35. },
  36. percent() {
  37. if (!this.total) return 0
  38. return Math.round((this.completed / this.total) * 100)
  39. },
  40. visible() {
  41. if (!this.taskList || this.taskList.length === 0) return false
  42. // 全部 CLAIMED 后不再展示
  43. for (var i = 0; i < this.taskList.length; i++) {
  44. if (this.taskList[i].status !== 'CLAIMED') return true
  45. }
  46. return false
  47. }
  48. },
  49. created() {
  50. this.reload()
  51. },
  52. methods: {
  53. reload: function() {
  54. var self = this
  55. getOnboardingProgress().then(function(res) {
  56. var records = (res.data && res.data.records) || res.data || []
  57. if (!Array.isArray(records)) {
  58. records = []
  59. }
  60. self.taskList = records
  61. }).catch(function(e) {
  62. console.error('获取新手任务进度失败', e)
  63. })
  64. },
  65. goOnboarding: function() {
  66. uni.navigateTo({ url: '/pages/profile-extra/onboarding' })
  67. }
  68. }
  69. }
  70. </script>
  71. <style scoped>
  72. .opb-card {
  73. margin: 20rpx 24rpx;
  74. padding: 24rpx 28rpx;
  75. background: linear-gradient(135deg, #FFF7ED, #FFEDD5);
  76. border: 2rpx solid #FED7AA;
  77. border-radius: 20rpx;
  78. }
  79. .opb-head {
  80. display: flex;
  81. align-items: center;
  82. justify-content: space-between;
  83. margin-bottom: 14rpx;
  84. }
  85. .opb-title {
  86. font-size: 28rpx;
  87. font-weight: 600;
  88. color: #9A3412;
  89. }
  90. .opb-count {
  91. font-size: 24rpx;
  92. color: #C2410C;
  93. }
  94. .opb-bar {
  95. height: 16rpx;
  96. background: #FED7AA;
  97. border-radius: 8rpx;
  98. overflow: hidden;
  99. }
  100. .opb-bar-fill {
  101. height: 100%;
  102. background: linear-gradient(90deg, #F97316, #FF8C42);
  103. border-radius: 8rpx;
  104. }
  105. .opb-tip {
  106. margin-top: 12rpx;
  107. font-size: 24rpx;
  108. color: #C2410C;
  109. }
  110. </style>