html
复制代码
<template>
<div class="box">
<el-row type="flex">
<el-col :span="13" :order="7">
<el-row type="flex">
<el-col :span="7" :order="7" style="margin-left: 30px">
<el-form>
<el-form-item label="库区">
<el-select v-model="areaCodeRadio" placeholder="请选择">
<el-option
v-for="item in storeyList"
:key="item.areaCode"
:label="item.areaName"
:value="item.areaCode"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
</el-col>
<el-col :span="14" :order="7">
<div style="display: inline-block; margin-top: -7px">
<ul
style="list-style-type: none; display: flex; margin-left: -20px"
>
<li>空货位</li>
<li
style="
width: 20px;
height: 20px;
background-color: #e6e6e6;
margin-left: 8px;
margin-right: 20px;
"
></li>
<li>有货</li>
<li
style="
width: 20px;
height: 20px;
background-color: #759ffa;
margin-left: 8px;
margin-right: 20px;
"
></li>
<li>入库中</li>
<li
style="
width: 20px;
height: 20px;
background-color: #d8bfd8;
margin-left: 8px;
margin-right: 20px;
"
></li>
<li>有货入库中</li>
<li
style="
width: 20px;
height: 20px;
background-color: #ffdead;
margin-left: 8px;
margin-right: 20px;
"
></li>
<li>有货出库中</li>
<li
style="
width: 20px;
height: 20px;
background-color: #ff8247;
margin-left: 8px;
margin-right: 20px;
"
></li>
<!-- <li>通道</li>
<li
style="
width: 20px;
height: 20px;
background-color: #90ee90;
margin-left: 8px;
margin-right: 20px;
"
></li> -->
</ul>
</div>
</el-col>
<el-col :span="2" :order="7">
<el-button type="primary" @click="getreset">刷新</el-button>
</el-col>
</el-row>
<div
id="content"
class="layoutBox"
@wheel="onWheel"
:style="{
transform: `scale(${scale})`,
transformOrigin: 'top left',
}"
>
<!--
col-num表示网格有多少列
row-height表示一行的高度(以像素为单位) 数字
-->
<grid-layout
ref="gridlayout"
:layout.sync="layout"
:col-num="8"
:row-height="50"
:responsive="false"
:vertical-compact="true"
:prevent-collision="true"
:use-css-transforms="true"
:is-draggable="false"
:is-resizable="false"
class="grid_cals"
>
<!-- 背景框 -->
<!-- x:列 y:行 w:网格项的初始宽度 h:网格项的初始高度-->
<!-- :style="{ background: getColor(item) }" -->
<grid-item
v-for="(item, index) in layout"
:key="item.i + '-' + index"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:style="{
background: item.locStatusList.length == 0 ? '#e6e6e6' : '',
}"
>
<div class="clmodule">
<span class="top-right">{{
item.locStatusList.length == 0
? ""
: item.locStatusList.length
}}</span>
<span
:style="{ color: item.color === '1' ? 'red' : '#3d3d3d' }"
@click="getEdit(item)"
>{{ item.i }}</span
>
<div
class="segments-container"
v-if="item.locStatusList.length > 0"
>
<div
v-for="segIndex in 5"
:key="segIndex"
class="segment"
:style="{
background: getSegmentColor(item, segIndex),
}"
></div>
</div>
</div>
</grid-item>
</grid-layout>
</div>
</el-col>
<el-col :span="11" :order="7">
<div class="nav-title">
<el-row type="flex">
<el-col :span="4" :order="7">货位编号:</el-col>
<el-col :span="10" :order="7">{{
tableDataClick.length > 0 ? tableDataClick[0].locationCode : ""
}}</el-col>
<el-col :span="3" :order="7">库区:</el-col>
<el-col :span="7" :order="7">{{
tableDataClick.length > 0 ? tableDataClick[0].areaName : ""
}}</el-col>
</el-row>
</div>
<heavy-table
style="margin-top: 40px; height: 360px"
:data="tableDataClick"
:config="tableConfig"
:tableProps="tableProps"
>
</heavy-table>
<div>
<el-button type="primary" style="margin-right: 15px" @click="handleIn"
>入库</el-button
>
<el-button
type="primary"
style="margin-right: 15px"
@click="handleOut"
>出库</el-button
>
</div>
<div style="width: 660px; text-align: center">
<div v-if="inOff">
<el-form :inline="true" :model="fromIn" label-width="120px">
<el-form-item label="AGV停靠点位" prop="agvPlatform">
<el-select
v-model="fromIn.issuanceList[0].agvPlatform"
placeholder="请选择"
clearable
filterable
@change="agvDockChange"
>
<el-option
v-for="item in agvDockList"
:key="item.id"
:label="item.agvPlatform"
:value="item.agvPlatform"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="AGV物料暂存位" prop="agvStorage">
<el-select
v-model="fromIn.issuanceList[0].agvStorage"
placeholder="请选择"
clearable
filterable
>
<el-option
v-for="item in agvStagList"
:key="item.id"
:label="item.agvStorage"
:value="item.agvStorage"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="入库物料" prop="materialMsg">
<el-input
v-model="fromIn.materialMsg"
placeholder="请输入入库物料"
@keyup.enter.native="getGoodsMaterial"
/>
</el-form-item>
<el-form-item label="物料长度" prop="matterLength">
<el-input
v-model="fromIn.issuanceList[0].matterLength"
placeholder="请输入物料长度"
/>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="formCancel">取消</el-button>
<el-button type="primary" @click="inFormSave">入库确认</el-button>
</span>
</div>
<div v-if="outOff">
<el-form :inline="true" :model="fromOut" label-width="120px">
<el-form-item label="AGV停靠点位" prop="agvPlatform">
<el-select
v-model="fromOut.issuanceList[0].agvPlatform"
placeholder="请选择"
clearable
filterable
@change="agvDockChangeOut"
>
<el-option
v-for="item in agvDockList"
:key="item.id"
:label="item.agvPlatform"
:value="item.agvPlatform"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="AGV物料暂存位" prop="agvStorage">
<el-select
v-model="fromOut.issuanceList[0].agvStorage"
placeholder="请选择"
clearable
filterable
>
<el-option
v-for="item in agvStagList"
:key="item.id"
:label="item.agvStorage"
:value="item.agvStorage"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="formCancel">取消</el-button>
<el-button type="primary" @click="outFormSave"
>出库确认</el-button
>
</span>
</div>
</div>
</el-col>
</el-row>
<!-- 物料信息 -->
<el-dialog
:close-on-click-modal="false"
title="物料信息"
:visible.sync="materialOff"
width="1000px"
append-to-body
>
<el-form
:model="queryParams"
ref="queryForm"
size="small"
:inline="true"
label-width="100px"
>
<el-form-item label="物料信息" prop="materialMsg">
<el-input
v-model="queryParams.materialMsg"
placeholder="请输入物料信息"
clearable
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="getGoodsList"
>搜索</el-button
>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
>重置</el-button
>
</el-form-item>
</el-form>
<heavy-table
style="width: 900px"
:data="tableMaterial"
:config="MaterialConfig"
:tableProps="tablePropsMaterial"
:paging="paging"
@current-change="handleCurrentChange"
>
</heavy-table>
<span slot="footer" class="dialog-footer">
<el-button @click="formCancel">取消</el-button>
<el-button type="primary" @click="materialSave">确认</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { GridLayout, GridItem } from "vue-grid-layout";
import {
queryBaseAreaList,
getBaseLocationForMap,
getMaterialByLocationCode,
getPointByArea,
wcsInOrderAdd,
wcsOutOrderAdd,
} from "@/api/wms/busFunctions/storeManager/sysStock";
import { getGoods } from "@/api/basicData/goods";
import { dealEmptyQueryCondition } from "@/utils/index";
export default {
components: {
GridLayout,
GridItem,
},
data() {
return {
dialogVisible: false,
tableConfig: [
{
label: "",
prop: "radio",
type: "radio",
event: this.handleRadio,
istrue: true,
},
{
label: "序号",
prop: "index",
type: "index",
istrue: true,
},
{
label: "物料编号",
prop: "materialCode",
istrue: true,
// width: 100,
},
{
label: "物料名称",
prop: "materialName",
istrue: true,
width: 200,
},
{
label: "物料长度",
prop: "matterLength",
istrue: true,
},
{
label: "入库中",
prop: "inLength",
istrue: true,
},
{
label: "出库出",
prop: "outLength",
istrue: true,
},
{
label: "入库时间",
prop: "createTime",
istrue: true,
// width: 120,
},
],
tableDataClick: [],
tableProps: {
"max-height": 350,
},
inOff: false,
outOff: false,
queryParams: {
materialMsg: "",
},
layout: [
//x:列 y:行
{
w: 1,
h: 1,
x: 4,
y: 9,
i: "4-4-9",
warehouse: "",
isDel: "0",
id: 0,
locationCode: "4-4-9",
locationName: "4-4-9",
tunnel: "",
locationStatus: "0",
type: "1",
locStatusList: [
// {
// matterLength: 200,
// startSegment: 2,
// endSegment: 3,
// inLength: 0,
// outLength: 100,
// },
// {
// matterLength: 200,
// startSegment: 1,
// endSegment: 2,
// inLength: 3300,
// outLength: 0,
// },
],
},
],
tableData: {
stockLots: [],
storageId: "",
areaName: "",
layer: "",
targetLocationId: "",
},
inList: [], //入库目的货位列表
outList: [], //出库目的货位列表
scale: 1,
fromIn: {
warehouseAreaCode: "", //不可为空
issuanceList: [
//明细都为必填项
{
matterId: "",
materialCode: "",
materialName: "",
matterLength: "",
agvPlatform: "",
agvStorage: "",
shelfCode: "",
},
],
},
fromOut: {
warehouseAreaCode: "", //不可为空
issuanceList: [
//明细都为必填项
{
matterId: "",
materialCode: "",
materialName: "",
matterLength: "",
agvPlatform: "",
agvStorage: "",
shelfCode: "",
},
],
},
regionList: [],
storeyList: [],
areaCodeRadio: "",
agvDockList: [],
agvStagList: [],
inMaterialList: [],
materialOff: false,
tableMaterial: [],
MaterialConfig: [
{
label: "",
prop: "radio",
type: "radio",
event: this.handleCommand,
istrue: true,
},
{
label: "序号",
prop: "index",
type: "index",
istrue: true,
},
{
label: "物料编号",
prop: "materialCode",
istrue: true,
},
{
label: "物料名称",
prop: "materialName",
istrue: true,
},
{
label: "物料高度",
prop: "height",
istrue: true,
},
{
label: "物料长度",
prop: "length",
istrue: true,
"min-width": 120,
},
{
label: "物料宽度",
prop: "width",
istrue: true,
},
],
tablePropsMaterial: {
"max-height": 350,
},
paging: {
page: 1, // 当前页
size: 10, // 页面大小
total: 0, // 总条数
},
objOldIn: {},
objOldOut: {},
};
},
watch: {
areaCodeRadio(newVal, oldVal) {
this.areaCodeRadio = newVal;
this.getList();
},
},
created() {
this.queryBaseAreaList();
// this.getList();
},
methods: {
// 获取全部数据
getList() {
// console.log("初始化列表····");
getBaseLocationForMap({
pageNum: 1,
pageSize: 9999,
// storageCode: "002",
areaCode: this.areaCodeRadio,
}).then((res) => {
if (res.code == 200) {
this.layout = res.rows;
}
});
},
// getSegmentColor(item, segIndex) {
// if (item.type === "2") return "#90ee90";
// let currentStatus;
// // 遍历所有状态区间,看哪些覆盖了 segIndex
// for (const status of item.locStatusList) {
// const { startSegment, endSegment, matterLength, inLength, outLength } =
// status;
// if (segIndex >= startSegment && segIndex <= endSegment) {
// if (matterLength > 0) {
// if (inLength == 0 && outLength == 0) {
// currentStatus = "has";
// } else if (inLength > 0 && outLength == 0) {
// currentStatus = "hasIn";
// } else if (inLength == 0 && outLength > 0) {
// currentStatus = "hasOut";
// }
// } else {
// currentStatus = "in";
// }
// }
// }
// // 根据最终状态返回颜色
// const colorMap = {
// empty: "#e6e6e6",
// in: "#d8bfd8",
// has: "#759ffa",
// hasIn: "#ffdead",
// hasOut: "#ff8247",
// };
// return colorMap[currentStatus] || "#e6e6e6";
// },
getSegmentColor(item, segIndex) {
if (item.type === "2") return "#90ee90"; // 通道
const colorMap = {
empty: "#e6e6e6",
in: "#d8bfd8",
has: "#759ffa",
hasIn: "#ffdead",
hasOut: "#ff8247",
};
// 收集所有覆盖 segIndex 的状态标识
const statuses = new Set();
for (const status of item.locStatusList) {
const { startSegment, endSegment, matterLength, inLength, outLength } =
status;
if (segIndex >= startSegment && segIndex <= endSegment) {
let currentStatus;
if (matterLength > 0) {
if (inLength > 0 && outLength > 0) {
currentStatus = "hasInOut"; // 新增:同时有入库和出库
} else if (inLength > 0) {
currentStatus = "hasIn";
} else if (outLength > 0) {
currentStatus = "hasOut";
} else {
currentStatus = "has";
}
} else {
currentStatus = "in";
}
statuses.add(currentStatus);
}
}
// 如果没有状态,默认为空
if (statuses.size === 0) {
return colorMap.empty;
}
// 转为数组便于处理
const statusArray = Array.from(statuses);
// 单状态:直接返回颜色
if (statusArray.length === 1) {
return colorMap[statusArray[0]] || colorMap.empty;
}
// 多状态:生成渐变(目前只处理两个状态)
if (statusArray.length === 2) {
const [a, b] = statusArray;
const colorA = colorMap[a] || colorMap.empty;
const colorB = colorMap[b] || colorMap.empty;
return `linear-gradient(90deg, ${colorB} 50%, ${colorA} 50%)`;
}
// 三个及以上状态(罕见),可选:返回警示色或混合色
if (statusArray.length >= 3) {
return "#ff00ff"; // 或使用更复杂的渐变
}
},
//库区列表
queryBaseAreaList() {
queryBaseAreaList().then((res) => {
if (res.code == 200) {
this.storeyList = res.data;
if (this.storeyList.length > 0) {
this.areaCodeRadio = this.storeyList[0].areaCode;
}
}
});
},
// 刷新
getreset() {
this.getList();
},
// 颜色
getColor(item) {
if (item.type == "1") {
if (item.locStatusList.length > 0) {
//状态
const { matterLength, inLength, outLength } = item.locStatusList[0];
if (matterLength > 0 && outLength > 0) {
return "#ff8247"; //有货出库
} else if (matterLength > 0 && inLength > 0) {
return "#ffdead"; //有货入库
} else if (matterLength > 0 && inLength == 0 && outLength == 0) {
return "#759ffa"; //有货
} else if (matterLength == 0 && inLength > 0 && outLength > 0) {
return "#d8bfd8"; //入库中
} else if (matterLength == 0 && inLength > 0) {
return "#d8bfd8"; //入库中
} else {
return ""; //入库中
}
} else {
return "#E6E6E6"; //空货位
}
} else if (item.type == "2") {
return "#90EE90"; //通道
}
},
//显示标题
getTitle(item) {
if (item.type == "2") {
return "通道";
} else {
switch (item.locationStatus) {
default:
case "0":
return "空货位";
break;
case "1":
return "有货";
break;
case "3":
return "入库中";
break;
case "4":
return "出库中";
break;
}
}
},
// 货位点击事件
getEdit(item) {
getMaterialByLocationCode({ locationCode: item.locationCode }).then(
(res) => {
this.tableDataClick = res.rows;
this.fromIn.issuanceList[0].shelfCode = item.locationCode;
this.fromOut.issuanceList[0].shelfCode = item.locationCode;
if (res.rows.length > 0) {
this.fromIn.warehouseAreaCode = this.tableDataClick[0].areaCode;
this.fromOut.warehouseAreaCode = this.tableDataClick[0].areaCode;
this.agvDockList = [];
this.agvStagList = [];
this.fromIn.issuanceList[0].agvStorage = "";
this.fromIn.issuanceList[0].agvPlatform = "";
this.fromOut.issuanceList[0].agvStorage = "";
this.fromOut.issuanceList[0].agvPlatform = "";
this.getPointByArea();
}
}
);
},
// 入库
handleIn() {
this.inOff = true;
this.outOff = false;
},
// 出库
handleOut() {
this.inOff = false;
this.outOff = true;
},
// 处理鼠标滚轮事件
onWheel(event) {
if (event.deltaY < 0) {
this.scale = Math.min(this.scale + 0.1, 1); // 最大放大1倍
} else {
this.scale = Math.max(this.scale - 0.1, 0.1);
}
},
// 取消
formCancel() {
this.outOff = false;
this.inOff = false;
this.materialOff = false;
},
//AGV停靠点位
getPointByArea() {
getPointByArea({
areaCode: this.fromIn.warehouseAreaCode,
}).then((res) => {
this.agvDockList = res.data;
});
},
// 选择AGV停靠点位触发的事件(出库)
agvDockChangeOut(e) {
// console.log("AGV物料暂存位····", e);
this.fromOut.issuanceList[0].agvStorage = "";
this.agvStagList = [];
getPointByArea({
areaCode: this.fromOut.warehouseAreaCode,
agvPlatform: e,
}).then((res) => {
this.agvStagList = res.data;
this.fromOut.issuanceList[0].agvStorage =
this.agvStagList[0].agvStorage;
});
},
// 选择AGV停靠点位触发的事件(入库)
agvDockChange(e) {
// console.log("AGV物料暂存位····", e);
this.fromIn.issuanceList[0].agvStorage = "";
this.agvStagList = [];
getPointByArea({
areaCode: this.fromIn.warehouseAreaCode,
agvPlatform: e,
}).then((res) => {
this.agvStagList = res.data;
this.fromIn.issuanceList[0].agvStorage = this.agvStagList[0].agvStorage;
});
},
// 入库物料
getGoodsMaterial() {
this.materialOff = true;
this.resetQuery();
this.getGoodsList();
},
async getGoodsList() {
const request = {
pageSize: this.paging.size,
pageNum: this.paging.page,
materialMsg: this.queryParams.materialMsg
? this.queryParams.materialMsg
: this.fromIn.materialMsg,
};
dealEmptyQueryCondition(request);
const { rows, total } = await getGoods(request);
this.tableMaterial = rows;
this.paging.total = total;
},
// 点击分页
handleCurrentChange(val) {
if (Object.prototype.toString.call(val) === "[object Object]") {
this.paging.size = val.size;
this.getGoodsList();
} else {
this.paging.page = val;
this.getGoodsList();
}
},
// 重置查询条件
resetQuery() {
this.queryParams.materialMsg = "";
this.getGoodsList();
},
// 入库单选
handleCommand(data, row, prop) {
this.objOldIn = row;
},
// 弹窗确认
materialSave() {
this.fromIn.issuanceList[0].matterId = this.objOldIn.id;
this.fromIn.issuanceList[0].matterCode = this.objOldIn.materialCode;
this.fromIn.issuanceList[0].matterName = this.objOldIn.materialName;
this.fromIn.issuanceList[0].matterLength = this.objOldIn.length;
this.fromIn.materialMsg = this.objOldIn.materialName;
this.materialOff = false;
},
// 必填判断
validateForm(data) {
// 判断 issuanceList 是否为空
if (!data.issuanceList || data.issuanceList.length === 0) {
return "issuanceList不能为空";
}
// 判断 issuanceList 中每个项的属性是否都填写
for (let i = 0; i < data.issuanceList.length; i++) {
let item = data.issuanceList[i];
if (
!item.matterId ||
!item.matterCode ||
!item.matterName ||
!item.matterLength ||
!item.agvPlatform ||
!item.agvStorage ||
!item.shelfCode
) {
return `第 ${i + 1} 项的必填项不能为空`;
}
}
// 如果都通过验证
return "验证通过";
},
// 入库确认保存
async inFormSave() {
// console.log("this.fromIn", this.fromIn);
if (this.fromIn.warehouseAreaCode == "") {
return this.$message.error("请选择货位!");
}
this.validateForm(this.fromIn);
await wcsInOrderAdd(this.fromIn).then((res) => {
if (res.code == 200) {
this.$message.success("入库成功!");
this.fromIn = {
warehouseAreaCode: "", //不可为空
issuanceList: [
//明细都为必填项
{
matterId: "",
materialCode: "",
materialName: "",
matterLength: "",
agvPlatform: "",
agvStorage: "",
shelfCode: "",
},
],
};
this.objOldIn = {};
this.tableDataClick = [];
this.agvStagList = [];
this.agvDockList = [];
this.inOff = false;
this.getList();
}
});
},
// 出库单选
handleRadio(data, row, prop) {
this.fromOut.issuanceList[0].matterId = row.matterId;
this.fromOut.issuanceList[0].matterCode = row.materialCode;
this.fromOut.issuanceList[0].matterName = row.materialName;
this.fromOut.issuanceList[0].matterLength = row.matterLength;
},
// 出库保存
async outFormSave() {
if (this.fromOut.warehouseAreaCode == "") {
return this.$message.error("请选择货位!");
}
this.validateForm(this.fromOut);
await wcsOutOrderAdd(this.fromOut).then((res) => {
if (res.code == 200) {
this.$message.success("出库成功!");
this.fromOut = {
warehouseAreaCode: "", //不可为空
issuanceList: [
//明细都为必填项
{
matterId: "",
materialCode: "",
materialName: "",
matterLength: "",
agvPlatform: "",
agvStorage: "",
shelfCode: "",
},
],
};
this.tableDataClick = [];
this.agvStagList = [];
this.agvDockList = [];
this.outOff = false;
this.getList();
}
});
},
},
};
</script>
<style lang="less" scoped>
.clmodule {
display: flex;
justify-content: center;
align-items: center;
align-self: center;
height: 100%;
color: #fff;
position: relative;
.top-right {
position: absolute;
top: 5px;
right: 5px;
color: #fd0f0f;
}
.segments-container {
position: absolute;
left: 0;
top: 0;
display: flex;
width: 100%;
height: 100%;
z-index: -1;
.segment {
flex: 1;
border-right: 1px solid rgba(0, 0, 0, 0.17);
&:last-child {
border-right: none;
}
}
}
}
.vue-grid-item .no-drag {
height: 100%;
width: 100%;
}
.vue-grid-item .minMax {
font-size: 14px;
}
.vue-grid-item .add {
cursor: pointer;
}
.layoutBox {
width: 100%;
// height: 1200px;
overflow-y: none;
}
.grid_cals {
height: 1200px;
display: grid;
grid-template-columns: repeat(7, 120px); /* 设置75列,每列宽100px */
grid-template-rows: repeat(40, 50px); /* 设置12行,每行高75px */
// width: max-content; /* 内容宽度自适应 */
// overflow-x: auto; /* 横向滚动 */
height: max-content; /* 内容宽度自适应 */
overflow-y: none; /* 横向滚动 */
// // margin-left: -100px;
// border: 1px solid #ccc; /* 可选:添加边框来查看效果 */
}
.nav-title {
padding: 20px;
height: 30px;
line-height: 18px;
font-size: 22px;
font-weight: 600;
margin-top: -10px;
}
::v-deep .el-dialog .el-dialog__body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
::v-deep .el-dialog__footer {
text-align: center;
}
::v-deep .el-table {
background-color: transparent;
}
</style>