Files
klp-oa/klp-ui/src/views/wms/coil/typing.vue
砂糖 8e6f89ee55 feat(生产时间): 添加生产开始时间自动填充功能
在卷材操作的各个页面中,自动将待操作任务的创建时间设置为生产开始时间。同时在生产面板中新增生产时间相关字段的显示列
2026-03-18 10:24:28 +08:00

1122 lines
37 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="typing-coil-container">
<!-- 顶部操作栏 -->
<div class="header-bar">
<div class="header-title">
<i class="el-icon-edit"></i>
<span>钢卷信息更新</span>
</div>
<div class="header-actions">
<el-button type="primary" size="small" @click="handleSave" :loading="loading">保存更新</el-button>
</div>
</div>
<el-alert v-if="acidPrefill.visible" :title="acidPrefill.title" :type="acidPrefill.type" :closable="false" show-icon
style="margin-bottom: 20px;" />
<!-- 主内容区 - 左右布局 -->
<div class="content-wrapper">
<!-- 左侧当前信息 -->
<div class="left-panel">
<el-card class="info-card">
<div slot="header" class="card-header">
<span><i class="el-icon-info"></i> 当前信息</span>
</div>
<div class="info-section">
<div class="info-row">
<span class="info-label">入场钢卷号</span>
<span class="info-value">{{ currentInfo.enterCoilNo || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">当前钢卷号</span>
<span class="info-value">{{ currentInfo.currentCoilNo || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">厂家原料卷号</span>
<span class="info-value">{{ currentInfo.supplierCoilNo || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">班组</span>
<span class="info-value">{{ currentInfo.team || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">物品类型</span>
<span class="info-value">{{ getItemTypeText(currentInfo.itemType) }}</span>
</div>
<div class="info-row">
<span class="info-label">物料名称</span>
<span class="info-value">{{ currentInfo.itemName || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">毛重</span>
<span class="info-value">{{ currentInfo.grossWeight ? currentInfo.grossWeight + ' t' : '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">净重</span>
<span class="info-value">{{ currentInfo.netWeight ? currentInfo.netWeight + ' t' : '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">长度</span>
<span class="info-value">{{ currentInfo.length ? currentInfo.length + ' m' : '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">调制度</span>
<span class="info-value">{{ currentInfo.temperGrade || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">镀层种类</span>
<span class="info-value">{{ currentInfo.coatingType || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">逻辑库区</span>
<span class="info-value">{{ currentInfo.nextWarehouseName || '—' }}</span>
</div>
<div class="info-row" v-if="currentInfo.remark">
<span class="info-label">备注</span>
<span class="info-value">{{ currentInfo.remark }}</span>
</div>
</div>
</el-card>
</div>
<!-- 右侧更新表单 -->
<div class="right-panel">
<el-card class="form-card">
<div slot="header" class="card-header">
<span><i class="el-icon-edit-outline"></i> {{ '更新信息' }}</span>
<!-- <el-button type="text" size="mini" @click="copyFromCurrent" icon="el-icon-document-copy">
复制当前信息
</el-button> -->
</div>
<el-form ref="updateForm" :model="updateForm" :rules="rules" label-width="80px" size="small">
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="updateForm.currentCoilNo" placeholder="请输入当前钢卷号">
<template slot="prepend">
<i class="el-icon-document"></i>
</template>
</el-input>
<current-coil-no :current-coil-no="updateForm.currentCoilNo"></current-coil-no>
</el-form-item>
<el-form-item label="班组" prop="team">
<el-select v-model="updateForm.team" placeholder="请选择班组" style="width: 100%">
<el-option key="甲" label="甲" value="甲" />
<el-option key="乙" label="乙" value="乙" />
</el-select>
</el-form-item>
<el-form-item label="材料类型" prop="materialType">
<el-select v-model="updateForm.materialType" placeholder="请选择材料类型" style="width: 100%" @change="handleMaterialTypeChange">
<el-option label="原料" value="原料" />
<el-option label="成品" value="成品" />
</el-select>
</el-form-item>
<el-form-item :label="getItemLabel" prop="itemId" :rules="rules.itemId">
<RawMaterialSelect v-if="updateForm.materialType === '原料'" v-model="updateForm.itemId" placeholder="请选择原料"
style="width: 100%" clearable :disabled="!updateForm.materialType" />
<ProductSelect v-else-if="updateForm.materialType === '成品'" v-model="updateForm.itemId"
placeholder="请选择成品" style="width: 100%" clearable :disabled="!updateForm.materialType" />
<div v-else>请先选择物料类型</div>
</el-form-item>
<el-form-item label="质量状态" prop="qualityStatus">
<el-select v-model="updateForm.qualityStatus" placeholder="请选择质量状态" style="width: 100%">
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="切边要求" prop="trimmingRequirement">
<el-select v-model="updateForm.trimmingRequirement" placeholder="请选择切边要求" style="width: 100%">
<el-option label="净边料" value="净边料" />
<el-option label="毛边料" value="毛边料" />
</el-select>
</el-form-item>
<el-form-item label="打包状态" prop="packingStatus">
<el-input v-model="updateForm.packingStatus" placeholder="请输入打包状态">
</el-input>
</el-form-item>
<el-form-item label="包装要求" prop="packagingRequirement">
<el-select v-model="updateForm.packagingRequirement" placeholder="请选择包装要求" style="width: 100%">
<el-option label="裸包" value="裸包" />
<el-option label="普包" value="普包" />
<el-option label="简包" value="简包" />
</el-select>
</el-form-item>
<el-form-item label="毛重(t)" prop="grossWeight">
<el-input-number :precision="3" :controls="false" v-model="updateForm.grossWeight" placeholder="请输入毛重"
type="number" :step="0.01">
</el-input-number>
</el-form-item>
<el-form-item label="净重(t)" prop="netWeight">
<el-input-number :precision="3" :controls="false" v-model="updateForm.netWeight" placeholder="请输入净重"
type="number" :step="0.001">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="updateForm.actualLength" placeholder="请输入实测长度" type="number"
:step="0.001">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth">
<el-input-number :controls="false" v-model="updateForm.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.001">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="updateForm.temperGrade" placeholder="请输入调制度" />
</el-form-item>
<el-form-item label="镀层种类" prop="coatingType">
<MemoInput storageKey="coatingType" v-model="updateForm.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
<el-form-item label="逻辑库区" prop="warehouseId">
<WarehouseSelect v-model="updateForm.warehouseId" placeholder="请选择逻辑库区" />
</el-form-item>
<el-form-item label="真实库区" prop="actualWarehouseId">
<ActualWarehouseSelect :clearInput="false" clearable v-model="updateForm.actualWarehouseId" placeholder="请选择真实库区" block />
</el-form-item>
<el-form-item label="生产开始时间" prop="productionStartTime">
<TimeInput v-model="updateForm.productionStartTime" @input="calculateProductionDuration" />
</el-form-item>
<el-form-item label="生产结束时间" prop="productionEndTime">
<TimeInput v-model="updateForm.productionEndTime" @input="calculateProductionDuration" :show-now-button="true" />
</el-form-item>
<el-form-item label="生产耗时" prop="productionDuration">
<el-input v-model="updateForm.formattedDuration" placeholder="自动计算" disabled />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="updateForm.remark" type="textarea" :rows="4" placeholder="请输入备注信息(非必填)" maxlength="500"
show-word-limit />
</el-form-item>
</el-form>
</el-card>
<!-- 酸连轧最近10条记录展示 -->
<el-card class="recent-records-card" v-if="acidRecentRecords && acidRecentRecords.length > 0">
<div slot="header" class="card-header">
<span><i class="el-icon-time"></i> 酸连轧最近记录</span>
</div>
<el-table :data="acidRecentRecords" stripe size="small" @row-click="handleClickRecord">
<el-table-column prop="currentCoilNo" label="加工前卷号" width="120" show-overflow-tooltip></el-table-column>
<el-table-column prop="excoilId" label="出口卷号" width="120" show-overflow-tooltip></el-table-column>
<el-table-column prop="exitWeight" label="出口重量(t)" width="100">
<template slot-scope="scope">
{{ scope.row.exitWeight ? scope.row.exitWeight + ' t' : '—' }}
</template>
</el-table-column>
<!-- <el-table-column prop="exitLength" label="出口长度(m)" width="120">
<template slot-scope="scope">
{{ scope.row.exitLength ? scope.row.exitLength + ' m' : '—' }}
</template>
</el-table-column> -->
<el-table-column prop="team" label="班组" width="80"></el-table-column>
</el-table>
</el-card>
</div>
</div>
</div>
</template>
<script>
import { getMaterialCoil, updateMaterialCoil, getMaterialCoilTrace, checkCoilNo } from '@/api/wms/coil';
import { completeAction, getPendingAction } from '@/api/wms/pendingAction';
import { listWarehouse } from '@/api/wms/warehouse';
import { listRawMaterialWithBom } from '@/api/wms/rawMaterial';
import { listProductWithBom } from '@/api/wms/product';
import { getAcidTypingPrefill } from '@/api/pocket/acidTyping';
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
import ProductSelect from "@/components/KLPService/ProductSelect";
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import TimeInput from "@/components/TimeInput";
import { generateCoilNoPrefix } from "@/utils/coil/coilNo";
export default {
name: 'TypingCoil',
components: {
ActualWarehouseSelect,
RawMaterialSelect,
ProductSelect,
WarehouseSelect,
TimeInput,
},
dicts: ['coil_quality_status'],
data() {
return {
loading: false,
historyLoading: false,
// 当前信息(只读)
currentInfo: {
coilId: null,
enterCoilNo: '',
currentCoilNo: '',
supplierCoilNo: '',
team: '',
itemType: null,
itemId: null,
itemName: '',
grossWeight: undefined,
netWeight: undefined,
warehouseId: null,
warehouseId: null,
nextWarehouseName: '',
status: 0,
remark: '',
length: undefined,
},
// 更新表单
updateForm: {
currentCoilNo: '',
team: '',
materialType: null,
itemType: null,
itemId: null,
grossWeight: undefined,
netWeight: undefined,
warehouseId: null,
actualWarehouseId: null,
remark: '',
qualityStatus: '',
packagingRequirement: '',
packingStatus: '',
trimmingRequirement: '',
length: undefined,
temperGrade: '',
coatingType: '',
actualLength: undefined,
actualWidth: undefined,
productionStartTime: '',
productionEndTime: '',
productionDuration: '',
formattedDuration: '',
},
rules: {
currentCoilNo: [
{ required: true, message: '请输入当前钢卷号', trigger: 'blur' },
{
// 当前钢卷号必须大于等于10位
validator: (rule, value, callback) => {
if (value.length < 10) {
callback(new Error('当前钢卷号必须大于等于10位'));
} else {
callback();
}
}, trigger: 'blur'
},
// 仅在新增的时候校验
// {
// validator: (rule, value, callback) => {
// // 没有coilId则为新增 触发校验
// checkCoilNo({ currentCoilNo: value, coilId: this.updateForm.coilId }).then(res => {
// const { duplicateType } = res.data;
// if (duplicateType === 'current' || duplicateType === 'both') {
// // alert('当前钢卷号重复,请重新输入');
// callback(new Error('当前钢卷号重复,请重新输入'));
// } else {
// callback();
// }
// })
// }, trigger: 'blur'
// }
],
team: [
{ required: true, message: '请输入班组', trigger: 'blur' }
],
materialType: [
{ required: true, message: '请选择材料类型', trigger: 'change' }
],
itemType: [
{ required: true, message: '请选择物品类型', trigger: 'change' }
],
itemId: [
{ required: true, message: '请选择物品', trigger: 'change' }
],
grossWeight: [
{ required: true, message: '请输入毛重', trigger: 'blur' },
{ type: 'number', message: '毛重必须为数字', trigger: 'blur' }
],
netWeight: [
{ required: true, message: '请输入净重', trigger: 'blur' },
{ type: 'number', message: '净重必须为数字', trigger: 'blur' }
],
warehouseId: [
{ required: true, message: '请选择逻辑库区', trigger: 'change' }
],
},
warehouseList: [],
historySteps: [],
actionId: null,
acidPrefill: {
visible: false,
type: 'info',
title: ''
},
isAcidRolling: false,
// 原材料和产品列表(实时搜索,不再保存完整备份)
rawMaterialList: [],
productList: [],
itemSearchLoading: false,
// 酸连轧最近记录
acidRecentRecords: []
};
},
computed: {
// 动态显示标签
getItemLabel() {
if (this.updateForm.materialType === '成品') {
return '产品类型';
} else if (this.updateForm.materialType === '原料') {
return '原料类型';
}
return '物品';
},
// 动态显示占位符
getItemPlaceholder() {
if (this.updateForm.materialType === '成品') {
return '请选择产品类型';
} else if (this.updateForm.materialType === '原料') {
return '请选择原料类型';
}
return '请先选择材料类型';
},
// 当前物品列表(根据物品类型动态切换)
currentItemList() {
if (this.updateForm.itemType === 'raw_material') {
return this.rawMaterialList.map(item => ({
id: item.rawMaterialId,
name: this.formatItemName(item)
}));
} else if (this.updateForm.itemType === 'product') {
return this.productList.map(item => ({
id: item.productId,
name: this.formatItemName(item)
}));
}
return [];
}
},
async created() {
// 先加载库区列表
await this.loadWarehouses();
// 从路由参数获取coilId和actionId
const coilId = this.$route.query.coilId;
const actionId = this.$route.query.actionId;
let actionType = ''
const pendingActionRes = await getPendingAction(actionId)
actionType = pendingActionRes.data.actionType
// 填写生产开始时间
this.$set(this.updateForm, 'productionStartTime', pendingActionRes.data.createTime)
this.
this.isAcidRolling = actionType == 11
if (this.isAcidRolling) {
this.acidPrefill.visible = true
this.acidPrefill.type = 'info'
this.acidPrefill.title = '正在结合酸轧二级系统自动填写部分信息...'
}
if (coilId) {
await this.loadCoilInfo(coilId);
if (this.isAcidRolling) {
const currentCoilNo = this.currentInfo && this.currentInfo.currentCoilNo
if (!currentCoilNo) {
this.acidPrefill.type = 'warning'
this.acidPrefill.title = '当前钢卷号为空'
} else {
try {
const prefillRes = await getAcidTypingPrefill(currentCoilNo)
const prefill = prefillRes && prefillRes.data
// this.acidRecentRecords = [
// {
// currentCoilNo: '12345678',
// excoilId: '12345678',
// exitWeight: 245.567,
// exitLength: 1490,
// team: '甲'
// }
// ]
// return;
if (!prefill || prefill.length === 0) {
this.acidPrefill.type = 'info'
this.acidPrefill.title = '未在二级系统中查找到对应信息,请自行填写'
} else {
// 处理返回的列表数据
if (Array.isArray(prefill)) {
this.acidRecentRecords = prefill;
// 使用第一条记录填充表单(保持原有逻辑)
const firstRecord = prefill[0];
if (firstRecord) {
if (firstRecord.exitWeight != null && firstRecord.exitWeight !== '') {
const w = Number(firstRecord.exitWeight)
if (!Number.isNaN(w)) {
this.$set(this.updateForm, 'grossWeight', w)
this.$set(this.updateForm, 'netWeight', w)
}
}
if (firstRecord.exitLength != null && firstRecord.exitLength !== '') {
const len = Number(firstRecord.exitLength)
if (!Number.isNaN(len)) {
this.$set(this.updateForm, 'length', len)
}
}
if (firstRecord.team) {
this.$set(this.updateForm, 'team', firstRecord.team)
}
}
} else {
// 为了兼容旧版本的单个对象返回格式
if (prefill.exitWeight != null && prefill.exitWeight !== '') {
const w = Number(prefill.exitWeight)
if (!Number.isNaN(w)) {
this.$set(this.updateForm, 'grossWeight', w)
this.$set(this.updateForm, 'netWeight', w)
}
}
if (prefill.exitLength != null && prefill.exitLength !== '') {
const len = Number(prefill.exitLength)
if (!Number.isNaN(len)) {
this.$set(this.updateForm, 'length', len)
}
}
if (prefill.team) {
this.$set(this.updateForm, 'team', prefill.team)
}
}
this.acidPrefill.type = 'success'
this.acidPrefill.title = '已结合酸轧二级系统完成部分信息填写'
console.log('[typing] acid rolling prefill applied:', prefill)
}
} catch (e) {
console.error('[typing] acid rolling prefill request failed:', e)
this.acidPrefill.type = 'error'
this.acidPrefill.title = '未在二级系统中查找到对应信息,故自动填写失败'
}
}
}
}
const currentCoilNoPrefix = generateCoilNoPrefix()
this.$set(this.updateForm, 'currentCoilNo', currentCoilNoPrefix)
if (actionId) {
this.actionId = actionId;
}
},
methods: {
// 处理材料类型变化
handleMaterialTypeChange(value) {
// 清空物品选择
this.$set(this.updateForm, 'itemId', null);
// 根据材料类型设置物品类型
if (value === '成品') {
this.$set(this.updateForm, 'itemType', 'product');
// 清空列表,等待用户搜索
this.productList = [];
} else if (value === '原料') {
this.$set(this.updateForm, 'itemType', 'raw_material');
// 清空列表,等待用户搜索
this.rawMaterialList = [];
}
},
handleClickRecord(row) {
this.updateForm = {
currentCoilNo: row.excoilId,
team: row.team,
netWeight: row.exitWeight,
grossWeight: row.exitWeight,
length: row.exitLength,
}
},
// 加载钢卷信息
async loadCoilInfo(coilId) {
try {
this.loading = true;
const response = await getMaterialCoil(coilId);
if (response.code === 200 && response.data) {
const data = response.data;
// 填充当前信息(左侧)
this.currentInfo = {
...data,
itemName: this.getItemName(data),
nextWarehouseName: this.getWarehouseName(data.warehouseId),
};
// 填充时间相关字段
if (data.productionStartTime) {
this.updateForm.productionStartTime = data.productionStartTime;
}
if (data.productionEndTime) {
this.updateForm.productionEndTime = data.productionEndTime;
}
if (data.productionDuration) {
this.updateForm.productionDuration = data.productionDuration;
this.updateForm.formattedDuration = this.formatDuration(data.productionDuration);
}
// 不再预加载物品列表,改为实时搜索
// 加载变更历史
// this.loadHistory();
}
} catch (error) {
this.$message.error('加载钢卷信息失败');
} finally {
this.loading = false;
}
},
// 获取物料名称
getItemName(data) {
if (data.rawMaterial) {
return data.rawMaterial.rawMaterialName;
} else if (data.product) {
return data.product.productName;
}
return '';
},
// 获取物品类型文本
getItemTypeText(itemType) {
if (itemType === 'raw_material') return '原材料';
if (itemType === 'product') return '产品';
return '—';
},
// 获取库区名称
getWarehouseName(warehouseId) {
if (!warehouseId) return '';
const warehouse = this.warehouseList.find(w => w.warehouseId === warehouseId);
return warehouse ? warehouse.warehouseName : '';
},
// 格式化物品名称(添加规格和参数信息)
formatItemName(item) {
if (!item) return '';
// 获取名称(原材料或产品)
const name = item.rawMaterialName || item.productName || '';
if (!name) return '';
let displayName = name;
const specs = [];
// 1. 优先显示规格从对象的specification字段
if (item.specification) {
specs.push(item.specification);
}
// 2. 添加参数参数最多2个
if (item.bomItems && item.bomItems.length > 0) {
const bomParams = item.bomItems
.filter(bomItem => bomItem.attrKey && bomItem.attrValue)
.slice(0, 2); // 最多2个参数参数
bomParams.forEach(param => {
specs.push(`${param.attrKey}:${param.attrValue}`);
});
}
// 3. 拼接成最终格式
if (specs.length > 0) {
displayName += `${specs.join(' ')}`;
}
return displayName;
},
// 加载库区列表
async loadWarehouses() {
try {
const response = await listWarehouse({ pageNum: 1, pageSize: 1000 });
if (response.code === 200) {
this.warehouseList = response.rows || response.data || [];
}
} catch (error) {
console.error('加载库区列表失败', error);
}
},
// 已移除 loadAllItems改为实时搜索
// 已移除 loadItemList改为实时搜索
// 实时搜索物品(后端搜索)
async searchItems(query) {
if (!this.updateForm.itemType) {
this.$message.warning('请先选择材料类型');
return;
}
// 如果没有输入,清空列表
if (!query || query.trim() === '') {
if (this.updateForm.itemType === 'raw_material') {
this.rawMaterialList = [];
} else if (this.updateForm.itemType === 'product') {
this.productList = [];
}
return;
}
try {
this.itemSearchLoading = true;
const searchQuery = query.trim();
if (this.updateForm.itemType === 'raw_material') {
// 后端搜索原材料(支持名称或规格模糊搜索)
const response = await listRawMaterialWithBom({
pageNum: 1,
pageSize: 20,
rawMaterialName: searchQuery,
specification: searchQuery // 同时传入,后端会使用 OR 条件
});
if (response.code === 200) {
this.rawMaterialList = response.rows || [];
}
} else if (this.updateForm.itemType === 'product') {
// 后端搜索产品(支持名称或规格模糊搜索)
const response = await listProductWithBom({
pageNum: 1,
pageSize: 20,
productName: searchQuery,
specification: searchQuery // 同时传入,后端会使用 OR 条件
});
if (response.code === 200) {
this.productList = response.rows || [];
}
}
} catch (error) {
console.error('搜索物品失败', error);
this.$message.error('搜索失败,请重试');
} finally {
this.itemSearchLoading = false;
}
},
// 物品选择变化
handleItemChange(itemId) {
// 物品选择变化处理
},
// 加载变更历史
async loadHistory() {
if (!this.currentInfo.enterCoilNo) {
return;
}
try {
this.historyLoading = true;
const response = await getMaterialCoilTrace({
enterCoilNo: this.currentInfo.enterCoilNo,
currentCoilNo: this.currentInfo.currentCoilNo || undefined
});
if (response.code === 200 && response.data) {
this.historySteps = response.data.steps || [];
}
} catch (error) {
console.error('加载变更历史失败', error);
} finally {
this.historyLoading = false;
}
},
// 复制当前信息到更新表单
copyFromCurrent() {
const itemType = this.currentInfo.materialType === '原料' ? 'raw_material' : 'product';
this.updateForm = {
currentCoilNo: this.currentInfo.currentCoilNo,
team: this.currentInfo.team,
materialType: this.currentInfo.materialType,
// 不复制 itemType 和 itemId让它们由 materialType 自动决定
itemType,
itemId: this.currentInfo.itemId,
grossWeight: parseFloat(this.currentInfo.grossWeight) || null,
netWeight: parseFloat(this.currentInfo.netWeight) || null,
warehouseId: this.currentInfo.warehouseId,
length: parseFloat(this.currentInfo.length) || null,
remark: this.currentInfo.remark
};
// materialType 会触发 watch自动设置 itemType 并加载物品列表
this.$message.success('已复制当前信息,包含' + this.currentInfo.materialType + '类型的相关信息, 请根据需要修改');
},
// 保存更新
async handleSave() {
this.$refs.updateForm.validate(async (valid) => {
if (!valid) {
return false;
}
// 验证时间逻辑
const { productionStartTime, productionEndTime } = this.updateForm;
if (productionStartTime && productionEndTime) {
const start = new Date(productionStartTime).getTime();
const end = new Date(productionEndTime).getTime();
if (end < start) {
this.$message({
message: '结束时间不能早于开始时间',
type: 'error',
});
return false;
}
}
const loadingInstance = this.$loading({
lock: true,
text: '正在更新钢卷信息,请稍后...',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
this.loading = true;
// 构造更新数据使用标准update接口直接更新原记录
const updateData = {
...this.updateForm,
coilId: this.currentInfo.coilId,
enterCoilNo: this.currentInfo.enterCoilNo,
supplierCoilNo: this.currentInfo.supplierCoilNo,
// 注意不要传newCoils否则会走批量更新逻辑
};
const response = await updateMaterialCoil(updateData);
if (response.code === 200) {
this.$message.success('钢卷信息更新成功');
// 如果是从待操作列表进来的,标记操作为完成
if (this.actionId) {
await completeAction(this.actionId);
}
// 延迟返回
setTimeout(() => {
this.$router.back();
}, 100);
} else {
this.$message.error(response.msg || '更新失败');
}
} catch (error) {
this.$message.error('更新失败');
console.error(error);
} finally {
this.loading = false;
loadingInstance.close();
}
});
},
// 格式化毫秒值为xx天xx小时xx分钟
formatDuration(milliseconds) {
if (!milliseconds || milliseconds < 0) return '';
const seconds = Math.floor(milliseconds / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const remainingHours = hours % 24;
const remainingMinutes = minutes % 60;
let result = '';
if (days > 0) result += `${days}`;
if (remainingHours > 0) result += `${remainingHours}小时`;
if (remainingMinutes > 0) result += `${remainingMinutes}分钟`;
return result || '0分钟';
},
// 计算生产耗时
calculateProductionDuration() {
const { productionStartTime, productionEndTime } = this.updateForm;
if (productionStartTime && productionEndTime) {
const start = new Date(productionStartTime).getTime();
const end = new Date(productionEndTime).getTime();
if (end < start) {
this.$message({
message: '结束时间不能早于开始时间',
type: 'error',
});
this.updateForm.productionDuration = '';
this.updateForm.formattedDuration = '';
} else {
const durationMs = end - start;
const durationMinutes = Math.round(durationMs / (1000 * 60));
this.updateForm.productionDuration = durationMinutes;
this.updateForm.formattedDuration = this.formatDuration(durationMinutes * 60 * 1000);
}
} else {
this.updateForm.productionDuration = '';
this.updateForm.formattedDuration = '';
}
},
// 取消操作
handleCancel() {
this.$router.back();
}
}
};
</script>
<style scoped lang="scss">
.typing-coil-container {
padding: 20px;
background: #f5f7fa;
min-height: calc(100vh - 84px);
}
/* 顶部操作栏 */
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
padding: 16px 20px;
margin-bottom: 20px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.header-title {
font-size: 18px;
font-weight: 500;
color: #303133;
display: flex;
align-items: center;
gap: 8px;
i {
color: #0066cc;
font-size: 20px;
}
}
/* 主内容区 */
.content-wrapper {
display: grid;
grid-template-columns: 300px 1fr;
gap: 10px;
align-items: stretch; // 改为stretch让子元素高度一致
}
/* 左侧面板 */
.left-panel {
min-width: 0;
display: flex;
flex-direction: column;
}
/* 右侧面板 */
.right-panel {
min-width: 0;
display: flex;
gap: 10px; // 添加间距
}
/* 确保两侧卡片高度一致 */
.info-card,
.form-card {
flex: 1;
display: flex;
flex-direction: column;
::v-deep .el-card__body {
flex: 1;
display: flex;
flex-direction: column;
}
}
// 新增:最近记录卡片样式
.recent-records-card {
flex: none // 不伸缩,只占据内容所需空间
}
/* 变更历史区域(占满整行) */
.history-section {
margin-top: 20px;
}
/* 卡片头部 */
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
font-weight: 500;
i {
color: #0066cc;
margin-right: 5px;
}
}
/* 当前信息展示 */
.info-section {
.info-row {
display: flex;
align-items: flex-start;
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
font-size: 14px;
min-width: 80px;
flex-shrink: 0;
}
.info-value {
color: #303133;
font-size: 14px;
font-weight: 500;
flex: 1;
word-break: break-all;
}
}
}
/* 变更历史 */
.history-card {
::v-deep .el-card__body {
max-height: 400px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #dcdfe6;
border-radius: 3px;
}
}
::v-deep .el-timeline {
padding-left: 10px;
}
}
.history-item {
.history-title {
font-weight: 500;
color: #303133;
margin-bottom: 8px;
}
.history-detail {
font-size: 13px;
color: #606266;
margin-bottom: 4px;
.detail-label {
color: #909399;
margin-right: 5px;
}
}
}
.empty-history {
text-align: center;
padding: 40px 0;
color: #909399;
i {
font-size: 48px;
margin-bottom: 10px;
display: block;
}
p {
margin: 0;
}
}
/* 表单样式优化 */
.form-card {
::v-deep .el-input-number {
width: 100%;
.el-input__inner {
text-align: left;
}
}
::v-deep .el-form-item {
margin-bottom: 20px;
}
// 修复数字输入框的样式
::v-deep input[type="number"] {
appearance: textfield;
-moz-appearance: textfield;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
appearance: none;
margin: 0;
}
}
}
// 优化按钮文字颜色
// 实心primary按钮白色文字
::v-deep .el-button--primary.el-button--small:not(.is-plain) {
color: #fff;
}
// plain按钮和text按钮蓝色文字
::v-deep .el-button--primary.el-button--small.is-plain,
::v-deep .el-button--text {
color: #409eff;
&:hover {
color: #66b1ff;
}
}
</style>