Browse Source

提交栈板

master
常熟吴彦祖 4 months ago
parent
commit
d9f5ebc456
  1. 22
      src/api/automatedWarehouse/palletPacking.js
  2. 2
      src/router/index.js
  3. 6
      src/views/main.vue
  4. 505
      src/views/modules/automatedWarehouse/palletPacking.vue

22
src/api/automatedWarehouse/palletPacking.js

@ -0,0 +1,22 @@
import { createAPI } from "@/utils/httpRequest.js";
// 检查栈板是否存在并获取位置信息 - AI制作
export const checkPalletExists = data => createAPI(`/wcsIntegration/checkPalletExists`,'post',data)
// 获取栈板位置信息 - AI制作
export const getPalletPositions = data => createAPI(`/wcsIntegration/getPalletPositions`,'post',data)
// 获取栈板明细 - AI制作
export const getPalletDetails = data => createAPI(`/wcsIntegration/getPalletDetails`,'post',data)
// 根据位置获取层数 - AI制作
export const getLayersByPosition = data => createAPI(`/wcsIntegration/getLayersByPosition`,'post',data)
// 验证标签 - AI制作
export const validateLabel = data => createAPI(`/wcsIntegration/validateLabel`,'post',data)
// 保存栈板明细(扫进) - AI制作
export const savePalletDetail = data => createAPI(`/wcsIntegration/savePalletDetail`,'post',data)
// 删除栈板明细(扫出) - AI制作
export const deletePalletDetail = data => createAPI(`/wcsIntegration/deletePalletDetail`,'post',data)

2
src/router/index.js

