|
|
@@ -15,7 +15,7 @@
|
|
|
</picker>
|
|
|
<text class="selector-status">{{ pendingOrders[selectedOrderIndex]?.statusLabel || '' }}</text>
|
|
|
</view>
|
|
|
- <view class="order-banner" v-if="orderNo">
|
|
|
+ <view class="order-banner" v-else-if="orderNo && pendingOrders.length <= 1">
|
|
|
<text class="order-banner-text">补货单 {{ orderNo }}</text>
|
|
|
</view>
|
|
|
|
|
|
@@ -53,8 +53,14 @@
|
|
|
</view>
|
|
|
|
|
|
<view class="item-stock">
|
|
|
- <text class="stock-label">标准库存 {{ item.warning_threshold || item.warningThreshold || '-' }}</text>
|
|
|
- <text class="stock-label">剩余库存 <text :class="{ warn: isLowStock(item), danger: isOutOfStock(item) }">{{ item.stock || 0 }}</text></text>
|
|
|
+ <view class="stock-col">
|
|
|
+ <text class="stock-label">标准库存</text>
|
|
|
+ <text class="stock-num">{{ item.warning_threshold || item.warningThreshold || '-' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="stock-col">
|
|
|
+ <text class="stock-label">剩余库存</text>
|
|
|
+ <text class="stock-num" :class="{ warn: isLowStock(item), danger: isOutOfStock(item) }">{{ item.stock || 0 }}</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
|
|
|
<view class="replenish-row">
|
|
|
@@ -69,7 +75,17 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <view class="bottom-bar" v-if="inventoryList.length > 0">
|
|
|
+ <!-- 补货员底部操作 -->
|
|
|
+ <view class="bottom-bar" v-if="inventoryList.length > 0 && isReplenisherUser">
|
|
|
+ <view class="bottom-btn secondary" @click="handleCancel"><text>终止任务</text></view>
|
|
|
+ <view class="bottom-btn secondary" @click="handleReopen"><text>重新开门</text></view>
|
|
|
+ <view class="bottom-btn primary" :class="{ disabled: submitting || totalReplenishCount === 0 }" @click="handleSubmit">
|
|
|
+ <view class="btn-spinner" v-if="submitting"></view>
|
|
|
+ <text>{{ submitting ? '提交中' : '一键提交' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <!-- 运营人员底部操作 -->
|
|
|
+ <view class="bottom-bar" v-else-if="inventoryList.length > 0">
|
|
|
<text class="total-label">共补货 <text class="total-num">{{ totalReplenishCount }}</text> 件</text>
|
|
|
<view class="submit-btn" :class="{ disabled: submitting || totalReplenishCount === 0 }" @click="handleSubmit">
|
|
|
<view class="btn-spinner" v-if="submitting"></view>
|
|
|
@@ -83,7 +99,8 @@
|
|
|
<script setup lang="ts">
|
|
|
import { ref, computed, onMounted } from 'vue';
|
|
|
import NavBar from '@/components/NavBar.vue';
|
|
|
-import { getDeviceInventory, replenishStock, getDevicePendingOrders, getReplenisherOrderDetail } from '@/api/replenish';
|
|
|
+import { getDeviceInventory, replenishStock, getDevicePendingOrders, getReplenisherOrderDetail, openDeviceDoor } from '@/api/replenish';
|
|
|
+import { isReplenisher } from '@/utils/auth';
|
|
|
|
|
|
interface ReplenishInput {
|
|
|
productId: number;
|
|
|
@@ -100,6 +117,7 @@ const inventoryList = ref<any[]>([]);
|
|
|
const replenishItems = ref<ReplenishInput[]>([]);
|
|
|
const loading = ref(true);
|
|
|
const submitting = ref(false);
|
|
|
+const isReplenisherUser = ref(false);
|
|
|
const orderId = ref('');
|
|
|
const orderNo = ref('');
|
|
|
const showOrderOnly = ref(false);
|
|
|
@@ -196,9 +214,34 @@ const onOrderChange = (e: any) => {
|
|
|
if (o) loadOrderItems(String(o.id));
|
|
|
};
|
|
|
|
|
|
+const handleCancel = () => {
|
|
|
+ uni.showModal({
|
|
|
+ title: '终止任务',
|
|
|
+ content: '确定要终止当前补货任务吗?',
|
|
|
+ success: (res) => { if (res.confirm) uni.navigateBack(); }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleReopen = () => {
|
|
|
+ uni.showModal({
|
|
|
+ title: '重新开门',
|
|
|
+ content: '确定要远程打开柜门吗?',
|
|
|
+ success: async (res) => {
|
|
|
+ if (!res.confirm) return;
|
|
|
+ try {
|
|
|
+ await openDeviceDoor(deviceId.value);
|
|
|
+ uni.showToast({ title: '开门指令已发送', icon: 'success' });
|
|
|
+ } catch (e: any) {
|
|
|
+ uni.showToast({ title: e.message || '开门失败', icon: 'none' });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
onMounted(async () => {
|
|
|
const pages = getCurrentPages();
|
|
|
const opts = (pages[pages.length - 1] as any)?.$page?.options || (pages[pages.length - 1] as any)?.options || {};
|
|
|
+ isReplenisherUser.value = isReplenisher();
|
|
|
deviceId.value = opts.deviceId || '';
|
|
|
orderId.value = opts.orderId || '';
|
|
|
if (!deviceId.value) { uni.showToast({ title: '缺少设备ID', icon: 'none' }); setTimeout(() => uni.navigateBack(), 500); return; }
|
|
|
@@ -332,11 +375,12 @@ onMounted(async () => {
|
|
|
&.danger { background: $error-color-bg; color: $error-color; }
|
|
|
}
|
|
|
|
|
|
-.item-stock { display: flex; gap: 24rpx; margin-bottom: 12rpx; }
|
|
|
-.stock-label { font-size: $font-size-sm; color: $text-color-muted;
|
|
|
- text { font-weight: 600; }
|
|
|
- .warn { color: $warning-color; }
|
|
|
- .danger { color: $error-color; }
|
|
|
+.item-stock { display: flex; gap: 16rpx; margin-bottom: 12rpx; padding: 12rpx 0; background: $bg-color-page; border-radius: $radius-sm; }
|
|
|
+.stock-col { flex: 1; display: flex; flex-direction: column; align-items: center; }
|
|
|
+.stock-label { font-size: 22rpx; color: $text-color-muted; margin-bottom: 4rpx; }
|
|
|
+.stock-num { font-size: $font-size-lg; font-weight: 700; color: $text-color-primary;
|
|
|
+ &.warn { color: $warning-color; }
|
|
|
+ &.danger { color: $error-color; }
|
|
|
}
|
|
|
|
|
|
.replenish-row { display: flex; align-items: center; background: $bg-color-page; border-radius: $radius-base; padding: 12rpx 16rpx; }
|
|
|
@@ -353,9 +397,16 @@ onMounted(async () => {
|
|
|
}
|
|
|
|
|
|
// ====== Bottom ======
|
|
|
-.bottom-bar { display: flex; align-items: center; gap: 20rpx; padding: 20rpx 24rpx; padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); background: $bg-color-card; border-top: 1rpx solid $border-color-light; }
|
|
|
+.bottom-bar { display: flex; align-items: center; gap: 16rpx; padding: 20rpx 24rpx; padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); background: $bg-color-card; border-top: 1rpx solid $border-color-light; }
|
|
|
.total-label { font-size: $font-size-sm; color: $text-color-muted; flex-shrink: 0; }
|
|
|
.total-num { font-size: $font-size-xl; font-weight: 700; color: $primary-color-dark; margin: 0 4rpx; }
|
|
|
+.bottom-btn { flex: 1; height: 80rpx; display: flex; align-items: center; justify-content: center; border-radius: $radius-base;
|
|
|
+ text { font-size: $font-size-md; font-weight: 600; line-height: 1; }
|
|
|
+ &:active { opacity: 0.8; }
|
|
|
+ &.secondary { background: $bg-color-page; text { color: $text-color-secondary; } }
|
|
|
+ &.primary { background: $primary-color; text { color: $text-color-primary; } }
|
|
|
+ &.disabled { opacity: 0.5; pointer-events: none; }
|
|
|
+}
|
|
|
.submit-btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 12rpx; height: 80rpx; background: $primary-color; border-radius: $radius-base;
|
|
|
text { font-size: $font-size-md; font-weight: 600; color: $text-color-primary; }
|
|
|
&:active { opacity: 0.8; }
|