taskList.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <template>
  2. <view class="app-container pb-20">
  3. <TopBar title="任务列表" />
  4. <!-- 筛选标签 - 使用 uni-segmented-control -->
  5. <uni-segmented-control
  6. :current="currentFilterIndex"
  7. :values="filterLabels"
  8. style-type="text"
  9. active-color="#4f8ef7"
  10. @clickItem="onFilterChange"
  11. />
  12. <!-- 任务列表 -->
  13. <view class="mt-2">
  14. <view v-if="taskStore.loading" class="py-10 text-center">
  15. <text class="text-gray-400">加载中...</text>
  16. </view>
  17. <view v-else-if="filteredTasks.length === 0">
  18. <EmptyState message="暂无任务" />
  19. </view>
  20. <uni-list v-else border>
  21. <uni-swipe-action
  22. v-for="task in filteredTasks"
  23. :key="task.id"
  24. :actions="getSwipeActions(task)"
  25. @click="(action: any) => onSwipeAction(task, action)"
  26. >
  27. <uni-list-item
  28. :title="task.name"
  29. :note="task.address"
  30. :right-text="formatStatus(task.status)"
  31. show-arrow
  32. @click="goToDetail(task.id)"
  33. >
  34. <template #header>
  35. <view class="w-10 h-10 rounded-xl flex items-center justify-center mr-3" :class="getStatusBgClass(task.status)">
  36. <text class="uni-icons text-lg" :class="getStatusIconClass(task.status)"></text>
  37. </view>
  38. </template>
  39. </uni-list-item>
  40. </uni-swipe-action>
  41. </uni-list>
  42. </view>
  43. </view>
  44. </template>
  45. <script setup lang="ts">
  46. import { ref, computed, onMounted } from 'vue'
  47. import { useTaskStore } from '../../stores/task'
  48. import TopBar from '../../components/common/TopBar.vue'
  49. import EmptyState from '../../components/common/EmptyState.vue'
  50. import UniList from '../../components/uni-list/uni-list.vue'
  51. import UniListItem from '../../components/uni-list/uni-list-item.vue'
  52. import UniSwipeAction from '../../components/uni-swipe-action/uni-swipe-action.vue'
  53. import UniSegmentedControl from '../../components/uni-segmented-control/uni-segmented-control.vue'
  54. const taskStore = useTaskStore()
  55. const currentFilterIndex = ref(0)
  56. const filterStatuses = [
  57. { value: 'all', label: '全部' },
  58. { value: 'pending', label: '待确认' },
  59. { value: 'confirmed', label: '待排班' },
  60. { value: 'scheduled', label: '待出车' },
  61. { value: 'constructing', label: '施工中' },
  62. { value: 'completed', label: '已完成' },
  63. ]
  64. const filterLabels = filterStatuses.map(s => s.label)
  65. const filteredTasks = computed(() => {
  66. const filterValue = filterStatuses[currentFilterIndex.value].value
  67. if (filterValue === 'all') return taskStore.tasks
  68. return taskStore.tasks.filter(t => t.status === filterValue)
  69. })
  70. function formatStatus(status: string) {
  71. const map: Record<string, string> = {
  72. pending: '待确认',
  73. confirmed: '待排班',
  74. scheduled: '待出车',
  75. constructing: '施工中',
  76. completed: '已完成',
  77. cancelled: '已取消',
  78. }
  79. return map[status] || status
  80. }
  81. function getStatusBgClass(status: string) {
  82. const map: Record<string, string> = {
  83. pending: 'bg-yellow-50',
  84. confirmed: 'bg-blue-50',
  85. scheduled: 'bg-purple-50',
  86. constructing: 'bg-orange-50',
  87. completed: 'bg-green-50',
  88. cancelled: 'bg-gray-50',
  89. }
  90. return map[status] || 'bg-gray-50'
  91. }
  92. function getStatusIconClass(status: string) {
  93. const map: Record<string, string> = {
  94. pending: 'uniui-compose text-yellow-500',
  95. confirmed: 'uniui-flag text-blue-500',
  96. scheduled: 'uniui-cart-filled text-purple-500',
  97. constructing: 'uniui-gear-filled text-orange-500',
  98. completed: 'uniui-checkmarkempty text-green-500',
  99. cancelled: 'uniui-close text-gray-400',
  100. }
  101. return map[status] || 'uniui-flag text-gray-400'
  102. }
  103. function getSwipeActions(task: any) {
  104. const actions = []
  105. if (task.status === 'pending') {
  106. actions.push({ text: '催办', color: '#ff9500', key: 'urge' })
  107. }
  108. if (task.status !== 'completed' && task.status !== 'cancelled') {
  109. actions.push({ text: '取消', color: '#ff3b30', key: 'cancel' })
  110. }
  111. return actions
  112. }
  113. function onFilterChange(index: number) {
  114. currentFilterIndex.value = index
  115. }
  116. function onSwipeAction(task: any, action: { key: string; text: string }) {
  117. if (action.key === 'cancel') {
  118. uni.showModal({
  119. title: '确认取消',
  120. content: '取消后无法恢复,是否继续?',
  121. success: (res) => {
  122. if (res.confirm) {
  123. taskStore.cancelTask(task.id)
  124. uni.showToast({ title: '已取消', icon: 'success' })
  125. }
  126. }
  127. })
  128. } else if (action.key === 'urge') {
  129. taskStore.urgeTask(task.id)
  130. uni.showToast({ title: '已催办', icon: 'success' })
  131. }
  132. }
  133. function goToDetail(taskId: string) {
  134. taskStore.setCurrentTask(taskId)
  135. uni.navigateTo({ url: '/pages/common/taskDetail' })
  136. }
  137. onMounted(() => {
  138. taskStore.fetchTasks()
  139. })
  140. // 下拉刷新
  141. onPullDownRefresh(async () => {
  142. await taskStore.fetchTasks()
  143. uni.stopPullDownRefresh()
  144. })
  145. </script>