Browse Source

pda界面

dev
常熟吴彦祖 1 hour ago
parent
commit
32db994063
  1. 6
      src/api/haianAutoWarehouse/callOut.js
  2. 37
      src/api/haianAutoWarehouse/palletAssembly.js
  3. 16
      src/api/haianAutoWarehouse/palletManualMove.js
  4. 7
      src/api/haianAutoWarehouse/wmsCancelReserve.js
  5. 6
      src/router/index.js
  6. 58
      src/views/main.vue
  7. 280
      src/views/modules/haianAutoWarehouse/haianCallOut.vue
  8. 295
      src/views/modules/haianAutoWarehouse/haianCallOutForHetuo.vue
  9. 1276
      src/views/modules/haianAutoWarehouse/haianPalletAssembly.vue
  10. 639
      src/views/modules/haianAutoWarehouse/haianPalletManualMove.vue
  11. 3
      src/views/modules/haianAutoWarehouse/haianPalletPacking.vue
  12. 403
      src/views/modules/haianAutoWarehouse/haianWmsCancelReserve.vue
  13. 5
      src/views/modules/inventory/label-query.vue

6
src/api/haianAutoWarehouse/callOut.js

@ -5,3 +5,9 @@ export const getPalletList = data => createAPI(`/haiAnWcsIntegration/palletListF
// 海安-旧页面兼容占位:当前页面未实际使用IFS查料接口 - rqrq // 海安-旧页面兼容占位:当前页面未实际使用IFS查料接口 - rqrq
export const getShopOrderFromIFSWithOrderNo = data => createAPI(`/haiAnWcsIntegration/palletListForPartNo`, 'post', data) export const getShopOrderFromIFSWithOrderNo = data => createAPI(`/haiAnWcsIntegration/palletListForPartNo`, 'post', data)
// 海安-立库特殊操作/Call料:固定目标区域“出库口”的下达接口 - rqrq
export const callOutToOutboundPort = data => createAPI(`/haiAnWcsIntegration/callOutToOutboundPort`, 'post', data)
// 海安-立库特殊操作/合托Call板:扫描托盘后直接下达(目的地固定入库口)- rqrq
export const scanAndCallPalletForHetuo = data => createAPI(`/haiAnWcsIntegration/scanAndCallPalletForHetuo`, 'post', data)

37
src/api/haianAutoWarehouse/palletAssembly.js

@ -0,0 +1,37 @@
import { createAPI } from "@/utils/httpRequest.js";
// 海安-直接组盘页:扫描栈板并返回基础信息 - rqrq
export const checkPalletExists = data => createAPI(`/haiAnWcsIntegration/checkPalletExists`, 'post', data)
// 海安-直接组盘页:查询栈板明细 - rqrq
export const getPalletDetails = data => createAPI(`/haiAnWcsIntegration/getPalletDetails`, 'post', data)
// 海安-直接组盘页:扫进标签 - rqrq
export const savePalletDetail = data => createAPI(`/haiAnWcsIntegration/savePalletDetail`, 'post', data)
// 海安-直接组盘页:扫出标签 - rqrq
export const deletePalletDetail = data => createAPI(`/haiAnWcsIntegration/deletePalletDetail`, 'post', data)
// 海安-直接组盘页:获取栈板扩展信息 - rqrq
export const getPalletInfo = data => createAPI(`/haiAnWcsIntegration/getPalletInfo`, 'post', data)
// 海安-直接组盘页:获取托盘类型列表 - rqrq
export const getPalletTypeList = data => createAPI(`/haiAnWcsIntegration/getPalletTypeList`, 'post', data)
// 海安-直接组盘页:更新托盘类型与自动分拣配置 - rqrq
export const updatePalletTypeAndAutoSort = data => createAPI(`/haiAnWcsIntegration/updatePalletTypeAndAutoSort`, 'post', data)
// 海安-直接组盘页:获取指定层可用位置 - rqrq
export const getAvailablePositionsForLayer = data => createAPI(`/haiAnWcsIntegration/getAvailablePositionsForLayer`, 'post', data)
// 海安-直接组盘页:按区域查询站点列表 - rqrq
export const getStationsByArea = data => createAPI(`/haiAnWcsIntegration/getStationsByArea`, 'post', data)
// 海安-直接组盘页:查询可选区域列表 - rqrq
export const getAreaOptionsForChange = data => createAPI(`/haiAnWcsIntegration/getAreaOptionsForChange`, 'post', data)
// 海安-直接组盘页:调用空托盘 - rqrq
export const callEmptyPalletToStation = data => createAPI(`/haiAnWcsIntegration/callEmptyPalletToStation`, 'post', data)
// 海安-直接组盘页:推送组盘到入库口(入库口1/2)- rqrq
export const pushPalletAssemblyToInboundPort = data => createAPI(`/haiAnWcsIntegration/pushPalletAssemblyToInboundPort`, 'post', data)

16
src/api/haianAutoWarehouse/palletManualMove.js

@ -0,0 +1,16 @@
import { createAPI } from "@/utils/httpRequest.js";
// 海安-手工移动:校验托盘是否可操作 - rqrq
export const checkPalletForManualMove = data => createAPI(`/haiAnWcsIntegration/checkPalletForManualMove`, 'post', data)
// 海安-手工移动:移出站点(完成后同步下发地面点位状态type=2)- rqrq
export const removeFromStation = data => createAPI(`/haiAnWcsIntegration/removeFromStation`, 'post', data)
// 海安-手工移动:获取可绑定区域 - rqrq
export const getAreaOptionsForBind = data => createAPI(`/haiAnWcsIntegration/getAreaOptionsForBind`, 'post', data)
// 海安-手工移动:按区域查询可绑定站点 - rqrq
export const getStationsForBind = data => createAPI(`/haiAnWcsIntegration/getStationsForBind`, 'post', data)
// 海安-手工移动:绑定托盘到站点(完成后同步下发地面点位状态type=1)- rqrq
export const bindPalletToStation = data => createAPI(`/haiAnWcsIntegration/bindPalletToStation`, 'post', data)

7
src/api/haianAutoWarehouse/wmsCancelReserve.js

@ -0,0 +1,7 @@
import { createAPI } from "@/utils/httpRequest.js";
// 海安-取消预留:查询标签信息 - rqrq
export const queryLabelInfo = data => createAPI(`/haiAnWcsIntegration/queryLabelInfo`, 'post', data)
// 海安-取消预留:取消单标签预留 - rqrq
export const cancelReserve = data => createAPI(`/haiAnWcsIntegration/cancelReserve`, 'post', data)

6
src/router/index.js

@ -157,6 +157,12 @@ const globalRoutes = [
{path: "/haianEmptyPalletAssembly",name: "haianEmptyPalletAssembly", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianEmptyPalletAssembly.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}}, {path: "/haianEmptyPalletAssembly",name: "haianEmptyPalletAssembly", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianEmptyPalletAssembly.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianCancelWcsPallet",name: "haianCancelWcsPallet", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianCancelWcsPallet.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}}, {path: "/haianCancelWcsPallet",name: "haianCancelWcsPallet", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianCancelWcsPallet.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianPalletMerge",name: "haianPalletMerge", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianPalletMerge.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}}, {path: "/haianPalletMerge",name: "haianPalletMerge", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianPalletMerge.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
// 海安立库特殊操作(固定工厂54)- rqrq
{path: "/haianCallOut",name: "haianCallOut", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianCallOut.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianPalletAssembly",name: "haianPalletAssembly", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianPalletAssembly.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianPalletManualMove",name: "haianPalletManualMove", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianPalletManualMove.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianWmsCancelReserve",name: "haianWmsCancelReserve", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianWmsCancelReserve.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/haianCallOutForHetuo",name: "haianCallOutForHetuo", component: resolve => require(["@/views/modules/haianAutoWarehouse/haianCallOutForHetuo.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
] ]

58
src/views/main.vue

@ -124,57 +124,95 @@
<div class="section" v-site-auth="'54'"> <div class="section" v-site-auth="'54'">
<div class="section-header"> <div class="section-header">
<span class="bullet"></span> <span class="bullet"></span>
<span class="section-title">海安立库操作</span>
<span class="section-title">立库日常操作</span>
</div> </div>
<div class="button-grid"> <div class="button-grid">
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianCallOutToStation')"> <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianCallOutToStation')">
<div class="menu-icon purchase"> <div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" /> <van-icon name="shopping-cart-o" size="24" />
</div> </div>
<div class="menu-text">海安立库取货</div>
<div class="menu-text">立库取货</div>
</div> </div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletPacking')"> <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletPacking')">
<div class="menu-icon purchase"> <div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" /> <van-icon name="shopping-cart-o" size="24" />
</div> </div>
<div class="menu-text">海安组盘入库</div>
<div class="menu-text">组盘入库</div>
</div> </div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletSorting')"> <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletSorting')">
<div class="menu-icon purchase"> <div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" /> <van-icon name="shopping-cart-o" size="24" />
</div> </div>
<div class="menu-text">海安分拣组盘</div>
<div class="menu-text">分拣组盘</div>
</div> </div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletSearch')"> <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletSearch')">
<div class="menu-icon purchase"> <div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" /> <van-icon name="shopping-cart-o" size="24" />
</div> </div>
<div class="menu-text">海安查看托盘</div>
<div class="menu-text">查看托盘</div>
</div> </div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletChangeStation')"> <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletChangeStation')">
<div class="menu-icon purchase"> <div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" /> <van-icon name="shopping-cart-o" size="24" />
</div> </div>
<div class="menu-text">海安托盘运输</div>
<div class="menu-text">托盘运输</div>
</div> </div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianEmptyPalletAssembly')"> <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianEmptyPalletAssembly')">
<div class="menu-icon purchase"> <div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" /> <van-icon name="shopping-cart-o" size="24" />
</div> </div>
<div class="menu-text">海安空托盘入库</div>
<div class="menu-text">空托盘入库</div>
</div> </div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianCancelWcsPallet')"> <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianCancelWcsPallet')">
<div class="menu-icon purchase"> <div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" /> <van-icon name="shopping-cart-o" size="24" />
</div> </div>
<div class="menu-text">海安取消组盘</div>
<div class="menu-text">取消组盘</div>
</div> </div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletMerge')"> <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletMerge')">
<div class="menu-icon purchase"> <div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" /> <van-icon name="shopping-cart-o" size="24" />
</div> </div>
<div class="menu-text">海安栈板合托</div>
<div class="menu-text">栈板合托</div>
</div>
</div>
</div>
<div class="section" v-site-auth="'54'">
<div class="section-header">
<span class="bullet"></span>
<span class="section-title">立库特殊操作</span>
</div>
<div class="button-grid">
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianCallOut')">
<div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" />
</div>
<div class="menu-text">Call料</div>
</div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletAssembly')">
<div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" />
</div>
<div class="menu-text">直接组盘</div>
</div> </div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianPalletManualMove')">
<div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" />
</div>
<div class="menu-text">栈板人工移动</div>
</div>
<div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianWmsCancelReserve')">
<div class="menu-icon inventory">
<van-icon name="orders-o" size="24" />
</div>
<div class="menu-text">取消预留</div>
</div>
<!-- <div class="menu-item" v-site-auth="'54'" @click="navigateWithWarehouseCheck('haianCallOutForHetuo')">-->
<!-- <div class="menu-icon purchase">-->
<!-- <van-icon name="shopping-cart-o" size="24" />-->
<!-- </div>-->
<!-- <div class="menu-text">合托Call板</div>-->
<!-- </div>-->
</div> </div>
</div> </div>
<div class="section" v-site-auth="'55'"> <div class="section" v-site-auth="'55'">
@ -303,7 +341,7 @@
<div class="menu-text">标签查询</div> <div class="menu-text">标签查询</div>
</div> </div>
<div class="menu-item" v-site-auth="'*'" @click="navigateWithWarehouseCheck('labelCalibration')">
<div class="menu-item" v-site-auth="'55'" @click="navigateWithWarehouseCheck('labelCalibration')">
<div class="menu-icon inventory"> <div class="menu-icon inventory">
<van-icon name="orders-o" size="24" /> <van-icon name="orders-o" size="24" />
</div> </div>

280
src/views/modules/haianAutoWarehouse/haianCallOut.vue

@ -0,0 +1,280 @@
<template>
<div>
<div class="pda-container">
<!-- 头部栏 - rqrq -->
<div class="header-bar">
<div class="header-left" @click="handleBack">
<i class="el-icon-arrow-left"></i>
<span>Call料</span>
</div>
<div class="header-right" @click="$router.push({ path: '/' })">
首页
</div>
</div>
<div class="table-body" style="max-height: 500px; overflow-y: auto;">
<div class="main-content form-section">
<!-- 查询条件区域保持与海安立库取货一致 - rqrq -->
<div class="input-group">
<label class="input-label">物料编码</label>
<el-input
v-model="formData.partNo"
placeholder="请输入物料编码"
class="form-input"
ref="partNoInput"
clearable
/>
</div>
<div class="input-group">
<label class="input-label">栈板编码</label>
<el-input
v-model="formData.palletId"
placeholder="请输入栈板编码"
class="form-input"
clearable
/>
</div>
<div class="input-group">
<label class="input-label">批号</label>
<el-input
v-model="formData.batchNo"
class="form-input"
clearable
/>
</div>
<!-- 固定出库口提示此页面下达目标区域固定不允许页面改写 - rqrq -->
<div class="input-group">
<label class="input-label">默认目标区域</label>
<el-input
:value="fixedTargetArea"
class="form-input"
readonly
/>
</div>
<div class="bottom-actions" style="display: flex; gap: 10px; flex-wrap: nowrap;">
<button class="action-btn secondary" @click="confirmDo" style="flex: 1;" :disabled="dispatchLoading">
查询
</button>
<button class="action-btn secondary" @click="cleanData" style="flex: 1;" :disabled="dispatchLoading">
清空
</button>
<button
class="action-btn secondary"
@click="handleDispatch"
:disabled="dispatchLoading || !selectedPallet"
style="flex: 1;"
>
{{ dispatchLoading ? '下达中...' : '下达' }}
</button>
</div>
</div>
<!-- 单选栈板列表保持海安立库取货交互一致 - rqrq -->
<div v-if="palletList.length > 0" class="rma-list">
<div class="list-title" style="flex: 0.75">可用栈板列表单选</div>
<el-form>
<el-row v-for="(pallet, index) in palletList" :key="index" class="rma-row">
<el-col :span="24">
<div class="rma-item" @click="selectPallet(pallet)" :class="{ 'selected': isSelected(pallet) }">
<div class="item-info">
<span class="part-no">栈板号: {{ pallet.palletId }}</span>
<span class="batch-qty" v-if="pallet.partNo">
物料: {{ pallet.partNo }} | 数量: {{ pallet.qty }}
</span>
<span class="batch-qty" v-if="pallet.partNo && pallet.batchNo">
| 批号: {{ pallet.batchNo }}
</span>
<span class="batch-qty" v-if="pallet.partNo && pallet.receiveDate">
| 接收日期: {{ pallet.receiveDate }}
</span>
</div>
<div class="item-status">
<i class="el-icon-check" v-if="isSelected(pallet)"></i>
</div>
</div>
</el-col>
</el-row>
</el-form>
</div>
</div>
</div>
</div>
</template>
<script>
import {
getPalletList,
callOutToOutboundPort
} from '../../../api/haianAutoWarehouse/callOut'
export default {
name: 'haianCallOut',
data() {
return {
// - rqrq
fixedTargetArea: '出库口',
formData: {
palletId: '',
partNo: '',
batchNo: ''
},
palletList: [],
selectedPallet: null,
dispatchLoading: false
}
},
computed: {
// sitestore - rqrq
site() {
return this.$store.state.user.site
}
},
methods: {
handleBack() {
this.resetPage(false)
this.$router.back()
},
// keep-alive - rqrq
resetPage(needFocus = true) {
this.formData = {
palletId: '',
partNo: '',
batchNo: ''
}
this.palletList = []
this.selectedPallet = null
this.dispatchLoading = false
if (needFocus) {
this.$nextTick(() => {
if (this.$refs.partNoInput) {
this.$refs.partNoInput.focus()
}
})
}
},
confirmDo() {
if ((!this.formData.partNo || this.formData.partNo === '') &&
(!this.formData.palletId || this.formData.palletId === '')) {
this.$alert('请输入物料编码或栈板编码', '提示', {
confirmButtonText: '确定'
})
return
}
if (!this.site) {
this.$alert('当前用户缺少site,无法查询', '提示', {
confirmButtonText: '确定'
})
return
}
const queryParams = {
site: this.site
}
if (this.formData.palletId && this.formData.palletId.trim()) {
queryParams.palletId = this.formData.palletId.trim()
}
if (this.formData.partNo && this.formData.partNo.trim()) {
queryParams.partNo = this.formData.partNo.trim()
}
if (this.formData.batchNo && this.formData.batchNo.trim()) {
queryParams.batchNo = this.formData.batchNo.trim()
}
getPalletList(queryParams).then(({ data }) => {
if (data && data.code === 0) {
this.palletList = data.rows || []
this.selectedPallet = null
if (this.palletList.length === 0) {
this.$message.warning('未找到满足条件的栈板')
} else {
this.$message.success(`找到 ${this.palletList.length} 个栈板`)
}
} else {
this.$alert(data.msg || '查询失败', '错误', { confirmButtonText: '确定' })
this.palletList = []
this.selectedPallet = null
}
}).catch(error => {
this.$alert(error.message || '查询失败', '错误', { confirmButtonText: '确定' })
this.palletList = []
this.selectedPallet = null
})
},
selectPallet(pallet) {
if (this.selectedPallet && this.selectedPallet.palletId === pallet.palletId) {
this.selectedPallet = null
this.$message.success('已取消选择')
} else {
this.selectedPallet = {
palletId: pallet.palletId,
partNo: pallet.partNo || '',
qty: pallet.qty || 0,
batchNo: pallet.batchNo || this.formData.batchNo || ''
}
this.$message.success(`已选择栈板: ${pallet.palletId}`)
}
},
isSelected(pallet) {
return this.selectedPallet && this.selectedPallet.palletId === pallet.palletId
},
// 沿 - rqrq
handleDispatch() {
if (!this.selectedPallet) {
this.$alert('请选择一个栈板', '提示', { confirmButtonText: '确定' })
return
}
this.$confirm('确定下达Call料任务到出库口?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.dispatchLoading = true
callOutToOutboundPort({
site: this.site,
palletId: this.selectedPallet.palletId,
partNo: this.selectedPallet.partNo,
qty: this.selectedPallet.qty,
batchNo: this.selectedPallet.batchNo,
targetArea: this.fixedTargetArea
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('任务下达成功')
this.resetPage(true)
} else {
this.$alert(data.msg || '任务下达失败', '错误', { confirmButtonText: '确定' })
}
}).catch(error => {
this.$alert(error.message || '任务下达失败', '错误', { confirmButtonText: '确定' })
}).finally(() => {
this.dispatchLoading = false
})
}).catch(() => {
// 便 - rqrq
})
},
cleanData() {
this.resetPage(true)
}
},
activated() {
this.resetPage(true)
},
beforeRouteLeave(to, from, next) {
this.resetPage(false)
next()
},
mounted() {
this.resetPage(true)
}
}
</script>
<style scoped>
.action-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
background-color: #ccc !important;
border-color: #ccc !important;
}
</style>

295
src/views/modules/haianAutoWarehouse/haianCallOutForHetuo.vue

@ -0,0 +1,295 @@
<template>
<div>
<div class="pda-container">
<div class="header-bar">
<div class="header-left" :class="{ 'header-action-disabled': scanLoading }" @click="handleBack">
<i class="el-icon-arrow-left"></i>
<span>合托Call板</span>
</div>
<div class="header-right" :class="{ 'header-action-disabled': scanLoading }" @click="goHome">
首页
</div>
</div>
<div class="table-body" style="max-height: 500px; overflow-y: auto;">
<div class="main-content form-section">
<div class="input-group">
<label class="input-label">栈板编码扫描后自动下达</label>
<el-input
v-model="formData.palletId"
placeholder="请扫描或输入栈板编码"
class="form-input"
clearable
ref="palletInput"
@keyup.enter.native="handleScanAndCall"
:disabled="scanLoading"
/>
</div>
<!-- 目标固定提醒合托Call板统一下达到入库口 - rqrq -->
<div class="input-group">
<label class="input-label">固定目标</label>
<el-input value="入库口" class="form-input" readonly />
</div>
<div v-if="scanLoading" class="status-tip loading">
<i class="el-icon-loading"></i> 正在下达中...
</div>
<div class="bottom-actions" style="display: flex; gap: 10px; flex-wrap: nowrap;">
<button
class="action-btn primary"
@click="handleScanAndCall"
:disabled="scanLoading || !formData.palletId"
style="flex: 2;"
>
{{ scanLoading ? '下达中...' : '扫描下达' }}
</button>
<button class="action-btn secondary" @click="cleanData" :disabled="scanLoading" style="flex: 1;">
清空
</button>
</div>
<div v-if="callHistory.length > 0" class="history-section">
<div class="list-title">本次下达记录{{ callHistory.length }}</div>
<div v-for="(record, index) in callHistory" :key="index" class="history-item" :class="record.success ? 'success' : 'error'">
<span class="history-pallet">{{ record.palletId }}</span>
<span class="history-status">{{ record.success ? '✓ 成功' : '✗ ' + record.reason }}</span>
<span class="history-time">{{ record.time }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { scanAndCallPalletForHetuo } from '../../../api/haianAutoWarehouse/callOut'
export default {
name: 'haianCallOutForHetuo',
data() {
return {
formData: {
palletId: '',
site: this.$store.state.user.site
},
scanLoading: false,
callHistory: []
}
},
methods: {
handleBack() {
if (this.scanLoading) {
return
}
this.resetPage(false)
this.$router.back()
},
goHome() {
if (this.scanLoading) {
return
}
this.resetPage(false)
this.$router.push({ path: '/' })
},
resetPage(needFocus = true) {
this.formData = {
palletId: '',
site: this.$store.state.user.site
}
this.scanLoading = false
this.callHistory = []
if (needFocus) {
this.focusInput()
}
},
cleanData() {
this.formData.palletId = ''
this.focusInput()
},
focusInput() {
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus()
}
})
},
getCurrentTime() {
const now = new Date()
return now.getHours().toString().padStart(2, '0') + ':' +
now.getMinutes().toString().padStart(2, '0') + ':' +
now.getSeconds().toString().padStart(2, '0')
},
// - rqrq
handleScanAndCall() {
const palletId = this.formData.palletId ? this.formData.palletId.trim() : ''
if (!this.formData.site) {
this.$message.error('当前用户缺少site,无法下达')
return
}
if (!palletId) {
this.$message.warning('请输入或扫描栈板编码')
this.focusInput()
return
}
this.scanLoading = true
scanAndCallPalletForHetuo({
site: this.formData.site,
palletId
}).then(({ data }) => {
if (data && data.code === 0) {
const failedCount = data.failedCount || 0
const successCount = data.successCount || 0
if (failedCount === 0 && successCount > 0) {
this.$message.success('栈板【' + palletId + '】下达成功!')
this.callHistory.unshift({
palletId,
success: true,
reason: '',
time: this.getCurrentTime()
})
} else if (failedCount > 0) {
const failedReasons = data.failedReasons || []
const errorMsg = failedReasons.length > 0 ? failedReasons[0] : '未知错误'
this.$message.error('下达失败:' + errorMsg)
this.callHistory.unshift({
palletId,
success: false,
reason: errorMsg,
time: this.getCurrentTime()
})
}
} else {
const errorMsg = (data && data.msg) || '下达失败'
this.$message.error(errorMsg)
this.callHistory.unshift({
palletId,
success: false,
reason: errorMsg,
time: this.getCurrentTime()
})
}
}).catch(error => {
const errorMsg = error.message || '下达失败'
this.$message.error(errorMsg)
this.callHistory.unshift({
palletId,
success: false,
reason: errorMsg,
time: this.getCurrentTime()
})
}).finally(() => {
this.scanLoading = false
this.formData.palletId = ''
this.focusInput()
if (this.callHistory.length > 20) {
this.callHistory = this.callHistory.slice(0, 20)
}
})
}
},
mounted() {
this.resetPage(true)
},
activated() {
this.resetPage(true)
},
beforeRouteLeave(to, from, next) {
this.resetPage(false)
next()
}
}
</script>
<style scoped>
.header-action-disabled {
opacity: 0.5;
pointer-events: none;
}
.action-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
background-color: #ccc !important;
border-color: #ccc !important;
}
.action-btn.primary {
background-color: #409EFF;
border-color: #409EFF;
color: #fff;
}
.action-btn.primary:hover:not(:disabled) {
background-color: #66b1ff;
border-color: #66b1ff;
}
.status-tip {
padding: 10px;
margin: 10px 0;
border-radius: 4px;
text-align: center;
font-size: 14px;
}
.status-tip.loading {
background-color: #e6f7ff;
color: #1890ff;
border: 1px solid #91d5ff;
}
.history-section {
margin-top: 15px;
border-top: 1px solid #eee;
padding-top: 10px;
}
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
margin: 5px 0;
border-radius: 4px;
font-size: 13px;
}
.history-item.success {
background-color: #f0f9eb;
border-left: 3px solid #67c23a;
}
.history-item.error {
background-color: #fef0f0;
border-left: 3px solid #f56c6c;
}
.history-pallet {
font-weight: bold;
color: #333;
flex: 1;
}
.history-status {
flex: 2;
text-align: center;
}
.history-item.success .history-status {
color: #67c23a;
}
.history-item.error .history-status {
color: #f56c6c;
font-size: 12px;
}
.history-time {
color: #999;
font-size: 12px;
flex: 0.5;
text-align: right;
}
</style>

1276
src/views/modules/haianAutoWarehouse/haianPalletAssembly.vue
File diff suppressed because it is too large
View File

639
src/views/modules/haianAutoWarehouse/haianPalletManualMove.vue

@ -0,0 +1,639 @@
<template>
<div>
<div class="pda-container">
<div class="header-bar">
<div class="header-left" :class="{ 'header-action-disabled': pageBusy }" @click="handleBack">
<i class="el-icon-arrow-left"></i>
<span>栈板人工移动</span>
</div>
<div class="header-right" :class="{ 'header-action-disabled': pageBusy }" @click="goHome">
首页
</div>
</div>
<div class="table-body" style="max-height: 600px; overflow-y: auto;">
<div class="main-content form-section">
<div class="input-group">
<label class="input-label">托盘编码</label>
<el-input
v-model="palletCode"
placeholder="请扫描托盘编码"
class="form-input"
clearable
@keyup.enter.native="handlePalletScan"
inputmode="none"
autocomplete="off"
autocorrect="off"
spellcheck="false"
ref="palletInput"
/>
</div>
<div v-if="palletScanned" class="pallet-info-section">
<div class="info-row">
<label class="info-label">当前站点ID:</label>
<span class="info-value">{{ palletInfo.currentStationId || '-' }}</span>
</div>
<div class="info-row">
<label class="info-label">当前站点编码:</label>
<span class="info-value">{{ palletInfo.currentStationCode || '未绑定站点' }}</span>
</div>
<div class="button-row">
<button class="action-btn primary" @click="showDetailModal" style="width: 100%;" :disabled="pageBusy">
浏览明细 ({{ detailList.length }})
</button>
</div>
<div v-if="palletInfo.callingFlag !== 'Y' && palletInfo.canOperate === 'Y'">
<div v-if="palletInfo.currentStationCode" class="button-row">
<button
class="action-btn primary"
@click="handleRemoveFromStation"
:disabled="removeLoading || pageBusy"
style="width: 100%;"
>
{{ removeLoading ? '移出中...' : '移出站点' }}
</button>
</div>
<div v-if="!palletInfo.currentStationCode" class="button-row">
<button
class="action-btn primary"
@click="showBindStationDialog"
:disabled="bindLoading || pageBusy"
style="width: 100%;"
>
绑定站点
</button>
</div>
</div>
<div v-if="palletInfo.canOperate !== 'Y'" class="warning-hint">
当前站点位置不可变更
</div>
</div>
</div>
</div>
</div>
<el-dialog
:title="'托盘明细 (共'+detailList.length+'条)'"
:visible.sync="detailModalVisible"
width="90%"
:close-on-click-modal="false"
:show-close="false"
:modal="true"
:modal-append-to-body="true"
:append-to-body="true"
>
<div class="table-body" style="max-height: 400px; overflow-y: auto;">
<div class="detail-table">
<div class="table-header">
<div class="col-position">位置</div>
<div class="col-layer">层数</div>
<div class="col-serial">标签号</div>
</div>
<div
v-for="(detail, index) in detailList"
:key="index"
class="table-row"
>
<div class="col-position">{{ detail.position }}</div>
<div class="col-layer">{{ detail.layer }}</div>
<div class="col-serial">{{ detail.serialNo }}</div>
</div>
<div v-if="detailList.length === 0" class="table-row empty-row">
<div class="empty-hint">暂无托盘明细数据</div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<button class="action-btn secondary" @click="detailModalVisible=false" :disabled="pageBusy">关闭</button>
</div>
</el-dialog>
<el-dialog
title="绑定站点"
:visible.sync="bindDialogVisible"
width="90%"
:close-on-click-modal="false"
:show-close="false"
:modal="true"
:modal-append-to-body="true"
:append-to-body="true"
>
<div class="bind-dialog-content">
<div class="input-group">
<label class="input-label">选择区域 <span style="color: red;">*</span></label>
<el-select
v-model="selectedArea"
placeholder="请选择区域"
style="width: 100%;"
@change="handleAreaChange"
:disabled="pageBusy"
>
<el-option
v-for="area in areaOptions"
:key="area.areaId"
:label="area.areaDesc"
:value="area.areaId"
/>
</el-select>
</div>
<div class="input-group">
<label class="input-label">选择站点 <span style="color: red;">*</span></label>
<el-select
v-model="selectedStation"
placeholder="请选择站点"
style="width: 100%;"
:disabled="!selectedArea || pageBusy"
>
<el-option
v-for="station in stationOptions"
:key="station.stationCode"
:label="`${station.stationCode}${station.status ? ' (' + station.status + ')' : ''}`"
:value="station.stationCode"
/>
</el-select>
</div>
</div>
<div slot="footer" class="dialog-footer">
<button
class="action-btn primary"
@click="confirmBindStation"
:disabled="bindLoading || pageBusy"
style="flex: 1; margin-right: 8px;"
>
{{ bindLoading ? '绑定中...' : '确定' }}
</button>
<button
class="action-btn secondary"
@click="closeBindDialog"
:disabled="bindLoading || pageBusy"
style="flex: 1;"
>
取消
</button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getPalletDetails
} from '../../../api/haianAutoWarehouse/palletAssembly'
import {
checkPalletForManualMove,
removeFromStation,
getAreaOptionsForBind,
getStationsForBind,
bindPalletToStation
} from '../../../api/haianAutoWarehouse/palletManualMove'
export default {
name: 'haianPalletManualMove',
data() {
return {
site: this.$store.state.user.site,
palletCode: '',
palletScanned: false,
palletInfo: {
callingFlag: '',
currentStationCode: '',
currentStationId: '',
canOperate: 'N'
},
bindDialogVisible: false,
selectedArea: '',
selectedStation: '',
areaOptions: [],
stationOptions: [],
detailList: [],
detailModalVisible: false,
removeLoading: false,
bindLoading: false,
scanLoading: false
}
},
computed: {
pageBusy() {
return this.scanLoading || this.removeLoading || this.bindLoading
}
},
methods: {
handleBack() {
if (this.pageBusy) {
return
}
this.resetPage(false)
this.$router.back()
},
goHome() {
if (this.pageBusy) {
return
}
this.resetPage(false)
this.$router.push({ path: '/' })
},
resetPage(needFocus = true) {
this.site = this.$store.state.user.site
this.palletCode = ''
this.palletScanned = false
this.palletInfo = {
callingFlag: '',
currentStationCode: '',
currentStationId: '',
canOperate: 'N'
}
this.bindDialogVisible = false
this.selectedArea = ''
this.selectedStation = ''
this.areaOptions = []
this.stationOptions = []
this.detailList = []
this.detailModalVisible = false
this.removeLoading = false
this.bindLoading = false
this.scanLoading = false
if (needFocus) {
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus()
}
})
}
},
handlePalletScan() {
if (!this.site) {
this.$alert('当前用户缺少site,无法执行海安移库', '提示', {
confirmButtonText: '确定'
})
return
}
if (!this.palletCode || !this.palletCode.trim()) {
this.$alert('请输入托盘编码', '提示', {
confirmButtonText: '确定'
})
return
}
this.scanLoading = true
checkPalletForManualMove({
site: this.site,
palletId: this.palletCode.trim()
}).then(({ data }) => {
if (data && data.code === 0) {
this.palletCode = data.row.palletId || this.palletCode.trim()
if (data.row.callingFlag === 'Y') {
this.$alert('托盘被调用,无法进行移动操作', '提示', {
confirmButtonText: '确定',
callback: () => {
this.resetPage(true)
}
})
return
}
this.palletInfo = data.row
this.palletScanned = true
this.loadPalletDetails()
} else {
this.$alert((data && data.msg) || '托盘不存在', '错误', {
confirmButtonText: '确定',
callback: () => {
this.palletCode = ''
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus()
}
})
}
})
}
}).catch(error => {
this.$alert(error.message || '查询托盘失败', '错误', {
confirmButtonText: '确定',
callback: () => {
this.palletCode = ''
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus()
}
})
}
})
}).finally(() => {
this.scanLoading = false
})
},
loadPalletDetails() {
getPalletDetails({
site: this.site,
palletId: this.palletCode,
position: '',
layer: ''
}).then(({ data }) => {
if (data && data.code === 0) {
this.detailList = data.details || []
} else {
this.detailList = []
}
}).catch(() => {
this.detailList = []
})
},
showDetailModal() {
this.detailModalVisible = true
},
handleRemoveFromStation() {
if (this.pageBusy) {
return
}
this.$confirm('确定要将托盘从当前站点移出吗?', '确认操作', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.removeLoading = true
removeFromStation({
site: this.site,
palletId: this.palletCode,
stationCode: this.palletInfo.currentStationCode
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('移出站点成功')
this.handlePalletScan()
} else {
this.$alert((data && data.msg) || '移出站点失败', '错误', {
confirmButtonText: '确定'
})
}
}).catch(error => {
this.$alert(error.message || '移出站点失败', '错误', {
confirmButtonText: '确定'
})
}).finally(() => {
this.removeLoading = false
})
}).catch(() => {
// - rqrq
})
},
showBindStationDialog() {
this.bindDialogVisible = true
this.selectedArea = ''
this.selectedStation = ''
this.areaOptions = []
this.stationOptions = []
this.loadAreaOptions()
},
// bindLoading=truepageBusy - rqrq
closeBindDialog(forceClose = false) {
if (!forceClose && this.pageBusy) {
return
}
this.bindDialogVisible = false
this.selectedArea = ''
this.selectedStation = ''
this.areaOptions = []
this.stationOptions = []
},
loadAreaOptions() {
getAreaOptionsForBind({
site: this.site
}).then(({ data }) => {
if (data && data.code === 0) {
this.areaOptions = data.rows || []
} else {
this.areaOptions = []
this.$alert('获取区域选项失败', '错误', {
confirmButtonText: '确定'
})
}
}).catch(() => {
this.areaOptions = []
})
},
handleAreaChange(areaId) {
this.selectedStation = ''
this.stationOptions = []
if (!areaId) {
return
}
getStationsForBind({
site: this.site,
areaId
}).then(({ data }) => {
if (data && data.code === 0) {
this.stationOptions = data.rows || []
} else {
this.stationOptions = []
this.$alert('获取站点选项失败', '错误', {
confirmButtonText: '确定'
})
}
}).catch(() => {
this.stationOptions = []
})
},
confirmBindStation() {
if (!this.selectedArea) {
this.$alert('请选择区域', '提示', { confirmButtonText: '确定' })
return
}
if (!this.selectedStation) {
this.$alert('请选择站点', '提示', { confirmButtonText: '确定' })
return
}
this.$confirm('确定要将托盘绑定到选中的站点吗?', '确认操作', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.bindLoading = true
bindPalletToStation({
site: this.site,
palletId: this.palletCode,
// areaIdwcs_area_code - rqrq
areaId: this.selectedArea,
targetArea: this.selectedArea,
stationCode: this.selectedStation
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('绑定站点成功')
// loading - rqrq
this.closeBindDialog(true)
this.handlePalletScan()
} else {
this.$alert((data && data.msg) || '绑定站点失败', '错误', {
confirmButtonText: '确定'
})
}
}).catch(error => {
this.$alert(error.message || '绑定站点失败', '错误', {
confirmButtonText: '确定'
})
}).finally(() => {
this.bindLoading = false
})
}).catch(() => {
// - rqrq
})
}
},
mounted() {
this.resetPage(true)
},
activated() {
this.resetPage(true)
},
beforeRouteLeave(to, from, next) {
this.resetPage(false)
next()
}
}
</script>
<style scoped>
.header-action-disabled {
opacity: 0.5;
pointer-events: none;
}
.pallet-info-section {
margin-top: 16px;
padding: 12px;
background: #f5f7fa;
border-radius: 6px;
}
.info-row {
display: flex;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #e4e7ed;
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
font-weight: bold;
color: #606266;
width: 100px;
flex-shrink: 0;
}
.info-value {
color: #303133;
font-size: 14px;
}
.button-row {
margin-top: 12px;
}
.warning-hint {
margin-top: 12px;
padding: 10px;
background: #fff3cd;
color: #856404;
border: 1px solid #ffeaa7;
border-radius: 4px;
text-align: center;
font-weight: bold;
}
.bind-dialog-content {
padding: 10px 0;
}
.detail-table {
background: white;
border-radius: 6px;
overflow: hidden;
border: 1px solid #e0e0e0;
}
.table-header,
.table-row {
display: flex;
align-items: center;
padding: 8px;
border-bottom: 1px solid #e0e0e0;
}
.table-header {
background: #f5f5f5;
font-weight: bold;
font-size: 14px;
}
.table-row {
font-size: 13px;
}
.table-row:last-child {
border-bottom: none;
}
.col-position {
flex: 1;
text-align: center;
}
.col-layer {
flex: 1;
text-align: center;
}
.col-serial {
flex: 4;
text-align: center;
word-break: break-all;
}
.empty-hint {
text-align: center;
color: #999;
padding: 20px;
background: white;
border-radius: 6px;
}
.empty-row {
justify-content: center;
align-items: center;
padding: 20px;
border-bottom: none;
}
.empty-row .empty-hint {
text-align: center;
color: #999;
width: 100%;
}
.dialog-footer {
display: flex;
gap: 8px;
text-align: center;
}
.action-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
background-color: #ccc !important;
border-color: #ccc !important;
}
::v-deep .el-dialog__wrapper {
z-index: 2000 !important;
}
::v-deep .el-overlay {
z-index: 2000 !important;
}
</style>

3
src/views/modules/haianAutoWarehouse/haianPalletPacking.vue

@ -990,6 +990,9 @@ export default {
this.callEmptyLoading = true this.callEmptyLoading = true
callEmptyPalletToStation({ callEmptyPalletToStation({
site: this.site, site: this.site,
// targetAreaIDhaian_area.wcs_area_code - rqrq
areaId: this.callEmptyForm.areaId,
targetArea: this.callEmptyForm.areaId,
stationCode: this.callEmptyForm.stationCode, stationCode: this.callEmptyForm.stationCode,
palletType: this.callEmptyForm.palletType palletType: this.callEmptyForm.palletType
}).then(({ data }) => { }).then(({ data }) => {

403
src/views/modules/haianAutoWarehouse/haianWmsCancelReserve.vue

@ -0,0 +1,403 @@
<template>
<div>
<div class="pda-container">
<div class="header-bar">
<div class="header-left" :class="{ 'header-action-disabled': pageBusy }" @click="handleBack">
<i class="el-icon-arrow-left"></i>
<span>取消预留</span>
</div>
<div class="header-right" :class="{ 'header-action-disabled': pageBusy }" @click="goHome">
首页
</div>
</div>
<div class="table-body" style="max-height: 500px; overflow-y: auto;">
<div class="main-content form-section">
<div class="input-group">
<label class="input-label">标签编码</label>
<el-input
v-model="labelCode"
placeholder="请扫描标签编码"
class="form-input"
clearable
inputmode="none"
autocomplete="off"
autocorrect="off"
spellcheck="false"
@keyup.enter.native="handleLabelScan"
ref="labelInput"
/>
</div>
<div v-if="labelInfo" class="info-section">
<div class="info-title">
<i class="el-icon-document"></i>
<span>标签信息</span>
</div>
<div class="info-row">
<span class="info-label">标签编码:</span>
<span class="info-value">{{ labelInfo.unitId || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">工厂编码:</span>
<span class="info-value">{{ labelInfo.site || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">物料编码:</span>
<span class="info-value">{{ labelInfo.partNo || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">数量:</span>
<span class="info-value">{{ labelInfo.qty || '0' }}</span>
</div>
<div class="info-row">
<span class="info-label">批次号:</span>
<span class="info-value">{{ labelInfo.batchNo || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">仓库:</span>
<span class="info-value">{{ labelInfo.warehouseId || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">库位:</span>
<span class="info-value">{{ labelInfo.locationId || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">WDR:</span>
<span class="info-value">{{ labelInfo.wdr || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">是否被WMS预留:</span>
<span class="info-value" :style="{ color: labelInfo.reserveFlag === 'Y' ? '#F56C6C' : '#67C23A' }">
{{ labelInfo.reserveFlag === 'Y' ? '是' : '否' }}
</span>
</div>
<div class="info-row" v-if="labelInfo.reserveOrderRef1">
<span class="info-label">预留申请单号:</span>
<span class="info-value">{{ labelInfo.reserveOrderRef1 || '-' }}</span>
</div>
<div class="info-row" v-if="labelInfo.reserveOrderRef3">
<span class="info-label">预留订单号:</span>
<span class="info-value">{{ labelInfo.reserveOrderRef3 || '-' }}</span>
</div>
</div>
<div v-if="labelInfo" class="bottom-actions">
<button class="action-btn secondary" @click="clearData" :disabled="pageBusy">清空</button>
<button
class="action-btn primary"
@click="handleCancelReserve"
:disabled="cancelReserveLoading || labelInfo.reserveFlag !== 'Y'"
>
{{ cancelReserveLoading ? '取消中...' : '取消预留' }}
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { queryLabelInfo, cancelReserve } from '@/api/haianAutoWarehouse/wmsCancelReserve'
export default {
name: 'HaianWmsCancelReserve',
data() {
return {
site: this.$store.state.user.site,
labelCode: '',
labelInfo: null,
loading: false,
cancelReserveLoading: false
}
},
computed: {
pageBusy() {
return this.loading || this.cancelReserveLoading
}
},
methods: {
handleBack() {
if (this.pageBusy) {
return
}
this.resetPage(false)
this.$router.back()
},
goHome() {
if (this.pageBusy) {
return
}
this.resetPage(false)
this.$router.push({ path: '/' })
},
// - rqrq
resetPage(needFocus = true) {
this.site = this.$store.state.user.site
this.labelCode = ''
this.labelInfo = null
this.loading = false
this.cancelReserveLoading = false
if (needFocus) {
this.focusLabelInput()
}
},
handleLabelScan() {
if (!this.labelCode || !this.labelCode.trim()) {
this.$message.error('请扫描有效的标签编码')
return
}
this.loading = true
queryLabelInfo({
site: this.site,
serialNo: this.labelCode.trim()
}).then(({ data }) => {
if (data && data.code === 0) {
this.labelInfo = data.data
this.$message.success('查询成功')
} else {
this.$message.error((data && data.msg) || '标签不存在')
this.labelCode = ''
this.labelInfo = null
this.focusLabelInput()
}
}).catch(() => {
this.$message.error('查询异常')
this.labelCode = ''
this.labelInfo = null
this.focusLabelInput()
}).finally(() => {
this.loading = false
})
},
handleCancelReserve() {
if (!this.labelInfo || this.labelInfo.reserveFlag !== 'Y') {
this.$message.warning('当前标签未被预留')
return
}
this.$confirm('确定要取消该标签的WMS预留吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.doCancelReserve()
}).catch(() => {
// - rqrq
})
},
doCancelReserve() {
this.cancelReserveLoading = true
cancelReserve({
site: this.site,
serialNo: this.labelInfo.unitId
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('取消预留成功')
this.clearData()
} else {
this.$message.error((data && data.msg) || '取消预留失败')
}
}).catch(() => {
this.$message.error('取消预留异常')
}).finally(() => {
this.cancelReserveLoading = false
})
},
clearData() {
this.labelCode = ''
this.labelInfo = null
this.focusLabelInput()
},
focusLabelInput() {
this.$nextTick(() => {
if (this.$refs.labelInput) {
this.$refs.labelInput.focus()
}
})
}
},
mounted() {
this.resetPage(true)
},
activated() {
this.resetPage(true)
},
beforeRouteLeave(to, from, next) {
this.resetPage(false)
next()
}
}
</script>
<style scoped>
.header-action-disabled {
opacity: 0.5;
pointer-events: none;
}
.pda-container {
width: 100vw;
height: 120vh;
display: flex;
flex-direction: column;
background: #f5f5f5;
font-family: 'Arial', sans-serif;
}
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 16px;
background: #17B3A3;
color: white;
height: 40px;
min-height: 40px;
max-height: 40px;
}
.header-left {
display: flex;
align-items: center;
cursor: pointer;
}
.header-left i {
margin-right: 8px;
font-size: 18px;
}
.header-left span {
font-size: 16px;
font-weight: 500;
}
.header-right {
cursor: pointer;
font-size: 14px;
padding: 4px 8px;
border-radius: 4px;
}
.table-body {
flex: 1;
overflow-y: auto;
}
.main-content {
padding: 16px;
}
.input-label {
display: block;
margin-bottom: 8px;
font-size: 14px;
font-weight: 500;
color: #333;
}
.form-input {
width: 100%;
height: 44px;
}
.info-section {
background: white;
border-radius: 8px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.info-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
color: #17B3A3;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #17B3A3;
}
.info-title i {
margin-right: 8px;
font-size: 18px;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 10px 0;
border-bottom: 1px solid #f0f0f0;
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
font-size: 14px;
color: #666;
min-width: 90px;
flex-shrink: 0;
}
.info-value {
font-size: 14px;
font-weight: 500;
color: #333;
flex: 1;
text-align: right;
word-break: break-all;
}
.bottom-actions {
display: flex;
gap: 12px;
padding-top: 16px;
}
.action-btn {
flex: 1;
padding: 12px 24px;
border: none;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
min-height: 44px;
}
.action-btn.primary {
background: #17B3A3;
color: white;
}
.action-btn.primary:hover {
background: #15a394;
}
.action-btn.primary:disabled {
background: #ccc;
cursor: not-allowed;
opacity: 0.6;
}
.action-btn.secondary {
background: #f5f5f5;
color: #333;
border: 1px solid #ddd;
}
.action-btn.secondary:hover {
background: #e8e8e8;
}
.action-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>

5
src/views/modules/inventory/label-query.vue

@ -49,6 +49,11 @@
<span class="info-value">{{ labelInfo.unitId || '-' }}</span> <span class="info-value">{{ labelInfo.unitId || '-' }}</span>
</div> </div>
<div class="info-row">
<span class="info-label">工厂编码:</span>
<span class="info-value">{{ labelInfo.site || '-' }}</span>
</div>
<div class="info-row"> <div class="info-row">
<span class="info-label">物料编码:</span> <span class="info-label">物料编码:</span>
<span class="info-value">{{ labelInfo.partNo || '-' }}</span> <span class="info-value">{{ labelInfo.partNo || '-' }}</span>

Loading…
Cancel
Save