6 changed files with 1293 additions and 6 deletions
-
7src/api/yieldReport/com_material_loss.js
-
7src/api/yieldReport/com_material_roll_up.js
-
4src/views/modules/qc/OQCResultEntry.vue
-
616src/views/modules/yieldReport/com_material_loss.vue
-
616src/views/modules/yieldReport/com_material_roll_up.vue
-
49src/views/modules/yieldReport/com_produce_report_normal.vue
@ -0,0 +1,7 @@ |
|||
import { createAPI } from '@/utils/httpRequest.js' |
|||
|
|||
/** |
|||
* 材料损耗(调用 MaterialProcessLoss 存储过程) |
|||
*/ |
|||
export const materialProcessLoss = data => createAPI(`/pms/yieldReportCommons/materialProcessLoss`, 'post', data) |
|||
|
|||
@ -0,0 +1,7 @@ |
|||
import { createAPI } from '@/utils/httpRequest.js' |
|||
|
|||
/** |
|||
* 材料接卷(调用 MaterialProcessRollUp 存储过程) |
|||
*/ |
|||
export const materialProcessRollUp = data => createAPI(`/pms/yieldReportCommons/materialProcessRollUp`, 'post', data) |
|||
|
|||
@ -0,0 +1,616 @@ |
|||
<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> |
|||
|
|||
@ -0,0 +1,616 @@ |
|||
<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="submitMaterialRollUp"> |
|||
{{ buttons.confirmButton }} |
|||
</button> |
|||
<button class="action-btn secondary" @click="closeDialog"> |
|||
{{ buttons.closeButton }} |
|||
</button> |
|||
</span> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { |
|||
materialProcessRollUp |
|||
} from '@/api/yieldReport/com_material_roll_up.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; |
|||
}, |
|||
|
|||
/*提交接卷*/ |
|||
submitMaterialRollUp() { |
|||
// 如果没有填写接卷数量,默认为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(调用 MaterialProcessRollUp 存储过程) |
|||
materialProcessRollUp(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> |
|||
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue