<template>
|
<div class="app-container">
|
<div class="search_form">
|
<el-form :model="searchForm"
|
:inline="true">
|
<el-form-item label="产品名称:">
|
<el-input v-model="searchForm.productCategory"
|
placeholder="请输入"
|
clearable
|
prefix-icon="Search"
|
style="width: 160px;"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary"
|
@click="handleQuery">搜索</el-button>
|
</el-form-item>
|
</el-form>
|
<div>
|
<el-button type="primary" @click="isShowNewModal = true">新增</el-button>
|
<el-button type="danger" @click="handleDelete">删除</el-button>
|
<el-button @click="handleOut">导出</el-button>
|
</div>
|
</div>
|
<div class="table_list">
|
<PIMTable rowKey="id"
|
:column="tableColumn"
|
:tableData="tableData"
|
:page="page"
|
:tableLoading="tableLoading"
|
:row-class-name="tableRowClassName"
|
:isSelection="true"
|
@selection-change="handleSelectionChange"
|
@pagination="pagination">
|
<template #completionStatus="{ row }">
|
<el-progress
|
:percentage="toProgressPercentage(row?.completionStatus)"
|
:color="progressColor(toProgressPercentage(row?.completionStatus))"
|
:status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''"
|
/>
|
</template>
|
<template #productWorkOrders="{ row }">
|
<div class="work-order-circles">
|
<div
|
v-for="(workOrder, index) in row.productWorkOrders"
|
:key="index"
|
class="work-order-circle"
|
:class="getWorkOrderColorClass(workOrder.color)"
|
:title="workOrder.processName || workOrder.workOrderNo"
|
>
|
{{ workOrder.processName ? workOrder.processName.substring(0, 2) : index + 1 }}
|
</div>
|
</div>
|
</template>
|
</PIMTable>
|
</div>
|
<el-dialog v-model="bindRouteDialogVisible"
|
title="绑定工艺路线"
|
width="500px">
|
<el-form label-width="90px">
|
<el-form-item label="工艺路线">
|
<el-select v-model="bindForm.routeId"
|
placeholder="请选择工艺路线"
|
style="width: 100%;"
|
:loading="bindRouteLoading">
|
<el-option v-for="item in routeOptions"
|
:key="item.id"
|
:label="item.processRouteName"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button type="primary" :loading="bindRouteSaving" @click="handleBindRouteConfirm">确 认</el-button>
|
<el-button @click="bindRouteDialogVisible = false">取 消</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
|
<new-product-order v-if="isShowNewModal"
|
v-model:visible="isShowNewModal"
|
type="qualified"
|
@completed="handleQuery" />
|
|
<!-- 查看投入弹框 -->
|
<el-dialog v-model="inputDialogVisible"
|
title="投入与退料"
|
width="1200px"
|
:close-on-click-modal="false">
|
<el-table
|
:data="inputTableData"
|
border
|
size="small"
|
@selection-change="handleInputSelectionChange"
|
:header-cell-style="{ background: '#f5f7fa' }"
|
show-summary
|
:summary-method="summarizeInputTable"
|
>
|
<el-table-column type="selection" width="50" align="center" />
|
<el-table-column label="投入产品名称" prop="productName" min-width="120" />
|
<el-table-column label="图纸编号" prop="model" min-width="100" />
|
<el-table-column label="投入数量" prop="quantity" min-width="100" align="center" />
|
<el-table-column label="已退料数量" prop="returnQuantity" min-width="100" align="center" />
|
<el-table-column label="单位" prop="unit" min-width="80" align="center" />
|
<el-table-column label="本次退料数量" min-width="180" align="center" prop="currentReturnQuantity">
|
<template #default="{ row }">
|
<el-input-number
|
v-model="row.currentReturnQuantity"
|
:min="0"
|
:max="row.quantity - (row.returnQuantity || 0)"
|
:precision="0"
|
size="small"
|
style="width: 160px"
|
@change="(val) => handleInputReturnQuantityChange(val, row)"
|
/>
|
</template>
|
</el-table-column>
|
</el-table>
|
<div class="picking-footer-info">
|
<span>已选 {{ inputSelectedRows.length }} 条</span>
|
<span>{{ inputTableData.length }} 条记录</span>
|
</div>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="warning" @click="handleReturnSubmit">确认退料</el-button>
|
<el-button @click="inputDialogVisible = false">关闭</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
<!-- 领料弹框 -->
|
<el-dialog v-model="pickingDialogVisible"
|
title="工单领料"
|
width="1200px"
|
:close-on-click-modal="false">
|
|
<el-table
|
:data="pickingTableData"
|
border
|
size="small"
|
@selection-change="handlePickingSelectionChange"
|
:header-cell-style="{ background: '#f5f7fa' }"
|
show-summary
|
:summary-method="summarizePickingTable"
|
>
|
<el-table-column type="selection" width="50" align="center" />
|
<el-table-column label="产品名称" prop="productName" min-width="120" />
|
<el-table-column label="图纸编号" prop="model" min-width="100" />
|
<el-table-column label="单位用量" prop="unitQuantity" min-width="100" align="center" />
|
<el-table-column label="单位" prop="unit" min-width="100" align="center" />
|
<el-table-column label="需求数量" prop="demandedQuantity" min-width="100" align="center" />
|
<el-table-column label="已领料数量" prop="completedQuantity" min-width="100" align="center" />
|
<el-table-column label="未领料数量" prop="unpickedQuantity" min-width="100" align="center" />
|
<el-table-column label="领料数量" min-width="180" align="center" prop="quantity">
|
<template #default="{ row }">
|
<el-input-number
|
v-model="row.quantity"
|
:min="0"
|
:max="row.unpickedQuantity"
|
:precision="0"
|
size="small"
|
style="width: 160px"
|
@change="(val) => handlePickingQuantityChange(val, row)"
|
/>
|
</template>
|
</el-table-column>
|
</el-table>
|
<div class="picking-footer-info">
|
<span>已选 {{ pickingSelectedRows.length }} 条</span>
|
<span>{{ pickingTableData.length }} 条记录</span>
|
</div>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="success" @click="handlePickingNext">确认</el-button>
|
<el-button @click="pickingDialogVisible = false">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
<!-- 查看图纸弹窗 -->
|
<el-dialog
|
v-model="drawingDialogVisible"
|
title="查看图纸"
|
width="800px"
|
:close-on-click-modal="false"
|
>
|
<div class="drawing-container">
|
<div v-if="currentDrawingFiles.length === 0" class="empty-drawing">
|
<el-empty description="暂无图纸" />
|
</div>
|
<div v-else class="drawing-list">
|
<div v-for="(file, index) in currentDrawingFiles" :key="index" class="drawing-item">
|
<el-image
|
v-if="isImage(file.name)"
|
:src="getFileUrl(file)"
|
:preview-src-list="imagePreviewList"
|
fit="cover"
|
style="width: 150px; height: 150px; border-radius: 4px; cursor: pointer;"
|
/>
|
<div v-else class="file-item" @click="downloadFile(file)">
|
<el-icon :size="50"><Document /></el-icon>
|
<span class="file-name">{{ file.name }}</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="drawingDialogVisible = false">关闭</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
</div>
|
</template>
|
|
<script setup>
|
import { onMounted, ref, computed } from "vue";
|
import { ElMessageBox } from "element-plus";
|
import { Setting, Document } from '@element-plus/icons-vue';
|
import dayjs from "dayjs";
|
import { useRouter } from "vue-router";
|
import {
|
productOrderListPage,
|
bindingRoute,
|
listProcessBom, delProductOrder, startOrPause,
|
} from "@/api/productionManagement/productionOrder.js";
|
import { listPage as getProcessRouteList } from "@/api/productionManagement/processRoute.js";
|
import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
|
import { productionProductInputListPage, returnMaterial } from "@/api/productionManagement/productionProductInput.js";
|
import { listPage as listProductStructureRecord, pick as pickMaterial } from "@/api/productionManagement/productStructureRecord.js";
|
|
import {fileDel} from "@/api/financialManagement/revenueManagement.js";
|
import PIMTable from "@/components/PIMTable/PIMTable.vue";
|
const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
|
|
const { proxy } = getCurrentInstance();
|
|
const router = useRouter();
|
const isShowNewModal = ref(false);
|
|
// 查看图纸相关
|
const drawingDialogVisible = ref(false);
|
const currentDrawingFiles = ref([]);
|
|
// 判断是否为图片
|
const isImage = (fileName) => {
|
if (!fileName) return false;
|
const ext = fileName.toLowerCase().split('.').pop();
|
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext);
|
};
|
|
// 获取文件URL
|
const getFileUrl = (file) => {
|
if (file.url) {
|
if (file.url.startsWith('http')) {
|
return file.url;
|
}
|
return import.meta.env.VITE_APP_BASE_API + file.url;
|
}
|
return '';
|
};
|
|
// 图片预览列表
|
const imagePreviewList = computed(() => {
|
return currentDrawingFiles.value
|
.filter(file => isImage(file.name))
|
.map(file => getFileUrl(file));
|
});
|
|
// 下载文件
|
const downloadFile = (file) => {
|
const url = getFileUrl(file);
|
if (url) {
|
const link = document.createElement('a');
|
link.href = url;
|
link.download = file.name;
|
document.body.appendChild(link);
|
link.click();
|
document.body.removeChild(link);
|
}
|
};
|
|
// 显示查看图纸弹窗
|
const showDrawingDialog = (row) => {
|
currentDrawingFiles.value = row.salesLedgerFiles || [];
|
drawingDialogVisible.value = true;
|
};
|
|
// 获取工单圆圈颜色类名
|
// color: 1-灰色 2-黄色 3-绿色 4-红色
|
const getWorkOrderColorClass = (color) => {
|
const colorMap = {
|
1: 'gray',
|
2: 'yellow',
|
3: 'green',
|
4: 'red'
|
};
|
return colorMap[color] || 'gray';
|
};
|
|
const tableColumn = ref([
|
{
|
label: "生产订单号",
|
prop: "npsNo",
|
width: '120px',
|
},
|
{
|
label: "产品名称",
|
prop: "productCategory",
|
width: '120px',
|
},
|
{
|
label: "图纸编号",
|
prop: "specificationModel",
|
width: '160px',
|
},
|
{
|
label: "工艺路线编号",
|
prop: "processRouteCode",
|
width: '200px',
|
},
|
{
|
label: "需求数量",
|
prop: "quantity",
|
},
|
{
|
label: "完成数量",
|
prop: "completeQuantity",
|
},
|
{
|
label: "库存数量",
|
prop: "inventoryQuantity",
|
},
|
{
|
dataType: "slot",
|
label: "工序",
|
prop: "productWorkOrders",
|
slot: "productWorkOrders",
|
width: 200,
|
},
|
{
|
dataType: "slot",
|
label: "完成进度",
|
prop: "completionStatus",
|
slot: "completionStatus",
|
width: 180,
|
},
|
{
|
label: "开始日期",
|
prop: "startTime",
|
formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
|
width: 120,
|
},
|
{
|
label: "结束日期",
|
prop: "endTime",
|
formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
|
width: 120,
|
},
|
{
|
label: "交付日期",
|
prop: "deliveryDate",
|
formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
|
width: 120,
|
},
|
{
|
dataType: "action",
|
label: "操作",
|
align: "center",
|
fixed: "right",
|
width: 420,
|
operation: [
|
{
|
name: "开始",
|
type: "success",
|
showHide: row => row.status === '待生产',
|
clickFun: row => {
|
handleStartOrPause(row);
|
},
|
},
|
{
|
name: "暂停",
|
type: "danger",
|
showHide: row => row.status === '生产中',
|
clickFun: row => {
|
handleStartOrPause(row);
|
},
|
},
|
{
|
name: "领料",
|
type: "success",
|
clickFun: row => {
|
showPickingDialog(row);
|
},
|
},
|
{
|
name: "工艺路线",
|
type: "text",
|
clickFun: row => {
|
showRouteItemModal(row);
|
},
|
},
|
// {
|
// name: "绑定工艺路线",
|
// type: "text",
|
// showHide: row => !row.processRouteCode,
|
// clickFun: row => {
|
// openBindRouteDialog(row);
|
// },
|
// },
|
{
|
name: "物料清单",
|
type: "text",
|
clickFun: row => {
|
showProductStructure(row);
|
},
|
},
|
{
|
name: "投入/退料",
|
type: "text",
|
clickFun: row => {
|
showInputDialog(row);
|
},
|
},
|
{
|
name: "查看图纸",
|
type: "text",
|
showHide: row => row.salesLedgerFiles && row.salesLedgerFiles.length > 0,
|
clickFun: row => {
|
showDrawingDialog(row);
|
},
|
},
|
],
|
},
|
]);
|
const tableData = ref([]);
|
const tableLoading = ref(false);
|
const page = reactive({
|
current: 1,
|
size: 100,
|
total: 0,
|
});
|
const selectedRows = ref([]);
|
|
// 查看投入相关
|
const inputDialogVisible = ref(false);
|
const inputTableData = ref([]);
|
const inputTableLoading = ref(false);
|
const inputCurrentRow = ref(null);
|
const inputSelectedRows = ref([]);
|
const inputPage = reactive({
|
current: 1,
|
size: 100,
|
total: 0,
|
});
|
|
// 领料相关
|
const pickingDialogVisible = ref(false);
|
const pickingTableData = ref([]);
|
const pickingSelectedRows = ref([]);
|
const pickingForm = reactive({
|
orderId: null,
|
});
|
|
|
|
const data = reactive({
|
searchForm: {
|
projectName: "",
|
productCategory: "",
|
},
|
});
|
const { searchForm } = toRefs(data);
|
|
const toProgressPercentage = val => {
|
const n = Number(val);
|
if (!Number.isFinite(n)) return 0;
|
if (n <= 0) return 0;
|
if (n >= 100) return 100;
|
return Math.round(n);
|
};
|
|
// 30/50/80/100 分段颜色:红/橙/蓝/绿
|
const progressColor = percentage => {
|
const p = toProgressPercentage(percentage);
|
if (p < 30) return "#f56c6c";
|
if (p < 50) return "#e6a23c";
|
if (p < 80) return "#409eff";
|
return "#67c23a";
|
};
|
|
// 添加表行类名方法
|
const tableRowClassName = ({ row }) => {
|
if (!row.deliveryDate) return '';
|
if (row.isFh) return '';
|
|
const diff = row.deliveryDaysDiff;
|
if (diff === undefined || diff === null || diff === '' || diff < 0) return '';
|
|
if (diff === 15) {
|
return 'yellow';
|
} else if (diff === 10) {
|
return 'pink';
|
} else if (diff === 2) {
|
return 'purple';
|
} else if (diff < 2) {
|
return 'red';
|
}
|
};
|
|
// 绑定工艺路线弹框
|
const bindRouteDialogVisible = ref(false);
|
const bindRouteLoading = ref(false);
|
const bindRouteSaving = ref(false);
|
const routeOptions = ref([]);
|
const bindForm = reactive({
|
orderId: null,
|
routeId: null,
|
});
|
|
const openBindRouteDialog = async row => {
|
bindForm.orderId = row.id;
|
bindForm.routeId = null;
|
bindRouteDialogVisible.value = true;
|
routeOptions.value = [];
|
bindRouteLoading.value = true;
|
try {
|
const res = await getProcessRouteList({ current: -1, size: -1 });
|
routeOptions.value = res.data?.records || [];
|
} catch (e) {
|
console.error("获取工艺路线列表失败:", e);
|
proxy.$modal.msgError("获取工艺路线列表失败");
|
} finally {
|
bindRouteLoading.value = false;
|
}
|
};
|
|
const handleBindRouteConfirm = async () => {
|
if (!bindForm.routeId) {
|
proxy.$modal.msgWarning("请选择工艺路线");
|
return;
|
}
|
bindRouteSaving.value = true;
|
try {
|
await bindingRoute({
|
id: bindForm.orderId,
|
routeId: bindForm.routeId,
|
});
|
proxy.$modal.msgSuccess("绑定成功");
|
bindRouteDialogVisible.value = false;
|
getList();
|
} catch (e) {
|
console.error("绑定工艺路线失败:", e);
|
proxy.$modal.msgError("绑定工艺路线失败");
|
} finally {
|
bindRouteSaving.value = false;
|
}
|
};
|
|
// 查询列表
|
/** 搜索按钮操作 */
|
const handleQuery = () => {
|
page.current = 1;
|
getList();
|
};
|
const pagination = obj => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
const changeDaterange = value => {
|
if (value) {
|
searchForm.value.entryDateStart = value[0];
|
searchForm.value.entryDateEnd = value[1];
|
} else {
|
searchForm.value.entryDateStart = undefined;
|
searchForm.value.entryDateEnd = undefined;
|
}
|
handleQuery();
|
};
|
const getList = () => {
|
tableLoading.value = true;
|
// 构造一个新的对象,不包含entryDate字段
|
const params = { ...searchForm.value, ...page };
|
params.entryDate = undefined;
|
productOrderListPage(params)
|
.then(res => {
|
tableLoading.value = false;
|
tableData.value = res.data.records;
|
page.total = res.data.total;
|
})
|
.catch(() => {
|
tableLoading.value = false;
|
});
|
};
|
|
const showRouteItemModal = async row => {
|
const orderId = row.id;
|
try {
|
const res = await getOrderProcessRouteMain(orderId);
|
const dataList = res.data || [];
|
if (!dataList || dataList.length === 0 || !dataList[0].id) {
|
proxy.$modal.msgWarning("未找到关联的工艺路线");
|
return;
|
}
|
const data = dataList[0];
|
router.push({
|
path: "/productionManagement/processRouteItem",
|
query: {
|
id: data.id,
|
processRouteCode: data.processRouteCode || "",
|
productName: data.productName || "",
|
drawingNumber: data.drawingNumber || "",
|
model: data.model || "",
|
bomNo: data.bomNo || "",
|
description: data.description || "",
|
orderId,
|
type: "order",
|
},
|
});
|
} catch (e) {
|
console.error("获取工艺路线主信息失败:", e);
|
proxy.$modal.msgError("获取工艺路线信息失败");
|
}
|
};
|
|
const handleStartOrPause = async (row) => {
|
const operation = row.status === '待生产' ? 1 : 2;
|
const operationText = operation === 1 ? "开始" : "暂停";
|
try {
|
await startOrPause({ id: row.id, operation });
|
proxy.$modal.msgSuccess(`${operationText}成功`);
|
getList();
|
} catch (e) {
|
console.error(`${operationText}失败:`, e);
|
proxy.$modal.msgError(`${operationText}失败`);
|
}
|
};
|
|
const showProductStructure = async row => {
|
let bomNo = row.bomNo || "";
|
if (!bomNo && row.id) {
|
try {
|
const res = await getOrderProcessRouteMain(row.id);
|
const dataList = res.data || [];
|
if (dataList && dataList.length > 0 && dataList[0].bomNo) {
|
bomNo = dataList[0].bomNo;
|
}
|
} catch (e) {
|
console.error("获取BOM编号失败:", e);
|
}
|
}
|
router.push({
|
path: "/productionManagement/productStructureDetail",
|
query: {
|
id: row.id,
|
bomNo: bomNo,
|
drawingNumber: row.drawingNumber || "",
|
productName: row.productCategory || "",
|
productModelName: row.specificationModel || "",
|
orderId: row.id,
|
type: "order",
|
},
|
});
|
};
|
|
// 表格选择数据
|
const handleSelectionChange = (selection) => {
|
selectedRows.value = selection;
|
};
|
|
const handleDelete = () => {
|
let ids = [];
|
if (selectedRows.value.length > 0) {
|
ids = selectedRows.value.map((item) => item.id);
|
} else {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
}).then(() => {
|
delProductOrder(ids).then((res) => {
|
proxy.$modal.msgSuccess("删除成功");
|
getList();
|
});
|
}).catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
};
|
|
// 导出
|
const handleOut = () => {
|
ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
proxy.download("/productOrder/export", {...searchForm.value}, "生产订单.xlsx");
|
})
|
.catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
};
|
|
const handleConfirmRoute = () => {};
|
|
// 显示查看投入弹框
|
const showInputDialog = async (row) => {
|
inputCurrentRow.value = row;
|
inputDialogVisible.value = true;
|
inputPage.current = 1;
|
inputPage.total = 0;
|
inputSelectedRows.value = [];
|
fetchInputData();
|
};
|
|
// 查看投入分页
|
const handleInputPagination = (obj) => {
|
inputPage.current = obj.page;
|
inputPage.size = obj.limit;
|
fetchInputData();
|
};
|
|
// 获取投入数据
|
const fetchInputData = () => {
|
inputTableLoading.value = true;
|
const params = { productOrderId: inputCurrentRow.value.id, ...inputPage };
|
productionProductInputListPage(params)
|
.then(res => {
|
inputTableLoading.value = false;
|
inputTableData.value = res.data.records.map(item => ({
|
...item,
|
currentReturnQuantity: 0,
|
}));
|
inputPage.total = res.data.total;
|
})
|
.catch(err => {
|
inputTableLoading.value = false;
|
console.error("获取投入数据失败:", err);
|
});
|
};
|
|
// 显示领料弹框
|
const showPickingDialog = async (row) => {
|
pickingForm.orderId = row.id;
|
pickingDialogVisible.value = true;
|
pickingTableData.value = [];
|
|
// 获取物料清单数据
|
try {
|
const res = await listProductStructureRecord({ productOrderId: row.id });
|
const materials = res.data?.records || [];
|
pickingTableData.value = materials.map(item => ({
|
...item,
|
quantity: 0,
|
unpickedQuantity: (item.demandedQuantity || 0) - (item.completedQuantity || 0),
|
}));
|
} catch (e) {
|
console.error("获取物料清单失败:", e);
|
proxy.$modal.msgError("获取物料清单失败");
|
}
|
};
|
|
// 领料表格选择变化
|
const handlePickingSelectionChange = (selection) => {
|
pickingSelectedRows.value = selection;
|
};
|
|
// 领料数量变化处理
|
const handlePickingQuantityChange = (val, row) => {
|
if (val > row.unpickedQuantity) {
|
proxy.$modal.msgWarning("领料数量不能超过未领料数量");
|
row.quantity = row.unpickedQuantity;
|
}
|
};
|
|
// 确认领料
|
const handlePickingNext = async () => {
|
if (pickingSelectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请选择要领料的物料");
|
return;
|
}
|
// 校验领料数量
|
for (const row of pickingSelectedRows.value) {
|
if (row.quantity > row.unpickedQuantity) {
|
proxy.$modal.msgWarning(`${row.productName} 的领料数量不能超过未领料数量`);
|
return;
|
}
|
if (row.quantity <= 0) {
|
proxy.$modal.msgWarning(`${row.productName} 的领料数量必须大于0`);
|
return;
|
}
|
}
|
|
// 提交领料数据
|
try {
|
const pickData = pickingSelectedRows.value.map(row => ({
|
productOrderId: row.productOrderId,
|
productStructureRecordId: row.id,
|
productModelId: row.productModelId,
|
quantity: row.quantity,
|
}));
|
await pickMaterial(pickData);
|
proxy.$modal.msgSuccess("领料成功");
|
pickingDialogVisible.value = false;
|
} catch (e) {
|
console.error("领料失败:", e);
|
proxy.$modal.msgError("领料失败");
|
}
|
};
|
|
// 领料表格合计方法
|
const summarizePickingTable = (param) => {
|
return proxy.summarizeTable(param, [
|
"quantity",
|
"unpickedQuantity",
|
"inventoryQuantity",
|
"demandedQuantity",
|
]);
|
};
|
|
// 投入表格选择变化
|
const handleInputSelectionChange = (selection) => {
|
inputSelectedRows.value = selection;
|
};
|
|
// 投入退料数量变化处理
|
const handleInputReturnQuantityChange = (val, row) => {
|
const maxReturn = row.quantity - (row.returnQuantity || 0);
|
if (val > maxReturn) {
|
proxy.$modal.msgWarning("本次退料数量不能超过剩余可退数量");
|
row.currentReturnQuantity = maxReturn;
|
}
|
};
|
|
// 确认退料
|
const handleReturnSubmit = async () => {
|
if (inputSelectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请选择要退料的物料");
|
return;
|
}
|
// 校验退料数量
|
const invalidRows = inputSelectedRows.value.filter(row => !row.currentReturnQuantity || row.currentReturnQuantity <= 0);
|
if (invalidRows.length > 0) {
|
proxy.$modal.msgWarning("请填写本次退料数量");
|
return;
|
}
|
|
const returnData = inputSelectedRows.value.map(row => ({
|
...row,
|
returnQuantity: row.currentReturnQuantity,
|
}));
|
|
try {
|
await returnMaterial(returnData);
|
proxy.$modal.msgSuccess("退料成功");
|
inputDialogVisible.value = false;
|
getList();
|
} catch (e) {
|
console.error("退料失败:", e);
|
proxy.$modal.msgError("退料失败");
|
}
|
};
|
|
// 投入表格合计方法
|
const summarizeInputTable = (param) => {
|
return proxy.summarizeTable(param, [
|
"quantity",
|
"returnQuantity",
|
"currentReturnQuantity",
|
]);
|
};
|
|
onMounted(() => {
|
getList();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.search_form{
|
align-items: start;
|
}
|
|
:deep(.yellow) {
|
background-color: #FAF0DE;
|
}
|
|
:deep(.pink) {
|
background-color: #FAE1DE;
|
}
|
|
:deep(.red) {
|
background-color: #FFCCCC;
|
}
|
|
:deep(.purple){
|
background-color: #F4DEFA;
|
}
|
|
.picking-footer-info {
|
display: flex;
|
justify-content: space-between;
|
padding: 10px;
|
font-size: 14px;
|
color: #606266;
|
}
|
|
.drawing-container {
|
min-height: 200px;
|
}
|
|
.empty-drawing {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
min-height: 200px;
|
}
|
|
.drawing-list {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 16px;
|
padding: 10px;
|
}
|
|
.drawing-item {
|
border: 1px solid #dcdfe6;
|
border-radius: 4px;
|
overflow: hidden;
|
transition: all 0.3s;
|
|
&:hover {
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
}
|
}
|
|
.file-item {
|
width: 150px;
|
height: 150px;
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
background: #f5f7fa;
|
cursor: pointer;
|
padding: 10px;
|
|
.file-name {
|
font-size: 12px;
|
color: #606266;
|
margin-top: 10px;
|
text-align: center;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
max-width: 130px;
|
}
|
|
&:hover {
|
background: #e4e7ed;
|
}
|
}
|
|
// 工单圆圈样式
|
.work-order-circles {
|
display: flex;
|
gap: 8px;
|
flex-wrap: wrap;
|
align-items: center;
|
}
|
|
.work-order-circle {
|
width: 32px;
|
height: 32px;
|
border-radius: 6px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
font-size: 12px;
|
font-weight: 500;
|
color: #fff;
|
cursor: pointer;
|
transition: all 0.2s ease;
|
|
// 灰色 - 待开始
|
&.gray {
|
background-color: #909399;
|
|
&:hover {
|
background-color: #a6a9ad;
|
}
|
}
|
|
// 黄色 - 进行中
|
&.yellow {
|
background-color: #e6a23c;
|
|
&:hover {
|
background-color: #ebb563;
|
}
|
}
|
|
// 绿色 - 已完成
|
&.green {
|
background-color: #67c23a;
|
|
&:hover {
|
background-color: #85ce61;
|
}
|
}
|
|
// 红色 - 异常/暂停
|
&.red {
|
background-color: #f56c6c;
|
|
&:hover {
|
background-color: #f78989;
|
}
|
}
|
|
&:hover {
|
transform: translateY(-2px);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
}
|
}
|
|
</style>
|