This commit is contained in:
2026-08-26 16:50:25 +08:00
parent 5868e774d4
commit 083299602d
31 changed files with 816 additions and 239 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
<view class="popup-header">
<view class="popup-header-spacer" aria-hidden="true"></view>
<text class="popup-header-title" :class="{ 'popup-header-title-danger': tone === 'danger' }">{{ title }}</text>
<button class="popup-header-close" :aria-label="`关闭${title}`" @tap="$emit('close')">
<button class="popup-header-close" :aria-label="`${$t('common.close')} ${title}`" @tap="$emit('close')">
<uni-icons type="closeempty" color="#52657c" size="24" />
</button>
</view>
+7 -7
View File
@@ -2,20 +2,20 @@
<view class="portal-header-shell">
<view class="portal-header">
<view class="portal-header-row">
<button v-if="menu" class="portal-header-button" aria-label="打开功能菜单" @tap="openMenu"><uni-icons type="bars" color="#ffffff" size="26" /></button>
<button v-else class="portal-header-button" aria-label="返回上一页" @tap="goBack"><uni-icons type="back" color="#ffffff" size="26" /></button>
<button v-if="menu" class="portal-header-button" :aria-label="$t('nav.openMenu')" @tap="openMenu"><uni-icons type="bars" color="#ffffff" size="26" /></button>
<button v-else class="portal-header-button" :aria-label="$t('nav.back')" @tap="goBack"><uni-icons type="back" color="#ffffff" size="26" /></button>
<text class="portal-title">{{ title }}</text>
<button v-if="showProfile" class="avatar-button" aria-label="打开个人中心" @tap="goProfile"><uni-icons type="person" color="#ffffff" size="27" /></button>
<button v-if="showProfile" class="avatar-button" :aria-label="$t('nav.profile')" @tap="goProfile"><uni-icons type="person" color="#ffffff" size="27" /></button>
<view v-else class="portal-header-spacer" aria-hidden="true"></view>
</view>
</view>
<uni-popup ref="menuPopup" type="bottom" background-color="#ffffff" border-radius="12px 12px 0 0" :is-mask-click="true" @change="handleMenuChange">
<view class="header-menu-sheet">
<view class="header-menu-content">
<PopupHeader title="功能菜单" @close="closeMenu" />
<button class="header-menu-item" @tap="goHistory"><uni-icons type="list" color="#334155" size="22" /><text>作业记录</text><uni-icons type="right" color="#94a3b8" size="18" /></button>
<button class="header-menu-item" @tap="goProfile"><uni-icons type="person" color="#334155" size="22" /><text>个人中心</text><uni-icons type="right" color="#94a3b8" size="18" /></button>
<button class="header-menu-close" @tap="closeMenu">关闭</button>
<PopupHeader :title="$t('nav.menu')" @close="closeMenu" />
<button class="header-menu-item" @tap="goHistory"><uni-icons type="list" color="#334155" size="22" /><text>{{ $t('nav.history') }}</text><uni-icons type="right" color="#94a3b8" size="18" /></button>
<button class="header-menu-item" @tap="goProfile"><uni-icons type="person" color="#334155" size="22" /><text>{{ $t('nav.profile') }}</text><uni-icons type="right" color="#94a3b8" size="18" /></button>
<button class="header-menu-close" @tap="closeMenu">{{ $t('common.close') }}</button>
</view>
</view>
</uni-popup>
@@ -0,0 +1,46 @@
<template>
<view class="receiving-summary">
<view class="receiving-summary-head">
<view><text class="receiving-summary-label">{{ $t('receivingSummary.container') }}</text><text class="receiving-summary-container">{{ session?.containerNo || '—' }}</text></view>
<text class="receiving-summary-status">{{ statusLabel }}</text>
</view>
<view class="receiving-summary-context">
<text>{{ $t('receivingSummary.warehouse') }}:{{ session?.overseasWarehouseName || '—' }}</text>
<text>{{ $t('receivingSummary.destinations') }}:{{ destinationSummary }}</text>
</view>
<view class="receiving-summary-metrics">
<view><text class="metric-value">{{ inboundCodeCount }}</text><text class="metric-label">{{ $t('receivingSummary.inboundCodes') }}</text></view>
<view><text class="metric-value">{{ plannedPalletCount }}</text><text class="metric-label">{{ $t('receivingSummary.plannedPallets') }}</text></view>
<view><text class="metric-value">{{ totalPackages }}</text><text class="metric-label">{{ $t('receivingSummary.plannedBoxes') }}</text></view>
<view><text class="metric-value metric-pending">{{ pendingPackages }}</text><text class="metric-label">{{ $t('receivingSummary.pendingBoxes') }}</text></view>
</view>
<view class="receiving-summary-progress"><view><text>{{ $t('operation.receivingProgress') }}</text><text>{{ receivedPackages }} / {{ totalPackages }} {{ $t('common.boxes') }}</text></view><view class="progress-track"><view class="progress-fill" :style="{ width: percent + '%' }"></view></view></view>
</view>
</template>
<script>
export default {
props: { session: { type: Object, default: null } },
computed: {
inboundCodeCount() { return Array.isArray(this.session?.inbounds) ? this.session.inbounds.length : 0 },
plannedPalletCount() { return (this.session?.inbounds || []).reduce((sum, item) => sum + Math.max(0, Number(item?.plannedPalletCount || 0)), 0) },
destinationSummary() { const values = (this.session?.inbounds || []).map((item) => item?.fbaWarehouseCode || item?.destinationWarehouseName || item?.destinationWarehouseCode).filter(Boolean); return [...new Set(values)].join(' / ') || '—' },
totalPackages() { return Math.max(0, Number(this.session?.totalPackages || 0)) },
receivedPackages() { return Math.max(0, Number(this.session?.receivedPackages || 0)) },
pendingPackages() { return Math.max(0, Number(this.session?.pendingPackages ?? this.totalPackages - this.receivedPackages)) },
percent() { return this.totalPackages ? Math.min(100, Math.round(this.receivedPackages / this.totalPackages * 100)) : 0 },
statusLabel() { return this.$t(({ WAIT_SIGN: 'operation.statusWait', SIGNED: 'operation.statusSigned', RECEIVING: 'operation.statusReceiving', COMPLETED: 'operation.statusCompleted' })[this.session?.status] || 'operation.statusWait') }
}
}
</script>
<style scoped>
.receiving-summary{box-sizing:border-box;margin-bottom:10px;padding:10px 12px;border:1px solid #b8d2f3;border-radius:13px;background:linear-gradient(145deg,#fff,#f2f7ff);box-shadow:0 3px 12px rgba(31,74,125,.08)}
.receiving-summary-head,.receiving-summary-progress>view:first-child{display:flex;align-items:center;justify-content:space-between;gap:10px}
.receiving-summary-label,.receiving-summary-container,.metric-value,.metric-label{display:block}.receiving-summary-label{color:#718095;font-size:9px;line-height:13px}.receiving-summary-container{margin-top:1px;color:#17324d;font-size:17px;font-weight:850;line-height:22px}
.receiving-summary-status{flex-shrink:0;padding:4px 8px;border-radius:99px;color:#1668dc;font-size:9px;font-weight:700;background:#e3efff}
.receiving-summary-context{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.35fr);gap:8px;margin-top:7px;color:#617389;font-size:9px;line-height:14px}.receiving-summary-context text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.receiving-summary-metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin-top:7px;padding:7px 2px;border-radius:9px;background:rgba(255,255,255,.8)}.receiving-summary-metrics>view{display:flex;align-items:center;flex-direction:column;border-right:1px solid #e3eaf2}.receiving-summary-metrics>view:last-child{border-right:0}
.metric-value{color:#17324d;font-size:17px;font-weight:850;line-height:21px}.metric-pending{color:#b66a08}.metric-label{margin-top:1px;color:#718095;font-size:8px;line-height:12px;text-align:center}
.receiving-summary-progress{margin-top:7px;color:#607287;font-size:9px}.progress-track{height:5px;margin-top:5px;overflow:hidden;border-radius:99px;background:#dfe8f2}.progress-fill{height:100%;border-radius:inherit;background:#1677e8}
</style>
+4 -4
View File
@@ -15,13 +15,13 @@
class="scan-target-value"
:value="modelValue"
:placeholder="placeholder"
:aria-label="`${label},支持扫码或人工输入`"
:aria-label="label"
confirm-type="done"
@focus="$emit('activate', name)"
@input="handleInput"
@confirm="handleConfirm"
/>
<text v-if="active" class="scan-target-badge">当前扫码</text>
<text v-if="active" class="scan-target-badge">{{ $t('scanInput.active') }}</text>
</view>
</template>
@@ -31,8 +31,8 @@
props: {
name: { type: String, required: true },
modelValue: { type: String, default: '' },
label: { type: String, default: '扫码输入框' },
placeholder: { type: String, default: '扫描或人工输入' },
label: { type: String, default: '' },
placeholder: { type: String, default: '' },
active: Boolean
},
methods: {