You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
616 lines
17 KiB
616 lines
17 KiB
<template>
|
|
<div class="customer-css">
|
|
<el-dialog :title="titleCon" v-drag v-bind="$attrs" v-on="$listeners"
|
|
width="600px" class="material-dialog">
|
|
<div class="material-content">
|
|
<el-form :model="pageData" label-position="top" label-width="100px">
|
|
<!-- 材料信息卡片 -->
|
|
<div class="material-info-card">
|
|
<div class="info-header">
|
|
<i class="el-icon-document"></i>
|
|
<span>材料信息</span>
|
|
</div>
|
|
<div class="info-content">
|
|
<el-row :gutter="15">
|
|
<el-col :span="12">
|
|
<div class="info-row">
|
|
<label class="info-label">材料卷号:</label>
|
|
<span class="info-value">{{ pageData.rmRollNo || '-' }}</span>
|
|
</div>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<div class="info-row">
|
|
<label class="info-label">零部件编码:</label>
|
|
<span class="info-value">{{ pageData.partNo || '-' }}</span>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row :gutter="15">
|
|
<el-col :span="24">
|
|
<div class="info-row">
|
|
<label class="info-label">零部件名称:</label>
|
|
<span class="info-value">{{ pageData.partDesc || '-' }}</span>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row :gutter="15">
|
|
<el-col :span="12">
|
|
<div class="info-row">
|
|
<label class="info-label">规格型号:</label>
|
|
<span class="info-value">{{ pageData.spec || '-' }}</span>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 损耗设置区域 -->
|
|
<div class="return-settings">
|
|
<el-row :gutter="15">
|
|
<el-col :span="8">
|
|
<el-form-item label="上机数量" class="form-item-enhanced">
|
|
<el-input
|
|
v-model="displayOnMachineQty"
|
|
disabled
|
|
size="large"
|
|
style="width: 100%">
|
|
</el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="8">
|
|
<el-form-item label="暂存数量" class="form-item-enhanced">
|
|
<el-input class="inlineNumber numInput"
|
|
v-model="pageData.returnQty"
|
|
type="number"
|
|
placeholder="请输入暂存数量"
|
|
size="large"
|
|
@input="calculateRemainQty"
|
|
style="width: 100%">
|
|
</el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="8">
|
|
<el-form-item label="剩余数量" class="form-item-enhanced">
|
|
<el-input
|
|
v-model="displayRemainQty"
|
|
disabled
|
|
size="large"
|
|
:class="{'remain-negative': pageData.remainQty < 0}"
|
|
style="width: 100%">
|
|
</el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<!-- 备注 -->
|
|
<el-row style="margin-bottom: 30px">
|
|
<el-col :span="24">
|
|
<el-form-item label="备注" >
|
|
<el-input
|
|
v-model="pageData.remark"
|
|
type="textarea"
|
|
:rows="3"
|
|
placeholder="请输入备注"
|
|
show-word-limit>
|
|
</el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
</div>
|
|
</el-form>
|
|
</div>
|
|
|
|
<span slot="footer" class="dialog-footer">
|
|
<button class="action-btn secondary" @click="submitMaterialLoss">
|
|
{{ buttons.confirmButton }}
|
|
</button>
|
|
<button class="action-btn secondary" @click="closeDialog">
|
|
{{ buttons.closeButton }}
|
|
</button>
|
|
</span>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import {
|
|
materialProcessLoss
|
|
} from '@/api/yieldReport/com_material_loss.js';
|
|
import getLodop from '@/utils/LodopFuncs.js'; // 打印控件
|
|
import labelPrintTemplates from '@/mixins/labelPrintTemplates.js'; // 打印模板mixin
|
|
|
|
var functionId = 'C10000019';
|
|
|
|
export default {
|
|
mixins: [labelPrintTemplates], // 添加打印模板mixin
|
|
data() {
|
|
return {
|
|
titleCon: '材料暂存',
|
|
scheduleData: {
|
|
site: this.$store.state.user.site,
|
|
username: this.$store.state.user.name,
|
|
seqNo: '',
|
|
orderNo: '',
|
|
itemNo: 0,
|
|
},
|
|
pageData: {
|
|
site: this.$store.state.user.site,
|
|
orderNo: '',
|
|
itemNo: '',
|
|
seqNo: '',
|
|
rollNo: '',
|
|
rmRollNo: '',
|
|
partNo: '',
|
|
partDesc: '',
|
|
spec: '',
|
|
onMachineQty: 0, // 上机数量(来自行数据的数量)
|
|
returnQty: 0, // 损耗数量
|
|
remainQty: 0, // 剩余数量
|
|
remark: '', // 备注
|
|
histSeqNo: '',
|
|
operatorId: '',
|
|
},
|
|
operatorData: {
|
|
site: this.$store.state.user.site,
|
|
username: this.$store.state.user.name,
|
|
operatorId: '',
|
|
operatorName: '',
|
|
},
|
|
buttons: {
|
|
confirmButton: '确定',
|
|
closeButton: '关闭',
|
|
},
|
|
}
|
|
},
|
|
computed: {
|
|
// 显示上机数量(如果为0或空则显示空字符串)
|
|
displayOnMachineQty() {
|
|
return this.pageData.onMachineQty || this.pageData.onMachineQty === 0 ? String(this.pageData.onMachineQty) : '';
|
|
},
|
|
// 显示剩余数量(如果为0或空则显示空字符串)
|
|
displayRemainQty() {
|
|
return this.pageData.remainQty || this.pageData.remainQty === 0 ? String(this.pageData.remainQty) : '';
|
|
}
|
|
},
|
|
methods: {
|
|
//初始化组件的参数
|
|
init(scheduleData, operatorData, materialRow) {
|
|
//初始化参数
|
|
this.scheduleData = scheduleData;
|
|
this.operatorData = JSON.parse(JSON.stringify(operatorData));
|
|
|
|
//设置材料信息
|
|
this.pageData.orderNo = scheduleData.orderNo;
|
|
this.pageData.itemNo = scheduleData.itemNo;
|
|
this.pageData.seqNo = scheduleData.seqNo;
|
|
this.pageData.rollNo = scheduleData.rollNo;
|
|
this.pageData.operatorId = operatorData.operatorId;
|
|
|
|
// 从行数据获取材料信息
|
|
this.pageData.rmRollNo = materialRow.rmRollNo || '';
|
|
this.pageData.partNo = materialRow.partNo || '';
|
|
this.pageData.partDesc = materialRow.partDesc || '';
|
|
this.pageData.spec = materialRow.spec || '';
|
|
this.pageData.histSeqNo = materialRow.histSeqNo || '';
|
|
|
|
// 获取上机数量(从行数据的 transQty 字段)
|
|
const transQty = parseFloat(materialRow.transQty);
|
|
this.pageData.onMachineQty = isNaN(transQty) ? 0 : transQty;
|
|
// 重置损耗数量、剩余数量和备注
|
|
this.pageData.returnQty = 0;
|
|
this.pageData.remainQty = this.pageData.onMachineQty;
|
|
this.pageData.remark = '';
|
|
|
|
this.titleCon = '材料暂存';
|
|
},
|
|
|
|
/*关闭modal*/
|
|
closeDialog(){
|
|
//刷新报工的页面
|
|
this.$emit('refreshPageData');
|
|
//关闭当前的页面
|
|
this.$emit('update:visible', false);
|
|
},
|
|
|
|
/*计算剩余数量*/
|
|
calculateRemainQty() {
|
|
const onMachineQty = parseFloat(this.pageData.onMachineQty) || 0;
|
|
const returnQty = parseFloat(this.pageData.returnQty) || 0;
|
|
this.pageData.remainQty = onMachineQty - returnQty;
|
|
},
|
|
|
|
/*提交损耗*/
|
|
submitMaterialLoss() {
|
|
// 如果没有填写损耗数量,默认为0
|
|
if (!this.pageData.returnQty || this.pageData.returnQty === '' || this.pageData.returnQty < 0) {
|
|
this.pageData.returnQty = 0;
|
|
}
|
|
|
|
// 计算剩余数量
|
|
this.calculateRemainQty();
|
|
|
|
// 验证剩余数量必须大于等于0
|
|
if (this.pageData.remainQty < 0) {
|
|
this.$message.warning('暂存数量不能大于上机数量!');
|
|
return false;
|
|
}
|
|
|
|
// 构建提交数据(只传损耗数量和备注,不传上机数量和剩余数量)
|
|
const submitData = {
|
|
site: this.pageData.site,
|
|
orderNo: this.pageData.orderNo,
|
|
itemNo: this.pageData.itemNo,
|
|
seqNo: this.pageData.seqNo,
|
|
rollNo: this.pageData.rmRollNo,
|
|
returnQty: this.pageData.returnQty,
|
|
histSeqNo: this.pageData.histSeqNo,
|
|
operatorId: this.pageData.operatorId,
|
|
remark: this.pageData.remark || '' // 备注(可选,默认为空字符串)
|
|
};
|
|
|
|
// 调用后端API(调用 MaterialProcessLoss 存储过程)
|
|
materialProcessLoss(submitData).then(({data}) => {
|
|
//判断是否存在异常
|
|
if(data.code == 500 || data.code == 400){
|
|
this.$message.error(data.msg || data.message);
|
|
} else if (data.code == 201) {
|
|
// code=201 表示需要打印标签
|
|
this.$message.success(data.msg || '操作成功');
|
|
|
|
// 获取打印参数并打印(存储过程返回的打印参数在printData中)
|
|
if (data.printData) {
|
|
// 将单个打印数据对象包装成数组
|
|
const printDataList = [data.printData];
|
|
this.executePrint(printDataList);
|
|
} else {
|
|
console.warn('未获取到打印参数');
|
|
}
|
|
|
|
//关闭当前的页面
|
|
this.closeDialog();
|
|
} else {
|
|
//先提示 后关闭
|
|
this.$message.success(data.msg || data.message || '操作成功');
|
|
//关闭当前的页面
|
|
this.closeDialog();
|
|
}
|
|
}).catch((error) => {
|
|
this.$message.error('操作失败:' + (error.message || '未知错误'));
|
|
});
|
|
},
|
|
|
|
/**
|
|
* 执行打印(直接使用存储过程返回的打印参数)
|
|
* @param {Array} printDataList - 存储过程返回的打印数据列表
|
|
*/
|
|
executePrint(printDataList) {
|
|
try {
|
|
// 1. 获取 LODOP 打印控件
|
|
const LODOP = getLodop();
|
|
if (!LODOP) {
|
|
this.$message.warning('无法连接到打印控件,跳过打印');
|
|
return;
|
|
}
|
|
|
|
// 2. 获取默认打印机
|
|
const printerCount = LODOP.GET_PRINTER_COUNT();
|
|
if (printerCount === 0) {
|
|
this.$message.warning('未检测到打印机,跳过打印');
|
|
return;
|
|
}
|
|
const defaultPrinterName = LODOP.GET_PRINTER_NAME(0);
|
|
|
|
// 3. 检查打印数据中的labelNo(标签模板编号)
|
|
if (!printDataList || printDataList.length === 0) {
|
|
console.warn('打印数据为空');
|
|
return;
|
|
}
|
|
|
|
// 获取第一条数据的labelNo
|
|
const labelNo = printDataList[0].labelNo;
|
|
if (!labelNo) {
|
|
console.warn('未找到标签模板编号');
|
|
return;
|
|
}
|
|
|
|
// 4. 执行模板打印
|
|
this.executePrintWithTemplate(LODOP, printDataList, labelNo, defaultPrinterName);
|
|
|
|
this.$message.success('标签打印任务已发送!');
|
|
|
|
} catch (error) {
|
|
console.error('打印失败:', error);
|
|
this.$message.warning('打印失败: ' + error.message);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 执行模板打印
|
|
* @param {Object} LODOP - 打印控件对象
|
|
* @param {Array} printDataList - 打印数据列表
|
|
* @param {String} labelNo - 标签模板编号 (A001/A002/A003)
|
|
* @param {String} printerName - 打印机名称
|
|
*/
|
|
executePrintWithTemplate(LODOP, printDataList, labelNo, printerName) {
|
|
LODOP.PRINT_INIT('材料暂存标签打印');
|
|
|
|
// 设置打印模式,隐藏水印
|
|
LODOP.SET_PRINT_MODE("PRINT_NOCOLLATE", true);
|
|
|
|
// 设置打印机
|
|
LODOP.SET_PRINTER_INDEX(printerName);
|
|
|
|
// 循环打印每个标签
|
|
for (let i = 0; i < printDataList.length; i++) {
|
|
const printData = printDataList[i];
|
|
const isNewPage = i > 0;
|
|
// 根据 labelNo 调用不同的打印方法(来自 labelPrintTemplates mixin)
|
|
if (labelNo === 'A001') {
|
|
this.printLabelA001(LODOP, printData, isNewPage);
|
|
} else if (labelNo === 'A002') {
|
|
this.printLabelA002(LODOP, printData, isNewPage);
|
|
} else if (labelNo === 'A003') {
|
|
this.printLabelA003(LODOP, printData, isNewPage);
|
|
} else {
|
|
console.warn(`未知的标签模板:${labelNo}`);
|
|
}
|
|
}
|
|
|
|
// 预览打印(避免水印)
|
|
LODOP.PREVIEW();
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.numInput /deep/ .el-input__inner{
|
|
text-align: right;
|
|
}
|
|
/deep/ .inlineNumber input::-webkit-outer-spin-button,
|
|
/deep/ .inlineNumber input::-webkit-inner-spin-button {
|
|
-webkit-appearance: none;
|
|
|
|
}
|
|
/deep/ .inlineNumber input[type="number"]{
|
|
-moz-appearance: textfield;
|
|
padding-right: 5px !important;
|
|
}
|
|
|
|
// 材料暂存对话框样式
|
|
.material-dialog {
|
|
::v-deep .el-dialog {
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
|
|
.el-dialog__header {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
padding: 18px 20px;
|
|
|
|
.el-dialog__title {
|
|
color: #fff;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.el-dialog__headerbtn {
|
|
.el-dialog__close {
|
|
color: #fff;
|
|
font-size: 18px;
|
|
|
|
&:hover {
|
|
color: #f0f0f0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.el-dialog__body {
|
|
padding: 25px;
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.el-dialog__footer {
|
|
padding: 15px 20px;
|
|
background-color: #fff;
|
|
border-top: 1px solid #e9ecef;
|
|
}
|
|
}
|
|
}
|
|
|
|
.material-content {
|
|
.form-item-enhanced {
|
|
margin-bottom: 10px;
|
|
|
|
::v-deep .el-form-item__label {
|
|
color: #495057;
|
|
font-weight: 500;
|
|
font-size: 14px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
::v-deep .el-input {
|
|
.el-input__inner {
|
|
border-radius: 6px;
|
|
border: 1px solid #dee2e6;
|
|
transition: all 0.3s;
|
|
height: 42px;
|
|
line-height: 42px;
|
|
font-size: 15px;
|
|
|
|
&:focus {
|
|
border-color: #667eea;
|
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 文本域样式
|
|
::v-deep .el-textarea {
|
|
.el-textarea__inner {
|
|
border-radius: 6px;
|
|
border: 1px solid #dee2e6;
|
|
transition: all 0.3s;
|
|
font-size: 14px;
|
|
padding: 8px 12px;
|
|
line-height: 1.5;
|
|
|
|
&:focus {
|
|
border-color: #667eea;
|
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 剩余数量为负数时的红色警告样式
|
|
::v-deep .remain-negative {
|
|
.el-input__inner {
|
|
color: #f56c6c;
|
|
font-weight: 600;
|
|
border-color: #f56c6c;
|
|
background-color: #fef0f0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 物料信息卡片样式 - 白色框连起来
|
|
.material-info-card {
|
|
background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%);
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
margin-bottom: 20px;
|
|
border: 1px solid #e3e8f0;
|
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.08);
|
|
animation: fadeInDown 0.5s ease-out;
|
|
|
|
.info-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 12px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid #dee2e6;
|
|
|
|
i {
|
|
font-size: 18px;
|
|
color: #667eea;
|
|
margin-right: 8px;
|
|
}
|
|
|
|
span {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: #495057;
|
|
}
|
|
}
|
|
|
|
.info-content {
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|
border-radius: 4px;
|
|
padding: 12px;
|
|
|
|
.info-row {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 4px 0;
|
|
|
|
&:not(:last-child) {
|
|
border-bottom: 1px dashed #e9ecef;
|
|
}
|
|
|
|
.info-label {
|
|
font-size: 13px;
|
|
color: #6c757d;
|
|
min-width: 90px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.info-value {
|
|
font-size: 13px;
|
|
color: #212529;
|
|
font-weight: 600;
|
|
flex: 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 暂存设置区域
|
|
.return-settings {
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
border: 1px solid #e3e8f0;
|
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.05);
|
|
}
|
|
|
|
// 底部按钮样式
|
|
.dialog-footer {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 12px;
|
|
padding: 0;
|
|
|
|
.action-btn {
|
|
min-width: 80px;
|
|
padding: 6px 16px;
|
|
border-radius: 16px;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
|
|
i {
|
|
font-size: 13px;
|
|
}
|
|
|
|
&.primary {
|
|
background: #17B3A3;
|
|
border: none;
|
|
color: white;
|
|
|
|
&:hover {
|
|
background: #13998b;
|
|
box-shadow: 0 4px 12px rgba(23, 179, 163, 0.4);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
&:active {
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
&.secondary {
|
|
background: white;
|
|
border: 1px solid #17B3A3;
|
|
color: #17B3A3;
|
|
|
|
&:hover {
|
|
background: #17B3A3;
|
|
color: white;
|
|
}
|
|
|
|
&:active {
|
|
transform: scale(0.98);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 动画效果
|
|
@keyframes fadeInDown {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(-10px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
</style>
|
|
|