Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
tangyu 2025-06-11 10:54:43 +08:00
commit 77fff67d8f
15 changed files with 1526 additions and 30 deletions

View File

@ -108,3 +108,11 @@ export function operationOut(obj) {
data: obj
})
}
export function readBomComponentMultiShopOrder(obj) {
return request({
url: iep('/operation-out/readBomComponentMultiShopOrder'),
method: 'post',
data: obj
})
}

View File

@ -0,0 +1,48 @@
import request from "@/router/axios";
import {iep} from "@/api/prefix";
// 获取设备故障代码列表
export function getAbnCodeList(obj) {
return request({
url: iep('/equipment-abn-history/getAbnCodeList'),
method: 'post',
data: obj,
})
}
// 获取设备故障代码列表
export function getEquipAbnHistoryPage(query) {
return request({
url: iep('/equipment-abn-history/page'),
method: 'get',
params: query,
})
}
// 查询班次
export function getShiftList(query) {
return request({
url: iep('/equipment-abn-history/getShiftList'),
method: 'get',
params: query,
})
}
// 查询班次
export function getResrceByCode(query) {
return request({
url: iep('/equipment-abn-history/getResrceByCode'),
method: 'get',
params: query,
})
}
// 保存
export function saveEquipAbnHistory(data) {
return request({
url: iep('/equipment-abn-history/'),
method: 'post',
data: data,
})
}

View File

@ -0,0 +1,11 @@
import request from '@/router/axios'
import {iep} from '@/api/prefix'
// 检索主列表数据
export function readOutCostReportPage(query) {
return request({
url: iep('/nlv-wip/readOutCostReportPage'),
method: 'get',
params: query
})
}

View File

@ -8,10 +8,13 @@
width="60%"
center
:append-to-body="true"
@close="handleClose"
:show-close="false"
>
<div style="background-color: #f7f7f7; border-radius: 10px; padding: 10px; margin-top: -30px">
<h2>{{ $t('mes.inspectionItem') }} :{{ form.qcItem }} / {{ form.qcItemDesc }}</h2>
<h2>
<span v-if="form.isRequired === 'Y'" style="color: red;">*</span>
{{ $t('mes.inspectionItem') }} :{{ form.qcItem }} / {{ form.qcItemDesc }}
</h2>
<el-row>
<el-col :span="2"> {{ $t('mes.qms.samplingNumber') }}: {{ form.sampleSize }} </el-col>
</el-row>
@ -88,6 +91,13 @@
</el-tab-pane>
</el-tabs>
<div style="width: 100%; display: flex; justify-content: center; margin-top: 20px">
<el-button
type="primary"
icon="el-icon-circle-plus-outline"
size="small"
@click="previousItem"
>上一项
</el-button>
<el-button
v-if="state !== 'view'"
type="primary"
@ -96,6 +106,13 @@
@click="handleSave"
>{{ $t('el.button.save') }}
</el-button>
<el-button
type="primary"
icon="el-icon-circle-plus-outline"
size="small"
@click="nextItem"
>下一项
</el-button>
<el-button icon="el-icon-circle-close" size="small" @click="handleClose"
>{{ state == 'view' ? $t('mes.close') : $t('common.cancel') }}
</el-button>
@ -145,6 +162,7 @@ import { saveIqcDetailResult } from '@/api/mes/qms/inspec-job'
import { copyJSON } from '@/util/util'
import { hideLoading, showLoading } from '@/const/loading'
import { setSeq } from '@/util/table'
import {isBlank} from "@/util/string";
export default {
components: { inspecFactor, inspecResult },
name: 'inspec-count',
@ -234,9 +252,29 @@ export default {
this.$set(this.tableData[index].value, `inv`, [])
})
},
handleClose() {
// 上一项
previousItem() {
// 1.关闭当前页面,并把按钮类型传过去 'previousOrNextButton'
this.handleClose('previousOrNextButton');
// 调用父组件的方法打开上一项
this.$parent.preInspecItem();
},
// 下一项
nextItem() {
// 1.关闭当前页面,并把按钮类型传过去 'previousOrNextButton'
this.handleClose('previousOrNextButton');
// 调用父组件的方法打开上一项
this.$parent.nextInspecItem(); // 调用父组件的方法打开下一项
},
handleClose(buttonType) {
this.$emit('update:visible', false)
this.$emit('close', 'countModel')
if(isBlank(buttonType)) {
this.$emit('close', 'countModel')
} else {
this.$emit('close', buttonType)
}
},
handleSave() {
this.setData(this.form)
@ -271,6 +309,7 @@ export default {
handle: row.handle,
inspecJobBo: row.inspecJobBo,
inspecResultList: list,
qcItem: row.qcItem,
factorList: box,
}
},
@ -280,7 +319,7 @@ export default {
.then(() => {
hideLoading()
this.$message.success(this.$t('mes.save_successful'))
this.handleClose()
// this.handleClose()
})
.catch((e) => {
hideLoading()

View File

@ -8,13 +8,14 @@
width="60%"
:visible.sync="formVisible"
:title="title"
@close="closeForm"
center
top="50px"
:show-close="false"
>
<el-card class="box-card" :body-style="{ padding: '0px' }">
<div style="background-color: #f5f5f5; padding: 10px">
<h2 style="display: inline">
<span v-if="form.isRequired === 'Y'" style="color: red;">*</span>
{{ $t('mes.inspectionItem') }}: {{ `${form.qcItem} / ${form.qcItemDesc}` }}
</h2>
<div class="iqc-inspec-measure-title">
@ -100,6 +101,13 @@
</el-tabs>
<div style="width: 100%; display: flex; justify-content: center; margin-top: 20px">
<span slot="footer" class="dialog-footer">
<el-button
type="primary"
icon="el-icon-circle-plus-outline"
size="small"
@click="previousItem"
>上一项
</el-button>
<el-button
v-if="state != 'view'"
type="primary"
@ -108,6 +116,13 @@
@click="handleSave"
>{{ $t('el.button.save') }}
</el-button>
<el-button
type="primary"
icon="el-icon-circle-plus-outline"
size="small"
@click="nextItem"
>下一项
</el-button>
<el-button icon="el-icon-circle-close" size="small" @click="closeForm"
>{{ state == 'view' ? $t('mes.close') : $t('common.cancel') }}
</el-button>
@ -126,6 +141,7 @@ import { saveIqcDetailResult } from '@/api/mes/qms/inspec-job'
import { numberControl } from '@/util/number'
import { controlMode } from '../init'
import { setSeq } from '@/util/table'
import {isBlank} from "@/util/string";
export default {
components: {
inspecFactor,
@ -334,16 +350,38 @@ export default {
.then(() => {
hideLoading()
this.$message.success(this.$t('mes.save_successful'))
this.closeForm()
// this.closeForm()
})
.catch(() => {
hideLoading()
})
},
closeForm() {
this.$emit('update:visible', false)
this.$emit('close', 'measureModel')
},
// 上一项
previousItem() {
// 1.关闭当前页面,并把按钮类型传过去 'previousOrNextButton'
this.closeForm('previousOrNextButton');
// 调用父组件的方法打开上一项
this.$parent.preInspecItem();
},
// 下一项
nextItem() {
// 1.关闭当前页面,并把按钮类型传过去 'previousOrNextButton'
this.closeForm('previousOrNextButton');
// 调用父组件的方法打开上一项
this.$parent.nextInspecItem(); // 调用父组件的方法打开下一项
},
closeForm(buttonType) {
this.$emit('update:visible', false)
if(isBlank(buttonType)) {
this.$emit('close', 'measureModel')
} else {
this.$emit('close', buttonType)
}
},
// 数字输入限制
numInputChange(num, index, row, key) {
let data = {

View File

@ -8,13 +8,14 @@
width="60%"
:visible.sync="formVisible"
:title="title"
@close="closeForm"
center
top="100px"
:show-close="false"
>
<el-card class="box-card" :body-style="{ padding: '0px' }">
<div style="background-color: #f5f5f5; padding: 10px">
<h2 style="display: inline">
<span v-if="form.isRequired === 'Y'" style="color: red;">*</span>
{{ $t('mes.inspectionItem') }}: {{ `${form.qcItem} / ${form.qcItemDesc}` }}
</h2>
<div style="margin: 10px 0">{{ $t('mes.qms.textContentDescription') }}: {{ form.content }}</div>
@ -117,6 +118,13 @@
</el-tabs>
<div style="width: 100%; display: flex; justify-content: center; margin-top: 20px">
<span slot="footer" class="dialog-footer">
<el-button
type="primary"
icon="el-icon-circle-plus-outline"
size="small"
@click="previousItem"
>上一项
</el-button>
<el-button
v-if="state != 'view'"
type="primary"
@ -125,6 +133,13 @@
@click="handleSave"
>{{ $t('el.button.save') }}
</el-button>
<el-button
type="primary"
icon="el-icon-circle-plus-outline"
size="small"
@click="nextItem"
>下一项
</el-button>
<el-button icon="el-icon-circle-close" size="small" @click="closeForm"
>{{ state == 'view' ? $t('mes.close') : $t('common.cancel') }}
</el-button>
@ -141,6 +156,7 @@ import inspecFactor from '@/views/mes/qms/inspec/content/inspec-factor.vue'
import inspecResult from './inspec-result.vue'
import { saveIqcDetailResult } from '@/api/mes/qms/inspec-job'
import {numberControl} from "@/util/number";
import {isBlank} from "@/util/string";
export default {
components: {
inspecFactor,
@ -322,7 +338,7 @@ export default {
.then(() => {
hideLoading()
this.$message.success(this.$t('mes.save_successful'))
this.closeForm()
// this.closeForm()
})
.catch(() => {
hideLoading()
@ -334,9 +350,30 @@ export default {
this.setData(this.form)
this.saveAPI(this.reqObj)
},
closeForm() {
// 上一项
previousItem() {
// 1.关闭当前页面,并把按钮类型传过去 'previousOrNextButton'
this.closeForm('previousOrNextButton');
// 调用父组件的方法打开上一项
this.$parent.preInspecItem();
},
// 下一项
nextItem() {
// 1.关闭当前页面,并把按钮类型传过去 'previousOrNextButton'
this.closeForm('previousOrNextButton');
// 调用父组件的方法打开上一项
this.$parent.nextInspecItem(); // 调用父组件的方法打开下一项
},
closeForm(buttonType) {
this.$emit('update:visible', false)
this.$emit('close', 'textModel')
if(isBlank(buttonType)) {
this.$emit('close', 'textModel')
} else {
this.$emit('close', buttonType)
}
},
},
}

View File

@ -32,6 +32,7 @@ export const closeForm = {
testsampleQty: '0',
}
export const textForm = {
isRequired: '',
qcItem: '',
qcItemDesc: '',
contentDesc: '',
@ -53,6 +54,7 @@ export const textForm = {
}
export const measureForm = {
isRequired: '',
qcItem: '',
qcItemDesc: '',
sampleSize: 5,

View File

@ -402,7 +402,8 @@ export default {
toErp: false,
toOa: false,
toWms: false,
}
currentInspecIndex: -1, // 当前正在处理的检验项索引
}
},
computed: {
...mapGetters(['permissions', 'userInfo']),
@ -743,6 +744,7 @@ export default {
},
//qc table按鈕
async handleCommandQc(e, row, index) {
this.currentInspecIndex = index
switch (e) {
case 'view':
this.state = 'view'
@ -930,11 +932,67 @@ export default {
if (this.tableLoading) return
this.searchChange()
},
// 上一项
preInspecItem() {
// 关闭所有可能的弹窗
this.visibleCount = false;
this.visibleMeasure = false;
this.visibleText = false;
// 移动到上一项
this.currentInspecIndex -= 1;
this.nextOrPreviousItem(this.currentInspecIndex);
},
// 下一项
nextInspecItem() {
// 关闭所有可能的弹窗
this.visibleCount = false;
this.visibleMeasure = false;
this.visibleText = false;
// 移动到下一项
this.currentInspecIndex += 1;
this.nextOrPreviousItem(this.currentInspecIndex);
},
// 打开下一项或上一项数据
async nextOrPreviousItem(index) {
const row = this.qcTable[index];
if (!row) {
await this.searchChange()
await this.getOneDetailAPI(this.jobRow)
return;
}
switch (row.itemType) {
case '0':
// 計數
if (this.ncData.length > 0) {
this.ncData.forEach((n) => (n.disabled = this.state === 'view'))
}
await this.getOneDetailResultAPI(row, 'countModel')
this.visibleCount = true
break
case '1':
// 計量
await this.getOneDetailResultAPI(row, 'measureModel')
this.visibleMeasure = true
break
case '2':
// 內文
await this.getOneDetailResultAPI(row, 'textModel')
this.visibleText = true
break
}
},
async afterClose(key) {
this[key] = {}
if (this.tableLoadingQC) return
await this.searchChange()
await this.getOneDetailAPI(this.jobRow)
if (key !== 'previousOrNextButton') {
this[key] = {}
if (this.tableLoadingQC) return
await this.searchChange()
await this.getOneDetailAPI(this.jobRow)
}
},
},
}

View File

@ -0,0 +1,719 @@
<template>
<div class="execution">
<!-- 设备 弹出框 -->
<input-select-dialog
:modal-obj="resrceDialogObj"
:modal-fetch-fun="resrceDialogObj.fetchFun"
:modal-show.sync="resrceDialogObj.visible"
:before-loading-fun="fetchFilterResrce"
@inputDialogSelected="(row) => {dialogSelected(row, 'resrce')}"
/>
<basic-container>
<!-- 搜索条件区域 -->
<el-form ref="formObj" :model="formObj" :rules="formRules" label-width="120px">
<!-- 第一行 -->
<el-row :gutter="24">
<!-- 设备编码 -->
<el-col :span="6">
<el-form-item label="设备编码:" prop="resrce">
<el-input placeHolder="设备编码+" v-model="formObj.resrce" clearable>
<i slot="suffix" class="el-input__icon el-icon-copy-document" @click.stop="openDialog('resrce')"/>
</el-input>
</el-form-item>
</el-col>
<!-- 班次 -->
<el-col :span="6">
<el-form-item label="班次:" prop="shift">
<el-select v-model="formObj.shiftList" multiple clearable>
<el-option v-for="item in shiftList" :key="item.userWorkShift" :label="`${item.userWorkShift} - ${item.description}`" :value="item.userWorkShift"/>
</el-select>
</el-form-item>
</el-col>
<!-- 异常代码 -->
<el-col :span="6">
<el-form-item label="异常代码:" prop="abnCode">
<el-select v-model="formObj.abnCodeList" multiple clearable>
<el-option v-for="item in abnCodeSearchList" :key="item.reasonCode" :label="`${item.reasonCode} - ${item.description}`" :value="item.reasonCode"/>
</el-select>
</el-form-item>
</el-col>
<!-- 创建人 -->
<el-col :span="6">
<el-form-item label="创建人:" prop="creatorName">
<el-input placeHolder="创建人+" v-model="formObj.creatorName" clearable/>
</el-form-item>
</el-col>
</el-row>
<!-- 第二行 -->
<el-row :gutter="24">
<el-col :span="6">
<!-- 生产开始日期 -->
<el-form-item label="生产日期:" required prop="timeRange">
<el-date-picker
v-model="formObj.timeRange"
value-format="yyyy-MM-dd HH:mm:ss"
format="yyyy-MM-dd HH:mm:ss"
type="datetimerange"
range-separator="至"
:default-time="['00:00:00', '23:59:59']"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 操作栏 -->
<c-top-bar :offset="50" style="margin-bottom: 10px">
<el-button type="text" icon="el-icon-search" @click="doRetrieve(true)">检索</el-button>
<el-divider direction="vertical"/>
<el-button type="text" icon="el-icon-save" @click="doSave">保存</el-button>
<el-divider direction="vertical"/>
<el-button type="text" icon="el-icon-circle-close" @click="doClear()">清除</el-button>
<el-divider direction="vertical"/>
<el-button type="text" icon="el-icon-document" @click="doExport">导出</el-button>
<el-divider style="margin-top: 0;"/>
</c-top-bar>
<!-- 按钮行 -->
<el-row>
<div class="mb8 w100">
<el-button type="primary" @click="doAdd">插入新项</el-button>
<el-button type="danger" @click="doRemoveSelected">移除选定项</el-button>
</div>
</el-row>
<!-- 表格内容 -->
<div>
<el-table
size="mini"
:data="equipmentAbnHistoryList"
@selection-change="selectionChangHandle"
border
style="width: 100%"
height="550"
highlight-current-row>
<el-table-column type="selection" width="40" align="center"/>
<!-- 序号 -->
<el-table-column align="center" type="index" fixed="left" label="序号" width="60" />
<el-table-column align="center" prop="equipmentCode" fixed="left" label="设备编码" show-overflow-tooltip/>
<el-table-column align="center" prop="equipmentCodeDesc" fixed="left" label="设备描述" show-overflow-tooltip/>
<el-table-column align="center" prop="shift" label="班次">
<template #default="scope">
<el-select v-model="scope.row.shift" clearable @change="handleShiftChange(scope.$index)">
<el-option v-for="item in shiftList" :key="item.userWorkShift" :label="`${item.userWorkShift} - ${item.description}`" :value="item.userWorkShift"/>
</el-select>
</template>
</el-table-column>
<el-table-column align="center" prop="abnCodeGroup" label="异常代码组">
<template #default="scope">
<el-select v-model="scope.row.abnCodeGroup" clearable @change="handleAbnCodeGroupChange(scope.$index)">
<el-option v-for="item in abnCodeGroupList" :key="item.value" :label="`${item.value} - ${item.label}`" :value="item.value"/>
</el-select>
</template>
</el-table-column>
<el-table-column align="center" prop="abnCode" label="异常代码" min-width="140">
<template #default="scope">
<el-select v-model="scope.row.abnCode" clearable @change="handleAbnCodeChange(scope.$index)">
<el-option v-for="item in scope.row.abnCodeFilterList" :key="item.reasonCode" :label="`${item.reasonCode} - ${item.description}`" :value="item.reasonCode"/>
</el-select>
</template>
</el-table-column>
<el-table-column align="center" prop="abnCodeName" label="异常原因" show-overflow-tooltip/>
<el-table-column align="center" prop="countermeasure" label="处理对策" show-overflow-tooltip>
<template #default="scope">
<el-input v-model="scope.row.countermeasure"/>
</template>
</el-table-column>
<el-table-column align="center" prop="startTime" label="开始时间" min-width="140">
<template #default="scope">
<el-date-picker
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
format="yyyy-MM-dd HH:mm:ss"
:picker-options="pickerOptions"
style="width: 100%"
size="small"
@change="dateChange('START',scope.$index)"
v-model="scope.row.startTime"/>
</template>
</el-table-column>
<el-table-column align="center" prop="endTime" label="结束时间" min-width="140">
<template #default="scope">
<el-date-picker
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
format="yyyy-MM-dd HH:mm:ss"
:picker-options="pickerOptions"
style="width: 100%"
size="small"
@change="dateChange('END', scope.$index)"
v-model="scope.row.endTime"/>
</template>
</el-table-column>
<el-table-column align="center" prop="timeConsuming" label="耗时/min" show-overflow-tooltip/>
<el-table-column align="center" prop="creatorName" label="填写人" show-overflow-tooltip/>
</el-table>
<!-- 分页插件 -->
<div style="width: 100%;display: flex;flex-direction: column;align-items: center;justify-content: center;">
<el-pagination @current-change="handleCurrentChange"
@size-change="handleSizeChange"
:current-page.sync="page.current"
:page-sizes="[10, 20, 50, 100, 200]"
:page-size="page.size"
layout="total, sizes, prev, pager, next, jumper"
:total="page.total">
</el-pagination>
</div>
</div>
</basic-container>
</div>
</template>
<script>
import {hideLoading, showLoading} from '@/const/loading';
import {mapGetters} from 'vuex';
import {getStore} from "@/util/store";
import {fetchItemList as fetchDictList} from '@/api/admin/dict';
import {listByActivityId} from "@/api/admin/activity-option";
import {
initFormObj,
resrceInitDialogObj,
} from "@/views/mes/wip-nalinv/equipment-abn-history/init";
import {fetchSearchTextPage} from "@/api/wms/prd-code-status-query-report";
import {
getAbnCodeList,
getEquipAbnHistoryPage, getResrceByCode, getShiftList,
saveEquipAbnHistory
} from "@/api/mes/wip-nalinv/equipment-abn-history";
import {formatterDate} from "@/views/mes/wms/take-inventory/init";
export default {
// *****************************************************************************************************************
data() {
return {
selectObjs: [], // 多选ID集合
multiple: true, // 控制删除按钮是否禁用
formObj: {...initFormObj}, // 搜索条件对象
site: getStore({name: 'tenantId'}),
userName: getStore({name: 'userInfo'}).username,
name: getStore({name: 'userInfo'}).name,
fabNo: '', // 作业规则获取车间
resrceDialogObj: {...resrceInitDialogObj}, // 设备
shiftList: [], // 班组状态
reasonCodeCategoryList: [], // 异常代码类别(字典)
abnCodeGroupList: [], // 异常代码组(选择)
abnCodeGroupStringList: [], // 异常代码组(字符串)
abnCodeList: [], // 异常代码
abnCodeFilterList: [], // 异常代码
abnCodeSearchList: [], // 异常代码(搜索框)
resrceStringList: [], // 设备(字符串)
equipmentAbnHistoryList: [], // 查询结果
isSecrecy: '', // 作业规则
// 分页参数
page: {
total: 0,
current: 1,
size: 20
},
formRules: {
timeRange: [
{required: true, message: '请选择时间范围', trigger: 'change'}
],
},
// 时间查询参数
pickerOptions: {
disabledDate: time => {
if (!this.formObj.timeRange || this.formObj.timeRange.length !== 2) {
return false; // 没有设置时间范围则不禁用任何日期
}
const startDate = new Date(this.formObj.timeRange[0]).getTime();
const endDate = new Date(this.formObj.timeRange[1]).getTime();
const currentTime = time.getTime();
// 禁用不在范围内的日期
return currentTime < startDate || currentTime > endDate;
}
}
};
},
// *****************************************************************************************************************
created() {
let me = this
// 获取设备
if(me.$route.query.resrce){
me.formObj.resrce = me.$route.query.resrce
// 通过设备查询描述
getResrceByCode({equipmentCode:me.$route.query.resrce}).then((response) => {
if (response.data.code === 0) {
me.formObj.resrceDesc = response.data.data.description;
}
})
}
// 获取作业规则
let activityId = this.$route.query.ACTIVITY_ID
showLoading()
listByActivityId(activityId).then(async (response) => {
hideLoading();
if (response.data.code !== 0) {
return this.$message.error(response.data.msg)
}
let optionList = response.data.data
for (let i = 0; i < optionList.length; i++) {
// 车间
if (optionList[i].optionName === 'REASON_CODE_CATEGORY') {
let reasonCodeCategory = optionList[i].optionValue
// 通过分号截取 赋值给 abnCodeGroupList
// 先按分号分割字符串
me.abnCodeGroupStringList = reasonCodeCategory.split(';');
// 获取异常代码
getAbnCodeList(me.abnCodeGroupStringList).then((res) => {
me.abnCodeSearchList = res.data.data;
})
// 获取异常代码组
const codes = reasonCodeCategory.split(';');
// 过滤掉空字符串
const filteredCodes = codes.filter(code => code.trim() !== '');
// 获取字典数据
const reasonCodeCategoryList = await this.getDataDictionary("reason_code_category");
this.abnCodeGroupList = reasonCodeCategoryList.filter(item =>
filteredCodes.includes(item.value)
);
} else if (optionList[i].optionName === 'GET_RESOURCE') {
let equipmentCode = optionList[i].optionValue;
me.resrceStringList = equipmentCode.split(";")
}
}
}).catch((e) => {
hideLoading()
})
// 获取班次数据
getShiftList().then((response) => {
this.shiftList = response.data.data;
})
},
// *****************************************************************************************************************
computed: {
...mapGetters(['permissions']),
permissionList() {
return {};
}
},
// *****************************************************************************************************************
methods: {
// 过滤设备号
fetchFilterResrce(res) {
// 获取 作业规则中的 设备号 如果设备号不为空 则进行过滤
if (this.resrceStringList) {
// 对 records 进行过滤,只保留 resrce 在 resrceStringList 中的记录
res.data.data.records = res.data.data.records.filter(record => {
// 确保 record 和 record.resrce 存在
if (!record || !record.resrce) return false;
// 检查当前记录的 resrce 是否在允许的列表中
return this.resrceStringList.includes(record.resrce);
});
}
},
// 在methods中添加处理异常代码选择变化的方法
handleAbnCodeChange(rowIndex) {
// 获取选中的数据
const currentRow = this.equipmentAbnHistoryList[rowIndex];
if (!currentRow.abnCode) {
// 如果没有选择异常代码,清空相关字段
currentRow.abnCodeName = '';
return;
}
// 查找选中的异常代码对象
const selectedItem = currentRow.abnCodeFilterList.find(item =>
item.reasonCode === currentRow.abnCode
);
// 更新异常原因(假设 reasonDesc 是描述字段)
currentRow.abnCodeName = selectedItem.description;
},
// 在methods中添加处理异常代码组选择变化的方法
handleAbnCodeGroupChange(rowIndex) {
const selectedGroup = this.equipmentAbnHistoryList[rowIndex].abnCodeGroup;
if (!selectedGroup) {
// 如果没有选择组,清空异常代码
this.equipmentAbnHistoryList[rowIndex].abnCodeFilterList = [];
return;
}
// 更新 abnCodeList 集合
this.equipmentAbnHistoryList[rowIndex].abnCodeFilterList = this.abnCodeSearchList.filter(item => item.category === selectedGroup);
},
// 班次改变事件
handleShiftChange(rowIndex) {
// 获取当前行的数据
const currentRow = this.equipmentAbnHistoryList[rowIndex];
// 如果没有选择班次或者当前行不存在,直接返回
if (!currentRow || !currentRow.shift) return;
// 在 shiftList 中查找匹配的班次数据
const selectedShift = this.shiftList.find(item =>
item.userWorkShift === currentRow.shift
);
if (selectedShift) {
currentRow.shiftFrom = selectedShift.shiftFrom;
currentRow.shiftTo = selectedShift.shiftTo;
}
},
// 多选事件
selectionChangHandle(objs) {
// 使用 rowIndex 做为选中标识
this.selectObjs = objs.map(obj => obj.rowIndex);
this.multiple = !objs.length;
},
// 移除选定项
doRemoveSelected() {
if (this.selectObjs.length === 0) {
this.$message.warning('请先选择要移除的项');
return;
}
this.$confirm('是否确认移除选中行', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 根据 rowIndex 排序后倒序删除(防止删除顺序影响索引)
const sortedIndexes = [...this.selectObjs].sort((a, b) => b - a);
sortedIndexes.forEach(rowIndex => {
this.equipmentAbnHistoryList.splice(rowIndex, 1);
});
// 更新剩余行的 rowIndex
this.equipmentAbnHistoryList = this.equipmentAbnHistoryList.map((row, index) => {
row.rowIndex = index;
return row;
});
// 清空选中状态
this.selectObjs = [];
this.multiple = true;
}).catch(() => {
// 用户取消
console.log('用户取消删除');
});
},
// 保存
doSave() {
let me = this;
let obj = {
site: me.site,
equipmentCode: me.formObj.resrce,
shift: me.formObj.shift,
creatorName: me.formObj.creatorName,
abnCode: me.formObj.abnCode,
startTimeStr: formatterDate(me.formObj.timeRange[0], 'yyyy-MM-dd hh:mm:ss'),
endTimeStr: formatterDate(me.formObj.timeRange[1], 'yyyy-MM-dd hh:mm:ss'),
equipmentAbnHistoryList: this.equipmentAbnHistoryList,
}
// 保存接口
saveEquipAbnHistory(obj).then((res) => {
if (res.data.code === 0) {
return this.$message.success('保存成功!')
}
this.doRetrieve(true);
})
},
// 添加
doAdd() {
if (!this.formObj.resrce) {
return this.$message.warning("请选择设备编码");
}
if (!this.formObj.timeRange) {
return this.$message.error("请选择生产日期");
}
this.equipmentAbnHistoryList.push({
handle: "",
site: this.site,
equipmentCode: this.formObj.resrce,
equipmentCodeDesc: this.formObj.resrceDesc,
shift: '',
abnCodeGroup: '',
abnCode: '',
abnCodeName: '',
countermeasure: '',
startTime: '',
endTime: '',
timeConsuming: '',
creator: this.userName,
creatorName: this.name,
shiftFrom: '',
shiftTo: '',
dateCreate: formatterDate(new Date(), 'yyyy-MM-dd hh:mm:ss'),
abnCodeFilterList: []
})
},
// 检查时间改变
dateChange(t, rowIndex) {
let me = this;
// 获取当前行的数据
const row = me.equipmentAbnHistoryList[rowIndex];
// 确保行存在
if (!row) return;
if (!row.shift) {
row.startTime = '';
row.endTime = '';
return me.$message.error('请先选择班次!');
}
let date1 = row.startTime ? new Date(row.startTime) : null;
let date2 = row.endTime ? new Date(row.endTime) : null;
// 获取班次时间段(时分格式)
const shiftFrom = row.shiftFrom; // 格式:"HH:mm"
const shiftTo = row.shiftTo; // 格式:"HH:mm"
// 将时间转换为分钟数进行比较
const [fromHour, fromMinute] = shiftFrom.split(':').map(Number);
const [toHour, toMinute] = shiftTo.split(':').map(Number);
const shiftFromMinutes = fromHour * 60 + fromMinute;
const shiftToMinutes = toHour * 60 + toMinute;
// 计算班次时间段总分钟数(可能跨天)
let shiftDurationMinutes;
if (shiftFromMinutes <= shiftToMinutes) {
shiftDurationMinutes = shiftToMinutes - shiftFromMinutes;
} else {
// 跨天情况,假设第二天
shiftDurationMinutes = (24 * 60 - shiftFromMinutes) + shiftToMinutes;
}
// 校验开始时间
if (t === 'START' && date1) {
const date1Minutes = date1.getHours() * 60 + date1.getMinutes();
if ((shiftFromMinutes <= shiftToMinutes &&
(date1Minutes < shiftFromMinutes || date1Minutes > shiftToMinutes)) ||
(shiftFromMinutes > shiftToMinutes &&
(date1Minutes < shiftFromMinutes && date1Minutes > shiftToMinutes))) {
row.startTime = '';
row.timeConsuming = '';
return me.$message.warning('请选择班次时间段内的开始时间');
}
// 新增:校验同一设备、同班次下后续记录的开始时间不能大于前一条记录的开始时间
// 查找同一设备、同班次的所有之前记录
const sameRecords = me.equipmentAbnHistoryList
.filter((item, index) =>
item.equipmentCode === row.equipmentCode &&
item.shift === row.shift &&
index < rowIndex // 只检查之前的记录
);
// 如果有之前的记录
if (sameRecords.length > 0) {
// 获取最后一条记录
const lastRecord = sameRecords[sameRecords.length - 1];
// 比较开始时间
if (lastRecord.endTime) {
const lastDate = new Date(lastRecord.endTime);
// 如果当前开始时间大于最后一条记录的开始时间
if (date1 < lastDate) {
row.startTime = '';
row.timeConsuming = '';
return me.$message.warning(`同一个设备【${me.equipmentAbnHistoryList[rowIndex].equipmentCode}】相同班次【${me.equipmentAbnHistoryList[rowIndex].shift}】相同时间段内不能维护多笔数据!`);
}
}
}
}
// 校验结束时间
if (t === 'END' && date2) {
const date2Minutes = date2.getHours() * 60 + date2.getMinutes();
if ((shiftFromMinutes <= shiftToMinutes
&& (date2Minutes < shiftFromMinutes || date2Minutes > shiftToMinutes)) ||
(shiftFromMinutes > shiftToMinutes &&
(date2Minutes < shiftFromMinutes && date2Minutes > shiftToMinutes))) {
row.endTime = '';
row.timeConsuming = '';
return me.$message.warning('请选择班次时间段内的结束时间');
}
}
// 如果是开始时间修改且两个时间都存在
if (t === 'START' && date1 && date2 && date1 > date2) {
row.startTime = '';
row.timeConsuming = '';
return me.$message.warning('开始时间不能大于结束时间');
}
// 如果是结束时间修改且两个时间都存在
if (t === 'END' && date1 && date2 && date1 > date2) {
row.endTime = '';
row.timeConsuming = '';
return me.$message.warning('结束时间不能小于开始时间');
}
// 新增:校验时间范围是否超过班次时间段限制
if (date1 && date2) {
const diffMs = Math.abs(date2 - date1);
const diffMinutes = Math.floor(diffMs / (1000 * 60));
if (diffMinutes > shiftDurationMinutes) {
row.startTime = '';
row.endTime = '';
row.timeConsuming = '';
return me.$message.warning(`开始时间和结束时间不能超过班次时间段限制`);
}
}
// 计算时间差(分钟)
if (date1 && date2) {
const diffMs = Math.abs(date2 - date1);
const diffMinutes = Math.floor(diffMs / (1000 * 60));
row.timeConsuming = diffMinutes.toString(); // 更新耗时字段
}
},
// 弹出框通用选择
dialogSelected(row, type) {
switch (type) {
case 'resrce':
this.formObj.resrce = row.resrce;
this.formObj.resrceDesc = row.resrceDesc;
break;
}
},
// 弹出框通用打开
openDialog(type) {
switch (type) {
case 'resrce':
this.resrceDialogObj.visible = true;
this.resrceDialogObj.fetchFun = fetchSearchTextPage;
break;
}
},
// 获取数据字典
// 获取数据字典(返回Promise)
getDataDictionary(dictType) {
return fetchDictList({
current: "1",
size: "1000",
dictType: dictType,
}).then((response) => {
return response.data.data.records; // 直接返回 records 数组
});
},
// getDataDictionary(dictType, listKey) {
// return fetchDictList({
// current: "1",
// size: "1000",
// dictType: dictType,
// }).then((response) => {
// this[listKey] = response.data.data.records;
// });
// },
// 页面大小改变
handleSizeChange(val) {
this.page.size = val;
this.page.current = 1;
this.doRetrieve();
},
//页面切换
handleCurrentChange(val) {
this.page.current = val;
this.doRetrieve();
},
// 【检索按钮】方法
doRetrieve(flag) {
let me = this;
if (flag) {
me.page.current = 1;
}
if (!me.formObj.timeRange) {
return me.$message.error("请选择生产日期");
}
let obj = {
site: me.site,
equipmentCode: me.formObj.resrce,
shiftList: me.formObj.shiftList,
creatorName: me.formObj.creatorName,
abnCodeList: me.formObj.abnCodeList,
startTimeStr: formatterDate(me.formObj.timeRange[0], 'yyyy-MM-dd hh:mm:ss'),
endTimeStr: formatterDate(me.formObj.timeRange[1], 'yyyy-MM-dd hh:mm:ss'),
};
showLoading();
getEquipAbnHistoryPage(Object.assign({
current: me.page.current,
size: me.page.size,
site: this.site
}, obj)).then(response => {
hideLoading();
if (!response.data.data || response.data.data.length === 0) {
this.$message.error('检索无数据');
this.doClear();
return false;
}
me.equipmentAbnHistoryList = response.data.data.records;
me.equipmentAbnHistoryList = response.data.data.records.map(record => {
// 根据当前 record.abnCodeGroup 过滤出对应的 abnCodeFilterList
const filteredList = me.abnCodeSearchList.filter(
item => item.category === record.abnCodeGroup
);
// 返回新对象,带上过滤后的集合
return {
...record,
abnCodeFilterList: filteredList
};
});
me.page.total = response.data.data.total;
me.page.current = response.data.data.current;
}).catch(() => {
hideLoading();
});
},
// 【清空按钮】方法
doClear() {
let me = this;
me.formObj = {};
me.equipmentAbnHistoryList = []
me.page = {
total: 0,
current: 1,
size: 20
}
},
// 【导出按钮】方法
doExport() {
let me = this;
let search = {
site: me.site,
equipmentCode: me.formObj.resrce,
shift: me.formObj.shift,
creatorName: me.formObj.creatorName,
abnCode: me.formObj.abnCode,
startTimeStr: formatterDate(me.formObj.timeRange[0], 'yyyy-MM-dd hh:mm:ss'),
endTimeStr: formatterDate(me.formObj.timeRange[1], 'yyyy-MM-dd hh:mm:ss'),
};
this.downBlobFile("/iep-app/equipment-abn-history/tablePageExport", search, "设备异常履历.xlsx");
},
}
};
</script>

View File

@ -0,0 +1,35 @@
import {getStore} from "@/util/store";
export const resrceInitDialogObj= {
callBackKey: "resrce",
regex: ";",
condition: "resrce",
tableColumn: [
{prop: "resrce", label: "设备编码"},
{prop: "resrceDesc", label: "设备描述"}
],
queryParam: {
site: getStore({name: 'tenantId'}),
searchTextByGroup: "resrce",
},
visible: false,
fetchFun: null,
}
export const initFormObj = {
resrce: "",
resrceDesc: "",
shiftList: [],
creator: "",
abnCodeList: [],
startTime: "",
endTime: "",
timeRange: "",
}

View File

@ -0,0 +1,224 @@
<template>
<!--产出与成本报表-->
<div class="execution">
<basic-container>
<!-- 搜尋框 -->
<el-form ref="searchForm" :model="searchForm" label-width="120px" label-suffix=":" :inline="true">
<el-row>
<el-col :span="6">
<el-form-item label="日期始" prop="dateFrom">
<el-date-picker
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
v-model="searchForm.dateFrom"
type="date"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="日期止" prop="dateTo">
<el-date-picker
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
v-model="searchForm.dateTo"
type="date"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="6">
<el-button type="primary" icon="el-icon-search" size="small" @click="search(true)">检索</el-button>
<el-button type="primary" icon="el-icon-document" size="small" @click="doExport">导出</el-button>
<el-button icon="el-icon-delete" size="small" @click="searchReset">清空</el-button>
</el-col>
</el-row>
</el-form>
<el-tabs v-model="tabActiveName">
<el-tab-pane label="查询结果" name="outCostReportDetailTab">
<el-table ref="outCostReportData" :data="outCostReportData" tooltip-effect="dark" border style="width: 100%;"
:row-key="'handle'"
:highlight-current-row="true"
stripe>
<el-table-column prop="sumOutputQty" label="产出总米数" header-align="center">
<template slot-scope="scope">
<div>
{{ scope.row.sumOutputQty }}
</div>
</template>
</el-table-column>
<el-table-column prop="totalCost" label="总成本" header-align="center">
<template slot-scope="scope">
<div>
{{ scope.row.totalCost }}
</div>
</template>
</el-table-column>
<el-table-column prop="unitCost" label="单位成本" header-align="center">
<template slot-scope="scope">
<div>
{{ scope.row.unitCost }}
</div>
</template>
</el-table-column>
<el-table-column prop="unitEnergy" label="单位能耗" header-align="center">
<template slot-scope="scope">
<div>
{{ scope.row.unitEnergy }}
</div>
</template>
</el-table-column>
</el-table>
<div style="width: 100%;display: flex;flex-direction: column;align-items: center;justify-content: center;">
<el-pagination @current-change="handleCurrentChange"
@size-change="handleSizeChange"
:current-page.sync="page.current"
:page-sizes="[10, 20, 50, 100, 200]"
:page-size="page.size"
layout="total, sizes, prev, pager, next, jumper"
:total="page.total">
</el-pagination>
</div>
</el-tab-pane>
</el-tabs>
</basic-container>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
import {getStore} from '@/util/store';
import {hideLoading, showLoading} from "@/const/loading";
import {readOutCostReportPage} from "@/api/mes/wip-nalinv/outCostReport";
export default {
name: 'outCostReport',
data() {
return {
tabActiveName: "outCostReportDetailTab",
searchForm: {
site: getStore({name: 'tenantId'}),
dateFrom: this.formattedDate(),
dateTo: this.formattedDate()
},
outCostReportData: [],
site: getStore({name: 'tenantId'}),
page: {
total: 0,
current: 1,
size: 10
},
}
},
created() {
this.searchForm = Object.assign({}, this.searchForm);
},
computed: {
//读取权限
...mapGetters(['permissions', 'userInfo']),
permissionList() {
return {
addBtn: false,
delBtn: false,
editBtn: false,
}
},
},
methods: {
// 获取当前日期
formattedDate() {
const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份是从 0 开始的,所以需要加 1
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`; // 格式化为 YYYY-MM-DD
},
// 页面大小改变
handleSizeChange(val) {
this.page.size = val;
this.page.current = 1;
this.search();
},
//页面切换
handleCurrentChange(val) {
this.page.current = val;
this.search();
},
// 检索列表数据
search(flag) {
if (!this.searchForm.dateFrom) {
this.$message.error("日期始不可为空!");
return;
}
if (!this.searchForm.dateTo) {
this.$message.error("日期止不可为空!");
return;
}
if (flag) {
this.page.current = 1;
}
showLoading();
readOutCostReportPage({
...this.searchForm,
current: this.page.current,
size: this.page.size
}).then((response) => {
hideLoading();
if (response.data.code !== 0) {
this.$message.error(response.data.message);
} else {
this.outCostReportData = response.data.data.records;
this.page.total = response.data.data.total;
this.page.current = response.data.data.current;
}
}).catch(() => {
hideLoading();
});
},
// 导出
doExport() {
let me = this;
if (!me.searchForm.dateFrom) {
me.$message.error("日期始不可为空!");
return;
}
if (!me.searchForm.dateTo) {
me.$message.error("日期止不可为空!");
return;
}
me.$confirm(`是否确认导出?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.downBlobFile("/iep-app/nlv-wip/exportOutCostReport", me.searchForm, "产出与成本报表.xlsx");
})
},
// 清空事件
searchReset() {
this.searchForm = {
site: this.site,
dateFrom: this.formattedDate(),
dateTo: this.formattedDate()
};
this.outCostReportData = [];
},
},
}
</script>
<style lang="scss" scoped>
// 解决input框中添加disabled不可编辑属性后,改变字体颜色样式(主要解决:默认字体颜色为灰色)
::v-deep .el-input.is-disabled .el-input__inner {
color: black;
}
/* 禁用 el-input 时禁用图标和清除按钮 */
.el-input.is-disabled .el-input__icon,
.el-input.is-disabled .el-input__clear {
pointer-events: none;
}
</style>

View File

@ -261,12 +261,56 @@
</template>
<template slot-scope="scope">
<div>
<el-input v-model="scope.row.outMeter" type="number" :min="minValue" @input="outInput(scope.row, 'outMeter')"/>
<el-input v-model="scope.row.outMeter" type="number" :min="minValue" @input="outInput(scope.row, 'outMeter')" @change="outMeterChange(scope.row)"/>
</div>
</template>
</el-table-column>
</el-table>
</el-form>
<div v-if="isActualConsum === 'Y'">
<hr/>
<div>
<el-form-item style="margin-bottom: 0px;" label-width="250px" label="实际耗用量录入:损耗上限(%)" prop="maxLossLimit">
<el-input
style="width: 200px"
v-model.trim="searchForm.maxLossLimit"
clearable
oninput="value=value.replace(/^\D*(\d*(?:\.\d{0,3})?).*$/g, '$1')"
onafterpaste="value=value.replace(/^\D*(\d*(?:\.\d{0,3})?).*$/g, '$1')" @change="maxLossLimitChange">
</el-input>
</el-form-item>
<el-button type="primary" size="small" @click="fillMaxLossLimitField">填充</el-button>
</div>
<hr/>
<el-table ref="materialList" :data="materialList" tooltip-effect="dark" border style="width: 100%;"
:highlight-current-row="true"
stripe>
<el-table-column prop="shopOrder" label="工单号" header-align="center"></el-table-column>
<el-table-column prop="item" label="消耗物料编码" header-align="center"></el-table-column>
<el-table-column prop="itemDesc" label="消耗物料描述" header-align="center"></el-table-column>
<el-table-column prop="theoryConsumeQty" label="理论消耗量" header-align="center"></el-table-column>
<el-table-column prop="realConsumeQty" header-align="center" width="230px">
<template #header>
<span><span style="color: red;">*</span>实际消耗量</span>
</template>
<template slot-scope="scope">
<div>
<el-input v-model="scope.row.realConsumeQty" type="number" :min="minValue" @input="outInput(scope.row, 'realConsumeQty')"/>
</div>
</template>
</el-table-column>
<el-table-column prop="maxLossLimit" header-align="center" width="230px">
<template #header>
<span><span style="color: red;">*</span>损耗上限(%)</span>
</template>
<template slot-scope="scope">
<div>
<el-input v-model="scope.row.maxLossLimit" type="number" :min="minValue" @input="outInput(scope.row, 'maxLossLimit')"/>
</div>
</template>
</el-table-column>
</el-table>
</div>
</el-form>
</basic-container>
</div>
</template>
@ -292,12 +336,14 @@ import {
checkOperation,
fetchCustomFieldsByOperation,
fetchClickCopyPage,
fetchCustomFieldsByResrce
fetchCustomFieldsByResrce,
readBomComponentMultiShopOrder
} from "@/api/mes/prd/operation-out";
import {hideLoading, showLoading} from "@/const/loading";
import { isBlank } from '@/util/string';
import {listByActivityId} from "@/api/admin/activity-option";
import {fetchItemList as fetchDictList} from "@/api/admin/dict";
import {mul, div, toFixed} from "@/util/number";
export default {
name: 'operation-out',
data() {
@ -332,6 +378,7 @@ export default {
operationList: [], // 作业规则维护的工序列表
autoOperationList: [], // 出站需要自动完成的工序列表
selectedRows: [], // 选中行数据列表
materialList: [], // 物料消耗列表
showBarCodeNum: null, // 是否展示条码数
getResource: null, // 出站需要自动完成的设备
getStationNo: null, // 判断列表中工位号是否可选
@ -343,6 +390,8 @@ export default {
isParameter: null, // 工序出站列表中检验项目VLT、IRR、UVR是否显示且必输
showInspector: null, // 是否展示检验员
showPrintNum: null, // 是否展示打印数量
isActualConsum: null, // 是否展示实际消耗量
maxLossLimit: null
}
},
created() {
@ -363,6 +412,8 @@ export default {
this.getCustomFieldsByResrce(this.site, this.$route.query.resrce, "IS_INSPECTOR")
// 获取设备自定义字段工序出站展示打印数量
this.getCustomFieldsByResrce(this.site, this.$route.query.resrce, "IS_PRINT_COPIES")
// 获取设备自定义字实际消耗录入
this.getCustomFieldsByResrce(this.site, this.$route.query.resrce, "IS_ACTUAL_CONSUM")
}
if (this.$route.query.operation) {
this.searchForm.operation = this.$route.query.operation
@ -394,6 +445,7 @@ export default {
this.searchForm.shopOrder = shopOrder;
// 调用 工单选择方法
this.readOperationOutListByShopOrder(this.site,shopOrder);
this.readBomComponentMultiShopOrder(shopOrder)
}
})
.catch(() => {
@ -424,6 +476,19 @@ export default {
},
},
methods: {
maxLossLimitChange(value) {
this.searchForm.maxLossLimit = value
},
fillMaxLossLimitField() {
let maxLossLimit = this.searchForm.maxLossLimit;
let materialList = this.materialList;
if(materialList && materialList.length > 0) {
for (let i = 0; i < materialList.length; i++) {
let record = materialList[i];
record.maxLossLimit = maxLossLimit;
}
}
},
// number改变事件
outInput(row, flag) {
// 使用正则表达式校验非负数且最多三位小数
@ -469,6 +534,40 @@ export default {
});
}
}
} else if (flag === 'realConsumeQty') {
if (reg.test(row.realConsumeQty)) {
row.realConsumeQtyParsedValue = row.realConsumeQty;
} else {
if (row.realConsumeQty) {
this.$nextTick(() => {
row.realConsumeQty = row.realConsumeQtyParsedValue;
});
}
}
} else if (flag === 'maxLossLimit') {
if (reg.test(row.maxLossLimit)) {
row.maxLossLimitParsedValue = row.maxLossLimit;
} else {
if (row.maxLossLimit) {
this.$nextTick(() => {
row.maxLossLimit = row.maxLossLimitParsedValue;
});
}
}
}
},
outMeterChange(row) {
let outMeter = row.outMeter;
let materialList = this.materialList;
if(materialList && materialList.length > 0) {
for (let i = 0; i < materialList.length; i++) {
let record = materialList[i];
let theoryConsumeQty = toFixed(mul(outMeter, div(record.qty, record.unitQty)), 3);
theoryConsumeQty = Number(theoryConsumeQty);
if (record.shopOrder === row.shopOrder) {
record.theoryConsumeQty = theoryConsumeQty;
}
}
}
},
// 条码数需要为正整数
@ -570,6 +669,24 @@ export default {
}
});
},
readBomComponentMultiShopOrder(shopOrderStr) {
showLoading();
// 按分号分割工单字符串
let shopOrderList = shopOrderStr.split(";")
readBomComponentMultiShopOrder({
shopOrderList: shopOrderList,
operation: this.searchForm.operation
}).then((response) => {
hideLoading();
if (response.data.code !== 0) {
this.$message.error(response.data.message);
} else {
this.materialList = response.data.data
}
}).catch(() => {
hideLoading();
});
},
// 条码号失去焦点
barCodeBlur() {
if (!this.searchForm.resrce) {
@ -876,6 +993,9 @@ export default {
} else if (fieldName === "IS_PRINT_COPIES") {
// 工序出站展示检验员
this.showPrintNum = response.data.data
} else if (fieldName === "IS_ACTUAL_CONSUM") {
// 工序出站展示实际消耗录入表格
this.isActualConsum = response.data.data
}
}
});
@ -935,6 +1055,27 @@ export default {
seen.add(key); // 否则,记录该组合
}
});
// 校验实际消耗量是否录入
let validActualConsumResult = this.validateActualConsum();
if(validActualConsumResult && validActualConsumResult.length > 0) {
let messageType = validActualConsumResult[0];
let message = validActualConsumResult[1];
if(messageType === 'error') {
return this.$message.warning(message);
} else if (messageType === 'confirm') {
this.$confirm(message, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.doOperationOut(found);
})
}
} else {
this.doOperationOut(found);
}
},
doOperationOut(found) {
if (found) {
this.$refs.searchForm.validate((valid) => {
if (valid) {
@ -958,7 +1099,8 @@ export default {
shopOrderList: shopOrderList,
eqpCombineFeeding: this.eqpCombineFeeding,
inspector: this.searchForm.inspector,
printNum: this.searchForm.printNum
printNum: this.searchForm.printNum,
materialList: this.materialList
}).then((response) => {
hideLoading();
if (response.data.code !== 0) {
@ -973,6 +1115,7 @@ export default {
this.barCodeNumIsDisabled = false; // 切换条码数禁用状态
// 获取列表数据
this.readOperationOutListByShopOrder(this.site, this.searchForm.shopOrder)
this.readBomComponentMultiShopOrder(this.searchForm.shopOrder)
}
}).catch(() => {
hideLoading();
@ -982,6 +1125,44 @@ export default {
})
}
},
validateActualConsum() {
// 如果isActualConsum === 'Y',则校验实际消耗量和损耗上限不能为空,且实际消耗量不能大于理论消耗+(理论消耗*损耗上限的值)(保留三位小数)
if (this.isActualConsum === 'Y') {
// 获取operationOutData中勾选的工单编号shopOrder
let shopOrderList = this.selectedRows.map(item => item.shopOrder);
let materialList = this.materialList;
if(materialList && materialList.length > 0) {
for (let i=0; i<materialList.length; i++) {
let currentRow = materialList[i];
let shopOrder = currentRow.shopOrder;
if (!shopOrderList.includes(shopOrder)) {
continue;
}
if (!currentRow.realConsumeQty) {
return ["error", "工单[" + currentRow.shopOrder + "]物料[" + currentRow.item + "]的实耗量不能为空!"];
}
if (!currentRow.maxLossLimit) {
return ["error", "工单[" + currentRow.shopOrder +"]物料[" + currentRow.item + "]的损耗上限不能为空!"];
}
}
for (let i=0; i< materialList.length; i++) {
let currentRow = materialList[i];
let shopOrder = currentRow.shopOrder;
if (!shopOrderList.includes(shopOrder)) {
continue;
}
let realConsumeQty = Number(currentRow.realConsumeQty);
let theoryConsumeQty = Number(currentRow.theoryConsumeQty);
let maxLossLimit = Number(currentRow.maxLossLimit);
let maxQty = toFixed(theoryConsumeQty + (theoryConsumeQty * maxLossLimit / 100), 3);
if (realConsumeQty > Number(maxQty)) {
return ["confirm", "工单[" + currentRow.shopOrder + "]物料[" + currentRow.item + "]的实耗量大于理论消耗+(理论消耗*损耗上限的值)[" + Number(maxQty) + "],是否出站?"];
}
}
}
}
return null;
},
// 清空事件
searchReset() {
this.$confirm(`是否确认清空?`, '提示', {
@ -997,6 +1178,7 @@ export default {
// 获取列表数据
if (this.searchForm.shopOrder) {
this.readOperationOutListByShopOrder(this.site, this.searchForm.shopOrder)
this.readBomComponentMultiShopOrder(this.searchForm.shopOrder)
}
})
},
@ -1022,6 +1204,8 @@ export default {
this.getCustomFieldsByResrce(this.site, row.resrce, "IS_INSPECTOR")
// 获取设备自定义字段工序出站展示打印数量
this.getCustomFieldsByResrce(this.site, row.resrce, "IS_PRINT_COPIES")
// 获取设备自定义字实际消耗录入
this.getCustomFieldsByResrce(this.site, row.resrce, "IS_ACTUAL_CONSUM")
this.searchForm = Object.assign({}, this.searchForm)
},
// 工序点击开窗
@ -1073,6 +1257,7 @@ export default {
this.shopOrderIsDisabled = !this.shopOrderIsDisabled; // 切换禁用状态
// 获取列表数据
this.readOperationOutListByShopOrder(this.site, shopOrderStr)
this.readBomComponentMultiShopOrder(shopOrderStr)
} else {
return this.$message.warning("未选择生产订单!");
}

View File

@ -118,6 +118,7 @@
</el-tabs>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button v-if="showOneClickExecute" @click="oneClickExecute">一键完成</el-button>
<el-button @click="dialogDocumentDetailVisible = false">关 闭</el-button>
</div>
</el-dialog>
@ -360,6 +361,7 @@ import {
} from "@/api/mes/wms-nalinv/poRegister";
import {fetchList as fetchWarehouseList} from "@/api/wms/warehouse";
import {listByActivityId} from "@/api/admin/activity-option";
import {submit} from "@/api/wms/purchase-into-storage";
export default {
name: 'po-register',
@ -481,10 +483,14 @@ export default {
}
for (let i = 0; i < response.data.data.length; i++) {
// 判断 作业规则是否为 ITEM_GROUP物料组;
if (response.data.data[i].optionName == 'ITEM_GROUP') {
if (response.data.data[i].optionName === 'ITEM_GROUP') {
this.itemGroups = response.data.data[i].optionValue
} else if (response.data.data[i].optionName == 'QUALITY_INSPECTION_STATUS') {
} else if (response.data.data[i].optionName === 'QUALITY_INSPECTION_STATUS') {
this.qualityInspectionStatus = response.data.data[i].optionValue
} else if (response.data.data[i].optionName === 'FAST_EXEC_ITEM_GROUP') {
this.fastExecItemGroup = response.data.data[i].optionValue.split(',')
} else if (response.data.data[i].optionName === 'PRINTER') {
this.printer = response.data.data[i].optionValue
}
}
})
@ -496,7 +502,14 @@ export default {
this.getDataDictionary('DOCUMENT_STATE', 'documentStatusList');
this.getDataDictionary('IQC_STATUS', 'iqcStatusList')
},
computed: {},
computed: {
showOneClickExecute() {
if (this.detailFormObj.detailList.length === 0 || this.detailFormObj.detailList[0].state !== 'SUBMIT' || !this.fastExecItemGroup) return false;
return this.detailFormObj.detailList.every(item =>
this.fastExecItemGroup.includes(item.itemGroup)
);
}
},
mounted() {
let me = this;
@ -850,6 +863,36 @@ export default {
me.documentRegisterList[me.warehouseIndex].storagLocation = row.warehouse;
},
oneClickExecute() {
let me = this;
let submitList = [];
for (let row of me.detailFormObj.detailList) {
submitList.push({
handle: row.handle,
seq: row.seq,
targetWarehouse: row.targetWarehouse,
item: row.item,
itemDescription: row.itemDescription,
applicationsQuantity: row.applicationsQuantity,
inventoryList: [{
inventoryQty: row.applicationsQuantity
}]
})
}
submitList[0].documentNo = me.detailFormObj.detailList[0].documentNo;
submitList[0].printer = me.printer;
showLoading();
submit(submitList).then(res => {
hideLoading();
if (res.data.code === 0) {
me.$message.success("提交成功");
me.dialogDocumentDetailVisible = false;
me.searchFormObjAction();
}
}).catch(() => {
hideLoading();
});
}
}
};
</script>

View File

@ -198,6 +198,21 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="具有喷码样式:" prop="storageTime">
<el-select v-model="formObj.hasPmys" style="width: 100%" clearable>
<el-option label="" :value="null"/>
<el-option label="是" :value="true"/>
<el-option label="否" :value="false"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="入库单备注:" prop="storageRemark">
<el-input placeHolder="入库单备注" v-model="formObj.storageRemark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-tabs v-model="tabActiveName">
@ -262,6 +277,12 @@
{{ getValConvertShow(scope.row.storageTime,storageTimeList) }}
</template>
</el-table-column>
<el-table-column align="center" prop="hasPmys" label="具有喷码样式">
<template slot-scope="scope">
{{ scope.row.hasPmys ? '是' : '否' }}
</template>
</el-table-column>
<el-table-column align="center" prop="storageRemark" label="入库单备注" show-overflow-tooltip/>
</el-table>
<div style="width: 100%;display: flex;flex-direction: column;align-items: center;justify-content: center;">
@ -498,6 +519,8 @@
isSecrecy: me.isSecrecy,
bigBatchNo: me.formObj.bigBatchNo,
storageTime: me.formObj.storageTime,
hasPmys: me.formObj.hasPmys,
storageRemark: me.formObj.storageRemark,
};
showLoading();
retrieve(obj, me.page).then(response => {
@ -555,6 +578,8 @@
isSecrecy: me.isSecrecy,
bigBatchNo: me.formObj.bigBatchNo,
storageTime: me.formObj.storageTime,
hasPmys: me.formObj.hasPmys,
storageRemark: me.formObj.storageRemark,
};
this.downBlobFile("/mom-wms/inventory-query-report/tablePageExport", search, "库存查询报表.xlsx");
},

View File

@ -46,12 +46,12 @@
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="收货地址">
<el-input v-model="printParamForm.deliveryPartyAddress" disabled></el-input>
<el-input v-model="printParamForm.deliveryPartyAddress" :disabled="!dnPrintSpecial"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="物流单位">
<el-input v-model="printParamForm.reFields4" disabled></el-input>
<el-input v-model="printParamForm.reFields4" :disabled="!dnPrintSpecial"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
@ -90,6 +90,9 @@
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="24" v-if="dnPrintSpecial">
<el-button @click="addDetail" icon="el-icon-plus">新 增</el-button>
</el-col>
<el-col :span="24">
<el-table size="mini" :data="printParamForm.detailList" border style="width: 100%" height="250px"
highlight-current-row>
@ -128,6 +131,11 @@
<el-input v-model="scope.row.quality"></el-input>
</template>
</el-table-column>
<el-table-column align="center" label="操作" minWidth="10%" v-if="dnPrintSpecial">
<template slot-scope="scope">
<el-button circle size="small" type="danger" @click="removeDetail(scope.$index)" icon="el-icon-delete" :disabled="scope.row.removeDisable"/>
</template>
</el-table-column>
<!-- <el-table-column align="center" prop="remarks" label="备注" minWidth="20%">-->
<!-- <template slot-scope="scope">-->
<!-- <el-input v-model="scope.row.remarks"></el-input>-->
@ -410,8 +418,9 @@ export default {
callBack: {
target: null,
keys: null
}
},
},
dnPrintSpecial: false,
};
},
created() {
@ -442,6 +451,9 @@ export default {
if (data[i].optionName && data[i].optionName.toUpperCase() === "PRINTER_A4") {
me.printerA4 = data[i].optionValue;
}
if (data[i].optionName && data[i].optionName.toUpperCase() === "DN_PRINT_SPECIAL") {
me.dnPrintSpecial = data[i].optionValue === 'Y';
}
}
}
}).catch(e => {
@ -676,6 +688,9 @@ export default {
me.printParamForm.sumLength = resData.sumLength;
me.printParamForm.createDate = resData.createDate;
me.printParamForm.createUser = resData.createUser;
for (let row of me.printParamForm.detailList) {
row.removeDisable = true;
}
// me.printParamForm.detailList.forEach(item => {
// item.remarks = (!item.qualityInspectionStatus ? "" : item.qualityInspectionStatus) + ":"
// + (!item.zctKf ? "" : item.zctKf) + "mm x "
@ -861,6 +876,15 @@ export default {
}).catch(() => {
hideLoading();
});
},
addDetail() {
let me = this;
me.printParamForm.detailList.push({});
},
removeDetail(index) {
let me = this;
me.printParamForm.detailList.splice(index, 1);
}
},
};