rewards.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <template>
  2. <view class="container">
  3. <!-- 退出切换按钮 -->
  4. <view class="exit-switch" v-if="isSwitchedChild" @click="exitSwitch">
  5. <text>🔄 退出切换</text>
  6. </view>
  7. <view class="reward-list" v-if="rewards.length > 0">
  8. <view v-for="reward in rewards" :key="reward.id" class="reward-item">
  9. <view class="reward-info">
  10. <view class="reward-title">{{ reward.title }}</view>
  11. <view class="reward-progress">
  12. <progress :percent="reward.pointsRequired > 0 ? (currentPoints / reward.pointsRequired) * 100 : 0" stroke-width="6" activeColor="#F97316" backgroundColor="#eee" />
  13. <text class="progress-text">{{ currentPoints }}/{{ reward.pointsRequired }}积分</text>
  14. </view>
  15. </view>
  16. </view>
  17. </view>
  18. <view class="empty" v-else>
  19. <text>暂无心愿单,快去添加吧</text>
  20. </view>
  21. <button class="btn-primary add-btn" @click="showAddModal = true">+ 添加心愿</button>
  22. <view class="modal-mask" v-if="showAddModal" @click="showAddModal = false">
  23. <view class="modal" @click.stop>
  24. <view class="modal-title">添加心愿</view>
  25. <view class="form-item">
  26. <view class="form-label">心愿名称 <text class="required">*</text></view>
  27. <input v-model="newReward.title" placeholder="请输入心愿名称" />
  28. </view>
  29. <view class="form-tip">
  30. <text>孩子创建心愿后,需要家长填写所需积分才能生效</text>
  31. </view>
  32. <view class="modal-btns">
  33. <button @click="showAddModal = false">取消</button>
  34. <button class="btn-primary" @click="createChildReward">确定</button>
  35. </view>
  36. </view>
  37. </view>
  38. </view>
  39. </template>
  40. <script>
  41. import { getWishlist, createReward as createRewardApi, getPointsBalance, getChildren, switchBackToParent, verifyPassword } from '../../utils/api.js'
  42. export default {
  43. data() {
  44. return {
  45. rewards: [],
  46. currentPoints: 0,
  47. currentChildId: '',
  48. showAddModal: false,
  49. newReward: { title: '' },
  50. isSwitchedChild: false // 家长切换到孩子状态的标记
  51. }
  52. },
  53. onShow() {
  54. this.isSwitchedChild = uni.getStorageSync('isSwitchedChild') || false
  55. this.loadRewards()
  56. },
  57. methods: {
  58. async loadRewards() {
  59. try {
  60. const childrenRes = await getChildren()
  61. const children = childrenRes.data || []
  62. const storedChildId = uni.getStorageSync('currentChildId')
  63. const currentChild = children.find(c => c.id == storedChildId) || children[0]
  64. if (!currentChild) {
  65. this.rewards = []
  66. this.currentPoints = 0
  67. return
  68. }
  69. this.currentChildId = currentChild.id
  70. const balanceRes = await getPointsBalance(currentChild.id)
  71. this.currentPoints = balanceRes.data.balance
  72. const res = await getWishlist(currentChild.id)
  73. this.rewards = res.data || []
  74. } catch (e) {
  75. console.error('加载心愿单失败', e)
  76. }
  77. },
  78. async createChildReward() {
  79. if (!this.newReward.title) {
  80. uni.showToast({ title: '请填写心愿名称', icon: 'none' })
  81. return
  82. }
  83. try {
  84. await createRewardApi({ title: this.newReward.title, memberId: this.currentChildId })
  85. uni.showToast({ title: '已提交,等待家长填写积分', icon: 'success' })
  86. this.showAddModal = false
  87. this.newReward.title = ''
  88. this.loadRewards()
  89. } catch (e) {
  90. console.error('添加心愿失败', e)
  91. }
  92. },
  93. exitSwitch() {
  94. if (!this.isSwitchedChild) return
  95. uni.showModal({
  96. title: '退出切换',
  97. content: '请输入家长密码以确认退出',
  98. editable: true,
  99. success: async (res) => {
  100. if (res.confirm && res.content) {
  101. try {
  102. const verifyResult = await verifyPassword(res.content)
  103. if (verifyResult.code === 200) {
  104. await this.switchBackToParentMode()
  105. } else {
  106. uni.showToast({ title: '密码错误', icon: 'none' })
  107. }
  108. } catch (e) {
  109. uni.showToast({ title: '密码验证失败', icon: 'none' })
  110. }
  111. }
  112. }
  113. })
  114. },
  115. async switchBackToParentMode() {
  116. try {
  117. const result = await switchBackToParent()
  118. if (result.data) {
  119. this.$store.commit('switchBackToParent')
  120. uni.showToast({ title: '已切换回家长模式', icon: 'success' })
  121. uni.reLaunch({ url: '/pages/home-pages/parent-index' })
  122. }
  123. } catch (e) {
  124. uni.showToast({ title: '切换失败', icon: 'none' })
  125. }
  126. }
  127. }
  128. }
  129. </script>
  130. <style scoped>
  131. .container { padding: 30rpx; padding-bottom: 120rpx; }
  132. .exit-switch { background: #f5f5f5; padding: 20rpx; border-radius: 10rpx; margin-bottom: 20rpx; text-align: center; color: #666; font-size: 28rpx; }
  133. .reward-item { background: #fff; border-radius: 16rpx; padding: 30rpx; margin-bottom: 20rpx; }
  134. .reward-title { font-size: 30rpx; color: #333; margin-bottom: 15rpx; }
  135. .reward-progress { width: 100%; }
  136. .progress-text { font-size: 22rpx; color: #999; display: block; margin-top: 8rpx; }
  137. .add-btn { position: fixed; bottom: 30rpx; left: 30rpx; right: 30rpx; }
  138. .empty { text-align: center; color: #999; padding: 100rpx; }
  139. .modal-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; }
  140. .modal { background: #fff; border-radius: 20rpx; padding: 40rpx; width: 80%; }
  141. .modal-title { font-size: 32rpx; font-weight: bold; margin-bottom: 30rpx; text-align: center; }
  142. .form-item { margin-bottom: 20rpx; }
  143. .form-label { font-size: 28rpx; color: #333; margin-bottom: 10rpx; }
  144. .required { color: #F97316; }
  145. .form-tip { font-size: 24rpx; color: #999; padding: 20rpx; background: #f5f5f5; border-radius: 10rpx; margin-bottom: 20rpx; }
  146. .modal-btns { display: flex; gap: 20rpx; margin-top: 30rpx; }
  147. .modal-btns button { flex: 1; }
  148. </style>