taskReminder.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <template>
  2. <view class="sub-page">
  3. <TopBar title="任务提醒" show-back />
  4. <view class="px-4 pt-3">
  5. <view v-if="taskStore.loading" class="py-10 text-center">
  6. <text class="empty-text">加载中...</text>
  7. </view>
  8. <view v-else-if="reminderTasks.length === 0">
  9. <EmptyState message="暂无任务提醒" />
  10. </view>
  11. <view v-else class="glass-card">
  12. <view
  13. v-for="task in reminderTasks"
  14. :key="task.id"
  15. class="task-row"
  16. hover-class="row-hover"
  17. :hover-start-time="0"
  18. :hover-stay-time="120"
  19. @click="goToDetail(task.id)"
  20. >
  21. <view class="flex items-center justify-between mb-2">
  22. <view class="flex items-center flex-1 min-w-0 mr-2">
  23. <view class="icon-chip mr-3">
  24. <text class="uni-icons uniui-notification-filled chip-glyph"></text>
  25. </view>
  26. <text class="row-title truncate">{{ task.projectName }}</text>
  27. </view>
  28. <text class="pending-tag flex-shrink-0">待确认</text>
  29. </view>
  30. <view class="meta-line mb-1">
  31. <text class="uni-icons uniui-location-filled meta-icon mr-1"></text>
  32. <text class="meta-text truncate">{{ task.address }}</text>
  33. </view>
  34. <view class="meta-line mb-3">
  35. <text class="uni-icons uniui-calendar-filled meta-icon mr-1"></text>
  36. <text class="meta-text">预计: {{ task.scheduleDate }} {{ task.scheduleTime }}</text>
  37. </view>
  38. <view class="flex gap-3">
  39. <view class="action-btn action-btn-confirm" hover-class="action-btn-hover" :hover-start-time="0" :hover-stay-time="120" @click.stop="confirmTask(task.id)">
  40. 确认
  41. </view>
  42. <view class="action-btn action-btn-reject" hover-class="action-btn-hover" :hover-start-time="0" :hover-stay-time="120" @click.stop="rejectTask(task.id)">
  43. 拒绝
  44. </view>
  45. </view>
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. </template>
  51. <script setup lang="ts">
  52. import { computed, onMounted } from 'vue'
  53. import { useTaskStore } from '../../stores/task'
  54. import TopBar from '../../components/common/TopBar.vue'
  55. import EmptyState from '../../components/common/EmptyState.vue'
  56. const taskStore = useTaskStore()
  57. const reminderTasks = computed(() => {
  58. return taskStore.tasks.filter(t => t.status === 'pending')
  59. })
  60. function goToDetail(taskId: string) {
  61. taskStore.setCurrentTask(taskId)
  62. uni.navigateTo({ url: `/subPackages/pages-common/taskDetail?id=${taskId}` })
  63. }
  64. function confirmTask(taskId: string) {
  65. uni.showModal({
  66. title: '确认任务',
  67. content: '确认接受此任务吗?',
  68. success: (res) => {
  69. if (res.confirm) {
  70. uni.showToast({ title: '已确认', icon: 'success' })
  71. }
  72. },
  73. })
  74. }
  75. function rejectTask(taskId: string) {
  76. uni.showModal({
  77. title: '拒绝任务',
  78. content: '确定要拒绝此任务吗?',
  79. success: (res) => {
  80. if (res.confirm) {
  81. uni.showToast({ title: '已拒绝', icon: 'none' })
  82. }
  83. },
  84. })
  85. }
  86. onMounted(() => {
  87. taskStore.fetchTasks()
  88. })
  89. </script>
  90. <style scoped>
  91. .sub-page {
  92. max-width: 430px;
  93. margin: 0 auto;
  94. min-height: 100vh;
  95. background-color: #f6fbf9;
  96. padding-bottom: 24px;
  97. }
  98. .glass-card {
  99. background-color: rgba(255, 255, 255, 0.85);
  100. backdrop-filter: blur(14px);
  101. -webkit-backdrop-filter: blur(14px);
  102. border: 1px solid rgba(164, 216, 152, 0.35);
  103. border-radius: 24px;
  104. box-shadow: 0 18px 50px -12px rgba(54, 143, 111, 0.28);
  105. overflow: hidden;
  106. margin-bottom: 12px;
  107. }
  108. .task-row {
  109. padding: 14px 16px;
  110. border-top: 1px solid rgba(164, 216, 152, 0.18);
  111. }
  112. .task-row:first-child {
  113. border-top: none;
  114. }
  115. .row-hover {
  116. background-color: rgba(164, 216, 152, 0.1);
  117. }
  118. .icon-chip {
  119. width: 42px;
  120. height: 42px;
  121. border-radius: 12px;
  122. flex-shrink: 0;
  123. display: flex;
  124. align-items: center;
  125. justify-content: center;
  126. background-color: rgba(164, 216, 152, 0.2);
  127. }
  128. .chip-glyph {
  129. font-size: 20px;
  130. color: #368f6f;
  131. }
  132. .row-title {
  133. font-size: 14px;
  134. font-weight: 600;
  135. color: #1f2937;
  136. }
  137. .pending-tag {
  138. padding: 2px 10px;
  139. border-radius: 999px;
  140. font-size: 11px;
  141. font-weight: 600;
  142. color: #b7791f;
  143. background-color: rgba(251, 211, 141, 0.25);
  144. }
  145. .meta-line {
  146. display: flex;
  147. align-items: center;
  148. padding-left: 54px;
  149. }
  150. .meta-icon {
  151. font-size: 13px;
  152. color: #9ca3af;
  153. }
  154. .meta-text {
  155. font-size: 12px;
  156. color: #9ca3af;
  157. }
  158. .action-btn {
  159. flex: 1;
  160. padding: 8px 0;
  161. border-radius: 10px;
  162. text-align: center;
  163. font-size: 13px;
  164. font-weight: 600;
  165. }
  166. .action-btn-hover {
  167. opacity: 0.88;
  168. }
  169. .action-btn-confirm {
  170. color: #ffffff;
  171. background: linear-gradient(135deg, #368f6f 0%, #4ba98a 100%);
  172. }
  173. .action-btn-reject {
  174. color: #6b7280;
  175. background-color: #f3f4f6;
  176. }
  177. .empty-text {
  178. font-size: 13px;
  179. color: #9ca3af;
  180. }
  181. </style>