feat(plan): 工艺参数内联编辑 + 双分支保存流程
道次区域状态机:
- 未选计划:提示文字
- 已选/未绑方案:「选择已有方案」+ 「新增工艺参数」两个按钮
- 编辑模式:内联可编辑道次表 + 增减道次按钮
底部操作栏:取消 | 仅用于本计划 | 保存为方案...
- 已绑方案只读展示,支持「修改参数」进入编辑
「仅用于本计划」:创建 status=1 的私有方案并绑定,不出现在方案下拉中
「保存为方案」:弹窗填写方案号后以 status=0 保存并绑定,自动刷新方案列表
后端:MillProcessRecipeController.add 改为返回新方案 ID
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,8 @@ public class MillProcessRecipeController extends BaseController {
|
||||
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody MillProcessRecipe recipe) {
|
||||
return toAjax(recipeService.save(recipe));
|
||||
recipeService.save(recipe);
|
||||
return AjaxResult.success(recipe.getId());
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
@current-change="handleQueueSelect"
|
||||
highlight-current-row
|
||||
height="calc(50vh - 120px)">
|
||||
<el-table-column label="序号" prop="sortNo" width="50" align="center" fixed />
|
||||
<el-table-column label="钢卷编号" prop="inMatNo" width="110" />
|
||||
<el-table-column label="合金牌号" prop="alloyNo" width="90" />
|
||||
<el-table-column label="采料厚度(mm)" prop="inMatThick" width="105" align="right" />
|
||||
<el-table-column label="成品厚度(mm)" prop="outThick" width="105" align="right" />
|
||||
<el-table-column label="采料宽度(mm)" prop="inMatWidth" width="105" align="right" />
|
||||
<el-table-column label="道次数" prop="passCount" width="65" align="center" />
|
||||
<el-table-column label="序号" prop="sortNo" width="50" align="center" fixed />
|
||||
<el-table-column label="钢卷编号" prop="inMatNo" width="110" />
|
||||
<el-table-column label="合金牌号" prop="alloyNo" width="90" />
|
||||
<el-table-column label="采料厚度(mm)" prop="inMatThick" width="105" align="right" />
|
||||
<el-table-column label="成品厚度(mm)" prop="outThick" width="105" align="right" />
|
||||
<el-table-column label="采料宽度(mm)" prop="inMatWidth" width="105" align="right" />
|
||||
<el-table-column label="道次数" prop="passCount" width="65" align="center" />
|
||||
<el-table-column label="采料长度(m)" prop="inMatLength" width="100" align="right" />
|
||||
<el-table-column label="采料重量(t)" prop="inMatWeight" width="100" align="right" />
|
||||
<el-table-column label="采料外径(mm)" prop="inMatOd" width="105" align="right" />
|
||||
<el-table-column label="采料内径(mm)" prop="inMatId" width="105" align="right" />
|
||||
<el-table-column label="生产状态" prop="prodStatus" width="80" align="center">
|
||||
<el-table-column label="采料外径(mm)" prop="inMatOd" width="105" align="right" />
|
||||
<el-table-column label="采料内径(mm)" prop="inMatId" width="105" align="right" />
|
||||
<el-table-column label="生产状态" prop="prodStatus" width="80" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span :class="prodStatusClass(row.prodStatus)">{{ prodStatusLabel(row.prodStatus) }}</span>
|
||||
</template>
|
||||
@@ -32,31 +32,116 @@
|
||||
<!-- 下方 -->
|
||||
<div class="bottom-section">
|
||||
|
||||
<!-- 左侧:轧制工艺道次(只读) -->
|
||||
<!-- 左侧:轧制工艺 -->
|
||||
<div class="pass-panel">
|
||||
<div class="section-header">
|
||||
<span>轧制工艺</span>
|
||||
<span v-if="selectedPlan && selectedPlan.recipeNo" class="recipe-tag">{{ selectedPlan.recipeNo }}</span>
|
||||
</div>
|
||||
<el-table :data="passList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass"
|
||||
height="calc(50vh - 130px)">
|
||||
<el-table-column label="道次" prop="passNo" width="45" align="center" fixed />
|
||||
<el-table-column label="入口厚(mm)" prop="inThick" width="85" align="right" />
|
||||
<el-table-column label="出口厚(mm)" prop="outThick" width="85" align="right" />
|
||||
<el-table-column label="轧制力(kN)" prop="rollForce" width="85" align="right" />
|
||||
<el-table-column label="入口张力" prop="inTension" width="75" align="right" />
|
||||
<el-table-column label="出口张力" prop="outTension" width="75" align="right" />
|
||||
<el-table-column label="最高速度" prop="maxSpeed" width="75" align="right" />
|
||||
<el-table-column label="入口单位张力" prop="inUnitTension" width="100" align="right" />
|
||||
<el-table-column label="出口单位张力" prop="outUnitTension" width="100" align="right" />
|
||||
<el-table-column label="压下量(mm)" prop="reduction" width="85" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.reduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总压下量(mm)" prop="totalReduction" width="100" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.totalReduction }}</span></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 状态 A:未选中计划 -->
|
||||
<template v-if="!selectedPlan">
|
||||
<div class="section-header"><span>轧制工艺</span></div>
|
||||
<div class="pass-empty">请在上方选择一条计划</div>
|
||||
</template>
|
||||
|
||||
<!-- 状态 B:已选计划,已绑定方案,只读 -->
|
||||
<template v-else-if="selectedPlan.recipeId && !passEditMode">
|
||||
<div class="section-header">
|
||||
<span>轧制工艺</span>
|
||||
<div style="display:flex;align-items:center;gap:8px">
|
||||
<span class="recipe-tag">{{ selectedPlan.recipeNo }}</span>
|
||||
<el-button size="mini" icon="el-icon-edit" @click="enterEditMode">修改参数</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="passList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass" height="calc(50vh - 160px)">
|
||||
<el-table-column label="道次" prop="passNo" width="45" align="center" fixed />
|
||||
<el-table-column label="入口厚(mm)" prop="inThick" width="90" align="right" />
|
||||
<el-table-column label="出口厚(mm)" prop="outThick" width="90" align="right" />
|
||||
<el-table-column label="轧制力(kN)" prop="rollForce" width="85" align="right" />
|
||||
<el-table-column label="入口张力(kN)" prop="inTension" width="90" align="right" />
|
||||
<el-table-column label="出口张力(kN)" prop="outTension" width="90" align="right" />
|
||||
<el-table-column label="最高速度" prop="maxSpeed" width="80" align="right" />
|
||||
<el-table-column label="入口单位张力" prop="inUnitTension" width="100" align="right" />
|
||||
<el-table-column label="出口单位张力" prop="outUnitTension" width="100" align="right" />
|
||||
<el-table-column label="压下量(mm)" prop="reduction" width="85" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.reduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总压下量(mm)" prop="totalReduction" width="100" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.totalReduction }}</span></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<!-- 状态 C:已选计划,未绑定方案,等待操作 -->
|
||||
<template v-else-if="!selectedPlan.recipeId && !passEditMode">
|
||||
<div class="section-header"><span>轧制工艺</span></div>
|
||||
<div class="pass-empty">
|
||||
<span>该计划尚未绑定工艺参数</span>
|
||||
<div style="margin-top:12px;display:flex;gap:10px">
|
||||
<el-button size="mini" type="primary" icon="el-icon-document-copy" @click="openSelectRecipe">选择已有方案</el-button>
|
||||
<el-button size="mini" icon="el-icon-edit-outline" @click="enterEditMode">新增工艺参数</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 状态 D:编辑模式(新增 或 修改参数) -->
|
||||
<template v-else-if="passEditMode">
|
||||
<div class="section-header">
|
||||
<span>{{ selectedPlan.recipeId ? '修改工艺参数' : '新增工艺参数' }}</span>
|
||||
<div>
|
||||
<el-button size="mini" icon="el-icon-plus" @click="addEditPass">增加道次</el-button>
|
||||
<el-button size="mini" icon="el-icon-minus" @click="removeEditPass" :disabled="editingPassList.length===0">删除末道</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="editingPassList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass" height="calc(50vh - 200px)">
|
||||
<el-table-column label="道次" prop="passNo" width="45" align="center" fixed>
|
||||
<template slot-scope="{ row }"><b>{{ row.passNo }}</b></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口厚(mm)" width="90">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.inThick" size="mini" @blur="calcEditPass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口厚(mm)" width="90">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.outThick" size="mini" @blur="calcEditPass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="宽度(mm)" width="80">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.width" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="轧制力(kN)" width="85">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.rollForce" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口张力" width="80">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.inTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口张力" width="80">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.outTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最高速度" width="80">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.maxSpeed" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口单位张力" width="100">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.inUnitTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口单位张力" width="100">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.outUnitTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="压下量(mm)" prop="reduction" width="85" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.reduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总压下量(mm)" prop="totalReduction" width="100" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.totalReduction }}</span></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 编辑操作栏 -->
|
||||
<div class="edit-action-bar">
|
||||
<el-button size="mini" icon="el-icon-close" @click="cancelEditMode">取消</el-button>
|
||||
<el-button size="mini" type="warning" icon="el-icon-document" @click="savePassOnly">仅用于本计划</el-button>
|
||||
<el-button size="mini" type="primary" icon="el-icon-folder-checked" @click="openSaveAsRecipe">保存为方案...</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 右侧:查询 + 操作 -->
|
||||
@@ -90,11 +175,6 @@
|
||||
<el-button size="mini" icon="el-icon-top" :disabled="!selectedPlan" @click="handleMoveUp">Up 上移</el-button>
|
||||
<el-button size="mini" icon="el-icon-bottom" :disabled="!selectedPlan" @click="handleMoveDown">Down 下移</el-button>
|
||||
</div>
|
||||
|
||||
<div class="section-header" style="margin-top:8px"><span>工艺方案</span></div>
|
||||
<div class="op-buttons">
|
||||
<el-button size="mini" icon="el-icon-document-add" @click="openQuickRecipe">快速新增方案</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -120,7 +200,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 钢卷 新增/修改 对话框 -->
|
||||
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="640px"
|
||||
<el-dialog :title="planDialogTitle" :visible.sync="planDialogVisible" width="640px"
|
||||
:close-on-click-modal="false" append-to-body>
|
||||
<el-form :model="form" :rules="rules" ref="formRef" size="mini" label-width="90px">
|
||||
<el-row :gutter="16">
|
||||
@@ -136,7 +216,8 @@
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="工艺方案">
|
||||
<el-select v-model="form.recipeId" filterable clearable placeholder="可选,不绑定也可保存"
|
||||
<el-select v-model="form.recipeId" filterable clearable
|
||||
placeholder="可选,也可在新增后在下方绑定"
|
||||
style="width:100%" @change="onRecipeChange">
|
||||
<el-option v-for="r in recipeOptions" :key="r.id"
|
||||
:label="`${r.recipeNo}(${r.alloyNo})`" :value="r.id" />
|
||||
@@ -186,80 +267,50 @@
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="dialogVisible = false">取消</el-button>
|
||||
<el-button size="mini" @click="planDialogVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="handleSave">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 快速新增工艺方案 对话框 -->
|
||||
<el-dialog title="快速新增工艺方案" :visible.sync="recipeDialogVisible" width="700px"
|
||||
<!-- 选择已有方案 对话框 -->
|
||||
<el-dialog title="选择工艺方案" :visible.sync="selectRecipeVisible" width="480px"
|
||||
:close-on-click-modal="false" append-to-body>
|
||||
<el-form :model="recipeForm" :rules="recipeRules" ref="recipeFormRef" size="mini" label-width="88px">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="方案记录号" prop="recipeNo">
|
||||
<el-input v-model="recipeForm.recipeNo" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="合金号" prop="alloyNo">
|
||||
<el-input v-model="recipeForm.alloyNo" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="原料厚度" prop="inThick">
|
||||
<el-input v-model="recipeForm.inThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="成品厚度" prop="outThick">
|
||||
<el-input v-model="recipeForm.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 道次列表 -->
|
||||
<div class="recipe-pass-header">
|
||||
<span>道次参数</span>
|
||||
<div>
|
||||
<el-button size="mini" icon="el-icon-plus" @click="addRecipePass">增加道次</el-button>
|
||||
<el-button size="mini" icon="el-icon-minus" @click="removeRecipePass" :disabled="recipePassList.length===0">删除末道</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="recipePassList" border size="mini" max-height="280">
|
||||
<el-table-column label="道次" prop="passNo" width="45" align="center" />
|
||||
<el-table-column label="入口厚(mm)" width="90">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.inThick" size="mini" @blur="calcRecipePass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口厚(mm)" width="90">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.outThick" size="mini" @blur="calcRecipePass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="宽度(mm)" width="80">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.width" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="轧制力(kN)" width="85">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.rollForce" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口张力" width="80">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.inTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口张力" width="80">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.outTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最高速度" width="80">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.maxSpeed" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="压下量" prop="reduction" width="75" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.reduction }}</span></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-form size="mini" label-width="80px">
|
||||
<el-form-item label="工艺方案">
|
||||
<el-select v-model="selectRecipeId" filterable clearable
|
||||
placeholder="输入方案号或合金号搜索" style="width:100%">
|
||||
<el-option v-for="r in recipeOptions" :key="r.id"
|
||||
:label="`${r.recipeNo}(${r.alloyNo})${r.inThick}→${r.outThick}mm`"
|
||||
:value="r.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="recipeDialogVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="saveQuickRecipe">保存方案</el-button>
|
||||
<el-button size="mini" @click="selectRecipeVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="confirmSelectRecipe">确定绑定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 保存为方案 对话框 -->
|
||||
<el-dialog title="保存为工艺方案" :visible.sync="saveAsRecipeVisible" width="400px"
|
||||
:close-on-click-modal="false" append-to-body>
|
||||
<el-form :model="saveAsForm" :rules="saveAsRules" ref="saveAsRef" size="mini" label-width="88px">
|
||||
<el-form-item label="方案记录号" prop="recipeNo">
|
||||
<el-input v-model="saveAsForm.recipeNo" placeholder="方案唯一编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合金号" prop="alloyNo">
|
||||
<el-input v-model="saveAsForm.alloyNo" />
|
||||
</el-form-item>
|
||||
<el-form-item label="原料厚度">
|
||||
<el-input v-model="saveAsForm.inThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="成品厚度">
|
||||
<el-input v-model="saveAsForm.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="saveAsRecipeVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="confirmSaveAsRecipe">保存并绑定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
@@ -289,11 +340,17 @@ export default {
|
||||
return {
|
||||
planList: [],
|
||||
selectedPlan: null,
|
||||
// 只读展示用
|
||||
passList: [],
|
||||
recipeOptions: [],
|
||||
query: { inMatNo: '', dateRange: null, hideFinished: false },
|
||||
|
||||
// 编辑模式
|
||||
passEditMode: false,
|
||||
editingPassList: [],
|
||||
|
||||
// 钢卷对话框
|
||||
dialogVisible: false,
|
||||
planDialogVisible: false,
|
||||
isNew: true,
|
||||
form: emptyForm(),
|
||||
rules: {
|
||||
@@ -302,23 +359,23 @@ export default {
|
||||
inMatThick: [{ required: true, message: '请输入采料厚度', trigger: 'blur' }],
|
||||
outThick: [{ required: true, message: '请输入成品厚度', trigger: 'blur' }],
|
||||
},
|
||||
// 快速新增方案对话框
|
||||
recipeDialogVisible: false,
|
||||
recipeForm: { recipeNo: '', alloyNo: '', inThick: '', outThick: '', outWidth: '' },
|
||||
recipePassList: [],
|
||||
recipeRules: {
|
||||
|
||||
// 选择方案对话框
|
||||
selectRecipeVisible: false,
|
||||
selectRecipeId: null,
|
||||
|
||||
// 保存为方案对话框
|
||||
saveAsRecipeVisible: false,
|
||||
saveAsForm: { recipeNo: '', alloyNo: '', inThick: '', outThick: '' },
|
||||
saveAsRules: {
|
||||
recipeNo: [{ required: true, message: '请输入方案记录号', trigger: 'blur' }],
|
||||
alloyNo: [{ required: true, message: '请输入合金号', trigger: 'blur' }],
|
||||
inThick: [{ required: true, message: '请输入原料厚度', trigger: 'blur' }],
|
||||
outThick: [{ required: true, message: '请输入成品厚度', trigger: 'blur' }],
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogTitle() { return this.isNew ? '新增钢卷' : '修改钢卷' },
|
||||
currentCoil() {
|
||||
return this.planList.find(p => p.prodStatus === '1') || {}
|
||||
},
|
||||
planDialogTitle() { return this.isNew ? '新增钢卷' : '修改钢卷' },
|
||||
currentCoil() { return this.planList.find(p => p.prodStatus === '1') || {} },
|
||||
nextCoil() {
|
||||
const idx = this.planList.findIndex(p => p.prodStatus === '1')
|
||||
if (idx >= 0 && idx + 1 < this.planList.length) return this.planList[idx + 1]
|
||||
@@ -340,42 +397,185 @@ export default {
|
||||
params.beginDate = this.query.dateRange[0]
|
||||
params.endDate = this.query.dateRange[1]
|
||||
}
|
||||
listPlan(params).then(res => {
|
||||
this.planList = res.data || []
|
||||
})
|
||||
listPlan(params).then(res => { this.planList = res.data || [] })
|
||||
},
|
||||
resetQuery() {
|
||||
this.query = { inMatNo: '', dateRange: null, hideFinished: false }
|
||||
this.loadList()
|
||||
},
|
||||
|
||||
// ── 队列行点击 ──
|
||||
handleQueueSelect(row) {
|
||||
if (this.passEditMode) {
|
||||
// 正在编辑时禁止切换行
|
||||
this.$message.warning('请先保存或取消当前编辑')
|
||||
return
|
||||
}
|
||||
this.selectedPlan = row
|
||||
if (!row || !row.recipeId) { this.passList = []; return }
|
||||
getRecipeDetail(row.recipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
this.passList = []
|
||||
if (!row) return
|
||||
if (row.recipeId) {
|
||||
getRecipeDetail(row.recipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// ── 编辑模式 ──
|
||||
enterEditMode() {
|
||||
// 若已有方案,用当前道次数据初始化;否则空列表
|
||||
this.editingPassList = this.passList.map(p => ({ ...p }))
|
||||
this.passEditMode = true
|
||||
},
|
||||
cancelEditMode() {
|
||||
this.passEditMode = false
|
||||
this.editingPassList = []
|
||||
},
|
||||
addEditPass() {
|
||||
this.editingPassList.push(emptyPass(this.editingPassList.length + 1))
|
||||
},
|
||||
removeEditPass() {
|
||||
if (this.editingPassList.length) this.editingPassList.pop()
|
||||
},
|
||||
calcEditPass(row) {
|
||||
const inT = parseFloat(row.inThick) || 0
|
||||
const outT = parseFloat(row.outThick) || 0
|
||||
row.reduction = outT > 0 ? (inT - outT).toFixed(3) : ''
|
||||
const base = parseFloat(this.selectedPlan.inMatThick) || 0
|
||||
this.editingPassList.forEach(p => {
|
||||
const pOut = parseFloat(p.outThick) || 0
|
||||
if (base > 0 && pOut > 0) p.totalReduction = parseFloat((base - pOut).toFixed(3))
|
||||
})
|
||||
},
|
||||
|
||||
// ── 仅用于本计划 ──
|
||||
savePassOnly() {
|
||||
if (this.editingPassList.length === 0) {
|
||||
this.$message.warning('请至少添加一个道次')
|
||||
return
|
||||
}
|
||||
// 创建隐藏方案(recipeNo 以 __ 开头表示私有,不展示在下拉列表中)
|
||||
const autoNo = `__${this.selectedPlan.inMatNo || this.selectedPlan.id}`
|
||||
const payload = {
|
||||
recipeNo: autoNo,
|
||||
alloyNo: this.selectedPlan.alloyNo || '-',
|
||||
inThick: this.selectedPlan.inMatThick || '0',
|
||||
outThick: this.selectedPlan.outThick || '0',
|
||||
passCount: this.editingPassList.length,
|
||||
passList: this.editingPassList,
|
||||
status: '1'
|
||||
}
|
||||
this._doSaveRecipeAndBindPlan(payload)
|
||||
},
|
||||
|
||||
// ── 保存为方案(打开弹窗) ──
|
||||
openSaveAsRecipe() {
|
||||
this.saveAsForm = {
|
||||
recipeNo: '',
|
||||
alloyNo: this.selectedPlan.alloyNo || '',
|
||||
inThick: this.selectedPlan.inMatThick || '',
|
||||
outThick: this.selectedPlan.outThick || ''
|
||||
}
|
||||
this.saveAsRecipeVisible = true
|
||||
},
|
||||
confirmSaveAsRecipe() {
|
||||
this.$refs.saveAsRef.validate(valid => {
|
||||
if (!valid) return
|
||||
if (this.editingPassList.length === 0) {
|
||||
this.$message.warning('请至少添加一个道次')
|
||||
return
|
||||
}
|
||||
const payload = {
|
||||
...this.saveAsForm,
|
||||
passCount: this.editingPassList.length,
|
||||
passList: this.editingPassList,
|
||||
status: '0'
|
||||
}
|
||||
this._doSaveRecipeAndBindPlan(payload).then(() => {
|
||||
this.saveAsRecipeVisible = false
|
||||
this.refreshRecipeOptions()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 公共:新增 recipe,然后把 recipeId 写回 plan
|
||||
_doSaveRecipeAndBindPlan(recipePayload) {
|
||||
return addRecipe(recipePayload).then(res => {
|
||||
const newId = res.data // controller 返回新 ID
|
||||
const recipeNo = recipePayload.recipeNo.startsWith('__') ? '' : recipePayload.recipeNo
|
||||
return updatePlan({
|
||||
...this.selectedPlan,
|
||||
recipeId: newId,
|
||||
recipeNo: recipePayload.recipeNo,
|
||||
passCount: recipePayload.passCount
|
||||
})
|
||||
}).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.passEditMode = false
|
||||
this.editingPassList = []
|
||||
this.loadList()
|
||||
// 刷新已选行数据
|
||||
return listPlan({ inMatNo: this.selectedPlan.inMatNo }).then(res => {
|
||||
const updated = (res.data || []).find(p => p.id === this.selectedPlan.id)
|
||||
if (updated) {
|
||||
this.selectedPlan = updated
|
||||
getRecipeDetail(updated.recipeId).then(r => {
|
||||
this.passList = (r.data && r.data.passList) || []
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// ── 选择已有方案 ──
|
||||
openSelectRecipe() {
|
||||
this.selectRecipeId = null
|
||||
this.selectRecipeVisible = true
|
||||
},
|
||||
confirmSelectRecipe() {
|
||||
if (!this.selectRecipeId) {
|
||||
this.$message.warning('请选择一个方案')
|
||||
return
|
||||
}
|
||||
const r = this.recipeOptions.find(x => x.id === this.selectRecipeId)
|
||||
updatePlan({
|
||||
...this.selectedPlan,
|
||||
recipeId: this.selectRecipeId,
|
||||
recipeNo: r ? r.recipeNo : '',
|
||||
passCount: r ? r.passCount : 0
|
||||
}).then(() => {
|
||||
this.$message.success('方案绑定成功')
|
||||
this.selectRecipeVisible = false
|
||||
this.selectedPlan = { ...this.selectedPlan, recipeId: this.selectRecipeId, recipeNo: r ? r.recipeNo : '' }
|
||||
getRecipeDetail(this.selectRecipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
this.loadList()
|
||||
})
|
||||
},
|
||||
|
||||
// ── 钢卷 CRUD ──
|
||||
handleAdd() {
|
||||
this.isNew = true
|
||||
this.form = emptyForm()
|
||||
this.dialogVisible = true
|
||||
this.planDialogVisible = true
|
||||
},
|
||||
handleEdit() {
|
||||
this.isNew = false
|
||||
this.form = { ...this.selectedPlan }
|
||||
this.dialogVisible = true
|
||||
this.planDialogVisible = true
|
||||
},
|
||||
handleSave() {
|
||||
this.$refs.formRef.validate(valid => {
|
||||
if (!valid) return
|
||||
if (this.form.recipeId) {
|
||||
const matched = this.recipeOptions.find(r => r.id === this.form.recipeId)
|
||||
if (matched) { this.form.recipeNo = matched.recipeNo; this.form.passCount = matched.passCount }
|
||||
const r = this.recipeOptions.find(x => x.id === this.form.recipeId)
|
||||
if (r) { this.form.recipeNo = r.recipeNo; this.form.passCount = r.passCount }
|
||||
}
|
||||
const api = this.isNew ? addPlan : updatePlan
|
||||
api(this.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.dialogVisible = false
|
||||
this.planDialogVisible = false
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
@@ -386,6 +586,7 @@ export default {
|
||||
this.$message.success('删除成功')
|
||||
this.selectedPlan = null
|
||||
this.passList = []
|
||||
this.passEditMode = false
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
@@ -402,52 +603,15 @@ export default {
|
||||
if (!this.form.inMatWidth) this.form.inMatWidth = r.outWidth
|
||||
}
|
||||
},
|
||||
// 快速新增方案
|
||||
openQuickRecipe() {
|
||||
this.recipeForm = { recipeNo: '', alloyNo: '', inThick: '', outThick: '', outWidth: '' }
|
||||
this.recipePassList = []
|
||||
this.recipeDialogVisible = true
|
||||
},
|
||||
addRecipePass() {
|
||||
this.recipePassList.push(emptyPass(this.recipePassList.length + 1))
|
||||
},
|
||||
removeRecipePass() {
|
||||
if (this.recipePassList.length) this.recipePassList.pop()
|
||||
},
|
||||
calcRecipePass(row) {
|
||||
const inT = parseFloat(row.inThick) || 0
|
||||
const outT = parseFloat(row.outThick) || 0
|
||||
row.reduction = outT > 0 ? (inT - outT).toFixed(3) : ''
|
||||
},
|
||||
saveQuickRecipe() {
|
||||
this.$refs.recipeFormRef.validate(valid => {
|
||||
if (!valid) return
|
||||
const data = {
|
||||
...this.recipeForm,
|
||||
passCount: this.recipePassList.length,
|
||||
passList: this.recipePassList
|
||||
}
|
||||
addRecipe(data).then(() => {
|
||||
this.$message.success('工艺方案新增成功')
|
||||
this.recipeDialogVisible = false
|
||||
this.refreshRecipeOptions()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
queueRowClass({ row }) {
|
||||
if (row.prodStatus === '1') return 'row-rolling'
|
||||
if (row.prodStatus === '0' && this.currentCoil.sortNo && row.sortNo === this.currentCoil.sortNo + 1) return 'row-next'
|
||||
return ''
|
||||
},
|
||||
passRowClass({ rowIndex }) {
|
||||
return rowIndex % 2 === 0 ? '' : 'alt-row'
|
||||
},
|
||||
prodStatusLabel(s) {
|
||||
return { '0': '待轧', '1': '轧制中', '2': '已完成', '9': '异常' }[s] || s
|
||||
},
|
||||
prodStatusClass(s) {
|
||||
return { '0': 'status-wait', '1': 'status-rolling', '2': 'status-done', '9': 'status-err' }[s] || ''
|
||||
}
|
||||
passRowClass({ rowIndex }) { return rowIndex % 2 === 0 ? '' : 'alt-row' },
|
||||
prodStatusLabel(s) { return { '0': '待轧', '1': '轧制中', '2': '已完成', '9': '异常' }[s] || s },
|
||||
prodStatusClass(s) { return { '0': 'status-wait', '1': 'status-rolling', '2': 'status-done', '9': 'status-err' }[s] || '' }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -480,9 +644,10 @@ export default {
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
color: #a9bcd0;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
/* ── 上方队列 ── */
|
||||
/* 队列 */
|
||||
.queue-section {
|
||||
background: #fff;
|
||||
border: 1px solid #dde1e6;
|
||||
@@ -491,14 +656,13 @@ export default {
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.queue-table {
|
||||
::v-deep .row-rolling td { background: #fef3e2 !important; }
|
||||
::v-deep .row-next td { background: #fdfbe4 !important; }
|
||||
::v-deep .el-table__row.current-row td { background: #e8f0fb !important; }
|
||||
}
|
||||
|
||||
/* ── 下方区域 ── */
|
||||
/* 下方 */
|
||||
.bottom-section {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
@@ -506,6 +670,7 @@ export default {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 道次面板 */
|
||||
.pass-panel {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
@@ -516,6 +681,16 @@ export default {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pass-empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.pass-table {
|
||||
flex: 1;
|
||||
::v-deep .el-table__row.alt-row td { background: #f7f9fc !important; }
|
||||
@@ -527,6 +702,17 @@ export default {
|
||||
color: #1d4e89;
|
||||
}
|
||||
|
||||
/* 编辑操作栏 */
|
||||
.edit-action-bar {
|
||||
padding: 6px 12px;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
background: #f7f9fc;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 右侧操作区 */
|
||||
.op-panel {
|
||||
width: 260px;
|
||||
@@ -550,11 +736,10 @@ export default {
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
|
||||
.el-button { width: 100%; justify-content: flex-start; }
|
||||
}
|
||||
|
||||
/* ── 底部状态栏 ── */
|
||||
/* 底部状态栏 */
|
||||
.footer-bar {
|
||||
background: #1c2b3a;
|
||||
border-radius: 3px;
|
||||
@@ -564,51 +749,14 @@ export default {
|
||||
flex-shrink: 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.coil-info-block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.coil-label {
|
||||
color: #a9bcd0;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
&.next { color: #f0b429; }
|
||||
}
|
||||
|
||||
.coil-field {
|
||||
color: #bdc3c7;
|
||||
white-space: nowrap;
|
||||
b { color: #ecf0f1; }
|
||||
}
|
||||
|
||||
.coil-divider {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background: #2e4057;
|
||||
margin: 0 20px;
|
||||
}
|
||||
.coil-info-block { display: flex; align-items: center; gap: 16px; flex: 1; }
|
||||
.coil-label { color: #a9bcd0; font-size: 11px; font-weight: 700; white-space: nowrap; &.next { color: #f0b429; } }
|
||||
.coil-field { color: #bdc3c7; white-space: nowrap; b { color: #ecf0f1; } }
|
||||
.coil-divider { width: 1px; height: 20px; background: #2e4057; margin: 0 20px; }
|
||||
|
||||
/* 状态标签 */
|
||||
.status-wait { color: #7f8c8d; }
|
||||
.status-rolling { color: #d68910; font-weight: 700; }
|
||||
.status-done { color: #2471a3; }
|
||||
.status-err { color: #c0392b; font-weight: 700; }
|
||||
|
||||
/* 快速新增方案弹窗内道次表头 */
|
||||
.recipe-pass-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 6px 0 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #1c2b3a;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user