货无忧
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

836 lines
20 KiB

<template>
<BasicContainer ref='basicContainer' :option="option">
<!-- 头部 -->
<template #head>
<view class="">
<image class="header_bg"
src="https://huo5you.oss-cn-chengdu.aliyuncs.com/other/pdaImages/pdaImages/bgby.png"></image>
<view class="header-container">
<!-- 顶部背景 -->
<view class="header">
<view class="search_row">
<input placeholder="请输入包条码" v-model.trim='details.searchText' type="text" name="" id="">
<view class="submitBtn flex-c-c" @click="handleSearch" hover-class="clickClass">
<u-icon name="search" color="#fff" size="36" />
<text class="ml10">
</text>
</view>
</view>
<PullDownBox :isShowIcon="true" :ExistenceOrNot="true" @change="handlePullDownChange">
<template #title>
<view class="flex mt10 flex-wrap header_row">
<view class="mb10">
<text class="textTitleColor">托盘码</text>
{{details.pageInfo.trayCode || '暂无数据'}}
</view>
<view class="mb10">
<text class="textTitleColor">托盘名称</text>
{{details.pageInfo.trayName || '暂无数据'}}
</view>
<view class="mb10">
<text class="textTitleColor">打托方式</text>
{{details.pageInfo.pageName || '暂无数据'}}
</view>
<view class="mb10">
<text class="textTitleColor">名称</text>
{{details.detauser.name || '暂无数据'}}
</view>
</view>
<view class="header_row">
<view>
<text class="textTitleColor">备注</text>
{{details.detauser.reamrk || '暂无数据'}}
</view>
</view>
<view class="flex-c-sb mt10">
<view @click.stop="handleEditRemark" class="submitBtn flex-c-c rem-0-9"
hover-class="clickClass">
<u-icon name="edit-pen-fill" color="#fff" size="36" />
<text class="ml10">
编辑备注
</text>
</view>
<view @click.stop="print" class="submitBtn flex-c-c rem-0-9" hover-class="clickClass">
<u-icon name="file-text-fill" color="#fff" size="36" />
<text class="ml10">
</text>
</view>
</view>
</template>
<template #content>
<view class="pt20 ">
<view class="header_title header_content">
<view class="flex-c-sb">
<view>
<text class="textTitleColor">订单在托数</text>
{{details.detauser.orderlNum }}
</view>
<view>
<text class="textTitleColor">订单总数</text>
{{details.detauser.orderTotalNum }}
</view>
</view>
<view class="mt10">
<text class="textTitleColor">路线</text>
{{details.pageInfo.lineNameTitle || '暂无数据'}}
</view>
<view class="mt10">
<text class="textTitleColor">批次号</text>
{{details.pageInfo.billladingCode || '暂无数据'}}
</view>
</view>
</view>
</template>
</PullDownBox>
</view>
</view>
</view>
</template>
<!-- 主体 -->
<template #body>
<u-divider text="订 单 列 表" textPosition="left"></u-divider>
<!-- 提货单件数 -->
<view class="scollView">
<block v-for="(item, index) in details.data" :key="item.id">
<uni-swipe-action-item>
<view :class="{'list_container': true, 'active': details.chooseIndex === index}">
<view class="list_row">
<text class="mr20 flexnone textTitleColor">订单号: </text>
<text @click="() => godetaillist(item)"
:class="{err: Number(item.isFleeing) === 1, fwb: true, link: true,}">{{item.dataCode || '暂无数据'}}</text>
</view>
<view class="list_row">
<text class="mr20 flexnone textTitleColor">服务号: </text>
<text
:class="{err: Number(item.isFleeing) === 1, fwb: true}">{{item.serviceNumber || '暂无数据'}}</text>
</view>
<view class="list_row">
<view class="">
<text class="textTitleColor">
总数:
</text>
<text>
{{item.orderTotalNum }}
</text>
</view>
<view>
<text class="textTitleColor">
已扫:
</text>
<text style="color: #10d269;">
{{item.scanNum }}
</text>
</view>
<view class="">
<text class="textTitleColor">
未扫:
</text>
<text :style="{color: item.residueNum > 0? '#f00': '#000'}">
{{item.residueNum }}
</text>
</view>
</view>
<!-- 状态标签 -->
<view :class="{
'list_tips': true,
'none':item.scanNum === 0,
'portion':item.scanNum < item.orderTotalNum && item.scanNum > 0,
'all':item.scanNum === item.orderTotalNum}">
{{details.type[item.scanNum ===item.orderTotalNum? 3: item.scanNum !==0?2: 1 ]|| '暂无状态数据'}}
</view>
<view class="fleeingGoodsTip" v-if="Number(item.isFleeing) === 1">
</view>
</view>
<template v-slot:right>
<view @click="()=> handleRemoveItem(item)" class="removeButton" hover-class="clickClass"><u-icon
name="trash" color="#fff" size="40"></u-icon></view>
</template>
</uni-swipe-action-item>
</block>
<!-- 底部站位 -->
<view class="footer">
</view>
</view>
<!-- 底部站位 -->
<!-- <view class="button_container">
<view @click="handleConfirm">
确认打托
</view>
</view> -->
</template>
</BasicContainer>
<tips ref="tip" />
<saomiao2 :ishidestop="scanState !== 0"></saomiao2>
<BluetoothList ref="bluetoothList"></BluetoothList>
<PopUp ref="editRemarkPop">
<view class="textareabx">
<u-textarea maxlength="100" height="200px" placeholder="请输入备注" count v-model="details.formRemark"></u-textarea>
</view>
</PopUp>
</template>
<script lang="ts" setup>
import {
getBillladingList,
postIncomingIncomingPackage,
warehouseTrayTypeorderScanTrayCode,
warehouseTrayTypedeleteOrderCode,
warehouseTrayTypezeroOrderUpdateRemark
} from '@/api/user.js'
import {
onLoad,
onShow,
} from '@dcloudio/uni-app'
import { nextTick, reactive, ref } from "vue";
import utils from '@/utils/utils.js'
import useSystemSettingsStore from '@/store/useSystemSettingsStore';
import useBluetoothStore from '@/store/useBluetoothStore.js'
import dayjs from 'dayjs'
import { storeToRefs } from 'pinia';
const { scanState } = storeToRefs(useSystemSettingsStore())
// 组件配置
const option = reactive({
// 标题
title: '码板打托',
// 下拉刷新回调函数
async pullDownRefreshInitPage() {
// 重置被选中数据
details.chooseIndex = -1
details.data = []
return initpage()
},
// 触底加载回到函数
reachBottomInitPage: async () => { return null },
haveReachBottom: false,
haveData: true,
isEnd: false,
isFixed: true
})
let details = reactive({
/** 提货批次列表 */
data: [] as any[],
/** 被选中的元素的索引 */
chooseIndex: -1,
/** 提货状态 */
type: {
1: '未 扫', 2: '部分扫', 3: '齐 套',
},
/** 滚动区高度 */
height: '80vh',
/** 页面数据 */
pageInfo: {} as any,
/** 扫描的码值 */
scancode: '',
detauser: {},
/** 输入框中的值 */
searchText: '',
/** 是否是扫描请求后执行的刷新 */
isScan: false,
/** 提交的备注 */
formRemark: ''
})
// 组件实例
const basicContainer = ref()
const bluetoothList = ref(null)
const tip = ref()
const editRemarkPop = ref()
const bluetoothStore = useBluetoothStore()
const { bluetoothInfo } = storeToRefs(bluetoothStore)
/**
* 扫描托盘码
*/
async function scanTray() {
let submitData = {
trayCode: details.scancode,
}
let res = await warehouseTrayTypeorderScanTrayCode(submitData)
const { code, data } = res
if (code !== 200) return
console.log('res', res)
if (Number(data.isHasData) === 0) {
uni.setStorageSync('trayCodeType', data.data)
uni.redirectTo({
url: '/pagesHome/pages/ScanSortingType/ScanSortingType?trayCode=' + details.scancode + '&SkipRoute=/billsList/billsList'
})
} else {
details.detauser = data.data
details.pageInfo.trayName = data.data.trayName
details.pageInfo.pageName = data.data.trayTypeName
console.log('details.pageInfo :>> ', details.pageInfo);
let _totalScanNum = 0
for (let item of details.detauser.packageList) {
item.scanNum = item.scanNum || 0
item.orderTotalNum = item.orderTotalNum || 0
item.residueNum = (item.orderTotalNum || 0) - (item.scanNum || 0)
_totalScanNum += item.scanNum
}
details.data = details.detauser.packageList
}
}
/** 扫描定制品 */
const scanOrder = async () => {
const _code = details.scancode
const _submitData = {
orderPackageCode: _code,
billladingId: details.pageInfo.id,
incomingType: "1",
trayCode: details.pageInfo.trayCode,
trayType: details.pageInfo.trayType
}
const res = await postIncomingIncomingPackage(_submitData)
const { code, msg } = res
if (code !== 200) return
basicContainer.value.startPullDownRefresh()
if (msg !== '该包条已打托') details.isScan = true
}
/** 扫描后执行的回调函数 */
const scandata = async () => {
// 当扫描的码值为托盘码时
if (details.scancode[0] === 'T') scanTray()
// 定制品
else return scanOrder()
}
onLoad((op) => {
console.log('op :>> ', op);
details.pageInfo = JSON.parse(op.pageInfo)
// #ifdef APP
utils.ttsspke('请扫描或输入包条码')
// #endif
})
onShow(async () => {
// 初始化关闭监听
uni.$off('scancodedate')
uni.$on('scancodedate', (code) => {
if (code) {
details.scancode = code
scandata()
}
})
await nextTick()
basicContainer.value.startPullDownRefresh()
})
async function initpage() {
try {
const _submitData = {
trayCode: details.pageInfo.trayCode,
}
const res = await warehouseTrayTypeorderScanTrayCode(_submitData)
const { code, data } = res
console.log('data :>> ', data);
console.log('111 :>> ', 111);
if (code !== 200) return
if (res.data.isHasData == 1) {
// details.datelist = res.data.data.list
details.detauser = data.data
details.pageInfo.trayName = data.data.trayName
details.pageInfo.pageName = data.data.trayTypeName
console.log('details.pageInfo :>> ', details.pageInfo);
let _totalScanNum = 0
// 正常订单
const _normalArr = []
// 异常订单
const _abnormalArr = []
for (let item of details.detauser.packageList) {
item.isFleeing === 0 ? _normalArr.push(item) : _abnormalArr.push(item)
item.scanNum = item.scanNum || 0
item.orderTotalNum = item.orderTotalNum || 0
item.residueNum = (item.orderTotalNum || 0) - (item.scanNum || 0)
_totalScanNum += item.scanNum
}
details.detauser.packageList = [..._abnormalArr, ..._normalArr]
details.data = details.detauser.packageList
if (details.isScan) {
utils.handleToast(`${_totalScanNum}`)
details.isScan = false
}
}
return null
} catch (err) {
//TODO handle the exception
console.log('err :>> ', err);
} finally {
return null
}
}
async function godetaillist(item) {
const _data = JSON.stringify({
orderCode: item.dataCode,
totalNum: item.orderTotalNum,
scanNum: 0
})
uni.navigateTo({
url: '/pagesHome/pages/OrderDetailsInTheStorage/OrderDetailsInTheStorage?pageInfo='
+ _data
})
}
/** 输入包条码 */
const handleSearch = () => {
if (details.searchText === '') return uni.showToast({
title: '请输入包条码',
icon: 'none'
})
details.scancode = details.searchText
scandata()
}
/** 删除订单 */
const handleRemoveItem = (item) => {
tip.value.setdetails({
title: '提示',
content: '确认删除该订单与托盘码的绑定?',
confirmTxt: '确认',
isshow: true,
isshowcancel: true,
success: async () => {
let data = {
trayCode: details.pageInfo.trayCode,
orderCode: item.dataCode,
}
let res = await warehouseTrayTypedeleteOrderCode(data)
if (res.code !== 200) return
utils.handleToast('移除成功')
console.log('res :>> ', res)
basicContainer.value.startPullDownRefresh()
tip.value.setisshow(false)
},
cancel: () => {
tip.value.setisshow(false)
},
close: () => {
tip.value.setisshow(false)
},
})
}
/** 下拉盒状态变化时 */
const handlePullDownChange = () => {
nextTick(() => {
const timer = setTimeout(() => {
basicContainer.value.handleSetHeaderHeight()
clearTimeout(timer)
}, 500)
})
}
/** 编辑备注 */
const handleEditRemark = () => {
details.formRemark = details.detauser.reamrk || ''
editRemarkPop.value.setDetails({
showPopUp: true,
title: '编辑备注',
async success() {
if (!details.formRemark) return utils.handleToast('请输入备注')
let data = {
trayCode: details.pageInfo.trayCode,
remark: details.formRemark,
}
let response = await warehouseTrayTypezeroOrderUpdateRemark(data)
const { code } = response
if (code !== 200) return
editRemarkPop.value.setDetails({ showPopUp: false, })
initpage()
}
})
}
/**
* 打印
*/
const print = () => {
console.log('bluetoothList :>> ', bluetoothList)
console.log('details.detauser :>> ', details.detauser)
tip.value.setdetails({
title: '是否打印',
isshow: true,
confirmTxt: '确认打印',
isonecheck: true,
success: () => {
// 没有蓝牙信息时进行蓝牙信息设置
// #ifdef APP
if (!bluetoothInfo.value.name) return bluetoothList.value.setdetails({ isshow: true })
// 打印时间
const time = dayjs().format('YYYY/MM/DD HH:mm:ss')
const data = details.detauser
const _arr = [...data.packageList, ...data.zeroList, ...data.stockList]
let orderListText = ''
// 订单列表初始位置
let _position = 300
// 总件数
let totalOrder = 0
// 总在托数
let totalScanNum = 0
_arr.forEach((value, index) => {
_position += 30
// 订单自编号
if (value.isFleeing)
orderListText += `T 55 0 10 ${_position} ${'(窜)' + value.dataCode}\r\n`
else orderListText += `T 55 0 10 ${_position} ${value.dataCode}\r\n`
// orderListText += `T 55 0 10 ${_position} ${value.dataCode}\r\n`
// 总件数
orderListText += `T 55 0 300 ${_position} ${value.orderTotalNum}\r\n`
// 在托件数
orderListText += `T 55 0 380 ${_position} ${value.scanNum}\r\n`
totalOrder += value.orderTotalNum
totalScanNum += value.scanNum
if (index === _arr.length - 1) {
_position += 30
// 订单自编号
orderListText += `T 55 0 10 ${_position} 总件数\r\n`
// 总件数
orderListText += `T 55 0 300 ${_position} ${totalOrder}\r\n`
// 在托件数
orderListText += `T 55 0 380 ${_position} ${totalScanNum}\r\n`
}
})
// let text = `! 0 400 200 ${_position + 60} 1\r\n`
let text = `! 0 400 200 600 1\r\n`
text += 'SETBOLD 2\r\n'
text += 'T 56 0 10 0 打托清单\r\n'
text += 'B QR 300 0 M 2 U 4\r\n'
text += `MA,${data.trayCode}\r\n`
text += 'ENDQR\r\n'
text += `T 55 0 10 120 打印时间: ${time}\r\n`
text += `T 55 0 300 120 汇通龙泉\r\n`
// 商城
text += `T 55 0 10 150 按${data.trayTypeName}\r\n`
text += `T 55 0 300 150 ${data.name}\r\n`
// 车次号
text += `T 55 0 10 180 车次号\r\n`
text += `T 55 0 300 180 ${''}\r\n`
// 分拣人
text += `T 55 0 10 210 分拣人\r\n`
text += `T 55 0 300 210 ${data.userName || ''}\r\n`
// 备注
text += `T 55 0 10 240 备注:\r\n`
text += `T 55 0 10 270 ${data.reamrk || ''}:\r\n`
// 订单清单
text += `T 55 0 10 300 订单自编号\r\n`
text += `T 55 0 300 300 总件数\r\n`
text += `T 55 0 380 300 在托件数\r\n`
text += orderListText
text += 'FORM\r\n'
text += 'PRINT\r\n'
// 将数据传入打印函数中
utils
.getbl(bluetoothInfo.value, text)
.then(() => {
return tip.value.setdetails({ isshow: false })
})
.catch(() => {
return bluetoothList.value.setdetails({ isshow: true })
})
// #endif
},
cancel: details => {
tip.value.setdetails({ isshow: false })
},
close: details => {
tip.value.setdetails({ isshow: false })
},
})
}
</script>
<style lang="scss" scoped>
@import url('@/utils/style/common.scss');
// 顶部背景
.header-container {
position: relative;
}
// 头部背景
.header_bg {
position: absolute;
width: 100%;
height: 400upx;
top: -120upx;
}
// 头部
.header {
width: calc(100vw - 80upx);
background: #fff;
padding: 20upx;
border-radius: 10upx;
margin: 20upx 20upx 0;
font-size: 0.8rem;
// 搜索行
.search_row {
display: flex;
align-items: center;
input {
margin-right: 20upx;
background: #eee;
flex: 1;
padding: 10upx 20upx;
border-radius: 5upx;
}
.search_button {
padding: 10upx 30upx;
background: var(--subjectColor);
color: #fff;
border-radius: 5upx;
}
}
.header_row {
>view {
min-width: 50%;
}
}
.header_content {
padding: 20upx;
border-radius: 10upx;
background-color: #f5f5f6;
}
/** 按钮 */
.submitBtn {
padding: 0 30upx;
height: 2rem;
background-color: var(--subjectColor);
color: #fff;
box-sizing: border-box;
border-radius: 6upx;
transition: all 0.3s;
}
}
// 分割线
:deep(.u-divider__text) {
font-size: 1rem !important;
color: var(--subjectColor) !important;
}
:deep(.u-line) {
border-color: var(--subjectColor) !important;
}
// 列表容器
.list_container {
// 边框圆角
$borderRadius: 5upx;
position: relative;
overflow: hidden;
margin: 0 20upx 20upx;
font-size: 0.8rem;
background: #fff;
padding: 10upx;
border-radius: $borderRadius;
box-shadow: 0 0 10px #eee, 3px 3px #eee;
&.active {
box-shadow: 0 0 10px var(--subjectColor), 3px 3px var(--subjectColor);
}
.err {
color: var(--errColor);
}
.list_row {
margin: 10upx;
display: flex;
>view {
flex: 1;
}
}
.list_tips {
position: absolute;
top: 0;
right: 0;
padding: 10upx 20upx;
background: var(--subjectColor);
color: #fff;
border-top-right-radius: $borderRadius;
&.none {
color: #f8625a;
background-color: #feeded;
}
&.portion {
color: #fa8c16;
background: #fef3e7;
}
&.all {
color: #0086F1;
background-color: #e5f2fd;
}
}
// 窜
.fleeingGoodsTip {
position: absolute;
// padding: 20upx;
width: 60upx;
height: 60upx;
line-height: 60upx;
text-align: center;
color: var(--errColor);
border: 2upx solid var(--errColor);
font-weight: bold;
font-size: 30upx;
border-radius: 50%;
bottom: -10upx;
right: -10upx;
transform: rotate(-45deg);
// opacity: 0.8;
&::after {
width: 80upx;
height: 80upx;
content: '';
position: absolute;
border: 4upx solid var(--errColor);
border-radius: 50%;
top: -15upx;
left: -15upx;
}
}
}
// 底部按钮
.button_container {
display: flex;
justify-content: center;
position: fixed;
width: 100%;
bottom: 40upx;
left: 0;
>view {
width: 60vw;
padding: 20upx;
text-align: center;
background: var(--subjectColor);
border-radius: 5upx;
color: #fff;
box-shadow: 0 0 10px var(--subjectColor);
}
}
// 底部站位
.footer {
height: 160upx;
}
// 移除按钮
.removeButton {
margin: 0 20upx 20upx;
margin-left: 0;
background: #f8625a;
padding: 20upx 40upx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10upx;
color: #fff;
transition: all 0.3s;
}
.clickClass {
opacity: 0.7;
}
</style>