Commit 3fac4d59 by liangjianmin

feat(scanTally): 新增扫码理货搜索框及二维码识别功能

- 新增SearchBoxWithPicker组件,实现带选择器的搜索输入框
- scanTally页面集成搜索框组件,支持扫码输入和清除操作
- 实现二维码解析接口调用,根据扫码结果解析订单号、型号、数量、产地等信息
- 新增接口API配置,补充入库单明细查询相关接口地址
- 优化样式,实现搜索框固定定位效果和交互体验
- 添加输入防抖,避免频繁请求,提高性能和用户体验
parent 2ce69291
.scanTally { .scanTally {
.fix-box {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 99;
padding: 20rpx 24rpx;
background: #f1f4f6;
}
} }
<template>
<view class="search-box-container row bothSide verCenter">
<!-- 选择器区域 -->
<view class="picker-wrapper row rowCenter verCenter" v-if="showPicker">
<picker @change="handlePickerChange" :value="currentPickerIndex" :range="pickerOptions">
<view class="picker-content row verCenter">
<view class="picker-text">{{ pickerOptions[currentPickerIndex] }}</view>
<view class="picker-arrow"></view>
</view>
</picker>
</view>
<!-- 搜索输入框区域 -->
<view class="input-wrapper row bothSide verCenter" :class="{ 'full-width': !showPicker }">
<view class="input-content row verCenter">
<text class="search-icon iconfont icon-juxing11" @click="handleSearchIconClick"></text>
<input class="search-input" :placeholder="placeholder" :placeholder-style="placeholderStyle" :focus="inputFocus" v-model="inputValue" @input="handleInput" maxlength="-1" />
</view>
<text class="clear-icon iconfont icon-a-juxing111" @click="handleClearInput" v-if="showClearIcon"></text>
</view>
</view>
</template>
<script>
// #ifdef APP-PLUS
import { openScan } from '@/uni_modules/xtf-scanqrcode';
// #endif
export default {
name: 'SearchBoxWithPicker',
props: {
showPicker: {
type: Boolean,
default: true
},
pickerOptions: {
type: Array,
default: () => ['全量搜索']
},
pickerIndex: {
type: Number,
default: 0
},
placeholder: {
type: String,
default: '请输入搜索关键词'
},
placeholderStyle: {
type: String,
default: 'color:#919399'
},
focus: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
},
showClear: {
type: Boolean,
default: false
},
showScan: {
type: Boolean,
default: false
}
},
data() {
return {
currentPickerIndex: this.pickerIndex,
inputValue: this.value,
inputFocus: this.focus,
showClearIcon: this.showClear
};
},
watch: {
value(newVal) {
this.inputValue = newVal;
},
focus(newVal) {
this.inputFocus = newVal;
},
showClear(newVal) {
this.showClearIcon = newVal;
},
pickerIndex(newVal) {
this.currentPickerIndex = newVal;
}
},
methods: {
/**
* 选择器变化事件
*/
handlePickerChange(e) {
this.currentPickerIndex = e.detail.value;
this.$emit('picker-change', {
index: this.currentPickerIndex,
value: this.pickerOptions[this.currentPickerIndex]
});
},
/**
* 输入框输入事件
*/
handleInput(e) {
var value = e.detail.value;
this.inputValue = value;
this.showClearIcon = !!value;
this.$emit('input', value);
this.$emit('update:value', value);
},
/**
* 清空输入
*/
handleClearInput() {
this.inputValue = '';
this.showClearIcon = false;
this.$emit('clear');
this.$emit('update:value', '');
this.inputFocus = false;
setTimeout(() => {
this.inputFocus = true;
}, 200);
},
/**
* 搜索图标点击事件
*/
handleSearchIconClick() {
if (!this.showScan) return;
// #ifdef APP-PLUS
openScan({
scanHintText: '请将条码/二维码对准扫描框',
fullScreenScan: true,
isShowBeep: false,
isShowVibrate: true,
isShowLightController: true,
isShowPhotoAlbum: false,
success: (type, data) => {
if (type === 0) {
this.inputValue = data;
this.showClearIcon = true;
this.$emit('update:value', data);
this.$emit('scan', data);
}
}
});
// #endif
// #ifdef MP-WEIXIN
uni.scanCode({
success: (res) => {
var data = res.result;
this.inputValue = data;
this.showClearIcon = true;
this.$emit('update:value', data);
this.$emit('scan', data);
}
});
// #endif
}
}
};
</script>
<style scoped lang="scss">
.search-box-container {
height: 60rpx;
background: #ffffff;
border-radius: 10rpx;
padding: 0 18rpx;
.picker-wrapper {
width: 160rpx;
height: 100%;
border-right: 1px solid #f0f0f2;
padding: 0 12rpx 0 0;
.picker-text {
font-size: 24rpx;
color: #292b33;
font-weight: 600;
}
.picker-arrow {
width: 0;
height: 0;
border-left: 8rpx solid transparent;
border-right: 8rpx solid transparent;
border-top: 11rpx solid #666;
margin-left: 12rpx;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
transform-origin: center 30%;
&:active {
transform: rotate(180deg) scale(1.1);
border-top-color: #1969f9;
}
}
}
.input-wrapper {
flex: 1;
height: 100%;
margin-left: 2rpx;
&.full-width {
margin-left: 0;
}
.input-content {
flex: 1;
}
.search-icon {
font-size: 30rpx;
color: #919399;
margin-left: 10rpx;
margin-right: 14rpx;
flex-shrink: 0;
}
.search-input {
flex: 1;
font-size: 24rpx;
color: #484b59;
height: 100%;
}
.clear-icon {
font-size: 30rpx;
color: #c6c7cc;
margin-left: 10rpx;
flex-shrink: 0;
}
}
}
</style>
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"baseUrl": ".",
"paths": {
"@/*": [
"./*"
]
}
},
"vueCompilerOptions": {
"globalTypesPath": "./node_modules/vue/dist/vue.d.ts"
},
"include": [
"./**/*"
]
}
\ No newline at end of file
<template> <template>
<view class="scanTally"> <view class="scanTally">
<view class="fix-box">
<SearchBoxWithPicker :showPicker="false" placeholder="请扫描Digikey或Rochest二维码" :focus="is_focus" :value="keyword" :showClear="!!keyword" @input="handleSearchInput" @clear="clearInput" />
</view>
</view> </view>
</template> </template>
<script> <script>
import { API } from '@/util/api.js';
import debounce from 'lodash/debounce';
import SearchBoxWithPicker from '@/components/SearchBoxWithPicker.vue';
export default { export default {
components: {
SearchBoxWithPicker
},
data() { data() {
return {}; return {
is_focus: true,
keyword: '',
order_sn: '',
stock_in_id: '',
goods_type: '',
parsed_origin: '',
parsed_qty: '',
isRequestSent: false
};
},
methods: {
/**
* 搜索输入防抖处理
* @param {String} value 输入值
*/
handleSearchInput: debounce(function (value) {
this.keyword = value;
if (value) {
uni.hideKeyboard();
this.identifyQrCodeNumAndSn();
}
}, 500),
/**
* 扫码解析二维码,输出订单号、型号、数量、COO、D/C
*/
identifyQrCodeNumAndSn() {
var device = uni.getDeviceInfo();
if (!this.isRequestSent) {
this.isRequestSent = true;
this.request(API.scanQrCode, 'POST', { data: this.keyword, type: 'DigiKey', device: device.deviceModel }, true).then(res => {
this.isRequestSent = false;
// 调试用:写死返回数据
res = {
err_code: 0,
err_msg: '操作成功',
data: {
goods: '',
brand: '',
model: 'BL02RN2R1M75B',
model2: '',
qty: 9,
origin: 'CN',
batch: '2421',
putaway_sn: 'C00983'
}
};
if (res.err_code === 0) {
var { model, model2, putaway_sn, origin, qty } = res.data;
var goodsModel = model || model2;
if (goodsModel) {
this.keyword = goodsModel;
this.goods_type = goodsModel;
this.order_sn = putaway_sn;
}
this.parsed_origin = origin || '';
this.parsed_qty = qty || '';
this.getWaitTallyList();
} else {
uni.showToast({
title: res.err_msg,
icon: 'none'
});
}
});
}
},
/**
* 根据解析结果查询入库单明细(待理货任务)
*/
getWaitTallyList() {
this.request(API.stockInDetailList, 'POST', {
page: 1,
limit: 1000,
inhouse: this.order_sn,//入仓号
goods_name: this.goods_type,//货品名称
tally_status_in: [0, 1, 2],//待处理、待理货、部分理货
stock_in_items_with_stock_in_status_in: [1, 2]//新创建、已到货
}, true).then(res => {
if (res.code === 0) {
var list = res.data.list || [];
// TODO: 后续步骤 - 展示待理货列表
} else {
uni.showToast({
title: res.msg,
icon: 'none'
});
}
});
},
/**
* 清空输入并重新聚焦
*/
clearInput() {
this.keyword = '';
this.goods_type = '';
this.order_sn = '';
this.stock_in_id = '';
this.parsed_origin = '';
this.parsed_qty = '';
this.is_focus = false;
setTimeout(() => { this.is_focus = true; }, 200);
}
} }
}; };
</script> </script>
......
...@@ -7,13 +7,15 @@ var ENV_CONFIG = { ...@@ -7,13 +7,15 @@ var ENV_CONFIG = {
API_BASE_USER: 'https://user.ichunt.net', API_BASE_USER: 'https://user.ichunt.net',
API_BASE_PUR: 'https://purchase.ichunt.net', API_BASE_PUR: 'https://purchase.ichunt.net',
API_BASE: 'https://wms.ichunt.net', API_BASE: 'https://wms.ichunt.net',
API_BASE_OSS: 'https://image.ichunt.net' API_BASE_OSS: 'https://image.ichunt.net',
API_BASE_ICHUNT: 'https://api.ichunt.com'
}, },
development: { development: {
API_BASE_USER: 'http://user.liexindev.net', API_BASE_USER: 'http://user.liexindev.net',
API_BASE_PUR: 'http://pur.liexindev.net', API_BASE_PUR: 'http://pur.liexindev.net',
API_BASE: 'http://wms.liexindev.net', API_BASE: 'http://wms.liexindev.net',
API_BASE_OSS: 'http://image.liexindev.net' API_BASE_OSS: 'http://image.liexindev.net',
API_BASE_ICHUNT: 'http://api.liexin.com'
} }
}; };
...@@ -23,6 +25,7 @@ const API_BASE_USER = currentEnv.API_BASE_USER; //用户系统 ...@@ -23,6 +25,7 @@ const API_BASE_USER = currentEnv.API_BASE_USER; //用户系统
const API_BASE_PUR = currentEnv.API_BASE_PUR; //采购系统 const API_BASE_PUR = currentEnv.API_BASE_PUR; //采购系统
const API_BASE = currentEnv.API_BASE; //WMS系统 const API_BASE = currentEnv.API_BASE; //WMS系统
const API_BASE_OSS = currentEnv.API_BASE_OSS; //oss系统 const API_BASE_OSS = currentEnv.API_BASE_OSS; //oss系统
const API_BASE_ICHUNT = currentEnv.API_BASE_ICHUNT; //ichunt接口
// 环境日志输出 // 环境日志输出
var envText = ENV === 'production' ? '🔴 正式环境' : '🟢 测试环境'; var envText = ENV === 'production' ? '🔴 正式环境' : '🟢 测试环境';
...@@ -63,6 +66,10 @@ const API = { ...@@ -63,6 +66,10 @@ const API = {
* */ * */
waitTallyReceiveList: API_BASE + '/api/stockIn/tallyReceive/waitTallyReceiveList', waitTallyReceiveList: API_BASE + '/api/stockIn/tallyReceive/waitTallyReceiveList',
/** /**
* 入库单明细列表
* */
stockInDetailList: API_BASE + '/api/stockIn/stockInDetail/stockInDetailList',
/**
* 获取订单销售ID是否需要打印标签 * 获取订单销售ID是否需要打印标签
* */ * */
getOrderIsPrintLabel: API_BASE + '/api/stockIn/getOrderIsPrintLabel', getOrderIsPrintLabel: API_BASE + '/api/stockIn/getOrderIsPrintLabel',
...@@ -458,7 +465,11 @@ const API = { ...@@ -458,7 +465,11 @@ const API = {
/** /**
* 获取自营货品信息 * 获取自营货品信息
* */ * */
getZyGoodsInfo: API_BASE + '/api/zyGoods/getZyGoodsInfo' getZyGoodsInfo: API_BASE + '/api/zyGoods/getZyGoodsInfo',
/**
* 扫码解析二维码
* */
scanQrCode: API_BASE_ICHUNT + '/supplywechatwms/scanQrCode'
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment