<template>
|
<view class="choose-page">
|
<CardTitle title="库存操作" :hideAction="false" />
|
|
<!-- 两个大按钮:成品拆盘 / 绞线复绕 -->
|
<view
|
v-for="opt in OPERATION_TYPES"
|
:key="opt.value"
|
class="type-card"
|
:class="{ 'type-card-active': pendingType === opt.value }"
|
@click="chooseType(opt.value)"
|
>
|
<view class="type-icon">
|
<wd-icon :name="opt.icon" size="26px" color="#0D867F"></wd-icon>
|
</view>
|
<view class="type-body">
|
<view class="type-title">{{ opt.label }}</view>
|
<view class="type-desc">{{ opt.desc }}</view>
|
</view>
|
<wd-icon name="arrow-right" size="16px" color="#C8C8C8"></wd-icon>
|
</view>
|
|
<!-- 扫码领用源盘 -->
|
<view class="scan-panel">
|
<view v-if="pendingType" class="scan-status">
|
<wd-icon name="scan" size="16px" color="#0D867F"></wd-icon>
|
<text class="scan-text">正在扫码领用源盘({{ currentTypeLabel }}),扫到后进入办理</text>
|
</view>
|
<view v-else class="scan-status">
|
<wd-icon name="scan" size="16px" color="#9A9A9A"></wd-icon>
|
<text class="scan-text scan-text-idle">点击上方按钮后直接扫码领用源盘</text>
|
</view>
|
|
<!-- 扫码枪不可用时的手动兜底 -->
|
<view class="manual-row">
|
<view class="manual-input">
|
<wd-input
|
v-model="manualCode"
|
no-border
|
clearable
|
placeholder="或手动输入成品盘号,如 74082609001"
|
/>
|
</view>
|
</view>
|
<view class="manual-btns">
|
<wd-button size="small" plain :round="false" @click="scanSource">扫码</wd-button>
|
<wd-button size="small" plain :round="false" @click="searchManual">查询并进入</wd-button>
|
</view>
|
</view>
|
|
<Scan ref="scanRef" emitName="scanInventorySource" />
|
<wd-toast />
|
</view>
|
</template>
|
|
<script setup lang="ts">
|
import CardTitle from "@/components/card-title/index.vue";
|
import Scan from "@/components/scan/index.vue";
|
import { useToast } from "wot-design-uni";
|
import { onLoad, onUnload, onShow, onHide } from "@dcloudio/uni-app";
|
import {
|
OPERATION_TYPES,
|
OP_SPLIT,
|
REEL_CODE_KEYS,
|
SOURCE_STORAGE_KEY,
|
findSourceStock,
|
parseScanCode,
|
pickValue,
|
} from "./shared";
|
|
const toast = useToast();
|
const scanRef = ref();
|
/** 已选中的操作类型,为空表示还没点按钮 */
|
const pendingType = ref("");
|
const manualCode = ref("");
|
/** 防止扫码重复触发 */
|
const submitting = ref(false);
|
const isPageVisible = ref(true);
|
|
const currentTypeLabel = computed(
|
() => OPERATION_TYPES.find((opt) => opt.value === pendingType.value)?.label || ""
|
);
|
|
/** 点击大按钮:记录类型并立即扫码领用源盘 */
|
const chooseType = (type: string) => {
|
pendingType.value = type;
|
manualCode.value = "";
|
scanSource();
|
};
|
|
const scanSource = () => {
|
if (!pendingType.value) {
|
toast.warning("请先选择成品拆盘或绞线复绕");
|
return;
|
}
|
// #ifdef APP-PLUS
|
scanRef.value?.triggerScan();
|
// #endif
|
// #ifndef APP-PLUS
|
toast.warning("当前环境不支持硬件扫码,请用下方输入框手动查询");
|
// #endif
|
};
|
|
const searchManual = () => {
|
const code = String(manualCode.value ?? "").trim();
|
if (!code) {
|
toast.error("请输入成品盘号");
|
return;
|
}
|
applySourceCode(code);
|
};
|
|
/** 领用源盘:校验通过后带着源盘信息进入办理页 */
|
const applySourceCode = async (code: string) => {
|
if (submitting.value) return;
|
submitting.value = true;
|
try {
|
const { record, mocked } = await findSourceStock(code);
|
if (!record) {
|
toast.error(`未找到成品盘号 ${code} 的库存`);
|
return;
|
}
|
if (!(record.enableStatus === "启用" && record.qualityStatus === "合格")) {
|
toast.error(
|
`该盘状态不可用(${record.qualityStatus || "-"}·${record.enableStatus || "-"}),请更换源盘`
|
);
|
return;
|
}
|
|
// 源盘信息通过本地缓存传给办理页
|
uni.setStorageSync(SOURCE_STORAGE_KEY, { ...record, code, mocked });
|
if (mocked) {
|
toast.success("接口未联调,使用模拟源盘数据");
|
} else {
|
toast.success("源盘领用成功");
|
}
|
setTimeout(() => {
|
uni.navigateTo({
|
url: `/pages/production/inventory/form?type=${pendingType.value || OP_SPLIT}`,
|
});
|
}, 300);
|
} catch (error) {
|
// 请求层已统一提示
|
} finally {
|
submitting.value = false;
|
}
|
};
|
|
/** 扫码回调:把扫到的内容当成源盘盘号 */
|
const getScanCode = async (payload: any) => {
|
if (!isPageVisible.value || !pendingType.value) return;
|
const parsed = parseScanCode(payload);
|
if (!parsed) {
|
toast.error("扫码内容为空,请重新扫码");
|
return;
|
}
|
const code = pickValue(parsed, REEL_CODE_KEYS);
|
if (!code) {
|
toast.error("二维码无法识别盘号,请更换二维码");
|
return;
|
}
|
await applySourceCode(code);
|
};
|
|
onLoad(() => {
|
// 每次进来都从「未选类型」开始,避免用到上一次的缓存
|
uni.removeStorageSync(SOURCE_STORAGE_KEY);
|
uni.$off("scanInventorySource", getScanCode);
|
uni.$on("scanInventorySource", getScanCode);
|
});
|
|
onShow(() => {
|
isPageVisible.value = true;
|
});
|
|
onHide(() => {
|
isPageVisible.value = false;
|
});
|
|
onUnload(() => {
|
uni.$off("scanInventorySource", getScanCode);
|
isPageVisible.value = false;
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.choose-page {
|
min-height: 100vh;
|
padding: 12px;
|
background: #f3f9f8;
|
}
|
|
.type-card {
|
display: flex;
|
align-items: center;
|
padding: 20px 16px;
|
margin-bottom: 14px;
|
background: #ffffff;
|
border: 1px solid #e2ecea;
|
border-radius: 10px;
|
box-shadow: 0 2px 8px rgb(13 134 127 / 6%);
|
}
|
|
.type-card-active {
|
border-color: #0d867f;
|
box-shadow: 0 2px 12px rgb(13 134 127 / 18%);
|
}
|
|
.type-icon {
|
display: flex;
|
flex-shrink: 0;
|
align-items: center;
|
justify-content: center;
|
width: 48px;
|
height: 48px;
|
margin-right: 14px;
|
background: #e7f4f2;
|
border-radius: 50%;
|
}
|
|
.type-body {
|
flex: 1;
|
min-width: 0;
|
}
|
|
.type-title {
|
font-size: 17px;
|
font-weight: 600;
|
color: #252525;
|
}
|
|
.type-desc {
|
margin-top: 4px;
|
font-size: 12px;
|
color: #8a8a8a;
|
}
|
|
.scan-panel {
|
padding: 14px 16px;
|
background: #ffffff;
|
border: 1px solid #e2ecea;
|
border-radius: 10px;
|
}
|
|
.scan-status {
|
display: flex;
|
align-items: center;
|
}
|
|
.scan-text {
|
margin-left: 6px;
|
font-size: 13px;
|
color: #0d867f;
|
}
|
|
.scan-text-idle {
|
color: #9a9a9a;
|
}
|
|
.manual-row {
|
margin-top: 8px;
|
}
|
|
.manual-input {
|
display: flex;
|
align-items: center;
|
height: 36px;
|
padding: 0 10px;
|
background: #f7faf9;
|
border: 1px solid #e2ecea;
|
border-radius: 6px;
|
}
|
|
.manual-btns {
|
display: flex;
|
justify-content: flex-end;
|
margin-top: 8px;
|
|
:deep(.wd-button) {
|
margin-left: 8px;
|
}
|
}
|
</style>
|