tasks.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <template>
  2. <PlayfulCard elevation="1">
  3. <view class="container">
  4. <!-- 退出切换按钮 -->
  5. <view class="exit-switch" v-if="isSwitchedChild" @click="exitSwitch">
  6. <text>🔄 退出切换</text>
  7. </view>
  8. <view class="task-list" v-if="tasks.length > 0">
  9. <view v-for="task in tasks" :key="task.id" class="task-item" :class="{ completed: task.status === 'completed' }">
  10. <view class="task-left">
  11. <view class="task-title">
  12. {{ task.title }}
  13. <text v-if="task.category === '小游戏类'" class="minigame-badge">🎮</text>
  14. </view>
  15. <view class="task-meta">
  16. <text class="points">+{{ task.points }}分</text>
  17. <text class="deadline">截止 {{ formatTime(task.deadline) }}</text>
  18. </view>
  19. </view>
  20. <view class="task-right">
  21. <button
  22. v-if="task.status === 'pending'"
  23. class="btn-complete"
  24. @click="handleTaskClick(task)"
  25. >
  26. {{ task.category === '小游戏类' ? '开始游戏' : '完成' }}
  27. </button>
  28. <view v-else class="completed-badge">已完成</view>
  29. </view>
  30. </view>
  31. </view>
  32. <view class="empty" v-else>
  33. <text>暂无今日任务</text>
  34. </view>
  35. </view>
  36. </PlayfulCard>
  37. </template>
  38. <script>
  39. import PlayfulCard from '@/components/PlayfulCard.vue'
  40. import { getTodayTasks, completeTask as completeTaskApi, getChildren, switchBackToParent, verifyPassword } from '../../utils/api.js'
  41. export default {
  42. components: { PlayfulCard },
  43. data() {
  44. return {
  45. tasks: [],
  46. currentChildId: '',
  47. isSwitchedChild: false // 家长切换到孩子状态的标记
  48. }
  49. },
  50. onShow() {
  51. this.isSwitchedChild = uni.getStorageSync('isSwitchedChild') || false
  52. this.loadData()
  53. },
  54. methods: {
  55. async loadData() {
  56. try {
  57. const childrenRes = await getChildren()
  58. const children = childrenRes.data || []
  59. const storedChildId = uni.getStorageSync('currentChildId')
  60. const currentChild = children.find(c => c.id == storedChildId) || children[0]
  61. if (!currentChild) {
  62. this.tasks = []
  63. this.currentChildId = ''
  64. return
  65. }
  66. this.currentChildId = currentChild.id
  67. const res = await getTodayTasks(currentChild.id)
  68. this.tasks = res.data || []
  69. } catch (e) {
  70. console.error('加载孩子任务失败', e)
  71. }
  72. },
  73. async completeChildTask(taskId) {
  74. try {
  75. const res = await completeTaskApi(taskId, this.currentChildId, '')
  76. uni.showToast({ title: `获得 ${res.data.pointsEarned} 积分`, icon: 'success' })
  77. this.loadData()
  78. } catch (e) {
  79. console.error('完成任务失败', e)
  80. }
  81. },
  82. handleTaskClick(task) {
  83. // 如果是小游戏任务,跳转到对应的小游戏页面
  84. if (task.category === '小游戏类' && task.minigameCode) {
  85. const gamePages = {
  86. 'schulte': '/pages/games/schulte',
  87. '1a2b': '/pages/games/1a2b',
  88. 'sudoku': '/pages/games/sudoku'
  89. }
  90. const gamePage = gamePages[task.minigameCode]
  91. if (gamePage) {
  92. uni.navigateTo({
  93. url: `${gamePage}?taskId=${task.id}&childId=${this.currentChildId}`
  94. })
  95. }
  96. } else {
  97. // 普通任务,直接完成
  98. this.completeChildTask(task.id)
  99. }
  100. },
  101. formatTime(dateStr) {
  102. if (!dateStr) return ''
  103. const date = new Date(dateStr)
  104. return `${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`
  105. },
  106. exitSwitch() {
  107. // 只有家长切换到孩子状态时才显示退出切换功能
  108. if (!this.isSwitchedChild) return
  109. uni.showModal({
  110. title: '退出切换',
  111. content: '请输入家长密码以确认退出',
  112. editable: true,
  113. success: async (res) => {
  114. if (res.confirm && res.content) {
  115. try {
  116. const verifyResult = await verifyPassword(res.content)
  117. if (verifyResult.code === 200) {
  118. await this.switchBackToParentMode()
  119. } else {
  120. uni.showToast({ title: '密码错误', icon: 'none' })
  121. }
  122. } catch (e) {
  123. uni.showToast({ title: '密码验证失败', icon: 'none' })
  124. }
  125. }
  126. }
  127. })
  128. },
  129. async switchBackToParentMode() {
  130. try {
  131. const result = await switchBackToParent()
  132. if (result.data) {
  133. this.$store.commit('switchBackToParent')
  134. uni.showToast({ title: '已切换回家长模式', icon: 'success' })
  135. uni.reLaunch({ url: '/pages/index/parent-index' })
  136. }
  137. } catch (e) {
  138. uni.showToast({ title: '切换失败', icon: 'none' })
  139. }
  140. }
  141. }
  142. }
  143. </script>
  144. <style scoped>
  145. .container { padding: 30rpx; }
  146. .exit-switch { background: #f5f5f5; padding: 20rpx; border-radius: 10rpx; margin-bottom: 20rpx; text-align: center; color: #666; font-size: 28rpx; }
  147. .task-item { background: #fff; border-radius: 16rpx; padding: 30rpx; margin-bottom: 20rpx; display: flex; justify-content: space-between; align-items: center; }
  148. .task-item.completed { opacity: 0.6; }
  149. .task-title { font-size: 30rpx; color: #333; margin-bottom: 10rpx; }
  150. .task-meta { display: flex; gap: 20rpx; }
  151. .points { color: #FF6B6B; font-size: 24rpx; }
  152. .deadline { color: #999; font-size: 24rpx; }
  153. .btn-complete { background: #FF6B6B; color: #fff; font-size: 26rpx; padding: 10rpx 30rpx; border-radius: 30rpx; }
  154. .completed-badge { color: #52C41A; font-size: 26rpx; }
  155. .minigame-badge { font-size: 28rpx; margin-left: 10rpx; }
  156. .empty { text-align: center; color: #999; padding: 100rpx; }
  157. </style>