Files
pda-uniapp/pages/dropship-tasks/dropship-tasks.vue
T
2026-10-20 11:34:58 +08:00

103 lines
6.9 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 v-if="palletNo" class="state">继续装入托盘 {{ palletNo }} · 选择其他票,或进入后直接扫描其他客户箱码</view>
<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, resolveDropshipWorkspacePallet } 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: '', palletNo: '' } },
onLoad(options) { this.palletNo = String(options.palletNo || '') },
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
if (!this.user?.warehouseId) { this.error = '请返回首页选择作业仓库'; return }
this.loading = true; this.error = ''
try {
// 返回列表时重查跨票续装目标,已封托盘不再传入其他任务。
if (this.palletNo) {
const workspace = await resolveDropshipWorkspacePallet(this.user.warehouseId, this.palletNo)
if (workspace.pallet.status !== 'OPEN') this.palletNo = ''
}
const records = await listDropshipPalletizationTasks(this.keyword, this.user.warehouseId)
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)}&palletNo=${encodeURIComponent(this.palletNo)}` }) }
}
}
</script>
<style scoped>
.content { padding: 8px 10px 32px; }
.search-card { display: flex; align-items: center; gap: 8px; padding: 0; border: 0; background: transparent; box-shadow: none; }
.search-card :deep(.scan-target-input) { min-width: 0; height: 44px; flex: 1; border-radius: 6px; }
.search-card :deep(.scan-target-value) { height: 42px; }
.search-card :deep(.scan-target-icon) { top: 10px; }
.search-card :deep(.scan-target-input-active .scan-target-icon) { top: 9px; }
.search-card :deep(.scan-target-badge) { top: 10px; }
.primary-button { height: 44px; border: 0; border-radius: 6px; color: #fff; font-size: 14px; font-weight: 700; line-height: 44px; background: #1a73e8; }
.search-button { width: 92px; margin: 0; flex-shrink: 0; }
.heading-row { display: flex; align-items: center; justify-content: space-between; margin: 10px 0 7px; }
.heading-row > view { display: flex; align-items: baseline; gap: 8px; }
.heading { color: #12233f; font-size: 17px; font-weight: 700; }
.summary { color: #667085; font-size: 11px; }
.refresh-button { min-width: 64px; height: 40px; border: 0; border-radius: 6px; color: #155eef; font-size: 13px; line-height: 40px; 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-list { overflow: hidden; border: 1px solid #dce6f1; border-radius: 7px; background: #fff; }
.task-card { box-sizing: border-box; width: 100%; margin: 0; padding: 9px 11px 7px; border: 0; border-bottom: 1px solid #dce6f1; border-radius: 0; color: #12233f; text-align: left; background: #fff; box-shadow: none; }
.task-card:last-child { border-bottom: 0; }
.task-card:active { background: #f5f8fc; }
.task-head, .task-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.business-code { min-width: 0; font-size: 16px; font-weight: 700; line-height: 22px; overflow-wrap: anywhere; }
.status { flex-shrink: 0; padding: 2px 7px; border-radius: 4px; color: #9a5b13; font-size: 10px; line-height: 18px; background: #fff4e5; }
.status.claimed { color: #155eef; background: #eff4ff; }
.customer { display: block; margin-top: 1px; color: #667085; font-size: 11px; line-height: 17px; }
.metrics { display: grid; grid-template-columns: repeat(4, 1fr); margin-top: 6px; padding: 6px 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: 16px; line-height: 22px; }
.metrics text { color: #667085; font-size: 10px; line-height: 16px; }
.task-foot { margin-top: 3px; color: #667085; font-size: 11px; line-height: 30px; }
.enter { color: #155eef; font-size: 12px; font-weight: 700; }
</style>