Merge remote-tracking branch 'origin/0.8.X' into 0.8.X

This commit is contained in:
2026-06-01 14:39:03 +08:00
6 changed files with 465 additions and 257 deletions

View File

@@ -45,12 +45,14 @@ export function delRecords(id) {
} }
// 同步考勤记录 // 同步考勤记录
export function syncRecords(starttime) { export function syncRecords({ starttime, endtime }) {
return attendanceRequest({ return attendanceRequest({
url: '/sync_attendance', url: '/sync_attendance',
method: 'post', method: 'post',
timeout: 60000,
data: { data: {
starttime starttime,
endtime
} }
}) })
} }

View File

@@ -11,6 +11,12 @@ export const defaultColumns = [
prop: 'currentCoilNo', prop: 'currentCoilNo',
showOverflowTooltip: true showOverflowTooltip: true
}, },
{
label: '镀铬卷号',
align: 'center',
prop: 'chromelCoilNo',
showOverflowTooltip: true
},
{ {
label: '存储位置', label: '存储位置',
align: 'center', align: 'center',
@@ -83,6 +89,12 @@ export const fullPageDefaultColumns = [
prop: 'currentCoilNo', prop: 'currentCoilNo',
showOverflowTooltip: true showOverflowTooltip: true
}, },
{
label: '镀铬卷号',
align: 'center',
prop: 'chromelCoilNo',
showOverflowTooltip: true
},
{ {
label: '存储位置', label: '存储位置',
align: 'center', align: 'center',
@@ -171,6 +183,7 @@ export const fullPageDefaultColumns = [
export const optionalColumns = [ export const optionalColumns = [
{ label: '入场卷号', value: 'enterCoilNo' }, { label: '入场卷号', value: 'enterCoilNo' },
{ label: '当前卷号', value: 'currentCoilNo' }, { label: '当前卷号', value: 'currentCoilNo' },
{ label: '镀铬卷号', value: 'chromelCoilNo' },
{ label: '厂家钢卷号', value: 'supplierCoilNo' }, { label: '厂家钢卷号', value: 'supplierCoilNo' },
{ label: '逻辑库区', value: 'warehouseName' }, { label: '逻辑库区', value: 'warehouseName' },
{ label: '实际库区', value: 'actualWarehouseName' }, { label: '实际库区', value: 'actualWarehouseName' },

View File

@@ -64,7 +64,7 @@
<span class="param-value">{{ coil.netWeight }}t</span> <span class="param-value">{{ coil.netWeight }}t</span>
</div> </div>
<div class="param-row" v-if="coil.length"> <div class="param-row" v-if="coil.length">
<span class="param-label">长度</span> <span class="param-label">参考长度</span>
<span class="param-value">{{ coil.length }}m</span> <span class="param-value">{{ coil.length }}m</span>
</div> </div>
<div class="param-row" v-if="coil.actualLength"> <div class="param-row" v-if="coil.actualLength">

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="split-coil-container" v-loading="loading"> <div v-loading="loading" class="split-coil-container">
<!-- 左右分栏布局 --> <!-- 左右分栏布局 -->
<el-row :gutter="20"> <el-row :gutter="20">
<!-- 左侧钢卷信息 + 新增按钮 + 已分条列表 --> <!-- 左侧钢卷信息 + 新增按钮 + 已分条列表 -->
@@ -7,26 +7,41 @@
<div class="coil-info-card"> <div class="coil-info-card">
<el-row :gutter="20" flex justify="end"> <el-row :gutter="20" flex justify="end">
<!-- 新增分条按钮 --> <!-- 新增分条按钮 -->
<el-button type="primary" icon="el-icon-plus" @click="addSplitForm" :loading="buttonLoading" <el-button
v-if="actionStatus != 2"> v-if="actionStatus != 2"
type="primary"
icon="el-icon-plus"
:loading="buttonLoading"
@click="addSplitForm"
>
新增分条 新增分条
</el-button> </el-button>
<!-- 完成分条按钮 --> <!-- 完成分条按钮 -->
<el-button type="success" icon="el-icon-check" @click="completeSplit" :disabled="splitList.length === 0" <el-button
:loading="buttonLoading" v-if="actionStatus != 2"> v-if="actionStatus != 2"
type="success"
icon="el-icon-check"
:disabled="splitList.length === 0"
:loading="buttonLoading"
@click="completeSplit"
>
完成整体分条 完成整体分条
</el-button> </el-button>
<el-button type="primary" icon="el-icon-refresh" @click="refresh" :loading="buttonLoading"> <el-button type="primary" icon="el-icon-refresh" :loading="buttonLoading" @click="refresh">
刷新 刷新
</el-button> </el-button>
</el-row> </el-row>
<el-descriptions :column="2" border title="待分条钢卷信息"> <el-descriptions :column="2" border title="待分条钢卷信息">
<template slot="extra"> <template slot="extra">
<el-button v-if="showSplitForm" type="info" @click="copyFromSourceCoil" <el-button
icon="el-icon-document-copy">复制源卷信息</el-button> v-if="showSplitForm"
type="info"
icon="el-icon-document-copy"
@click="copyFromSourceCoil"
>复制源卷信息</el-button>
</template> </template>
<el-descriptions-item label="入场钢卷号">{{ coilInfo.enterCoilNo || '-' }}</el-descriptions-item> <el-descriptions-item label="入场钢卷号">{{ coilInfo.enterCoilNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="当前钢卷号">{{ coilInfo.currentCoilNo || '-' }}</el-descriptions-item> <el-descriptions-item label="当前钢卷号">{{ coilInfo.currentCoilNo || '-' }}</el-descriptions-item>
@@ -47,9 +62,15 @@
</el-descriptions> </el-descriptions>
<!-- 已分条钢卷列表 --> <!-- 已分条钢卷列表 -->
<el-descriptions :column="1" border title="已分出的钢卷列表"></el-descriptions> <el-descriptions :column="1" border title="已分出的钢卷列表" />
<el-table v-loading="splitListLoading" :data="splitList" @row-click="handleSplitItemClick" <el-table
highlight-current-row border stripe> v-loading="splitListLoading"
:data="splitList"
highlight-current-row
border
stripe
@row-click="handleSplitItemClick"
>
<el-table-column prop="enterCoilNo" label="入场钢卷号" /> <el-table-column prop="enterCoilNo" label="入场钢卷号" />
<el-table-column prop="currentCoilNo" label="当前钢卷号" /> <el-table-column prop="currentCoilNo" label="当前钢卷号" />
@@ -88,28 +109,25 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- <el-descriptions :column="1" border title="镀锌二级数据"
v-if="actionType == 501 && showSplitForm"></el-descriptions>
<el-table v-if="actionType == 501 && showSplitForm" v-loading="zincLoading" :data="zincList" border stripe
@row-click="handleZincItemClick" highlight-current-row>
<el-table-column type="index" label="序号" width="50" />
<el-table-column prop="enterCoilNo" label="入场钢卷号" />
<el-table-column prop="createTime" label="生产开始时间" />
<el-table-column prop="endTime" label="生产结束时间" />
<el-table-column prop="shiftNo" label="班组" />
</el-table> -->
<!-- 今日排产单 --> <!-- 今日排产单 -->
<div v-if="planSheetList.length > 0" class="plan-sheet-section"> <div v-if="planSheetList.length > 0" class="plan-sheet-section">
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ''"> <el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ''" />
</el-descriptions>
<el-tabs v-model="activePlanSheetId" type="card"> <el-tabs v-model="activePlanSheetId" type="card">
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId" <el-tab-pane
v-for="sheet in planSheetList"
:key="sheet.planSheetId"
:name="sheet.planSheetId" :name="sheet.planSheetId"
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" /> :label="sheet.planCode || ('排产单' + sheet.planSheetId)"
/>
</el-tabs> </el-tabs>
<el-table v-loading="planSheetLoading" :data="activePlanSheetDetails" border stripe size="mini" <el-table
max-height="400"> v-loading="planSheetLoading"
:data="activePlanSheetDetails"
border
stripe
size="mini"
max-height="400"
>
<el-table-column type="index" label="序号" width="50" /> <el-table-column type="index" label="序号" width="50" />
<el-table-column label="订单信息" header-align="center"> <el-table-column label="订单信息" header-align="center">
<el-table-column prop="contractCode" label="合同号" width="140" show-overflow-tooltip /> <el-table-column prop="contractCode" label="合同号" width="140" show-overflow-tooltip />
@@ -138,8 +156,7 @@
<!-- 今日排产单空状态 --> <!-- 今日排产单空状态 -->
<div v-if="planSheetList.length === 0 && planSheetLineName && !planSheetLoading" class="plan-sheet-section"> <div v-if="planSheetList.length === 0 && planSheetLineName && !planSheetLoading" class="plan-sheet-section">
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ''"> <el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ''" />
</el-descriptions>
<el-empty description="今天暂无排产单" :image-size="80" /> <el-empty description="今天暂无排产单" :image-size="80" />
</div> </div>
</div> </div>
@@ -147,19 +164,31 @@
<!-- 右侧分条表单 / 分条详情 --> <!-- 右侧分条表单 / 分条详情 -->
<el-col :span="12"> <el-col :span="12">
<div class="split-form-card" v-if="showSplitForm"> <div v-if="showSplitForm" class="split-form-card">
<el-card title="分条钢卷信息录入" shadow="hover"> <el-card title="分条钢卷信息录入" shadow="hover">
<el-alert v-if="!isExemptFromValidation" type="warning" :closable="false" show-icon style="margin-bottom:12px">
<template slot="title">
子卷的<b>净重</b><b>实测厚度</b>均不能超过父卷完成分条时所有子卷净重总和不能超过父卷净重
</template>
</el-alert>
<el-form ref="splitFormRef" :model="splitForm" :rules="rules" label-width="100px" style="max-width: 800px;"> <el-form ref="splitFormRef" :model="splitForm" :rules="rules" label-width="100px" style="max-width: 800px;">
<el-form-item label="入场钢卷号" prop="enterCoilNo"> <el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="splitForm.enterCoilNo" placeholder="请输入入场钢卷号" disabled /> <el-input v-model="splitForm.enterCoilNo" placeholder="请输入入场钢卷号" disabled />
</el-form-item> </el-form-item>
<el-form-item v-if="isGrindAction" label="镀铬卷号" prop="chromePlateCoilNo">
<el-input v-model="splitForm.chromePlateCoilNo" placeholder="请输入镀铬卷号" />
</el-form-item>
<el-form-item label="当前钢卷号" prop="currentCoilNo"> <el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="splitForm.currentCoilNo" placeholder="请输入当前钢卷号" /> <el-input v-model="splitForm.currentCoilNo" placeholder="请输入当前钢卷号" />
<current-coil-no :current-coil-no="splitForm.currentCoilNo" /> <current-coil-no :current-coil-no="splitForm.currentCoilNo" />
</el-form-item> </el-form-item>
<el-form-item label="所在库位" prop="warehouseId"> <el-form-item label="所在库位" prop="warehouseId">
<warehouse-select v-model="splitForm.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%;" <warehouse-select
clearable /> v-model="splitForm.warehouseId"
placeholder="请选择仓库/库区/库位"
style="width: 100%;"
clearable
/>
</el-form-item> </el-form-item>
<el-form-item label="班组" prop="team"> <el-form-item label="班组" prop="team">
<el-select v-model="splitForm.team" placeholder="请选择班组" style="width: 100%"> <el-select v-model="splitForm.team" placeholder="请选择班组" style="width: 100%">
@@ -174,16 +203,30 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="getItemLabel" prop="itemId"> <el-form-item :label="getItemLabel" prop="itemId">
<product-select v-if="splitForm.itemType === 'product'" v-model="splitForm.itemId" placeholder="请选择成品" <product-select
style="width: 100%;" clearable /> v-if="splitForm.itemType === 'product'"
<raw-material-select v-else-if="splitForm.itemType === 'raw_material'" v-model="splitForm.itemId" v-model="splitForm.itemId"
placeholder="请选择原料" style="width: 100%;" clearable /> placeholder="请选择成品"
style="width: 100%;"
clearable
/>
<raw-material-select
v-else-if="splitForm.itemType === 'raw_material'"
v-model="splitForm.itemId"
placeholder="请选择原料"
style="width: 100%;"
clearable
/>
<div v-else>请先选择材料类型</div> <div v-else>请先选择材料类型</div>
</el-form-item> </el-form-item>
<el-form-item label="质量状态" prop="qualityStatus"> <el-form-item label="质量状态" prop="qualityStatus">
<el-select v-model="splitForm.qualityStatus" placeholder="请选择质量状态" style="width: 100%"> <el-select v-model="splitForm.qualityStatus" placeholder="请选择质量状态" style="width: 100%">
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :label="item.label" <el-option
:value="item.value" /> v-for="item in dict.type.coil_quality_status"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="切边要求" prop="trimmingRequirement"> <el-form-item label="切边要求" prop="trimmingRequirement">
@@ -213,39 +256,64 @@
<el-input v-model="splitForm.length" placeholder="请输入长度" type="number" /> <el-input v-model="splitForm.length" placeholder="请输入长度" type="number" />
</el-form-item> </el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength"> <el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="splitForm.actualLength" placeholder="请输入实测长度" type="number" <el-input-number
:step="0.01" /> v-model="splitForm.actualLength"
:controls="false"
placeholder="请输入实测长度"
type="number"
:step="0.01"
/>
</el-form-item> </el-form-item>
<el-form-item label="实测厚度(mm)" prop="actualThickness"> <el-form-item label="实测厚度(mm)" prop="actualThickness">
<el-input-number :controls="false" v-model="splitForm.actualThickness" placeholder="请输入实测厚度" <el-input-number
type="number" :step="0.01" /> v-model="splitForm.actualThickness"
:controls="false"
placeholder="请输入实测厚度"
type="number"
:step="0.01"
/>
</el-form-item> </el-form-item>
<el-form-item label="实测宽度(mm)" prop="actualWidth"> <el-form-item label="实测宽度(mm)" prop="actualWidth">
<el-input-number :controls="false" v-model="splitForm.actualWidth" placeholder="请输入实测宽度" type="number" <el-input-number
:step="0.01" /> v-model="splitForm.actualWidth"
:controls="false"
placeholder="请输入实测宽度"
type="number"
:step="0.01"
/>
</el-form-item> </el-form-item>
<el-form-item label="业务目的" prop="businessPurpose"> <el-form-item label="业务目的" prop="businessPurpose">
<el-select v-model="splitForm.businessPurpose" placeholder="业务目的" filterable> <el-select v-model="splitForm.businessPurpose" placeholder="业务目的" filterable>
<el-option v-for="item in dict.type.coil_business_purpose" :key="item.value" :value="item.value" <el-option
:label="item.label" /> v-for="item in dict.type.coil_business_purpose"
:key="item.value"
:value="item.value"
:label="item.label"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="调制度" prop="temperGrade"> <el-form-item label="调制度" prop="temperGrade">
<el-input v-model="splitForm.temperGrade" placeholder="请输入调制度" /> <el-input v-model="splitForm.temperGrade" placeholder="请输入调制度" />
</el-form-item> </el-form-item>
<el-form-item label="镀层种类" prop="coatingType"> <el-form-item label="镀层种类" prop="coatingType">
<MemoInput storageKey="coatingType" v-model="splitForm.coatingType" placeholder="请输入镀层种类" /> <MemoInput v-model="splitForm.coatingType" storage-key="coatingType" placeholder="请输入镀层种类" />
</el-form-item> </el-form-item>
<el-form-item label="钢卷表面处理" prop="coilSurfaceTreatment"> <el-form-item label="钢卷表面处理" prop="coilSurfaceTreatment">
<MemoInput storageKey="surfaceTreatmentDesc" v-model="splitForm.coilSurfaceTreatment" <MemoInput
placeholder="请输入钢卷表面处理" /> v-model="splitForm.coilSurfaceTreatment"
storage-key="surfaceTreatmentDesc"
placeholder="请输入钢卷表面处理"
/>
</el-form-item> </el-form-item>
<el-form-item label="生产开始时间" prop="productionStartTime"> <el-form-item label="生产开始时间" prop="productionStartTime">
<TimeInput v-model="splitForm.productionStartTime" @input="calculateProductionDuration" /> <TimeInput v-model="splitForm.productionStartTime" @input="calculateProductionDuration" />
</el-form-item> </el-form-item>
<el-form-item label="生产结束时间" prop="productionEndTime"> <el-form-item label="生产结束时间" prop="productionEndTime">
<TimeInput v-model="splitForm.productionEndTime" @input="calculateProductionDuration" <TimeInput
:show-now-button="true" /> v-model="splitForm.productionEndTime"
:show-now-button="true"
@input="calculateProductionDuration"
/>
</el-form-item> </el-form-item>
<el-form-item label="生产耗时" prop="productionDuration"> <el-form-item label="生产耗时" prop="productionDuration">
<el-input v-model="splitForm.formattedDuration" placeholder="自动计算" disabled /> <el-input v-model="splitForm.formattedDuration" placeholder="自动计算" disabled />
@@ -260,19 +328,28 @@
<el-form-item label="异常信息"> <el-form-item label="异常信息">
<div class="abnormal-container"> <div class="abnormal-container">
<div v-for="(abnormal, index) in abnormals" :key="index" class="abnormal-item" <div
@click="editAbnormal(index)"> v-for="(abnormal, index) in abnormals"
:key="index"
class="abnormal-item"
@click="editAbnormal(index)"
>
<div class="abnormal-content"> <div class="abnormal-content">
<div class="abnormal-info"> <div class="abnormal-info">
<div class="abnormal-position">{{ getAbnormalPositionText(abnormal.position) }}</div> <div class="abnormal-position">{{ getAbnormalPositionText(abnormal.position) }}</div>
<div class="abnormal-code">{{ getAbnormalCodeText(abnormal.defectCode) }}</div> <div class="abnormal-code">{{ getAbnormalCodeText(abnormal.defectCode) }}</div>
</div> </div>
<el-button type="danger" size="mini" icon="el-icon-close" class="abnormal-delete" <el-button
@click.stop="deleteAbnormal(index)"></el-button> type="danger"
size="mini"
icon="el-icon-close"
class="abnormal-delete"
@click.stop="deleteAbnormal(index)"
/>
</div> </div>
</div> </div>
<div class="abnormal-add" @click="addAbnormal"> <div class="abnormal-add" @click="addAbnormal">
<i class="el-icon-plus"></i> <i class="el-icon-plus" />
</div> </div>
</div> </div>
</el-form-item> </el-form-item>
@@ -287,23 +364,27 @@
</div> </div>
<!-- 分条钢卷详情选中列表项时显示 --> <!-- 分条钢卷详情选中列表项时显示 -->
<div class="split-detail-card" v-else-if="selectedSplitItem"> <div v-else-if="selectedSplitItem" class="split-detail-card">
<el-card title="分条钢卷详情" shadow="hover"> <el-card title="分条钢卷详情" shadow="hover">
<CoilInfoRender :coilInfo="selectedSplitItem" :column="2" border /> <CoilInfoRender :coil-info="selectedSplitItem" :column="2" border />
</el-card> </el-card>
</div> </div>
<!-- 初始提示 --> <!-- 初始提示 -->
<div class="empty-tip" v-else> <div v-else class="empty-tip">
<el-empty description="请选择左侧已分条钢卷查看详情,或点击「新增分条」创建新分条"></el-empty> <el-empty description="请选择左侧已分条钢卷查看详情,或点击「新增分条」创建新分条" />
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<!-- 异常表单弹窗 --> <!-- 异常表单弹窗 -->
<el-dialog :title="currentAbnormalIndex === -1 ? '新增异常' : '编辑异常'" :visible.sync="abnormalDialogVisible" <el-dialog
width="600px" append-to-body> :title="currentAbnormalIndex === -1 ? '新增异常' : '编辑异常'"
<abnormal-form ref="abnormalForm" v-model="abnormalForm" :show-coil-selector="false"></abnormal-form> :visible.sync="abnormalDialogVisible"
width="600px"
append-to-body
>
<abnormal-form ref="abnormalForm" v-model="abnormalForm" :show-coil-selector="false" />
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click="abnormalDialogVisible = false"> </el-button> <el-button @click="abnormalDialogVisible = false"> </el-button>
<el-button type="primary" @click="saveAbnormal"> </el-button> <el-button type="primary" @click="saveAbnormal"> </el-button>
@@ -313,7 +394,7 @@
<!-- 缓存数据展示弹窗 --> <!-- 缓存数据展示弹窗 -->
<el-dialog title="发现暂存数据" :visible.sync="cacheDialogVisible" width="800px" append-to-body> <el-dialog title="发现暂存数据" :visible.sync="cacheDialogVisible" width="800px" append-to-body>
<div> <div>
<el-alert title="检测到您之前有暂存的分条数据,是否恢复使用?" type="info" show-icon :closable="false"></el-alert> <el-alert title="检测到您之前有暂存的分条数据,是否恢复使用?" type="info" show-icon :closable="false" />
<el-divider content-position="left">暂存的表单数据</el-divider> <el-divider content-position="left">暂存的表单数据</el-divider>
<el-descriptions :column="2" border size="small"> <el-descriptions :column="2" border size="small">
<el-descriptions-item label="入场钢卷号">{{ parsedCacheData && parsedCacheData.splitForm && <el-descriptions-item label="入场钢卷号">{{ parsedCacheData && parsedCacheData.splitForm &&
@@ -334,10 +415,15 @@
<el-descriptions-item label="备注">{{ parsedCacheData && parsedCacheData.splitForm && <el-descriptions-item label="备注">{{ parsedCacheData && parsedCacheData.splitForm &&
parsedCacheData.splitForm.remark || '-' }}</el-descriptions-item> parsedCacheData.splitForm.remark || '-' }}</el-descriptions-item>
</el-descriptions> </el-descriptions>
<el-divider v-if="parsedCacheData && parsedCacheData.abnormals && parsedCacheData.abnormals.length > 0" <el-divider
content-position="left">暂存的异常信息 ({{ parsedCacheData.abnormals.length }})</el-divider> v-if="parsedCacheData && parsedCacheData.abnormals && parsedCacheData.abnormals.length > 0"
<div v-if="parsedCacheData && parsedCacheData.abnormals && parsedCacheData.abnormals.length > 0" content-position="left"
class="abnormal-container" style="margin-bottom: 20px;"> >暂存的异常信息 ({{ parsedCacheData.abnormals.length }})</el-divider>
<div
v-if="parsedCacheData && parsedCacheData.abnormals && parsedCacheData.abnormals.length > 0"
class="abnormal-container"
style="margin-bottom: 20px;"
>
<div v-for="(abnormal, index) in parsedCacheData.abnormals" :key="index" class="abnormal-item"> <div v-for="(abnormal, index) in parsedCacheData.abnormals" :key="index" class="abnormal-item">
<div class="abnormal-content"> <div class="abnormal-content">
<div class="abnormal-info"> <div class="abnormal-info">
@@ -358,44 +444,26 @@
</template> </template>
<script> <script>
import { getMaterialCoil, listMaterialCoil, createSpecialChild, completeSpecialSplit, updateMaterialCoilSimple, checkCoilNo, delMaterialCoil, getFirstHeatCoilMaterial } from '@/api/wms/coil' import { getMaterialCoil, listMaterialCoil, createSpecialChild, completeSpecialSplit, updateMaterialCoilSimple, delMaterialCoil, getFirstHeatCoilMaterial } from '@/api/wms/coil'
import { completeAction, getPendingAction, updatePendingAction } from '@/api/wms/pendingAction' import { completeAction, getPendingAction, updatePendingAction } from '@/api/wms/pendingAction'
import { saveCoilCache, getCoilCacheByCoilId, delCoilCache } from '@/api/wms/coilCache' import { saveCoilCache, getCoilCacheByCoilId, delCoilCache } from '@/api/wms/coilCache'
import { getGalvanize1TypingPrefill } from '@/api/pocket/acidTyping'; import { getGalvanize1TypingPrefill } from '@/api/pocket/acidTyping'
import { listPlanSheet } from '@/api/aps/planSheet' import { listPlanSheet } from '@/api/aps/planSheet'
import { listPlanDetail } from '@/api/aps/planDetail' import { listPlanDetail } from '@/api/aps/planDetail'
import ProductSelect from "@/components/KLPService/ProductSelect"; import ProductSelect from '@/components/KLPService/ProductSelect'
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect"; import RawMaterialSelect from '@/components/KLPService/RawMaterialSelect'
import WarehouseSelect from "@/components/KLPService/WarehouseSelect"; import WarehouseSelect from '@/components/KLPService/WarehouseSelect'
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect"; import ActualWarehouseSelect from '@/components/KLPService/ActualWarehouseSelect'
import TimeInput from "@/components/TimeInput"; import TimeInput from '@/components/TimeInput'
import AbnormalForm from '../components/AbnormalForm'; import AbnormalForm from '../components/AbnormalForm'
import { generateCoilNoPrefix } from "@/utils/coil/coilNo"; import { generateCoilNoPrefix } from '@/utils/coil/coilNo'
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo"; import ProductInfo from '@/components/KLPService/Renderer/ProductInfo'
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo"; import RawMaterialInfo from '@/components/KLPService/Renderer/RawMaterialInfo'
import ContractSelect from "@/components/KLPService/ContractSelect"; import ContractSelect from '@/components/KLPService/ContractSelect'
import { addCoilContractRel } from "@/api/wms/coilContractRel"; import { addCoilContractRel } from '@/api/wms/coilContractRel'
export default { export default {
name: 'StepSplit', name: 'StepSplit',
props: {
actionId: {
type: [String, Number],
required: true,
},
coilId: {
type: String,
required: true,
},
actionStatus: {
type: Number,
default: 0,
},
actionType: {
type: Number,
required: true,
},
},
components: { components: {
ProductSelect, ProductSelect,
RawMaterialSelect, RawMaterialSelect,
@@ -405,7 +473,25 @@ export default {
AbnormalForm, AbnormalForm,
ProductInfo, ProductInfo,
RawMaterialInfo, RawMaterialInfo,
ContractSelect, ContractSelect
},
props: {
actionId: {
type: [String, Number],
required: true
},
coilId: {
type: String,
required: true
},
actionStatus: {
type: Number,
default: 0
},
actionType: {
type: Number,
required: true
}
}, },
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'], dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
data() { data() {
@@ -439,10 +525,11 @@ export default {
temperGrade: '', temperGrade: '',
coatingType: '', coatingType: '',
remark: '', remark: '',
chromePlateCoilNo: '',
productionStartTime: '', productionStartTime: '',
productionEndTime: '', productionEndTime: '',
productionDuration: '', productionDuration: '',
formattedDuration: '', formattedDuration: ''
}, },
// 已分条钢卷列表 // 已分条钢卷列表
splitList: [], splitList: [],
@@ -455,22 +542,22 @@ export default {
// 表单验证规则 // 表单验证规则
rules: { rules: {
currentCoilNo: [ currentCoilNo: [
{ required: true, message: "当前钢卷号不能为空", trigger: "blur" }, { required: true, message: '当前钢卷号不能为空', trigger: 'blur' },
{ {
// 当前钢卷号必须大于等于10位 // 当前钢卷号必须大于等于10位
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
if (value.length < 11) { if (value.length < 11) {
callback(new Error('当前钢卷号必须大于等于11位')); callback(new Error('当前钢卷号必须大于等于11位'))
} else { } else {
callback(); callback()
} }
}, trigger: 'blur' }, trigger: 'blur'
}, }
], ],
materialType: [{ required: true, message: '请选择材料类型', trigger: 'change' }], materialType: [{ required: true, message: '请选择材料类型', trigger: 'change' }],
itemId: [{ required: true, message: '请选择成品/原料', trigger: 'change' }], itemId: [{ required: true, message: '请选择成品/原料', trigger: 'change' }],
netWeight: [{ required: true, message: '请输入净重', trigger: 'blur' }], netWeight: [{ required: true, message: '请输入净重', trigger: 'blur' }],
warehouseId: [{ required: true, message: '请选择所在库位', trigger: 'change' }], warehouseId: [{ required: true, message: '请选择所在库位', trigger: 'change' }]
}, },
buttonLoading: false, buttonLoading: false,
currentAction: {}, currentAction: {},
@@ -504,7 +591,7 @@ export default {
planSheetList: [], planSheetList: [],
planSheetDetailMap: {}, planSheetDetailMap: {},
planSheetLoading: false, planSheetLoading: false,
activePlanSheetId: null, activePlanSheetId: null
} }
}, },
computed: { computed: {
@@ -518,20 +605,26 @@ export default {
11: '酸轧线', 11: '酸轧线',
200: '酸轧线', 200: '酸轧线',
520: '酸轧线', 520: '酸轧线',
206: '镀锌线', 206: '镀锌线',
501: '镀锌线', 501: '镀锌线',
521: '镀锌线', 521: '镀锌线',
203: '脱脂线', 203: '脱脂线',
502: '脱脂线', 502: '脱脂线',
522: '脱脂线', 522: '脱脂线',
204: '拉矫线', 204: '拉矫线',
503: '拉矫线', 503: '拉矫线',
523: '拉矫线', 523: '拉矫线',
205: '双机架', 205: '双机架',
504: '双机架', 504: '双机架',
524: '双机架', 524: '双机架',
206: '镀铬线',
505: '镀铬线', 505: '镀铬线',
525: '镀铬线', 525: '镀铬线'
} }
return mapping[this.actionType] || '' return mapping[this.actionType] || ''
}, },
@@ -545,6 +638,14 @@ export default {
activePlanSheetDetails() { activePlanSheetDetails() {
return this.planSheetDetailMap[this.activePlanSheetId] || [] return this.planSheetDetailMap[this.activePlanSheetId] || []
}, },
// 是否是镀铬操作
isGrindAction() {
return this.actionType == 505 || this.actionType == 525 || this.actionType == 206
},
// 镀锌/酸轧产线免验净重和厚度范围
isExemptFromValidation() {
return [11, 200, 520, 206, 501, 521].includes(Number(this.actionType))
}
}, },
watch: { watch: {
coilId: { coilId: {
@@ -558,13 +659,13 @@ export default {
// 更新父钢卷ID // 更新父钢卷ID
this.splitForm.parentCoilId = val this.splitForm.parentCoilId = val
} }
}, }
}, },
actionId: { actionId: {
immediate: true, immediate: true,
handler(val) { handler(val) {
// 若actionId变化需要重新加载数据可在此补充逻辑 // 若actionId变化需要重新加载数据可在此补充逻辑
}, }
}, },
actionType: { actionType: {
immediate: true, immediate: true,
@@ -589,7 +690,7 @@ export default {
const res = await listPlanSheet({ const res = await listPlanSheet({
lineName: this.planSheetLineName, lineName: this.planSheetLineName,
pageSize: 3, pageSize: 3,
pageNum: 1, pageNum: 1
}) })
this.planSheetList = res.rows || [] this.planSheetList = res.rows || []
this.planSheetDetailMap = {} this.planSheetDetailMap = {}
@@ -610,7 +711,7 @@ export default {
const res = await listPlanDetail({ const res = await listPlanDetail({
planSheetId, planSheetId,
pageSize: 100, pageSize: 100,
pageNum: 1, pageNum: 1
}) })
const details = res.rows || [] const details = res.rows || []
details.sort((a, b) => { details.sort((a, b) => {
@@ -624,7 +725,6 @@ export default {
} }
}, },
// 查询待分条的钢卷信息 // 查询待分条的钢卷信息
async getCoilInfo() { async getCoilInfo() {
try { try {
@@ -633,14 +733,13 @@ export default {
this.coilInfo = res.data || {} this.coilInfo = res.data || {}
// 获取最早的热轧卷板材质 // 获取最早的热轧卷板材质
try { try {
const firstHeatMaterial = await getFirstHeatCoilMaterial(this.coilId); const firstHeatMaterial = await getFirstHeatCoilMaterial(this.coilId)
if (firstHeatMaterial.code === 200 && firstHeatMaterial.msg) { if (firstHeatMaterial.code === 200 && firstHeatMaterial.msg) {
this.firstHeatMaterial = firstHeatMaterial.msg this.firstHeatMaterial = firstHeatMaterial.msg
} }
} catch { } catch {
} }
} else { } else {
this.$message.error('查询钢卷信息失败:' + res.msg) this.$message.error('查询钢卷信息失败:' + res.msg)
} }
@@ -653,7 +752,7 @@ export default {
this.zincLoading = true this.zincLoading = true
const res = await getGalvanize1TypingPrefill({ const res = await getGalvanize1TypingPrefill({
pageSize: 10, pageSize: 10,
pageNum: 1, pageNum: 1
}) })
this.zincList = res.rows || [] this.zincList = res.rows || []
this.zincLoading = false this.zincLoading = false
@@ -664,7 +763,7 @@ export default {
}, },
async handleDeleteSplit(row) { async handleDeleteSplit(row) {
this.$modal.confirm('确认删除该分卷吗?').then(async () => { this.$modal.confirm('确认删除该分卷吗?').then(async() => {
try { try {
await delMaterialCoil(row.coilId) await delMaterialCoil(row.coilId)
this.$message.success('删除成功') this.$message.success('删除成功')
@@ -693,7 +792,7 @@ export default {
} }
const action = await getPendingAction(this.actionId) const action = await getPendingAction(this.actionId)
this.currentAction = action.data || {} this.currentAction = action.data || {}
const coilIds = action.data.remark; const coilIds = action.data.remark
console.log('coilIds', coilIds) console.log('coilIds', coilIds)
if (!coilIds) { if (!coilIds) {
this.splitList = [] this.splitList = []
@@ -714,7 +813,7 @@ export default {
actionType: action.data.actionType, actionType: action.data.actionType,
coilId: action.data.coilId, coilId: action.data.coilId,
currentCoilNo: action.data.currentCoilNo, currentCoilNo: action.data.currentCoilNo,
remark: res.rows.map(item => item.coilId).join(','), remark: res.rows.map(item => item.coilId).join(',')
}) })
} catch (error) { } catch (error) {
this.$message.error('查询分条列表异常:' + error.message) this.$message.error('查询分条列表异常:' + error.message)
@@ -773,26 +872,27 @@ export default {
temperGrade: '', temperGrade: '',
coatingType: '', coatingType: '',
remark: '', remark: '',
chromePlateCoilNo: '',
productionStartTime: this.currentAction.createTime, productionStartTime: this.currentAction.createTime,
productionEndTime: '', productionEndTime: '',
productionDuration: '', productionDuration: '',
formattedDuration: '', formattedDuration: '',
parentCoilId: this.coilId, parentCoilId: this.coilId
} }
// 重置异常信息 // 重置异常信息
this.abnormals = []; this.abnormals = []
}, },
// 材料类型变更处理 // 材料类型变更处理
handleMaterialTypeChange(val) { handleMaterialTypeChange(val) {
// 清空物品选择 // 清空物品选择
this.splitForm.itemId = null; this.splitForm.itemId = null
// 根据材料类型设置物品类型 // 根据材料类型设置物品类型
if (val === '成品') { if (val === '成品') {
this.splitForm.itemType = 'product'; this.splitForm.itemType = 'product'
} else if (val === '原料') { } else if (val === '原料') {
this.splitForm.itemType = 'raw_material'; this.splitForm.itemType = 'raw_material'
} }
}, },
@@ -812,7 +912,7 @@ export default {
itemType: 'product', itemType: 'product',
materialType: '成品', materialType: '成品',
length: row.exitLength, length: row.exitLength,
netWeight: row.exitNetWeight, netWeight: row.exitNetWeight
} }
}, },
@@ -832,6 +932,22 @@ export default {
if (!valid) { if (!valid) {
return return
} }
// 校验子卷净重和实测厚度不超过父卷(镀锌/酸轧除外)
if (!this.isExemptFromValidation) {
const parentNetWeight = parseFloat(this.coilInfo.netWeight) || 0
const parentThickness = parseFloat(this.coilInfo.actualThickness) || 0
const childNetWeight = parseFloat(this.splitForm.netWeight) || 0
const childThickness = parseFloat(this.splitForm.actualThickness) || 0
if (childNetWeight > 0 && parentNetWeight > 0 && childNetWeight > parentNetWeight) {
this.$message.error(`子卷净重(${childNetWeight}T)不能超过父卷净重(${parentNetWeight}T)`)
return
}
if (childThickness > 0 && parentThickness > 0 && childThickness > parentThickness) {
this.$message.error(`子卷实测厚度(${childThickness}mm)不能超过父卷实测厚度(${parentThickness}mm)`)
return
}
}
try { try {
// 区分新增/编辑有coilId则为编辑否则为新增 // 区分新增/编辑有coilId则为编辑否则为新增
let res let res
@@ -841,7 +957,7 @@ export default {
const splitData = { const splitData = {
...this.splitForm, ...this.splitForm,
abnormals: this.abnormals abnormals: this.abnormals
}; }
if (this.splitForm.coilId) { if (this.splitForm.coilId) {
// 编辑分条:调用更新接口 // 编辑分条:调用更新接口
@@ -853,7 +969,7 @@ export default {
if (this.splitForm.contractId) { if (this.splitForm.contractId) {
addCoilContractRel({ addCoilContractRel({
coilId: res.data.coilId, coilId: res.data.coilId,
contractId: this.splitForm.contractId, contractId: this.splitForm.contractId
}) })
} }
} }
@@ -877,15 +993,34 @@ export default {
// 完成整体分条 // 完成整体分条
async completeSplit() { async completeSplit() {
// 校验所有子卷(镀锌/酸轧除外)
if (!this.isExemptFromValidation) {
const parentThickness = parseFloat(this.coilInfo.actualThickness) || 0
const parentNetWeight = parseFloat(this.coilInfo.netWeight) || 0
let totalChildNetWeight = 0
for (const child of this.splitList) {
const childThickness = parseFloat(child.actualThickness) || 0
const childNetWeight = parseFloat(child.netWeight) || 0
totalChildNetWeight += childNetWeight
if (childThickness > 0 && parentThickness > 0 && childThickness > parentThickness) {
this.$message.error(`子卷【${child.currentCoilNo}】实测厚度(${childThickness}mm)超过父卷实测厚度(${parentThickness}mm),请先修正`)
return
}
}
if (totalChildNetWeight > 0 && parentNetWeight > 0 && totalChildNetWeight > parentNetWeight) {
this.$message.error(`所有子卷净重总和(${totalChildNetWeight.toFixed(3)}T)超过父卷净重(${parentNetWeight}T),请先修正`)
return
}
}
this.$confirm('确认完成整体分条操作?完成后将无法修改分条信息', '提示', { this.$confirm('确认完成整体分条操作?完成后将无法修改分条信息', '提示', {
confirmButtonText: '确认', confirmButtonText: '确认',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning'
}).then(async () => { }).then(async() => {
const loading = this.$loading({ const loading = this.$loading({
lock: true, lock: true,
text: '正在记录分条操作...', text: '正在记录分条操作...',
background: 'rgba(0, 0, 0, 0.7)', background: 'rgba(0, 0, 0, 0.7)'
}) })
try { try {
this.buttonLoading = true this.buttonLoading = true
@@ -918,51 +1053,51 @@ export default {
}, },
// 格式化毫秒值为xx天xx小时xx分钟 // 格式化毫秒值为xx天xx小时xx分钟
formatDuration(milliseconds) { formatDuration(milliseconds) {
if (!milliseconds || milliseconds < 0) return ''; if (!milliseconds || milliseconds < 0) return ''
const seconds = Math.floor(milliseconds / 1000); const seconds = Math.floor(milliseconds / 1000)
const minutes = Math.floor(seconds / 60); const minutes = Math.floor(seconds / 60)
const hours = Math.floor(minutes / 60); const hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24); const days = Math.floor(hours / 24)
const remainingHours = hours % 24; const remainingHours = hours % 24
const remainingMinutes = minutes % 60; const remainingMinutes = minutes % 60
let result = ''; let result = ''
if (days > 0) result += `${days}`; if (days > 0) result += `${days}`
if (remainingHours > 0) result += `${remainingHours}小时`; if (remainingHours > 0) result += `${remainingHours}小时`
if (remainingMinutes > 0) result += `${remainingMinutes}分钟`; if (remainingMinutes > 0) result += `${remainingMinutes}分钟`
return result || '0分钟'; return result || '0分钟'
}, },
// 计算生产耗时 // 计算生产耗时
calculateProductionDuration() { calculateProductionDuration() {
const { productionStartTime, productionEndTime } = this.splitForm; const { productionStartTime, productionEndTime } = this.splitForm
if (productionStartTime && productionEndTime) { if (productionStartTime && productionEndTime) {
const start = new Date(productionStartTime).getTime(); const start = new Date(productionStartTime).getTime()
const end = new Date(productionEndTime).getTime(); const end = new Date(productionEndTime).getTime()
if (end < start) { if (end < start) {
this.$message({ this.$message({
message: '结束时间不能早于开始时间', message: '结束时间不能早于开始时间',
type: 'error', type: 'error'
}); })
this.$set(this.splitForm, 'productionDuration', ''); this.$set(this.splitForm, 'productionDuration', '')
this.$set(this.splitForm, 'formattedDuration', ''); this.$set(this.splitForm, 'formattedDuration', '')
} else { } else {
const durationMs = end - start; const durationMs = end - start
const durationMinutes = Math.round(durationMs / (1000 * 60)); const durationMinutes = Math.round(durationMs / (1000 * 60))
this.$set(this.splitForm, 'productionDuration', durationMinutes); this.$set(this.splitForm, 'productionDuration', durationMinutes)
this.$set(this.splitForm, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000)); this.$set(this.splitForm, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000))
} }
} else { } else {
this.$set(this.splitForm, 'productionDuration', ''); this.$set(this.splitForm, 'productionDuration', '')
this.$set(this.splitForm, 'formattedDuration', ''); this.$set(this.splitForm, 'formattedDuration', '')
} }
}, },
// 新增异常 // 新增异常
addAbnormal() { addAbnormal() {
this.currentAbnormalIndex = -1; this.currentAbnormalIndex = -1
this.abnormalForm = { this.abnormalForm = {
coilId: this.splitForm.coilId || null, coilId: this.splitForm.coilId || null,
position: null, position: null,
@@ -972,15 +1107,15 @@ export default {
defectCode: null, defectCode: null,
degree: null, degree: null,
remark: null remark: null
}; }
this.abnormalDialogVisible = true; this.abnormalDialogVisible = true
}, },
// 编辑异常 // 编辑异常
editAbnormal(index) { editAbnormal(index) {
this.currentAbnormalIndex = index; this.currentAbnormalIndex = index
this.abnormalForm = { ...this.abnormals[index] }; this.abnormalForm = { ...this.abnormals[index] }
this.abnormalDialogVisible = true; this.abnormalDialogVisible = true
}, },
// 保存异常 // 保存异常
@@ -988,19 +1123,19 @@ export default {
this.$refs.abnormalForm.validate(valid => { this.$refs.abnormalForm.validate(valid => {
if (valid) { if (valid) {
// 计算缺陷长度 // 计算缺陷长度
this.abnormalForm.length = this.abnormalForm.endPosition - this.abnormalForm.startPosition; this.abnormalForm.length = this.abnormalForm.endPosition - this.abnormalForm.startPosition
if (this.currentAbnormalIndex === -1) { if (this.currentAbnormalIndex === -1) {
// 新增异常 // 新增异常
this.abnormals.push({ ...this.abnormalForm }); this.abnormals.push({ ...this.abnormalForm })
} else { } else {
// 编辑异常 // 编辑异常
this.abnormals[this.currentAbnormalIndex] = { ...this.abnormalForm }; this.abnormals[this.currentAbnormalIndex] = { ...this.abnormalForm }
} }
this.abnormalDialogVisible = false; this.abnormalDialogVisible = false
} }
}); })
}, },
// 删除异常 // 删除异常
@@ -1010,32 +1145,32 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.abnormals.splice(index, 1); this.abnormals.splice(index, 1)
}); })
}, },
// 获取异常位置文本 // 获取异常位置文本
getAbnormalPositionText(position) { getAbnormalPositionText(position) {
if (!position) return ''; if (!position) return ''
const dict = this.dict.type.coil_abnormal_position; const dict = this.dict.type.coil_abnormal_position
if (!dict) return position; if (!dict) return position
const item = dict.find(item => item.value === position); const item = dict.find(item => item.value === position)
return item ? item.label : position; return item ? item.label : position
}, },
// 获取异常代码文本 // 获取异常代码文本
getAbnormalCodeText(code) { getAbnormalCodeText(code) {
if (!code) return ''; if (!code) return ''
const dict = this.dict.type.coil_abnormal_code; const dict = this.dict.type.coil_abnormal_code
if (!dict) return code; if (!dict) return code
const item = dict.find(item => item.value === code); const item = dict.find(item => item.value === code)
return item ? item.label : code; return item ? item.label : code
}, },
// 复制源卷信息到分条表单 // 复制源卷信息到分条表单
copyFromSourceCoil() { copyFromSourceCoil() {
// 复制除了指定字段之外的其他字段 // 复制除了指定字段之外的其他字段
const excludeFields = ['enterCoilNo', 'currentCoilNo', 'coilId', 'createTime', 'createBy']; const excludeFields = ['enterCoilNo', 'currentCoilNo', 'coilId', 'createTime', 'createBy']
// 构建要复制的字段 // 构建要复制的字段
const copiedFields = { const copiedFields = {
@@ -1057,20 +1192,21 @@ export default {
actualWidth: parseFloat(this.coilInfo.actualWidth) || null, actualWidth: parseFloat(this.coilInfo.actualWidth) || null,
temperGrade: this.coilInfo.temperGrade, temperGrade: this.coilInfo.temperGrade,
coatingType: this.coilInfo.coatingType, coatingType: this.coilInfo.coatingType,
chromePlateCoilNo: this.coilInfo.chromePlateCoilNo,
remark: this.coilInfo.remark, remark: this.coilInfo.remark,
productionStartTime: this.coilInfo.productionStartTime, productionStartTime: this.coilInfo.productionStartTime,
productionEndTime: this.coilInfo.productionEndTime, productionEndTime: this.coilInfo.productionEndTime,
productionDuration: this.coilInfo.productionDuration, productionDuration: this.coilInfo.productionDuration,
formattedDuration: this.coilInfo.productionDuration ? this.formatDuration(this.coilInfo.productionDuration * 60 * 1000) : '' formattedDuration: this.coilInfo.productionDuration ? this.formatDuration(this.coilInfo.productionDuration * 60 * 1000) : ''
}; }
// 合并到分条表单 // 合并到分条表单
this.splitForm = { this.splitForm = {
...this.splitForm, ...this.splitForm,
...copiedFields ...copiedFields
}; }
this.$message.success('已复制源卷信息,请根据需要修改'); this.$message.success('已复制源卷信息,请根据需要修改')
}, },
// 暂存表单内容 // 暂存表单内容
@@ -1114,7 +1250,7 @@ export default {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(async () => { }).then(async() => {
try { try {
await delCoilCache(this.currentCache.cacheId) await delCoilCache(this.currentCache.cacheId)
this.$message.success('删除缓存成功') this.$message.success('删除缓存成功')
@@ -1124,7 +1260,7 @@ export default {
} }
}) })
} }
}, }
} }
</script> </script>
@@ -1237,4 +1373,4 @@ export default {
.plan-sheet-section { .plan-sheet-section {
margin-top: 16px; margin-top: 16px;
} }
</style> </style>

View File

@@ -60,14 +60,20 @@
</div> </div>
<!-- 右侧更新表单 --> <!-- 右侧更新表单 -->
<div> <div>
<el-card class="form-card"> <el-card class="form-card">
<div slot="header" class="card-header"> <div slot="header" class="card-header">
<span><i class="el-icon-edit-outline"></i> {{ '更新信息' }}</span> <span><i class="el-icon-edit-outline"></i> {{ '更新信息' }}</span>
<div> <div>
<el-button size="small" @click="saveTemp" :loading="loading">暂存内容</el-button> <el-button size="small" @click="saveTemp" :loading="loading">暂存内容</el-button>
<el-button type="primary" size="small" @click="handleSave" :loading="loading">保存更新</el-button> <el-button type="primary" size="small" @click="handleSave" :loading="loading">保存更新</el-button>
</div>
</div> </div>
</div>
<el-alert v-if="!isExemptFromValidation" type="warning" :closable="false" show-icon style="margin-bottom:12px">
<template slot="title">
更新后的<b>净重</b><b>实测厚度</b>均不能超过源卷的对应值
</template>
</el-alert>
<div v-if="matchedSpec" style="margin-bottom:10px"> <div v-if="matchedSpec" style="margin-bottom:10px">
<el-tag type="success" size="small"> <el-tag type="success" size="small">
@@ -530,6 +536,10 @@ export default {
isDrAction() { isDrAction() {
return this.actionType === 504 || this.actionType === 524 return this.actionType === 504 || this.actionType === 524
}, },
/** 镀锌/酸轧产线免验净重和厚度范围 */
isExemptFromValidation() {
return [11, 120, 200, 201, 520, 202, 501, 521].includes(Number(this.actionType))
},
// 动态显示标签 // 动态显示标签
getItemLabel() { getItemLabel() {
if (this.updateForm.materialType === '成品') { if (this.updateForm.materialType === '成品') {
@@ -814,6 +824,22 @@ export default {
} }
} }
// 校验净重和实测厚度不超过源卷(镀锌/酸轧除外)
if (!this.isExemptFromValidation) {
const parentNetWeight = parseFloat(this.currentInfo.netWeight) || 0
const parentThickness = parseFloat(this.currentInfo.actualThickness) || 0
const updateNetWeight = parseFloat(this.updateForm.netWeight) || 0
const updateThickness = parseFloat(this.updateForm.actualThickness) || 0
if (updateNetWeight > 0 && parentNetWeight > 0 && updateNetWeight > parentNetWeight) {
this.$message.error(`更新后净重(${updateNetWeight}T)不能超过源卷净重(${parentNetWeight}T)`)
return false
}
if (updateThickness > 0 && parentThickness > 0 && updateThickness > parentThickness) {
this.$message.error(`更新后实测厚度(${updateThickness}mm)不能超过源卷实测厚度(${parentThickness}mm)`)
return false
}
}
const loadingInstance = this.$loading({ const loadingInstance = this.$loading({
lock: true, lock: true,
text: '正在更新钢卷信息,请稍后...', text: '正在更新钢卷信息,请稍后...',

View File

@@ -1,66 +1,66 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="" prop="pin"> <el-form-item label="员工编号" prop="pin">
<el-input <el-input
v-model="queryParams.pin" v-model="queryParams.pin"
placeholder="请输入" placeholder="请输入员工编号"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="" prop="ename"> <el-form-item label="姓名" prop="ename">
<el-input <el-input
v-model="queryParams.ename" v-model="queryParams.ename"
placeholder="请输入" placeholder="请输入姓名"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="" prop="deptname"> <el-form-item label="部门" prop="deptname">
<el-input <el-input
v-model="queryParams.deptname" v-model="queryParams.deptname"
placeholder="请输入" placeholder="请输入部门"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="" prop="sn"> <el-form-item label="考勤编号" prop="sn">
<el-input <el-input
v-model="queryParams.sn" v-model="queryParams.sn"
placeholder="请输入" placeholder="请输入考勤编号"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="" prop="checktime"> <el-form-item label="打卡日期" prop="checktime">
<el-date-picker clearable <el-date-picker clearable
v-model="queryParams.checktime" v-model="queryParams.checktime"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
placeholder="请选择"> placeholder="请选择打卡日期">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="" prop="verify"> <el-form-item label="验证状态" prop="verify">
<el-input <el-input
v-model="queryParams.verify" v-model="queryParams.verify"
placeholder="请输入" placeholder="请输入验证状态"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="" prop="stateno"> <el-form-item label="状态编码" prop="stateno">
<el-input <el-input
v-model="queryParams.stateno" v-model="queryParams.stateno"
placeholder="请输入" placeholder="请输入状态编码"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="" prop="state"> <el-form-item label="状态" prop="state">
<el-input <el-input
v-model="queryParams.state" v-model="queryParams.state"
placeholder="请输入" placeholder="请输入状态"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
@@ -68,7 +68,7 @@
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button type="warning" icon="el-icon-upload" size="mini" :disabled="!lastSyncTime" @click="handleSync">同步</el-button> <el-button type="warning" icon="el-icon-upload" size="mini" @click="handleSync">同步</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -124,42 +124,42 @@
<!-- 添加或修改考勤记录对话框 --> <!-- 添加或修改考勤记录对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="" prop="pin"> <el-form-item label="员工编号" prop="pin">
<el-input v-model="form.pin" placeholder="请输入" /> <el-input v-model="form.pin" placeholder="请输入员工编号" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="ename"> <el-form-item label="姓名" prop="ename">
<el-input v-model="form.ename" placeholder="请输入" /> <el-input v-model="form.ename" placeholder="请输入姓名" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="deptname"> <el-form-item label="部门" prop="deptname">
<el-input v-model="form.deptname" placeholder="请输入" /> <el-input v-model="form.deptname" placeholder="请输入部门" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="sn"> <el-form-item label="考勤编号" prop="sn">
<el-input v-model="form.sn" placeholder="请输入" /> <el-input v-model="form.sn" placeholder="请输入考勤编号" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="checktime"> <el-form-item label="打卡时间" prop="checktime">
<el-date-picker clearable <el-date-picker clearable
v-model="form.checktime" v-model="form.checktime"
type="datetime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择"> placeholder="请选择打卡时间">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="" prop="verify"> <el-form-item label="验证状态" prop="verify">
<el-input v-model="form.verify" placeholder="请输入" /> <el-input v-model="form.verify" placeholder="请输入验证状态" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="stateno"> <el-form-item label="状态编码" prop="stateno">
<el-input v-model="form.stateno" placeholder="请输入" /> <el-input v-model="form.stateno" placeholder="请输入状态编码" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="state"> <el-form-item label="状态" prop="state">
<el-input v-model="form.state" placeholder="请输入" /> <el-input v-model="form.state" placeholder="请输入状态" />
</el-form-item> </el-form-item>
<el-form-item label="" prop="createdAt"> <el-form-item label="创建时间" prop="createdAt">
<el-date-picker clearable <el-date-picker clearable
v-model="form.createdAt" v-model="form.createdAt"
type="datetime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择"> placeholder="请选择创建时间">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -168,12 +168,30 @@
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
<!-- 同步对话框 -->
<el-dialog title="同步考勤数据" :visible.sync="syncDialogVisible" width="420px" append-to-body>
<el-form ref="syncForm" :model="syncFormData" :rules="syncRules" label-width="80px">
<el-form-item label="同步月份" prop="syncMonth">
<el-date-picker
v-model="syncFormData.syncMonth"
type="month"
value-format="yyyy-MM"
placeholder="请选择同步月份"
style="width: 100%">
</el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="syncLoading" type="primary" @click="doSync">确定同步</el-button>
<el-button @click="syncDialogVisible = false">取消</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { listRecords, getRecords, delRecords, addRecords, updateRecords, syncRecords } from "@/api/wms/attendance"; import { listRecords, getRecords, delRecords, addRecords, updateRecords, syncRecords } from "@/api/wms/attendance";
import { getConfigKey, updateConfigByKey } from '@/api/system/config'
export default { export default {
name: "Records", name: "Records",
@@ -181,6 +199,18 @@ export default {
return { return {
// 按钮loading // 按钮loading
buttonLoading: false, buttonLoading: false,
// 同步loading
syncLoading: false,
// 同步弹窗
syncDialogVisible: false,
// 同步表单
syncFormData: {
syncMonth: ""
},
// 同步表单校验
syncRules: {
syncMonth: [{ required: true, message: "请选择同步月份", trigger: "change" }]
},
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组 // 选中数组
@@ -215,20 +245,12 @@ export default {
}, },
// 表单参数 // 表单参数
form: {}, form: {},
lastSyncTime: undefined
}; };
}, },
created() { created() {
this.getLastSyncTime();
this.getList(); this.getList();
}, },
methods: { methods: {
// 最后同步时间
getLastSyncTime() {
getConfigKey('hrm.attendance.lastsync').then(response => {
this.lastSyncTime = response.msg
})
},
/** 查询考勤记录列表 */ /** 查询考勤记录列表 */
getList() { getList() {
@@ -246,23 +268,32 @@ export default {
}, },
// 同步按钮 // 同步按钮
handleSync() { handleSync() {
this.buttonLoading = true; this.syncFormData.syncMonth = "";
if (!this.lastSyncTime) { this.syncDialogVisible = true;
this.$modal.msgError("请先查询最后同步时间"); this.$nextTick(() => {
return; this.$refs.syncForm && this.$refs.syncForm.clearValidate();
} });
this.$modal.confirm('确认同步吗?', { },
confirmButtonText: '确定', // 执行同步
cancelButtonText: '取消', doSync() {
type: 'warning' this.$refs.syncForm.validate(valid => {
}).then(() => { if (!valid) return;
syncRecords(this.lastSyncTime).then(response => { const { syncMonth } = this.syncFormData;
console.log(response) const [year, month] = syncMonth.split('-');
updateConfigByKey('hrm.attendance.lastsync', response.endtime) const lastDay = new Date(year, month, 0).getDate();
this.$modal.msgSuccess("同步成功"); const starttime = `${syncMonth}-01 00:00:00`;
const endtime = `${syncMonth}-${String(lastDay).padStart(2, '0')} 23:59:59`;
this.syncLoading = true;
syncRecords({ starttime, endtime }).then(res => {
const msg = `${res.message}(同步区间:${res.starttime} ~ ${res.endtime},共 ${res.records_synced} 条记录)`;
this.$modal.msgSuccess(msg);
this.syncLoading = false;
this.syncDialogVisible = false;
this.getList(); this.getList();
}).catch(() => {
this.syncLoading = false;
}); });
this.buttonLoading = false;
}); });
}, },
// 表单重置 // 表单重置