Files
delivery_manage_front/src/views/order/outWarehouse/index.vue
2026-03-19 15:46:30 +08:00

857 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-splitter>
<el-splitter-panel size="40%">
<el-form
:model="queryParams"
ref="queryRef"
v-show="showSearch"
label-width="90"
>
<el-row>
<el-col :span="10">
<el-form-item label="单据号" prop="billNoCk">
<el-input
v-model="queryParams.billNoCk"
placeholder="请输入单据号"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery"
>搜索</el-button
>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter="10"
class="mb8"
style="justify-content: flex-end; margin-right: 0"
>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="plus"
@click="delieryReceipt()"
:disabled="multipleBill"
>生成配送单</el-button
>
</el-col>
<!-- <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> -->
</el-row>
</el-form>
<el-table
v-loading="loading"
highlight-current-row
:data="billList"
ref="billTable"
@row-dblclick="billClick"
@select="handleBillSelectionChange"
@select-all="handleBillSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column
label="单据号"
align="center"
prop="billNo"
width="200"
/>
<el-table-column label="库存状态" align="center">
<template #default="scope">
<span>{{ isChukuFun(scope.row.isDelivery) }}</span>
</template>
</el-table-column>
<el-table-column label="理货员" align="center" prop="operatorName" />
<el-table-column
label="出库类型"
align="center"
prop="operationTypeName"
width="150"
/>
<el-table-column
label="出库时间"
align="center"
prop="operationTime"
width="170"
>
<template #default="scope">
<span>{{
parseTime(scope.row.operationTime, "{y}-{m}-{d} {h}:{i}:{s}")
}}</span>
</template>
</el-table-column>
</el-table>
<!-- 分页暂时注释掉 -->
<!-- <pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/> -->
<!-- <el-pagination background layout="prev, pager, next" :total="total" v-model:page="queryParams.pageNum" @pagination="getList"/> -->
</el-splitter-panel>
<el-splitter-panel :min="200">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="plus"
@click="delieryReceipt()"
:disabled="multiple"
>生成配送单</el-button
>
</el-col>
</el-row>
<el-table
v-loading="detailLoading"
show-overflow-tooltip
:data="stockList"
ref="detailTable"
@select="handleSelectionChange"
@select-all="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="库存状态" align="center">
<template #default="scope">
<span>{{ isChukuFun(scope.row.bizType) }}</span>
</template>
</el-table-column>
<el-table-column
label="项目号"
align="center"
prop="xmNo"
width="150"
/>
<el-table-column
label="项目描述"
align="center"
prop="xmMs"
width="250"
/>
<el-table-column
label="物料号"
align="center"
prop="wlNo"
width="100"
/>
<el-table-column
label="物料描述"
align="center"
prop="wlMs"
width="250"
/>
<el-table-column
label="供应商名称"
align="center"
prop="gysMc"
width="200"
/>
<el-table-column label="合同单价" align="center" prop="htDj" />
<el-table-column
label="订单编号"
align="center"
prop="sapNo"
width="150"
/>
<el-table-column label="计量单位" align="center" prop="dw" />
<el-table-column
label="实际出库数量"
align="center"
prop="realQty"
width="120"
/>
<el-table-column
label="库位码"
align="center"
prop="pcode"
width="120"
/>
<el-table-column label="托盘码" align="center" prop="trayCode" />
<el-table-column
label="身份码"
align="center"
prop="entityId"
width="200"
/>
<!-- <el-table-column label="出库类型" align="center" prop="operationTypeName" width="150"/> -->
<el-table-column
label="物资类型"
align="center"
prop="wlTypeName"
width="120"
/>
<el-table-column
label="所属仓库"
align="center"
prop="cangkuName"
width="150"
>
<template #default="scope">
<span
>{{ scope.row.parentWarehouseName }}-{{
scope.row.warehouseName
}}</span
>
</template>
</el-table-column>
<!-- <el-table-column label="操作时间" align="center" prop="operationTime" width="200">
<template #default="scope">
<span>{{ parseTime(scope.row.operationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column> -->
<!-- <el-table-column label="库龄" align="center" prop="stockAge" /> -->
<el-table-column
label="备注"
align="center"
prop="remark"
width="200"
/>
</el-table>
</el-splitter-panel>
</el-splitter>
<el-dialog title="生成配送单" v-model="dialogPicDetailVisible">
<div class="container">
<div class="billBox">
<span>出库单号</span><span>{{ detailQueryParams.billNoCk }}</span>
</div>
<el-form
:model="delieryData"
ref="form"
:rules="rules"
label-width="100"
>
<el-divider content-position="left">配送信息</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="起点" prop="originName">
<el-input
v-model="delieryData.originName"
placeholder="请输入起点"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="终点" prop="destName">
<el-input
v-model="delieryData.destName"
placeholder="请输入终点"
clearable
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="配送人" prop="shipperName">
<el-select
v-model="delieryData.shipperName"
placeholder="请选择配送人"
clearable
>
<el-option
v-for="dict in personList"
:key="dict.userId"
:label="dict.userName"
:value="dict.userName"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="配送人电话" prop="shipperPhone">
<el-input
v-model="delieryData.shipperPhone"
type="tel"
placeholder="请输入配送人电话"
clearable
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="收货人" prop="receiverName">
<el-input
v-model="delieryData.receiverName"
placeholder="请输入收货人"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="收货人电话" prop="receiverPhone">
<el-input
v-model="delieryData.receiverPhone"
type="tel"
placeholder="请输入收货人电话"
clearable
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="接收单位" prop="receiverOrgName">
<el-input
v-model="delieryData.receiverOrgName"
placeholder="请输入接收单位"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="配送日期" prop="deliveryDate">
<el-date-picker
v-model="delieryData.deliveryDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">货物信息</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="重量" prop="deliveryTon">
<el-input v-model="delieryData.deliveryTon" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="体积" prop="goodsSize">
<el-input v-model="delieryData.goodsSize" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="公里数" prop="totalKm">
<el-input
v-model="delieryData.totalKm"
placeholder="请输入公里数"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="4" :offset="1">
<el-button type="primary" @click="calculateFun(null)"
>计算</el-button
>
</el-col>
</el-row>
<el-divider content-position="left">计算信息</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="推荐车型" v-for="(item, index) in delieryData.vehicleTypeNameList" :key="index">
<el-select
v-model="item.vehicleTypeId"
placeholder="请选择推荐车型"
@change="changeCarType($event, index)"
>
<el-option
v-for="dict in carTypeList"
:key="dict.id"
:label="dict.name"
:value="dict.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="建议费用" prop="suggestFee">
<el-input
v-model="delieryData.suggestFee"
placeholder=""
clearable
disabled
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="outWarehouse">
import {
listBill,
listStock,
calculate,
addDelivery,
} from "@/api/outWarehouse/outWarehouse";
import { listType } from "@/api/document/type";
import { listUser } from "@/api/system/user"; //理货员
// let map = null;
// onMounted(() => {
// AMapLoader.load({
// key: "5617ac0ab71c7044bf96edb81b4efc9a", // 申请好的Web端开发者Key首次调用 load 时必填
// version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
// plugins: [], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
// })
// .then((AMap) => {
// map = new AMap.Map("container", {
// // 设置地图容器id
// viewMode: "3D", // 是否为3D地图模式
// zoom: 11, // 初始化地图级别
// center: [116.397428, 39.90923], // 初始化地图中心点位置
// });
// })
// .catch((e) => {
// console.log(e);
// });
// });
// onUnmounted(() => {
// map?.destroy();
// });
const { proxy } = getCurrentInstance();
const detailLoading = ref(false); //加载列表详情
const showSearch = ref(true);
const total = ref(0); //单据
const personList = ref([]); //理货员下拉数据
const carTypeList = ref([]); //推荐车型下拉数据
const dialogPicDetailVisible = ref(false);
const multiple = ref(true);
const data = reactive({
fileList: [],
form: {},
//配送单提交的数据
delieryData: {
deliveryTon: 0, //重量
goodsSize: 0, //体积
items: [],
vehicleTypeNameList: [{}], //推荐车型列表
},
queryParams: {},
detailQueryParams: {
pageNum: 1,
pageSize: 200,
id: null,
billNoCk: "",
},
rules: {
originName: [
{ required: true, message: "起点不能为空", trigger: "change" },
],
destName: [{ required: true, message: "终点不能为空", trigger: "change" }],
shipperName: [
{ required: true, message: "配送人不能为空", trigger: "change" },
],
shipperPhone: [
{
pattern: /^1[3456789]\d{9}$/,
message: "请输入有效的电话号码",
trigger: "blur",
},
],
receiverName: [
{ required: true, message: "收货人不能为空", trigger: "change" },
],
receiverPhone: [
{ required: true, message: "收货人电话不能为空", trigger: "change" },
{
pattern: /^1[3456789]\d{9}$/,
message: "请输入有效的电话号码",
trigger: "blur",
},
],
deliveryTon: [
{ required: true, message: "重量不能为空", trigger: "change" },
],
goodsSize: [{ required: true, message: "体积不能为空", trigger: "change" }],
totalKm: [{ required: true, message: "公里数不能为空", trigger: "change" }],
suggestFee: [
{ required: true, message: "建议费用不能为空", trigger: "change" },
],
deliveryDate: [
{ required: true, message: "配送日期不能为空", trigger: "change" },
],
},
switchRules: {
toCangku: [
{ required: true, message: "目标仓库不能为空", trigger: "change" },
],
toPcode: [
{ required: true, message: "目标存放位置不能为空", trigger: "change" },
],
},
});
const { queryParams, detailQueryParams, delieryData, rules } = toRefs(data);
//生成配送单弹框
function delieryReceipt() {
dialogPicDetailVisible.value = true;
//理货员下拉数据
listUser().then((response) => {
personList.value = response.rows;
});
//车型下拉数据
listType({ pageNum: 1, pageSize: 1000 }).then((response) => {
// carTypeList.value = response.rows;
});
}
//双击单据,查询明细
function billClick(row) {
stockList.value = row.recordList;
}
function isChukuFun(isChuku) {
// scope.row.isChuku==0?"已入库":(scope.row.isChuku==1?"已出库":"审批中")
return "已出库";
}
const stockList = ref([]); //明细列表
const billList = ref([]); //单据列表
const loading = ref(true);
/** 查询库存单据主列表 */
function getList() {
loading.value = true;
listBill(queryParams.value).then((response) => {
billList.value = response.data;
loading.value = false;
});
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
multipleBill.value = true;
multiple.value = true
stockList.value = []
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
const multipleBill = ref(true);
const billTable = ref(null);
const detailTable = ref(null);
// 多选框选中数据
function handleBillSelectionChange(selectionArr) {
if (!multiple.value) {
proxy.$confirm('此操作将删除右侧勾选, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
detailTable.value.clearSelection();
delieryData.value.deliveryTon = 0;
delieryData.value.goodsSize = 0;
let selection = selectionArr
.flatMap((item) => item.recordList)
if (selection.length > 0) {
for (let i = 0; i < selection.length; i++) {
delieryData.value.deliveryTon +=
((Number(selection[i].weightKg) * 1000) * (selection[i].realQty * 1000)) / 1000;
delieryData.value.goodsSize +=
((Number(selection[i].volumeM3) * 1000) * (selection[i].realQty * 1000)) / 1000;
// selection[i].rkInfoId = selection[i].id
selection[i].rkRecordId = selection[i].id;
}
delieryData.value.items = selection;
// selection.forEach(element => {
// delieryData.value.deliveryTon += Number(element.deliveryTon)
// delieryData.value.goodsSize += Number(element.goodsSize)
// });
} else {
delieryData.value.deliveryTon = 0;
delieryData.value.goodsSize = 0;
delieryData.value.items = [];
}
delieryData.value.deliveryTon = delieryData.value.deliveryTon / 1000000;
delieryData.value.goodsSize = delieryData.value.goodsSize / 1000;
multipleBill.value = !selectionArr.length;
multiple.value = true
console.log(selectionArr);
proxy.$message({
type: 'success',
message: '删除成功!',
})
})
.catch(() => {
billTable.value.clearSelection();
proxy.$message({
type: 'info',
message: '已取消删除',
})
})
} else {
delieryData.value.deliveryTon = 0;
delieryData.value.goodsSize = 0;
let selection = selectionArr
.flatMap((item) => item.recordList)
if (selection.length > 0) {
for (let i = 0; i < selection.length; i++) {
delieryData.value.deliveryTon +=
((Number(selection[i].weightKg) * 1000) * (selection[i].realQty * 1000)) / 1000;
delieryData.value.goodsSize +=
((Number(selection[i].volumeM3) * 1000) * (selection[i].realQty * 1000)) / 1000;
// selection[i].rkInfoId = selection[i].id
selection[i].rkRecordId = selection[i].id;
}
delieryData.value.items = selection;
// selection.forEach(element => {
// delieryData.value.deliveryTon += Number(element.deliveryTon)
// delieryData.value.goodsSize += Number(element.goodsSize)
// });
} else {
delieryData.value.deliveryTon = 0;
delieryData.value.goodsSize = 0;
delieryData.value.items = [];
}
delieryData.value.deliveryTon = delieryData.value.deliveryTon / 1000000;
delieryData.value.goodsSize = delieryData.value.goodsSize / 1000;
multipleBill.value = !selectionArr.length;
multiple.value = true
console.log(selectionArr);
}
}
function handleSelectionChange(selection) {
console.log(selection);
if (!multipleBill.value) {
proxy.$confirm('此操作将删除左侧勾选, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
billTable.value.clearSelection();
delieryData.value.deliveryTon = 0;
delieryData.value.goodsSize = 0;
if (selection.length > 0) {
for (let i = 0; i < selection.length; i++) {
delieryData.value.deliveryTon +=
((Number(selection[i].weightKg) * 1000) * (selection[i].realQty * 1000)) / 1000;
delieryData.value.goodsSize +=
((Number(selection[i].volumeM3) * 1000) * (selection[i].realQty * 1000)) / 1000;
// selection[i].rkInfoId = selection[i].id
selection[i].rkRecordId = selection[i].id;
}
delieryData.value.items = selection;
// selection.forEach(element => {
// delieryData.value.deliveryTon += Number(element.deliveryTon)
// delieryData.value.goodsSize += Number(element.goodsSize)
// });
} else {
delieryData.value.deliveryTon = 0;
delieryData.value.goodsSize = 0;
delieryData.value.items = [];
}
delieryData.value.deliveryTon = delieryData.value.deliveryTon / 1000000;
delieryData.value.goodsSize = delieryData.value.goodsSize / 1000;
multiple.value = !selection.length;
multipleBill.value = true
console.log(selection);
proxy.$message({
type: 'success',
message: '删除成功!',
})
})
.catch(() => {
detailTable.value.clearSelection();
proxy.$message({
type: 'info',
message: '已取消删除',
})
})
} else {
delieryData.value.deliveryTon = 0;
delieryData.value.goodsSize = 0;
if (selection.length > 0) {
for (let i = 0; i < selection.length; i++) {
delieryData.value.deliveryTon +=
((Number(selection[i].weightKg) * 1000) * (selection[i].realQty * 1000)) / 1000;
delieryData.value.goodsSize +=
((Number(selection[i].volumeM3) * 1000) * (selection[i].realQty * 1000)) / 1000;
// selection[i].rkInfoId = selection[i].id
selection[i].rkRecordId = selection[i].id;
}
delieryData.value.items = selection;
// selection.forEach(element => {
// delieryData.value.deliveryTon += Number(element.deliveryTon)
// delieryData.value.goodsSize += Number(element.goodsSize)
// });
} else {
delieryData.value.deliveryTon = 0;
delieryData.value.goodsSize = 0;
delieryData.value.items = [];
}
delieryData.value.deliveryTon = delieryData.value.deliveryTon / 1000000;
delieryData.value.goodsSize = delieryData.value.goodsSize / 1000;
multiple.value = !selection.length;
multipleBill.value = true
console.log(selection);
}
}
//根据重量、体积、公里数计算车型、费用
function calculateFun(id) {
if (
!delieryData.value.deliveryTon ||
!delieryData.value.goodsSize ||
!delieryData.value.totalKm
) {
proxy.$modal.msgWarning("请输入公里数、重量、体积");
return;
}
let info = {
weightTon: 0,
volumeM3: 0,
distanceKm: 0,
};
let hasVehicle = delieryData.value.vehicleTypeNameList.every(item => item.vehicleTypeId)
if (hasVehicle) {
info.vehicleTypeId = delieryData.value.vehicleTypeNameList.map(item => item.vehicleTypeId).join(',')
}
info.weightTon = delieryData.value.deliveryTon;
info.volumeM3 = delieryData.value.goodsSize;
info.distanceKm = delieryData.value.totalKm;
calculate(info).then((response) => {
// 检查后端是否返回了错误信息
if (response.data.warningMessage) {
proxy.$modal.msgError(response.data.warningMessage);
return;
}
if (response.data.bestPlan.length > 0 && !id) {
delieryData.value.vehicleTypeNameList = response.data.bestPlan;
}
carTypeList.value = response.data.candidates;
delieryData.value.suggestFee = response.data.suggestFee;
delieryData.value.vehicleTypeName = response.data.vehicleTypeName;
console.log(delieryData.value)
});
}
//切换车型
function changeCarType(id, index) {
console.log(id, index)
if (
!delieryData.value.totalKm ||
!delieryData.value.deliveryTon ||
!delieryData.value.goodsSize
) {
proxy.$modal.msgWarning("请输入公里数、重量、体积");
return;
}
calculateFun(id);
}
// 取消按钮
function cancel() {
delieryData.value.originName = null;
delieryData.value.destName = null;
delieryData.value.shipperName = null;
delieryData.value.shipperPhone = null;
delieryData.value.receiverName = null;
delieryData.value.receiverPhone = null;
delieryData.value.receiverOrgName = null;
delieryData.value.deliveryDate = null;
delieryData.value.totalKm = null;
delieryData.value.vehicleTypeNameList = [{}];
delieryData.value.suggestFee = null;
proxy.$refs["form"].resetFields()
dialogPicDetailVisible.value = false;
}
// function reset() {
// }
function submitForm() {
let hasVehicle = delieryData.value.vehicleTypeNameList.every(item => item.vehicleTypeId)
if (!hasVehicle) {
proxy.$modal.msgWarning('请选择配送车型')
return
}
proxy.$refs["form"].validate((valid) => {
// console.log(delieryData.value)
// return
if (valid) {
let obj = JSON.parse(JSON.stringify(delieryData.value))
obj.vehicleTypeName = obj.vehicleTypeNameList.map(item => item.vehicleTypeName).join(',')
obj.vehicleTypeId = obj.vehicleTypeNameList.map(item => item.vehicleTypeId).join(',')
addDelivery(obj).then((response) => {
proxy.$modal.msgSuccess("操作成功");
dialogPicDetailVisible.value = false;
stockList.value = [];
getList();
});
}
});
}
//数据列表
getList();
</script>
<style scoped>
.el-table .warning-row {
--el-table-tr-bg-color: var(--el-color-warning-light-9);
}
.el-table .success-row {
--el-table-tr-bg-color: var(--el-color-success-light-9);
}
.titleBox {
text-align: center;
}
.topBox {
margin-bottom: 10px;
display: flex;
}
.bottomBox {
margin-top: 20px;
}
.oneLineBox {
display: flex;
}
.everyBox {
width: 30%;
}
.examine {
margin-top: 20px;
height: 100px;
background-color: #ededed;
padding: 20px 0 0 20px;
border-radius: 10px;
}
.billBox {
font-weight: bold;
}
</style>