Files
pda-uniapp/pages/dropship-tasks/dropship-tasks.vue
T
2026-09-11 11:15:07 +08:00

87 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view v-if="user" class="page-shell dropship-task-page">
<PortalHeader title="一件代发合托" :user="user" :fallback-url="'/pages/home/home'" />
<view class="content">
<view class="search-card">
<ScanTargetInput v-model="keyword" name="taskKeyword" label="入仓码查询" placeholder="扫描或输入入仓码" :active="true" @submit="loadTasks" />
<button class="primary-button search-button" :disabled="loading" @tap="loadTasks">{{ loading ? '查询中…' : '查询任务' }}</button>
</view>
<view class="heading-row">
<view><text class="heading">待合托任务</text><text class="summary">{{ loading ? '正在同步' : `共 ${tasks.length} 个任务` }}</text></view>
<button class="refresh-button" :disabled="loading" @tap="refresh">刷新</button>
</view>
<view v-if="error" class="state error" role="alert">{{ error }}</view>
<view v-else-if="!loading && !tasks.length" class="state">暂无待合托任务</view>
<view class="task-list">
<button v-for="task in tasks" :key="task.taskId" class="task-card" :aria-label="`进入合托任务,入仓码 ${task.inboundCode || '未关联'}`" @tap="openTask(task)">
<view class="task-head"><text class="business-code">{{ task.inboundCode || '入仓码 —' }}</text><text class="status" :class="task.taskStatus === 'CLAIMED' ? 'claimed' : ''">{{ statusLabel(task.taskStatus) }}</text></view>
<text class="customer">{{ task.customerName || '客户未关联' }}</text>
<view class="metrics">
<view><strong>{{ task.totalCartons || 0 }}</strong><text>总箱</text></view>
<view><strong>{{ task.countedCartons || 0 }}</strong><text>已清点</text></view>
<view><strong>{{ task.boundCartons || 0 }}</strong><text>已归托</text></view>
<view><strong>{{ task.unboundCartons || 0 }}</strong><text>待归托</text></view>
</view>
<view class="task-foot"><text>仓库 {{ task.warehouseName || '—' }}</text><text class="enter">进入作业 ›</text></view>
</button>
</view>
</view>
</view>
</template>
<script>
import PortalHeader from '@/components/PortalHeader.vue'
import ScanTargetInput from '@/components/ScanTargetInput.vue'
import { listDropshipPalletizationTasks } from '@/api/pda-dropship.js'
import { session, requireSession } from '@/stores/session.js'
import { formatApiError } from '@/utils/user-facing.js'
export default {
components: { PortalHeader, ScanTargetInput },
data() { return { user: session.currentUser, keyword: '', tasks: [], loading: false, error: '' } },
onShow() { if (!requireSession()) return; this.user = session.currentUser; this.loadTasks() },
methods: {
statusLabel(status) { return status === 'CLAIMED' ? '作业中' : '待领取' },
refresh() { this.keyword = ''; this.loadTasks() },
async loadTasks() {
if (this.loading) return
this.loading = true; this.error = ''
try {
const records = await listDropshipPalletizationTasks(this.keyword)
this.tasks = Array.isArray(records) ? records : []
}
catch (error) { this.tasks = []; this.error = formatApiError(error, '合托任务加载失败') }
finally { this.loading = false }
},
openTask(task) { uni.navigateTo({ url: `/pages/dropship-palletization/dropship-palletization?taskId=${encodeURIComponent(task.taskId)}&warehouseId=${encodeURIComponent(task.warehouseId)}` }) }
}
}
</script>
<style scoped>
.content { padding: 12px 12px 40px; }
.search-card { padding: 12px; border: 1px solid #dce6f1; border-radius: 12px; background: #fff; box-shadow: 0 2px 8px rgba(23,55,93,.05); }
.primary-button { height: 46px; border: 0; border-radius: 9px; color: #fff; font-size: 15px; font-weight: 700; line-height: 46px; background: #1a73e8; }
.search-button { width: 100%; margin-top: 10px; }
.heading-row { display: flex; align-items: center; justify-content: space-between; margin: 16px 0 10px; }
.heading-row > view { display: flex; flex-direction: column; }
.heading { color: #12233f; font-size: 18px; font-weight: 700; }
.summary { margin-top: 2px; color: #667085; font-size: 11px; }
.refresh-button { min-width: 72px; height: 42px; border: 0; border-radius: 9px; color: #155eef; font-size: 14px; line-height: 42px; background: #eaf2ff; }
.state { padding: 24px 12px; border-radius: 10px; color: #667085; font-size: 13px; text-align: center; background: #fff; }
.state.error { color: #b42318; background: #fff1f0; }
.task-card { box-sizing: border-box; width: 100%; margin: 0 0 12px; padding: 13px; border: 1px solid #dce6f1; border-radius: 12px; color: #12233f; text-align: left; background: #fff; box-shadow: 0 2px 8px rgba(23,55,93,.05); }
.task-head, .task-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.business-code { min-width: 0; font-size: 17px; font-weight: 700; overflow-wrap: anywhere; }
.status { flex-shrink: 0; padding: 4px 8px; border-radius: 99px; color: #9a5b13; font-size: 10px; background: #fff4e5; }
.status.claimed { color: #155eef; background: #eff4ff; }
.customer { display: block; margin-top: 5px; color: #667085; font-size: 11px; }
.metrics { display: grid; grid-template-columns: repeat(4, 1fr); margin-top: 12px; padding: 10px 0; border-top: 1px solid #edf1f5; border-bottom: 1px solid #edf1f5; }
.metrics view { display: flex; align-items: center; flex-direction: column; border-right: 1px solid #edf1f5; }
.metrics view:last-child { border-right: 0; }
.metrics strong { font-size: 17px; }
.metrics text { margin-top: 2px; color: #667085; font-size: 10px; }
.task-foot { margin-top: 10px; color: #667085; font-size: 11px; }
.enter { min-height: 40px; color: #155eef; font-size: 12px; font-weight: 700; line-height: 40px; }
</style>