fix(plan): 恢复生产计划原始布局,工艺方案改可选,新增快速新增方案入口
- 恢复上下分栏:上方轧制队列表格 + 左下轧制工艺 + 右下操作面板 + 底部带卷栏 - 钢卷新增/修改弹窗中工艺方案字段改为可选(clearable,无必填校验) - 右侧操作面板增加「工艺方案」分组,提供「快速新增方案」按钮 弹窗内可填写方案基本信息并录入道次参数,保存后自动刷新方案下拉列表 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,185 +1,274 @@
|
||||
<template>
|
||||
<div class="plan-page">
|
||||
|
||||
<!-- 左侧:钢卷队列列表 -->
|
||||
<div class="left-panel">
|
||||
<div class="panel-header">
|
||||
<span>轧制队列</span>
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||||
</div>
|
||||
<!-- 上方:轧制队列 -->
|
||||
<div class="queue-section">
|
||||
<div class="section-header"><span>轧制队列</span></div>
|
||||
<el-table :data="planList" border size="mini" class="queue-table"
|
||||
:row-class-name="queueRowClass"
|
||||
@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="采料长度(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">
|
||||
<template slot-scope="{ row }">
|
||||
<span :class="prodStatusClass(row.prodStatus)">{{ prodStatusLabel(row.prodStatus) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工艺方案" prop="recipeNo" min-width="100" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 查询栏 -->
|
||||
<div class="search-bar">
|
||||
<el-input v-model="query.inMatNo" placeholder="钢卷编号" size="mini" clearable
|
||||
prefix-icon="el-icon-search" @input="loadList" />
|
||||
<el-checkbox v-model="query.hideFinished" size="mini" @change="loadList" style="margin-top:6px;font-size:11px">不显示完成</el-checkbox>
|
||||
</div>
|
||||
<!-- 下方 -->
|
||||
<div class="bottom-section">
|
||||
|
||||
<!-- 列表 -->
|
||||
<div class="coil-list">
|
||||
<div v-for="p in planList" :key="p.id"
|
||||
:class="['coil-item', { active: selectedId === p.id }, prodItemClass(p.prodStatus)]"
|
||||
@click="handleSelect(p)">
|
||||
<div class="coil-item__no">
|
||||
<span>{{ p.sortNo }}. {{ p.inMatNo }}</span>
|
||||
<span :class="prodStatusClass(p.prodStatus)" class="coil-status-dot">{{ prodStatusLabel(p.prodStatus) }}</span>
|
||||
</div>
|
||||
<div class="coil-item__info">
|
||||
<span>{{ p.alloyNo }}</span>
|
||||
<span>{{ p.inMatThick }} → {{ p.outThick }} mm</span>
|
||||
<span v-if="p.recipeNo">{{ p.recipeNo }}</span>
|
||||
</div>
|
||||
<!-- 左侧:轧制工艺道次(只读) -->
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:查询 + 操作 -->
|
||||
<div class="op-panel">
|
||||
<div class="section-header"><span>条件查询</span></div>
|
||||
<div class="query-form">
|
||||
<el-form size="mini" label-width="72px">
|
||||
<el-form-item label="钢卷编号">
|
||||
<el-input v-model="query.inMatNo" clearable placeholder="请输入" />
|
||||
</el-form-item>
|
||||
<el-form-item label="日期范围">
|
||||
<el-date-picker v-model="query.dateRange" type="daterange"
|
||||
range-separator="~" start-placeholder="开始" end-placeholder="结束"
|
||||
value-format="yyyy-MM-dd" style="width:100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label=" " label-width="72px">
|
||||
<el-checkbox v-model="query.hideFinished">不显示生产完成</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item label=" " label-width="72px">
|
||||
<el-button size="mini" type="primary" icon="el-icon-search" @click="loadList">条件查询</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="resetQuery">全部显示</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="section-header" style="margin-top:8px"><span>队列操作</span></div>
|
||||
<div class="op-buttons">
|
||||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="handleAdd">钢卷增加</el-button>
|
||||
<el-button size="mini" icon="el-icon-edit" :disabled="!selectedPlan" @click="handleEdit">修改</el-button>
|
||||
<el-button size="mini" type="danger" icon="el-icon-delete" :disabled="!selectedPlan" @click="handleDelete">删除</el-button>
|
||||
<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 v-if="planList.length === 0" class="empty-tip">暂无计划</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:详情 -->
|
||||
<div class="right-panel">
|
||||
<div v-if="!form.id && !isNew" class="no-select">
|
||||
<i class="el-icon-document"></i>
|
||||
<p>请在左侧选择钢卷</p>
|
||||
<!-- 底部状态栏 -->
|
||||
<div class="footer-bar">
|
||||
<div class="coil-info-block">
|
||||
<span class="coil-label">当前带卷</span>
|
||||
<span class="coil-field">卷号:<b>{{ currentCoil.inMatNo || '—' }}</b></span>
|
||||
<span class="coil-field">采料厚度:<b>{{ currentCoil.inMatThick || '—' }} mm</b></span>
|
||||
<span class="coil-field">成品厚度:<b>{{ currentCoil.outThick || '—' }} mm</b></span>
|
||||
<span class="coil-field">宽度:<b>{{ currentCoil.inMatWidth || '—' }} mm</b></span>
|
||||
<span class="coil-field">合金号:<b>{{ currentCoil.alloyNo || '—' }}</b></span>
|
||||
</div>
|
||||
<div class="coil-divider"></div>
|
||||
<div class="coil-info-block">
|
||||
<span class="coil-label next">下一带卷</span>
|
||||
<span class="coil-field">卷号:<b>{{ nextCoil.inMatNo || '—' }}</b></span>
|
||||
<span class="coil-field">采料厚度:<b>{{ nextCoil.inMatThick || '—' }} mm</b></span>
|
||||
<span class="coil-field">成品厚度:<b>{{ nextCoil.outThick || '—' }} mm</b></span>
|
||||
<span class="coil-field">宽度:<b>{{ nextCoil.inMatWidth || '—' }} mm</b></span>
|
||||
<span class="coil-field">合金号:<b>{{ nextCoil.alloyNo || '—' }}</b></span>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<!-- 顶部操作栏 -->
|
||||
<div class="detail-header">
|
||||
<span>{{ isNew ? '新建钢卷计划' : form.inMatNo }}</span>
|
||||
<div class="btn-group">
|
||||
<el-button size="mini" type="primary" icon="el-icon-check" @click="handleSave">保存</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||
<el-button v-if="!isNew" size="mini" icon="el-icon-top" @click="handleMoveUp">上移</el-button>
|
||||
<el-button v-if="!isNew" size="mini" icon="el-icon-bottom" @click="handleMoveDown">下移</el-button>
|
||||
<el-button v-if="!isNew" size="mini" type="danger" icon="el-icon-delete" @click="handleDelete">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 基本信息表单 -->
|
||||
<el-form :model="form" :rules="rules" ref="formRef" size="mini" label-width="88px" class="coil-form">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="钢卷编号" prop="inMatNo">
|
||||
<el-input v-model="form.inMatNo" :disabled="!isNew" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-form-item label="合金牌号" prop="alloyNo">
|
||||
<el-input v-model="form.alloyNo" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-form-item label="工艺方案">
|
||||
<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" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="采料厚度" prop="inMatThick">
|
||||
<el-input v-model="form.inMatThick"><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="form.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="4">
|
||||
<el-form-item label="采料宽度">
|
||||
<el-input v-model="form.inMatWidth"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="采料长度">
|
||||
<el-input v-model="form.inMatLength"><template slot="append">m</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="采料重量">
|
||||
<el-input v-model="form.inMatWeight"><template slot="append">t</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="采料外径">
|
||||
<el-input v-model="form.inMatOd"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="采料内径">
|
||||
<el-input v-model="form.inMatId"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<!-- 轧制工艺道次(只读展示) -->
|
||||
<div class="pass-section">
|
||||
<div class="pass-header">
|
||||
<span>轧制工艺参数</span>
|
||||
<span v-if="form.recipeNo" class="recipe-tag">{{ form.recipeNo }}</span>
|
||||
<span v-else class="recipe-tag gray">未绑定工艺方案</span>
|
||||
</div>
|
||||
<el-table :data="passList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass" height="calc(100vh - 400px)">
|
||||
<el-table-column label="道次" prop="passNo" width="50" align="center" fixed>
|
||||
<template slot-scope="{ row }"><b>{{ row.passNo }}</b></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口厚度(mm)" prop="inThick" width="100" align="right" />
|
||||
<el-table-column label="出口厚度(mm)" prop="outThick" width="100" align="right" />
|
||||
<el-table-column label="宽度(mm)" prop="width" width="85" align="right" />
|
||||
<el-table-column label="轧制力(kN)" prop="rollForce" width="85" align="right" />
|
||||
<el-table-column label="入口张力(kN)" prop="inTension" width="95" align="right" />
|
||||
<el-table-column label="出口张力(kN)" prop="outTension" width="95" align="right" />
|
||||
<el-table-column label="最高速度(m/min)" prop="maxSpeed" width="110" 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="90" 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>
|
||||
|
||||
<!-- 底部:当前/下一带卷信息栏 -->
|
||||
<div class="footer-bar">
|
||||
<div class="coil-info-block">
|
||||
<span class="coil-label">当前带卷</span>
|
||||
<span class="coil-field">卷号:<b>{{ currentCoil.inMatNo || '—' }}</b></span>
|
||||
<span class="coil-field">采料厚度:<b>{{ currentCoil.inMatThick || '—' }} mm</b></span>
|
||||
<span class="coil-field">成品厚度:<b>{{ currentCoil.outThick || '—' }} mm</b></span>
|
||||
<span class="coil-field">宽度:<b>{{ currentCoil.inMatWidth || '—' }} mm</b></span>
|
||||
<span class="coil-field">合金号:<b>{{ currentCoil.alloyNo || '—' }}</b></span>
|
||||
</div>
|
||||
<div class="coil-divider"></div>
|
||||
<div class="coil-info-block">
|
||||
<span class="coil-label next">下一带卷</span>
|
||||
<span class="coil-field">卷号:<b>{{ nextCoil.inMatNo || '—' }}</b></span>
|
||||
<span class="coil-field">采料厚度:<b>{{ nextCoil.inMatThick || '—' }} mm</b></span>
|
||||
<span class="coil-field">成品厚度:<b>{{ nextCoil.outThick || '—' }} mm</b></span>
|
||||
<span class="coil-field">宽度:<b>{{ nextCoil.inMatWidth || '—' }} mm</b></span>
|
||||
<span class="coil-field">合金号:<b>{{ nextCoil.alloyNo || '—' }}</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 钢卷 新增/修改 对话框 -->
|
||||
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" 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">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="钢卷编号" prop="inMatNo">
|
||||
<el-input v-model="form.inMatNo" :disabled="!isNew" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="合金牌号" prop="alloyNo">
|
||||
<el-input v-model="form.alloyNo" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="工艺方案">
|
||||
<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" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料厚度" prop="inMatThick">
|
||||
<el-input v-model="form.inMatThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="成品厚度" prop="outThick">
|
||||
<el-input v-model="form.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料宽度">
|
||||
<el-input v-model="form.inMatWidth"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料长度">
|
||||
<el-input v-model="form.inMatLength"><template slot="append">m</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料重量">
|
||||
<el-input v-model="form.inMatWeight"><template slot="append">t</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料外径">
|
||||
<el-input v-model="form.inMatOd"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料内径">
|
||||
<el-input v-model="form.inMatId"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="dialogVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="handleSave">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 快速新增工艺方案 对话框 -->
|
||||
<el-dialog title="快速新增工艺方案" :visible.sync="recipeDialogVisible" width="700px"
|
||||
: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>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="recipeDialogVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="saveQuickRecipe">保存方案</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listPlan, addPlan, updatePlan, delPlan, moveUpPlan, moveDownPlan } from '@/api/mill/plan'
|
||||
import { listAllRecipe, getRecipeDetail } from '@/api/mill/recipe'
|
||||
import { listAllRecipe, getRecipeDetail, addRecipe } from '@/api/mill/recipe'
|
||||
|
||||
const emptyForm = () => ({
|
||||
id: null, inMatNo: '', alloyNo: '', recipeId: null, recipeNo: '',
|
||||
@@ -187,26 +276,46 @@ const emptyForm = () => ({
|
||||
inMatWeight: '', inMatOd: '', inMatId: '', passCount: 0, remark: ''
|
||||
})
|
||||
|
||||
const emptyPass = (no) => ({
|
||||
passNo: no, inThick: '', outThick: '', width: '',
|
||||
rollForce: '', inTension: '', outTension: '',
|
||||
maxSpeed: '', inUnitTension: '', outUnitTension: '',
|
||||
reduction: '', totalReduction: '', remark: ''
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'MillPlan',
|
||||
data() {
|
||||
return {
|
||||
planList: [],
|
||||
selectedId: null,
|
||||
isNew: false,
|
||||
form: emptyForm(),
|
||||
selectedPlan: null,
|
||||
passList: [],
|
||||
recipeOptions: [],
|
||||
query: { inMatNo: '', hideFinished: false },
|
||||
query: { inMatNo: '', dateRange: null, hideFinished: false },
|
||||
// 钢卷对话框
|
||||
dialogVisible: false,
|
||||
isNew: true,
|
||||
form: emptyForm(),
|
||||
rules: {
|
||||
inMatNo: [{ required: true, message: '请输入钢卷编号', trigger: 'blur' }],
|
||||
alloyNo: [{ required: true, message: '请输入合金牌号', trigger: 'blur' }],
|
||||
inMatThick: [{ required: true, message: '请输入采料厚度', trigger: 'blur' }],
|
||||
outThick: [{ required: true, message: '请输入成品厚度', trigger: 'blur' }],
|
||||
},
|
||||
// 快速新增方案对话框
|
||||
recipeDialogVisible: false,
|
||||
recipeForm: { recipeNo: '', alloyNo: '', inThick: '', outThick: '', outWidth: '' },
|
||||
recipePassList: [],
|
||||
recipeRules: {
|
||||
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') || {}
|
||||
},
|
||||
@@ -218,92 +327,126 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.loadList()
|
||||
listAllRecipe({}).then(res => { this.recipeOptions = res.data || [] })
|
||||
this.refreshRecipeOptions()
|
||||
},
|
||||
methods: {
|
||||
refreshRecipeOptions() {
|
||||
listAllRecipe({}).then(res => { this.recipeOptions = res.data || [] })
|
||||
},
|
||||
loadList() {
|
||||
const params = { inMatNo: this.query.inMatNo }
|
||||
if (this.query.hideFinished) params.hideProdStatus = '2'
|
||||
if (this.query.dateRange && this.query.dateRange.length === 2) {
|
||||
params.beginDate = this.query.dateRange[0]
|
||||
params.endDate = this.query.dateRange[1]
|
||||
}
|
||||
listPlan(params).then(res => {
|
||||
this.planList = res.data || []
|
||||
})
|
||||
},
|
||||
handleSelect(p) {
|
||||
this.selectedId = p.id
|
||||
this.isNew = false
|
||||
this.form = { ...p }
|
||||
if (p.recipeId) {
|
||||
getRecipeDetail(p.recipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
} else {
|
||||
this.passList = []
|
||||
}
|
||||
resetQuery() {
|
||||
this.query = { inMatNo: '', dateRange: null, hideFinished: false }
|
||||
this.loadList()
|
||||
},
|
||||
handleQueueSelect(row) {
|
||||
this.selectedPlan = row
|
||||
if (!row || !row.recipeId) { this.passList = []; return }
|
||||
getRecipeDetail(row.recipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.isNew = true
|
||||
this.selectedId = null
|
||||
this.form = emptyForm()
|
||||
this.passList = []
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleEdit() {
|
||||
this.isNew = false
|
||||
this.form = { ...this.selectedPlan }
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleSave() {
|
||||
this.$refs.formRef.validate(valid => {
|
||||
if (!valid) return
|
||||
const matched = this.recipeOptions.find(r => r.id === this.form.recipeId)
|
||||
if (matched) { this.form.recipeNo = matched.recipeNo; this.form.passCount = matched.passCount }
|
||||
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 api = this.isNew ? addPlan : updatePlan
|
||||
api(this.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.dialogVisible = false
|
||||
this.loadList()
|
||||
this.isNew = false
|
||||
})
|
||||
})
|
||||
},
|
||||
handleReset() {
|
||||
if (this.isNew) { this.form = emptyForm(); this.passList = [] }
|
||||
else this.handleSelect({ ...this.form })
|
||||
},
|
||||
handleDelete() {
|
||||
this.$confirm(`确定删除钢卷「${this.form.inMatNo}」?`, '提示', { type: 'warning' }).then(() => {
|
||||
delPlan(this.form.id).then(() => {
|
||||
this.$confirm(`确定删除钢卷「${this.selectedPlan.inMatNo}」?`, '提示', { type: 'warning' }).then(() => {
|
||||
delPlan(this.selectedPlan.id).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.form = emptyForm(); this.passList = []
|
||||
this.selectedId = null; this.isNew = false
|
||||
this.selectedPlan = null
|
||||
this.passList = []
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleMoveUp() {
|
||||
moveUpPlan(this.form.id).then(() => this.loadList())
|
||||
},
|
||||
handleMoveDown() {
|
||||
moveDownPlan(this.form.id).then(() => this.loadList())
|
||||
},
|
||||
handleMoveUp() { moveUpPlan(this.selectedPlan.id).then(() => this.loadList()) },
|
||||
handleMoveDown() { moveDownPlan(this.selectedPlan.id).then(() => this.loadList()) },
|
||||
onRecipeChange(recipeId) {
|
||||
if (!recipeId) { this.passList = []; this.form.recipeNo = ''; return }
|
||||
if (!recipeId) return
|
||||
const r = this.recipeOptions.find(x => x.id === recipeId)
|
||||
if (r) {
|
||||
if (!this.form.alloyNo) this.form.alloyNo = r.alloyNo
|
||||
if (!this.form.alloyNo) this.form.alloyNo = r.alloyNo
|
||||
if (!this.form.inMatThick) this.form.inMatThick = r.inThick
|
||||
if (!this.form.outThick) this.form.outThick = r.outThick
|
||||
if (!this.form.inMatWidth) this.form.inMatWidth = r.outWidth
|
||||
this.form.recipeNo = r.recipeNo
|
||||
getRecipeDetail(recipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
if (!this.form.outThick) this.form.outThick = r.outThick
|
||||
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] || '待轧'
|
||||
return { '0': '待轧', '1': '轧制中', '2': '已完成', '9': '异常' }[s] || s
|
||||
},
|
||||
prodStatusClass(s) {
|
||||
return { '0': 'dot-wait', '1': 'dot-rolling', '2': 'dot-done', '9': 'dot-err' }[s] || 'dot-wait'
|
||||
},
|
||||
prodItemClass(s) {
|
||||
return { '1': 'item-rolling', '2': 'item-done' }[s] || ''
|
||||
return { '0': 'status-wait', '1': 'status-rolling', '2': 'status-done', '9': 'status-err' }[s] || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,164 +455,65 @@ export default {
|
||||
<style scoped lang="scss">
|
||||
.plan-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 84px);
|
||||
background: #f0f2f5;
|
||||
padding: 10px 12px;
|
||||
padding: 8px 12px;
|
||||
box-sizing: border-box;
|
||||
gap: 0;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* ── 左侧面板 ── */
|
||||
.left-panel {
|
||||
width: 240px;
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #dde1e6;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
.section-header {
|
||||
background: #1c2b3a;
|
||||
color: #ecf0f1;
|
||||
padding: 7px 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
padding: 6px 8px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.coil-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.coil-item {
|
||||
padding: 7px 10px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
cursor: pointer;
|
||||
transition: background .15s;
|
||||
|
||||
&:hover { background: #f7f9fc; }
|
||||
&.active { background: #e8f0fb; border-left: 3px solid #1d4e89; }
|
||||
&.item-rolling { background: #fff8ee; }
|
||||
&.item-done { opacity: 0.55; }
|
||||
|
||||
&__no {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #1c2b3a;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
&__info {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
font-size: 11px;
|
||||
color: #7f8c8d;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.coil-status-dot {
|
||||
font-size: 10px;
|
||||
font-weight: 400;
|
||||
&.dot-wait { color: #909399; }
|
||||
&.dot-rolling { color: #d68910; font-weight: 700; }
|
||||
&.dot-done { color: #2471a3; }
|
||||
&.dot-err { color: #c0392b; font-weight: 700; }
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
color: #bdc3c7;
|
||||
padding: 24px 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* ── 右侧面板 ── */
|
||||
.right-panel {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border: 1px solid #dde1e6;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.no-select {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #bdc3c7;
|
||||
font-size: 13px;
|
||||
i { font-size: 48px; margin-bottom: 10px; }
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
background: #1c2b3a;
|
||||
color: #ecf0f1;
|
||||
padding: 7px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btn-group { display: flex; gap: 6px; }
|
||||
|
||||
.coil-form {
|
||||
padding: 10px 12px 4px;
|
||||
flex-shrink: 0;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
/* ── 道次区域 ── */
|
||||
.pass-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pass-header {
|
||||
padding: 6px 12px;
|
||||
background: #f7f9fc;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #1c2b3a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-shrink: 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.recipe-tag {
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
color: #1d4e89;
|
||||
background: #e8f0fb;
|
||||
padding: 1px 6px;
|
||||
border-radius: 2px;
|
||||
&.gray { color: #909399; background: #f4f4f5; }
|
||||
color: #a9bcd0;
|
||||
}
|
||||
|
||||
/* ── 上方队列 ── */
|
||||
.queue-section {
|
||||
background: #fff;
|
||||
border: 1px solid #dde1e6;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
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;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pass-panel {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border: 1px solid #dde1e6;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pass-table {
|
||||
@@ -483,9 +527,37 @@ export default {
|
||||
color: #1d4e89;
|
||||
}
|
||||
|
||||
/* 右侧操作区 */
|
||||
.op-panel {
|
||||
width: 260px;
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #dde1e6;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.query-form {
|
||||
padding: 10px 12px 4px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.op-buttons {
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
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;
|
||||
padding: 6px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -520,4 +592,23 @@ export default {
|
||||
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