@ -96,6 +96,8 @@ const globalRoutes = [
// 立库-Call料
{path: "/callOut",name: "callOut", component: resolve => require(["@/views/modules/automatedWarehouse/callOut.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
// 立库-打托
{path: "/palletPacking",name: "palletPacking", component: resolve => require(["@/views/modules/automatedWarehouse/palletPacking.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
]

6
src/views/main.vue

@ -160,6 +160,12 @@
</div>
<div class="menu-text">Call料</div>
</div>
<div class="menu-item" @click="navigateWithWarehouseCheck('palletPacking')">
<div class="menu-icon purchase">
<van-icon name="shopping-cart-o" size="24" />
</div>
<div class="menu-text">立库打托</div>
</div>
</div>
</div>

505
src/views/modules/automatedWarehouse/palletPacking.vue

@ -0,0 +1,505 @@
<template>
<div>
<div class="pda-container">
<!-- 头部栏 -->
<div class="header-bar">
<div class="header-left" @click="handleBack">
<i class="el-icon-arrow-left"></i>
<span>打托</span>
</div>
<div class="header-right" @click="$router.push({ path: '/' })">
首页
</div>
</div>
<div class="main-content form-section">
<!-- 第一行栈板扫描 -->
<div class="input-group">
<label class="input-label">栈板编码</label>
<div style="display: flex; gap: 8px;">
<el-input
v-model="palletCode"
placeholder="请扫描栈板编码"
class="form-input"
style="flex: 0.75;"
clearable
@keyup.enter.native="handlePalletScan"
ref="palletInput"
/>
<button
class="action-btn secondary"
style="flex: 0.25; margin: 0;"
@click="handleCallPallet"
>
Call栈板
</button>
</div>
</div>
<!-- 第二行筛选条件 (扫描栈板后显示) -->
<div v-if="palletScanned" class="input-group">
<div style="display: flex; gap: 8px; align-items: end;">
<div style="flex: 1;">
<label class="input-label">位置</label>
<el-select
v-model="selectedPosition"
placeholder="请选择位置"
style="width: 100%;"
@change="handlePositionChange"
>
<el-option label="ALL" value=""></el-option>
<el-option
v-for="position in positionOptions"
:key="position"
:label="position"
:value="position"
/>
</el-select>
</div>
<div style="flex: 1;">
<label class="input-label">层数</label>
<el-select
v-model="selectedLayer"
placeholder="请选择层数"
style="width: 100%;"
>
<el-option label="ALL" value=""></el-option>
<el-option
v-for="layer in layerOptions"
:key="layer"
:label="`第${layer}层`"
:value="layer"
/>
</el-select>
</div>
<button
class="action-btn secondary"
style="margin: 0; white-space: nowrap;"
@click="refreshTable"
>
刷新
</button>
</div>
</div>
<!-- 第三行扫进/扫出选择 (扫描栈板后显示) -->
<div v-if="palletScanned" class="input-group">
<div style="display: flex; gap: 8px; align-items: center;">
<div style="flex: 1;">
<el-radio-group v-model="operationType">
<el-radio label="in">扫进</el-radio>
<el-radio label="out">扫出</el-radio>
</el-radio-group>
</div>
<button
class="action-btn secondary"
style="margin: 0; white-space: nowrap;"
@click="showScanModal"
>
扫描二维码
</button>
</div>
</div>
</div>
<!-- 栈板明细表格 (扫描栈板后显示) -->
<div v-if="palletScanned && detailList.length > 0" class="rma-list">
<div class="list-title">栈板明细</div>
<div class="detail-table">
<div class="table-header">
<div class="col-position">位置</div>
<div class="col-layer">层数</div>
<div class="col-serial">标签号</div>
<div class="col-part">物料编码</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 class="col-part">{{ detail.partNo }}</div>
</div>
</div>
</div>
<!-- 暂无数据提示 -->
<div v-if="palletScanned && detailList.length === 0" class="rma-list">
<div class="empty-hint">暂无栈板明细数据</div>
</div>
</div>
<!-- 扫码模态框 -->
<el-dialog
title="扫描标签"
:visible.sync="scanModalVisible"
width="90%"
:close-on-click-modal="false"
>
<div class="scan-modal-content">
<!-- 扫进时显示位置和层数选择 -->
<div v-if="operationType === 'in'" class="modal-form">
<div class="input-group">
<label class="input-label">位置</label>
<el-select
v-model="scanPosition"
placeholder="请选择位置"
style="width: 100%;"
@change="handleScanPositionChange"
>
<el-option
v-for="position in positionOptions"
:key="position"
:label="position"
:value="position"
/>
</el-select>
</div>
<div class="input-group">
<label class="input-label">层数</label>
<el-select
v-model="scanLayer"
placeholder="请选择层数"
style="width: 100%;"
>
<el-option
v-for="layer in scanLayerOptions"
:key="layer"
:label="`第${layer}层`"
:value="layer"
/>
</el-select>
</div>
</div>
<!-- 标签扫描 -->
<div class="input-group">
<label class="input-label">标签二维码</label>
<el-input
v-model="scanCode"
placeholder="请扫描标签二维码"
class="form-input"
clearable
@keyup.enter.native="handleLabelScan"
ref="scanInput"
/>
</div>
</div>
<div slot="footer" class="dialog-footer">
<button class="action-btn secondary" @click="handleLabelScan">确定</button>
<button class="action-btn secondary" style="margin-left: 10px;" @click="closeScanModal">取消</button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
checkPalletExists,
getPalletPositions,
getPalletDetails,
getLayersByPosition,
validateLabel,
savePalletDetail,
deletePalletDetail
} from '../../../api/automatedWarehouse/palletPacking'
export default {
data() {
return {
site: localStorage.getItem('site'),
palletCode: '',
palletScanned: false,
operationType: 'in', // 'in' 'out'
//
selectedPosition: '',
selectedLayer: '',
positionOptions: [],
layerOptions: [],
//
scanModalVisible: false,
scanCode: '',
scanPosition: '',
scanLayer: '',
scanLayerOptions: [],
//
detailList: [],
};
},
methods: {
handleBack() {
this.$router.back();
},
//
async handlePalletScan() {
if (!this.palletCode.trim()) {
this.$message.error('请输入栈板编码');
return;
}
try {
//
const { data } = await checkPalletExists({
site: this.site,
palletId: this.palletCode
});
if (data.code === 0) {
this.palletScanned = true;
this.positionOptions = data.positions || [];
this.$message.success('栈板验证成功');
this.refreshTable();
} else {
this.$message.error(data.msg || '栈板不存在');
}
} catch (error) {
console.error('验证栈板失败:', error);
this.$message.error('验证栈板失败');
}
},
// Call -
handleCallPallet() {
// TODO: Call
this.$message.info('Call栈板功能待实现');
},
//
async handlePositionChange() {
if (this.selectedPosition) {
try {
const { data } = await getLayersByPosition({
site: this.site,
palletId: this.palletCode,
position: this.selectedPosition
});
if (data.code === 0) {
this.layerOptions = data.layers || [];
}
} catch (error) {
console.error('获取层数失败:', error);
}
} else {
this.layerOptions = [];
}
this.selectedLayer = '';
},
//
async refreshTable() {
try {
const { data } = await getPalletDetails({
site: this.site,
palletId: this.palletCode,
position: this.selectedPosition,
layer: this.selectedLayer
});
if (data.code === 0) {
this.detailList = data.details || [];
} else {
this.detailList = [];
}
} catch (error) {
console.error('获取栈板明细失败:', error);
this.detailList = [];
}
},
//
showScanModal() {
this.scanModalVisible = true;
this.scanCode = '';
this.scanPosition = '';
this.scanLayer = '';
this.scanLayerOptions = [];
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
},
//
closeScanModal() {
this.scanModalVisible = false;
},
//
async handleScanPositionChange() {
if (this.scanPosition) {
try {
const { data } = await getLayersByPosition({
site: this.site,
palletId: this.palletCode,
position: this.scanPosition
});
if (data.code === 0) {
const maxLayer = Math.max(...(data.layers || [0]));
this.scanLayerOptions = Array.from({length: maxLayer + 1}, (_, i) => i + 1);
}
} catch (error) {
console.error('获取层数失败:', error);
this.scanLayerOptions = [1];
}
} else {
this.scanLayerOptions = [];
}
this.scanLayer = '';
},
//
async handleLabelScan() {
if (!this.scanCode.trim()) {
this.$message.error('请输入标签编码');
return;
}
if (this.operationType === 'in') {
//
if (!this.scanPosition) {
this.$message.error('请选择位置');
return;
}
if (!this.scanLayer) {
this.$message.error('请选择层数');
return;
}
try {
const { data } = await savePalletDetail({
site: this.site,
palletId: this.palletCode,
position: this.scanPosition,
layer: this.scanLayer,
serialNo: this.scanCode
});
if (data.code === 0) {
this.$message.success('扫进成功');
this.closeScanModal();
this.refreshTable();
} else {
this.$message.error(data.msg || '扫进失败');
}
} catch (error) {
console.error('扫进失败:', error);
this.$message.error('扫进失败');
}
} else {
//
try {
const { data } = await deletePalletDetail({
site: this.site,
palletId: this.palletCode,
serialNo: this.scanCode
});
if (data.code === 0) {
this.$message.success('扫出成功');
this.closeScanModal();
this.refreshTable();
} else {
this.$message.error(data.msg || '扫出失败');
}
} catch (error) {
console.error('扫出失败:', error);
this.$message.error('扫出失败');
}
}
},
},
mounted() {
this.$nextTick(() => {
if (this.$refs.palletInput) {
this.$refs.palletInput.focus();
}
});
}
};
</script>
<style scoped>
/* 表格样式 */
.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: 2;
text-align: center;
}
.col-part {
flex: 2;
text-align: center;
}
/* 空数据提示 */
.empty-hint {
text-align: center;
color: #999;
padding: 20px;
background: white;
border-radius: 6px;
margin-top: 16px;
}
/* 模态框样式 */
.scan-modal-content {
padding: 10px 0;
}
.modal-form {
margin-bottom: 16px;
}
.dialog-footer {
text-align: center;
}
</style>
Loading…
Cancel
Save