|
|
@@ -0,0 +1,174 @@
|
|
|
+<template>
|
|
|
+ <view class="app-container pb-20">
|
|
|
+ <TopBar :title="pageTitle">
|
|
|
+ <template #right>
|
|
|
+ <button
|
|
|
+ v-if="config.publishPath"
|
|
|
+ class="px-3 py-2 bg-primary text-white rounded-lg text-sm flex items-center"
|
|
|
+ @click="goToPublishTask"
|
|
|
+ >
|
|
|
+ <text class="uni-icons uniui-plusempty mr-1"></text>
|
|
|
+ {{ publishText }}
|
|
|
+ </button>
|
|
|
+ </template>
|
|
|
+ </TopBar>
|
|
|
+
|
|
|
+ <!-- 筛选标签 -->
|
|
|
+ <view class="bg-white px-4 py-3 flex gap-2 overflow-x-auto hide-scrollbar border-b border-gray-200">
|
|
|
+ <view
|
|
|
+ v-for="status in filterStatuses"
|
|
|
+ :key="status.value"
|
|
|
+ class="filter-tab px-3 py-2 rounded-full text-sm whitespace-nowrap transition-colors"
|
|
|
+ :class="currentFilter === status.value ? 'bg-primary text-white' : 'bg-surface text-gray-500'"
|
|
|
+ @click="currentFilter = status.value"
|
|
|
+ >
|
|
|
+ {{ status.label }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 加载/空态 -->
|
|
|
+ <view class="px-4 mt-3">
|
|
|
+ <view v-if="taskStore.loading" class="py-10 text-center">
|
|
|
+ <text class="text-gray-400">加载中...</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-else-if="filteredTasks.length === 0">
|
|
|
+ <EmptyState message="暂无任务" />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 销售端:任务卡片 -->
|
|
|
+ <view v-else-if="role === 'sales'" class="gap-y-3">
|
|
|
+ <SalesTaskCard
|
|
|
+ v-for="task in filteredTasks"
|
|
|
+ :key="task.id"
|
|
|
+ :task="task"
|
|
|
+ @click="goToDetail"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 调度端:任务卡片 -->
|
|
|
+ <view v-else-if="role === 'dispatch'" class="gap-y-3">
|
|
|
+ <DispatchTaskCard
|
|
|
+ v-for="task in filteredTasks"
|
|
|
+ :key="task.id"
|
|
|
+ :task="task"
|
|
|
+ @click="goToDetail"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 施工端:任务卡片 -->
|
|
|
+ <view v-else class="gap-y-3">
|
|
|
+ <ConstructionTaskCard
|
|
|
+ v-for="task in filteredTasks"
|
|
|
+ :key="task.id"
|
|
|
+ :task="task"
|
|
|
+ @click="goToDetail"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 发布/新增任务按钮 -->
|
|
|
+ <view v-if="config.publishPath && role !== 'dispatch'" class="fixed bottom-20 right-4">
|
|
|
+ <button
|
|
|
+ class="w-14 h-14 rounded-full bg-primary text-white flex items-center justify-center shadow-lg text-2xl"
|
|
|
+ @click="goToPublishTask"
|
|
|
+ >
|
|
|
+ +
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, computed } from 'vue'
|
|
|
+import { useTaskStore } from '@/stores/task'
|
|
|
+import TopBar from '@/components/common/TopBar.vue'
|
|
|
+import SalesTaskCard from '@/components/task/SalesTaskCard.vue'
|
|
|
+import DispatchTaskCard from '@/components/task/DispatchTaskCard.vue'
|
|
|
+import ConstructionTaskCard from '@/components/task/ConstructionTaskCard.vue'
|
|
|
+import EmptyState from '@/components/common/EmptyState.vue'
|
|
|
+
|
|
|
+const props = defineProps<{
|
|
|
+ role: 'sales' | 'dispatch' | 'construction'
|
|
|
+}>()
|
|
|
+
|
|
|
+const taskStore = useTaskStore()
|
|
|
+const currentFilter = ref('all')
|
|
|
+
|
|
|
+const roleConfig: Record<string, { filterStatuses: { value: string; label: string }[]; detailPath: string; publishPath?: string }> = {
|
|
|
+ sales: {
|
|
|
+ filterStatuses: [
|
|
|
+ { value: 'all', label: '全部' },
|
|
|
+ { value: 'dispatching', label: '调度中' },
|
|
|
+ { value: 'constructing', label: '施工中' },
|
|
|
+ { value: 'completed', label: '已完成' },
|
|
|
+ { value: 'emergency', label: '应急' },
|
|
|
+ ],
|
|
|
+ detailPath: '/subPackages/pages-common/taskDetail',
|
|
|
+ publishPath: '/subPackages/pages-common/publishTask',
|
|
|
+ },
|
|
|
+ dispatch: {
|
|
|
+ filterStatuses: [
|
|
|
+ { value: 'all', label: '全部' },
|
|
|
+ { value: 'pending', label: '待审核' },
|
|
|
+ { value: 'confirmed', label: '待排班' },
|
|
|
+ { value: 'processing', label: '进行中' },
|
|
|
+ { value: 'completed', label: '已完成' },
|
|
|
+ { value: 'rejected', label: '已驳回' },
|
|
|
+ ],
|
|
|
+ detailPath: '/subPackages/pages-dispatch/taskDetail',
|
|
|
+ publishPath: '/subPackages/pages-dispatch/publishTask',
|
|
|
+ },
|
|
|
+ construction: {
|
|
|
+ filterStatuses: [
|
|
|
+ { value: 'all', label: '全部' },
|
|
|
+ { value: 'pending', label: '待确认' },
|
|
|
+ { value: 'scheduled', label: '待出车' },
|
|
|
+ { value: 'departed', label: '已出车' },
|
|
|
+ { value: 'constructing', label: '施工中' },
|
|
|
+ { value: 'inspecting', label: '待验收' },
|
|
|
+ ],
|
|
|
+ detailPath: '/subPackages/pages-construction/taskDetail',
|
|
|
+ },
|
|
|
+}
|
|
|
+
|
|
|
+const config = computed(() => roleConfig[props.role] || roleConfig.sales)
|
|
|
+const filterStatuses = computed(() => config.value.filterStatuses)
|
|
|
+const detailPath = computed(() => config.value.detailPath)
|
|
|
+
|
|
|
+const pageTitle = computed(() => {
|
|
|
+ if (props.role === 'sales') return '我的任务'
|
|
|
+ if (props.role === 'dispatch') return '任务管理'
|
|
|
+ return '我的任务'
|
|
|
+})
|
|
|
+
|
|
|
+const publishText = computed(() => {
|
|
|
+ if (props.role === 'sales') return '发布'
|
|
|
+ if (props.role === 'dispatch') return '新增'
|
|
|
+ return '发布'
|
|
|
+})
|
|
|
+
|
|
|
+const filteredTasks = computed(() => {
|
|
|
+ if (currentFilter.value === 'all') return taskStore.tasks
|
|
|
+ if (currentFilter.value === 'dispatching') return taskStore.tasks.filter(t => ['confirmed', 'scheduled'].includes(t.status))
|
|
|
+ if (currentFilter.value === 'processing') return taskStore.tasks.filter(t => ['scheduled', 'departed', 'arrived', 'constructing'].includes(t.status))
|
|
|
+ if (currentFilter.value === 'emergency') return taskStore.tasks.filter(t => t.type === 'emergency')
|
|
|
+ return taskStore.tasks.filter(t => t.status === currentFilter.value)
|
|
|
+})
|
|
|
+
|
|
|
+function goToDetail(taskId: string) {
|
|
|
+ taskStore.setCurrentTask(taskId)
|
|
|
+ uni.navigateTo({ url: detailPath.value })
|
|
|
+}
|
|
|
+
|
|
|
+function goToPublishTask() {
|
|
|
+ if (!config.value.publishPath) return
|
|
|
+ uni.navigateTo({ url: config.value.publishPath })
|
|
|
+}
|
|
|
+
|
|
|
+function refresh() {
|
|
|
+ return taskStore.fetchTasks()
|
|
|
+}
|
|
|
+
|
|
|
+defineExpose({ refresh })
|
|
|
+</script>
|