feat(mill): 完成工艺管理与生产计划全栈业务模块
- 新增三张业务表 SQL:mill_process_recipe / mill_process_pass / mill_production_plan - 后端:Domain + Mapper + MyBatis XML + Service + Controller(工艺方案 & 生产计划) - 生产计划支持队列排序(sortNo)、上移/下移、软删除 - 工艺方案支持道次批量保存、事务管理 - 前端:工艺管理页(左侧方案列表 + 右侧表单 + 道次内联表格) - 前端:生产计划页(轧制队列 + 轧制工艺展示 + 操作面板 + 底部带卷状态栏) - 注册 /mill/process 与 /mill/plan 前端路由 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
package com.ruoyi.mill.controller;
|
||||
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.mill.domain.MillProcessRecipe;
|
||||
import com.ruoyi.mill.service.IMillProcessRecipeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/mill/recipe")
|
||||
public class MillProcessRecipeController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IMillProcessRecipeService recipeService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(MillProcessRecipe query) {
|
||||
startPage();
|
||||
List<MillProcessRecipe> list = recipeService.selectList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/** 不分页的全量列表(下拉选择用) */
|
||||
@GetMapping("/listAll")
|
||||
public AjaxResult listAll(MillProcessRecipe query) {
|
||||
return AjaxResult.success(recipeService.selectList(query));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult detail(@PathVariable Long id) {
|
||||
return AjaxResult.success(recipeService.selectDetailById(id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody MillProcessRecipe recipe) {
|
||||
return toAjax(recipeService.save(recipe));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody MillProcessRecipe recipe) {
|
||||
return toAjax(recipeService.update(recipe));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(recipeService.deleteByIds(ids));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.ruoyi.mill.controller;
|
||||
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.mill.domain.MillProductionPlan;
|
||||
import com.ruoyi.mill.service.IMillProductionPlanService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/mill/plan")
|
||||
public class MillProductionPlanController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IMillProductionPlanService planService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(MillProductionPlan query) {
|
||||
// 轧制队列不分页,按 sort_no 顺序全量返回
|
||||
List<MillProductionPlan> list = planService.selectList(query);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult getInfo(@PathVariable Long id) {
|
||||
return AjaxResult.success(planService.selectById(id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody MillProductionPlan plan) {
|
||||
return toAjax(planService.insert(plan));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody MillProductionPlan plan) {
|
||||
return toAjax(planService.update(plan));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public AjaxResult remove(@PathVariable Long id) {
|
||||
return toAjax(planService.deleteById(id));
|
||||
}
|
||||
|
||||
@PutMapping("/moveUp/{id}")
|
||||
public AjaxResult moveUp(@PathVariable Long id) {
|
||||
return toAjax(planService.moveUp(id));
|
||||
}
|
||||
|
||||
@PutMapping("/moveDown/{id}")
|
||||
public AjaxResult moveDown(@PathVariable Long id) {
|
||||
return toAjax(planService.moveDown(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.ruoyi.mill.domain;
|
||||
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/** 工艺方案道次详情 */
|
||||
public class MillProcessPass extends BaseEntity {
|
||||
|
||||
private Long recipeId;
|
||||
|
||||
@Excel(name = "道次")
|
||||
private Integer passNo;
|
||||
|
||||
@Excel(name = "入口厚度(mm)")
|
||||
private BigDecimal inThick;
|
||||
|
||||
@Excel(name = "出口厚度(mm)")
|
||||
private BigDecimal outThick;
|
||||
|
||||
@Excel(name = "宽度(mm)")
|
||||
private BigDecimal width;
|
||||
|
||||
@Excel(name = "轧制力(kN)")
|
||||
private BigDecimal rollForce;
|
||||
|
||||
@Excel(name = "入口张力(kN)")
|
||||
private BigDecimal inTension;
|
||||
|
||||
@Excel(name = "出口张力(kN)")
|
||||
private BigDecimal outTension;
|
||||
|
||||
@Excel(name = "最高速度(m/min)")
|
||||
private BigDecimal maxSpeed;
|
||||
|
||||
@Excel(name = "入口单位张力(N/mm²)")
|
||||
private BigDecimal inUnitTension;
|
||||
|
||||
@Excel(name = "出口单位张力(N/mm²)")
|
||||
private BigDecimal outUnitTension;
|
||||
|
||||
@Excel(name = "压下量(mm)")
|
||||
private BigDecimal reduction;
|
||||
|
||||
@Excel(name = "总压下量(mm)")
|
||||
private BigDecimal totalReduction;
|
||||
|
||||
private String delFlag;
|
||||
|
||||
public Long getRecipeId() { return recipeId; }
|
||||
public void setRecipeId(Long v) { this.recipeId = v; }
|
||||
public Integer getPassNo() { return passNo; }
|
||||
public void setPassNo(Integer v) { this.passNo = v; }
|
||||
public BigDecimal getInThick() { return inThick; }
|
||||
public void setInThick(BigDecimal v) { this.inThick = v; }
|
||||
public BigDecimal getOutThick() { return outThick; }
|
||||
public void setOutThick(BigDecimal v) { this.outThick = v; }
|
||||
public BigDecimal getWidth() { return width; }
|
||||
public void setWidth(BigDecimal v) { this.width = v; }
|
||||
public BigDecimal getRollForce() { return rollForce; }
|
||||
public void setRollForce(BigDecimal v) { this.rollForce = v; }
|
||||
public BigDecimal getInTension() { return inTension; }
|
||||
public void setInTension(BigDecimal v) { this.inTension = v; }
|
||||
public BigDecimal getOutTension() { return outTension; }
|
||||
public void setOutTension(BigDecimal v) { this.outTension = v; }
|
||||
public BigDecimal getMaxSpeed() { return maxSpeed; }
|
||||
public void setMaxSpeed(BigDecimal v) { this.maxSpeed = v; }
|
||||
public BigDecimal getInUnitTension() { return inUnitTension; }
|
||||
public void setInUnitTension(BigDecimal v) { this.inUnitTension = v; }
|
||||
public BigDecimal getOutUnitTension() { return outUnitTension; }
|
||||
public void setOutUnitTension(BigDecimal v){ this.outUnitTension = v; }
|
||||
public BigDecimal getReduction() { return reduction; }
|
||||
public void setReduction(BigDecimal v) { this.reduction = v; }
|
||||
public BigDecimal getTotalReduction() { return totalReduction; }
|
||||
public void setTotalReduction(BigDecimal v){ this.totalReduction = v; }
|
||||
public String getDelFlag() { return delFlag; }
|
||||
public void setDelFlag(String v) { this.delFlag = v; }
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.ruoyi.mill.domain;
|
||||
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/** 工艺方案主表 */
|
||||
public class MillProcessRecipe extends BaseEntity {
|
||||
|
||||
@Excel(name = "方案记录号")
|
||||
private String recipeNo;
|
||||
|
||||
@Excel(name = "合金号")
|
||||
private String alloyNo;
|
||||
|
||||
@Excel(name = "道次数量")
|
||||
private Integer passCount;
|
||||
|
||||
@Excel(name = "原料厚度(mm)")
|
||||
private BigDecimal inThick;
|
||||
|
||||
@Excel(name = "成品厚度(mm)")
|
||||
private BigDecimal outThick;
|
||||
|
||||
@Excel(name = "成品宽度(mm)")
|
||||
private BigDecimal outWidth;
|
||||
|
||||
/** 0-正常 1-停用 */
|
||||
private String status;
|
||||
|
||||
/** 删除标志 0-存在 2-删除 */
|
||||
private String delFlag;
|
||||
|
||||
/** 关联道次列表(非数据库字段) */
|
||||
private List<MillProcessPass> passList;
|
||||
|
||||
public String getRecipeNo() { return recipeNo; }
|
||||
public void setRecipeNo(String v) { this.recipeNo = v; }
|
||||
public String getAlloyNo() { return alloyNo; }
|
||||
public void setAlloyNo(String v) { this.alloyNo = v; }
|
||||
public Integer getPassCount() { return passCount; }
|
||||
public void setPassCount(Integer v) { this.passCount = v; }
|
||||
public BigDecimal getInThick() { return inThick; }
|
||||
public void setInThick(BigDecimal v) { this.inThick = v; }
|
||||
public BigDecimal getOutThick() { return outThick; }
|
||||
public void setOutThick(BigDecimal v) { this.outThick = v; }
|
||||
public BigDecimal getOutWidth() { return outWidth; }
|
||||
public void setOutWidth(BigDecimal v) { this.outWidth = v; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String v) { this.status = v; }
|
||||
public String getDelFlag() { return delFlag; }
|
||||
public void setDelFlag(String v) { this.delFlag = v; }
|
||||
public List<MillProcessPass> getPassList() { return passList; }
|
||||
public void setPassList(List<MillProcessPass> v) { this.passList = v; }
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.ruoyi.mill.domain;
|
||||
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/** 生产计划(轧制队列) */
|
||||
public class MillProductionPlan extends BaseEntity {
|
||||
|
||||
@Excel(name = "计划号")
|
||||
private String planNo;
|
||||
|
||||
private String matSeqNo;
|
||||
private String unitCode;
|
||||
private String planType;
|
||||
|
||||
/** 0-待生产 1-生产中 2-完成 3-撤销 */
|
||||
@Excel(name = "计划状态")
|
||||
private String planStatus;
|
||||
|
||||
/** Rolling / NextCoil / Idle */
|
||||
@Excel(name = "生产状态")
|
||||
private String prodStatus;
|
||||
|
||||
@Excel(name = "队列序号")
|
||||
private Integer sortNo;
|
||||
|
||||
@Excel(name = "钢卷编号")
|
||||
private String inMatNo;
|
||||
|
||||
@Excel(name = "采料厚度(mm)")
|
||||
private BigDecimal inMatThick;
|
||||
|
||||
@Excel(name = "采料宽度(mm)")
|
||||
private BigDecimal inMatWidth;
|
||||
|
||||
@Excel(name = "采料重量(kg)")
|
||||
private BigDecimal inMatWt;
|
||||
|
||||
@Excel(name = "采料长度(m)")
|
||||
private BigDecimal inMatLen;
|
||||
|
||||
@Excel(name = "采料内径(mm)")
|
||||
private BigDecimal inMatInDia;
|
||||
|
||||
@Excel(name = "采料外径(mm)")
|
||||
private BigDecimal inMatDia;
|
||||
|
||||
@Excel(name = "炉号")
|
||||
private String pono;
|
||||
|
||||
@Excel(name = "合金牌号")
|
||||
private String sgSign;
|
||||
|
||||
@Excel(name = "出口材料号")
|
||||
private String outMatNo;
|
||||
|
||||
@Excel(name = "成品厚度(mm)")
|
||||
private BigDecimal outThick;
|
||||
|
||||
@Excel(name = "工艺方案ID")
|
||||
private Long recipeId;
|
||||
|
||||
@Excel(name = "工艺方案号")
|
||||
private String recipeNo;
|
||||
|
||||
private String delFlag;
|
||||
|
||||
public String getPlanNo() { return planNo; }
|
||||
public void setPlanNo(String v) { this.planNo = v; }
|
||||
public String getMatSeqNo() { return matSeqNo; }
|
||||
public void setMatSeqNo(String v) { this.matSeqNo = v; }
|
||||
public String getUnitCode() { return unitCode; }
|
||||
public void setUnitCode(String v) { this.unitCode = v; }
|
||||
public String getPlanType() { return planType; }
|
||||
public void setPlanType(String v) { this.planType = v; }
|
||||
public String getPlanStatus() { return planStatus; }
|
||||
public void setPlanStatus(String v) { this.planStatus = v; }
|
||||
public String getProdStatus() { return prodStatus; }
|
||||
public void setProdStatus(String v) { this.prodStatus = v; }
|
||||
public Integer getSortNo() { return sortNo; }
|
||||
public void setSortNo(Integer v) { this.sortNo = v; }
|
||||
public String getInMatNo() { return inMatNo; }
|
||||
public void setInMatNo(String v) { this.inMatNo = v; }
|
||||
public BigDecimal getInMatThick() { return inMatThick; }
|
||||
public void setInMatThick(BigDecimal v) { this.inMatThick = v; }
|
||||
public BigDecimal getInMatWidth() { return inMatWidth; }
|
||||
public void setInMatWidth(BigDecimal v) { this.inMatWidth = v; }
|
||||
public BigDecimal getInMatWt() { return inMatWt; }
|
||||
public void setInMatWt(BigDecimal v) { this.inMatWt = v; }
|
||||
public BigDecimal getInMatLen() { return inMatLen; }
|
||||
public void setInMatLen(BigDecimal v) { this.inMatLen = v; }
|
||||
public BigDecimal getInMatInDia() { return inMatInDia; }
|
||||
public void setInMatInDia(BigDecimal v) { this.inMatInDia = v; }
|
||||
public BigDecimal getInMatDia() { return inMatDia; }
|
||||
public void setInMatDia(BigDecimal v) { this.inMatDia = v; }
|
||||
public String getPono() { return pono; }
|
||||
public void setPono(String v) { this.pono = v; }
|
||||
public String getSgSign() { return sgSign; }
|
||||
public void setSgSign(String v) { this.sgSign = v; }
|
||||
public String getOutMatNo() { return outMatNo; }
|
||||
public void setOutMatNo(String v) { this.outMatNo = v; }
|
||||
public BigDecimal getOutThick() { return outThick; }
|
||||
public void setOutThick(BigDecimal v) { this.outThick = v; }
|
||||
public Long getRecipeId() { return recipeId; }
|
||||
public void setRecipeId(Long v) { this.recipeId = v; }
|
||||
public String getRecipeNo() { return recipeNo; }
|
||||
public void setRecipeNo(String v) { this.recipeNo = v; }
|
||||
public String getDelFlag() { return delFlag; }
|
||||
public void setDelFlag(String v) { this.delFlag = v; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.ruoyi.mill.mapper;
|
||||
|
||||
import com.ruoyi.mill.domain.MillProcessPass;
|
||||
import java.util.List;
|
||||
|
||||
public interface MillProcessPassMapper {
|
||||
List<MillProcessPass> selectByRecipeId(Long recipeId);
|
||||
int insertBatch(List<MillProcessPass> list);
|
||||
int deleteByRecipeId(Long recipeId);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ruoyi.mill.mapper;
|
||||
|
||||
import com.ruoyi.mill.domain.MillProcessRecipe;
|
||||
import java.util.List;
|
||||
|
||||
public interface MillProcessRecipeMapper {
|
||||
List<MillProcessRecipe> selectList(MillProcessRecipe query);
|
||||
MillProcessRecipe selectById(Long id);
|
||||
MillProcessRecipe selectByRecipeNo(String recipeNo);
|
||||
int insert(MillProcessRecipe recipe);
|
||||
int update(MillProcessRecipe recipe);
|
||||
int deleteById(Long id);
|
||||
int deleteBatchByIds(Long[] ids);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.ruoyi.mill.mapper;
|
||||
|
||||
import com.ruoyi.mill.domain.MillProductionPlan;
|
||||
import java.util.List;
|
||||
|
||||
public interface MillProductionPlanMapper {
|
||||
List<MillProductionPlan> selectList(MillProductionPlan query);
|
||||
MillProductionPlan selectById(Long id);
|
||||
MillProductionPlan selectByPlanNo(String planNo);
|
||||
int insert(MillProductionPlan plan);
|
||||
int update(MillProductionPlan plan);
|
||||
int deleteById(Long id);
|
||||
/** 将 sortNo >= targetSort 的记录全部 +1(上移腾位) */
|
||||
int incrementSortFrom(int targetSort);
|
||||
/** 交换两条记录的 sortNo */
|
||||
int updateSortNo(Long id, int sortNo);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.ruoyi.mill.service;
|
||||
|
||||
import com.ruoyi.mill.domain.MillProcessRecipe;
|
||||
import java.util.List;
|
||||
|
||||
public interface IMillProcessRecipeService {
|
||||
List<MillProcessRecipe> selectList(MillProcessRecipe query);
|
||||
/** 查询方案详情(含道次列表) */
|
||||
MillProcessRecipe selectDetailById(Long id);
|
||||
int save(MillProcessRecipe recipe);
|
||||
int update(MillProcessRecipe recipe);
|
||||
int deleteByIds(Long[] ids);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ruoyi.mill.service;
|
||||
|
||||
import com.ruoyi.mill.domain.MillProductionPlan;
|
||||
import java.util.List;
|
||||
|
||||
public interface IMillProductionPlanService {
|
||||
List<MillProductionPlan> selectList(MillProductionPlan query);
|
||||
MillProductionPlan selectById(Long id);
|
||||
int insert(MillProductionPlan plan);
|
||||
int update(MillProductionPlan plan);
|
||||
int deleteById(Long id);
|
||||
int moveUp(Long id);
|
||||
int moveDown(Long id);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.ruoyi.mill.service.impl;
|
||||
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.mill.domain.MillProcessPass;
|
||||
import com.ruoyi.mill.domain.MillProcessRecipe;
|
||||
import com.ruoyi.mill.mapper.MillProcessPassMapper;
|
||||
import com.ruoyi.mill.mapper.MillProcessRecipeMapper;
|
||||
import com.ruoyi.mill.service.IMillProcessRecipeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class MillProcessRecipeServiceImpl implements IMillProcessRecipeService {
|
||||
|
||||
@Autowired private MillProcessRecipeMapper recipeMapper;
|
||||
@Autowired private MillProcessPassMapper passMapper;
|
||||
|
||||
@Override
|
||||
public List<MillProcessRecipe> selectList(MillProcessRecipe query) {
|
||||
return recipeMapper.selectList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MillProcessRecipe selectDetailById(Long id) {
|
||||
MillProcessRecipe recipe = recipeMapper.selectById(id);
|
||||
if (recipe != null) {
|
||||
recipe.setPassList(passMapper.selectByRecipeId(id));
|
||||
}
|
||||
return recipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int save(MillProcessRecipe recipe) {
|
||||
String user = SecurityUtils.getUsername();
|
||||
recipe.setCreateBy(user);
|
||||
recipe.setUpdateBy(user);
|
||||
recipeMapper.insert(recipe);
|
||||
savePassList(recipe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int update(MillProcessRecipe recipe) {
|
||||
recipe.setUpdateBy(SecurityUtils.getUsername());
|
||||
recipeMapper.update(recipe);
|
||||
// 先删除旧道次,再重新插入
|
||||
passMapper.deleteByRecipeId(recipe.getId());
|
||||
savePassList(recipe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int deleteByIds(Long[] ids) {
|
||||
for (Long id : ids) {
|
||||
passMapper.deleteByRecipeId(id);
|
||||
}
|
||||
return recipeMapper.deleteBatchByIds(ids);
|
||||
}
|
||||
|
||||
private void savePassList(MillProcessRecipe recipe) {
|
||||
List<MillProcessPass> list = recipe.getPassList();
|
||||
if (list == null || list.isEmpty()) return;
|
||||
String user = SecurityUtils.getUsername();
|
||||
for (MillProcessPass p : list) {
|
||||
p.setRecipeId(recipe.getId());
|
||||
p.setCreateBy(user);
|
||||
p.setUpdateBy(user);
|
||||
}
|
||||
passMapper.insertBatch(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.ruoyi.mill.service.impl;
|
||||
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.mill.domain.MillProductionPlan;
|
||||
import com.ruoyi.mill.mapper.MillProductionPlanMapper;
|
||||
import com.ruoyi.mill.service.IMillProductionPlanService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class MillProductionPlanServiceImpl implements IMillProductionPlanService {
|
||||
|
||||
@Autowired private MillProductionPlanMapper planMapper;
|
||||
|
||||
@Override
|
||||
public List<MillProductionPlan> selectList(MillProductionPlan query) {
|
||||
return planMapper.selectList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MillProductionPlan selectById(Long id) {
|
||||
return planMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insert(MillProductionPlan plan) {
|
||||
String user = SecurityUtils.getUsername();
|
||||
plan.setCreateBy(user);
|
||||
plan.setUpdateBy(user);
|
||||
// 新计划追加到队列末尾
|
||||
List<MillProductionPlan> all = planMapper.selectList(new MillProductionPlan());
|
||||
plan.setSortNo(all.size() + 1);
|
||||
return planMapper.insert(plan);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(MillProductionPlan plan) {
|
||||
plan.setUpdateBy(SecurityUtils.getUsername());
|
||||
return planMapper.update(plan);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteById(Long id) {
|
||||
return planMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int moveUp(Long id) {
|
||||
MillProductionPlan cur = planMapper.selectById(id);
|
||||
if (cur == null || cur.getSortNo() <= 1) return 0;
|
||||
// 找上一条
|
||||
MillProductionPlan query = new MillProductionPlan();
|
||||
List<MillProductionPlan> all = planMapper.selectList(query);
|
||||
MillProductionPlan prev = all.stream()
|
||||
.filter(p -> p.getSortNo() == cur.getSortNo() - 1)
|
||||
.findFirst().orElse(null);
|
||||
if (prev == null) return 0;
|
||||
planMapper.updateSortNo(cur.getId(), prev.getSortNo());
|
||||
planMapper.updateSortNo(prev.getId(), cur.getSortNo());
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int moveDown(Long id) {
|
||||
MillProductionPlan cur = planMapper.selectById(id);
|
||||
if (cur == null) return 0;
|
||||
List<MillProductionPlan> all = planMapper.selectList(new MillProductionPlan());
|
||||
MillProductionPlan next = all.stream()
|
||||
.filter(p -> p.getSortNo() == cur.getSortNo() + 1)
|
||||
.findFirst().orElse(null);
|
||||
if (next == null) return 0;
|
||||
planMapper.updateSortNo(cur.getId(), next.getSortNo());
|
||||
planMapper.updateSortNo(next.getId(), cur.getSortNo());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.mill.mapper.MillProcessPassMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.ruoyi.mill.domain.MillProcessPass">
|
||||
<id property="id" column="id"/>
|
||||
<result property="recipeId" column="recipe_id"/>
|
||||
<result property="passNo" column="pass_no"/>
|
||||
<result property="inThick" column="in_thick"/>
|
||||
<result property="outThick" column="out_thick"/>
|
||||
<result property="width" column="width"/>
|
||||
<result property="rollForce" column="roll_force"/>
|
||||
<result property="inTension" column="in_tension"/>
|
||||
<result property="outTension" column="out_tension"/>
|
||||
<result property="maxSpeed" column="max_speed"/>
|
||||
<result property="inUnitTension" column="in_unit_tension"/>
|
||||
<result property="outUnitTension" column="out_unit_tension"/>
|
||||
<result property="reduction" column="reduction"/>
|
||||
<result property="totalReduction" column="total_reduction"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectByRecipeId" resultMap="BaseRM">
|
||||
SELECT id, recipe_id, pass_no, in_thick, out_thick, width,
|
||||
roll_force, in_tension, out_tension, max_speed,
|
||||
in_unit_tension, out_unit_tension, reduction, total_reduction,
|
||||
del_flag, create_by, create_time, update_by, update_time, remark
|
||||
FROM mill_process_pass
|
||||
WHERE recipe_id = #{recipeId} AND del_flag = '0'
|
||||
ORDER BY pass_no ASC
|
||||
</select>
|
||||
|
||||
<insert id="insertBatch">
|
||||
INSERT INTO mill_process_pass (
|
||||
recipe_id, pass_no, in_thick, out_thick, width,
|
||||
roll_force, in_tension, out_tension, max_speed,
|
||||
in_unit_tension, out_unit_tension, reduction, total_reduction,
|
||||
create_by, create_time, update_by, update_time, remark, del_flag
|
||||
) VALUES
|
||||
<foreach collection="list" item="p" separator=",">
|
||||
(#{p.recipeId}, #{p.passNo}, #{p.inThick}, #{p.outThick}, #{p.width},
|
||||
#{p.rollForce}, #{p.inTension}, #{p.outTension}, #{p.maxSpeed},
|
||||
#{p.inUnitTension}, #{p.outUnitTension}, #{p.reduction}, #{p.totalReduction},
|
||||
#{p.createBy}, NOW(), #{p.updateBy}, NOW(), #{p.remark}, '0')
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<update id="deleteByRecipeId">
|
||||
UPDATE mill_process_pass SET del_flag = '2', update_time = NOW()
|
||||
WHERE recipe_id = #{recipeId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.mill.mapper.MillProcessRecipeMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.ruoyi.mill.domain.MillProcessRecipe">
|
||||
<id property="id" column="id"/>
|
||||
<result property="recipeNo" column="recipe_no"/>
|
||||
<result property="alloyNo" column="alloy_no"/>
|
||||
<result property="passCount" column="pass_count"/>
|
||||
<result property="inThick" column="in_thick"/>
|
||||
<result property="outThick" column="out_thick"/>
|
||||
<result property="outWidth" column="out_width"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="cols">
|
||||
id, recipe_no, alloy_no, pass_count, in_thick, out_thick, out_width,
|
||||
status, del_flag, create_by, create_time, update_by, update_time, remark
|
||||
</sql>
|
||||
|
||||
<select id="selectList" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/>
|
||||
FROM mill_process_recipe
|
||||
WHERE del_flag = '0'
|
||||
<if test="recipeNo != null and recipeNo != ''">
|
||||
AND recipe_no LIKE CONCAT('%', #{recipeNo}, '%')
|
||||
</if>
|
||||
<if test="alloyNo != null and alloyNo != ''">
|
||||
AND alloy_no LIKE CONCAT('%', #{alloyNo}, '%')
|
||||
</if>
|
||||
<if test="status != null and status != ''">
|
||||
AND status = #{status}
|
||||
</if>
|
||||
ORDER BY id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectById" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/> FROM mill_process_recipe
|
||||
WHERE id = #{id} AND del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectByRecipeNo" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/> FROM mill_process_recipe
|
||||
WHERE recipe_no = #{recipeNo} AND del_flag = '0' LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
|
||||
INSERT INTO mill_process_recipe (
|
||||
recipe_no, alloy_no, pass_count, in_thick, out_thick, out_width,
|
||||
status, create_by, create_time, update_by, update_time, remark, del_flag
|
||||
) VALUES (
|
||||
#{recipeNo}, #{alloyNo}, #{passCount}, #{inThick}, #{outThick}, #{outWidth},
|
||||
#{status}, #{createBy}, NOW(), #{updateBy}, NOW(), #{remark}, '0'
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="update">
|
||||
UPDATE mill_process_recipe
|
||||
SET recipe_no = #{recipeNo},
|
||||
alloy_no = #{alloyNo},
|
||||
pass_count = #{passCount},
|
||||
in_thick = #{inThick},
|
||||
out_thick = #{outThick},
|
||||
out_width = #{outWidth},
|
||||
status = #{status},
|
||||
update_by = #{updateBy},
|
||||
update_time = NOW(),
|
||||
remark = #{remark}
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<update id="deleteById">
|
||||
UPDATE mill_process_recipe SET del_flag = '2', update_time = NOW() WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<update id="deleteBatchByIds">
|
||||
UPDATE mill_process_recipe SET del_flag = '2', update_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.mill.mapper.MillProductionPlanMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.ruoyi.mill.domain.MillProductionPlan">
|
||||
<id property="id" column="id"/>
|
||||
<result property="planNo" column="plan_no"/>
|
||||
<result property="matSeqNo" column="mat_seq_no"/>
|
||||
<result property="unitCode" column="unit_code"/>
|
||||
<result property="planType" column="plan_type"/>
|
||||
<result property="planStatus" column="plan_status"/>
|
||||
<result property="prodStatus" column="prod_status"/>
|
||||
<result property="sortNo" column="sort_no"/>
|
||||
<result property="inMatNo" column="in_mat_no"/>
|
||||
<result property="inMatThick" column="in_mat_thick"/>
|
||||
<result property="inMatWidth" column="in_mat_width"/>
|
||||
<result property="inMatWt" column="in_mat_wt"/>
|
||||
<result property="inMatLen" column="in_mat_len"/>
|
||||
<result property="inMatInDia" column="in_mat_in_dia"/>
|
||||
<result property="inMatDia" column="in_mat_dia"/>
|
||||
<result property="pono" column="pono"/>
|
||||
<result property="sgSign" column="sg_sign"/>
|
||||
<result property="outMatNo" column="out_mat_no"/>
|
||||
<result property="outThick" column="out_thick"/>
|
||||
<result property="recipeId" column="recipe_id"/>
|
||||
<result property="recipeNo" column="recipe_no"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="cols">
|
||||
id, plan_no, mat_seq_no, unit_code, plan_type, plan_status, prod_status, sort_no,
|
||||
in_mat_no, in_mat_thick, in_mat_width, in_mat_wt, in_mat_len, in_mat_in_dia, in_mat_dia,
|
||||
pono, sg_sign, out_mat_no, out_thick, recipe_id, recipe_no,
|
||||
del_flag, create_by, create_time, update_by, update_time, remark
|
||||
</sql>
|
||||
|
||||
<select id="selectList" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/> FROM mill_production_plan
|
||||
WHERE del_flag = '0'
|
||||
<if test="inMatNo != null and inMatNo != ''">
|
||||
AND in_mat_no LIKE CONCAT('%', #{inMatNo}, '%')
|
||||
</if>
|
||||
<if test="sgSign != null and sgSign != ''">
|
||||
AND sg_sign LIKE CONCAT('%', #{sgSign}, '%')
|
||||
</if>
|
||||
<if test="planStatus != null and planStatus != ''">
|
||||
AND plan_status = #{planStatus}
|
||||
</if>
|
||||
<if test="params != null and params.beginTime != null and params.beginTime != ''">
|
||||
AND DATE(create_time) >= #{params.beginTime}
|
||||
</if>
|
||||
<if test="params != null and params.endTime != null and params.endTime != ''">
|
||||
AND DATE(create_time) <= #{params.endTime}
|
||||
</if>
|
||||
ORDER BY sort_no ASC, id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectById" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/> FROM mill_production_plan
|
||||
WHERE id = #{id} AND del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectByPlanNo" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/> FROM mill_production_plan
|
||||
WHERE plan_no = #{planNo} AND del_flag = '0' LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
|
||||
INSERT INTO mill_production_plan (
|
||||
plan_no, mat_seq_no, unit_code, plan_type, plan_status, prod_status, sort_no,
|
||||
in_mat_no, in_mat_thick, in_mat_width, in_mat_wt, in_mat_len, in_mat_in_dia, in_mat_dia,
|
||||
pono, sg_sign, out_mat_no, out_thick, recipe_id, recipe_no,
|
||||
create_by, create_time, update_by, update_time, remark, del_flag
|
||||
) VALUES (
|
||||
#{planNo}, #{matSeqNo}, #{unitCode}, #{planType},
|
||||
IFNULL(#{planStatus},'0'), IFNULL(#{prodStatus},'Idle'), IFNULL(#{sortNo},0),
|
||||
#{inMatNo}, #{inMatThick}, #{inMatWidth}, #{inMatWt}, #{inMatLen}, #{inMatInDia}, #{inMatDia},
|
||||
#{pono}, #{sgSign}, #{outMatNo}, #{outThick}, #{recipeId}, #{recipeNo},
|
||||
#{createBy}, NOW(), #{updateBy}, NOW(), #{remark}, '0'
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="update">
|
||||
UPDATE mill_production_plan
|
||||
SET plan_status = #{planStatus},
|
||||
prod_status = #{prodStatus},
|
||||
in_mat_no = #{inMatNo},
|
||||
in_mat_thick = #{inMatThick},
|
||||
in_mat_width = #{inMatWidth},
|
||||
in_mat_wt = #{inMatWt},
|
||||
in_mat_len = #{inMatLen},
|
||||
in_mat_in_dia= #{inMatInDia},
|
||||
in_mat_dia = #{inMatDia},
|
||||
pono = #{pono},
|
||||
sg_sign = #{sgSign},
|
||||
out_mat_no = #{outMatNo},
|
||||
out_thick = #{outThick},
|
||||
recipe_id = #{recipeId},
|
||||
recipe_no = #{recipeNo},
|
||||
update_by = #{updateBy},
|
||||
update_time = NOW(),
|
||||
remark = #{remark}
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<update id="deleteById">
|
||||
UPDATE mill_production_plan SET del_flag = '2', update_time = NOW() WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<update id="incrementSortFrom">
|
||||
UPDATE mill_production_plan SET sort_no = sort_no + 1
|
||||
WHERE sort_no >= #{targetSort} AND del_flag = '0'
|
||||
</update>
|
||||
|
||||
<update id="updateSortNo">
|
||||
UPDATE mill_production_plan SET sort_no = #{sortNo} WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
23
ruoyi-ui/src/api/mill/plan.js
Normal file
23
ruoyi-ui/src/api/mill/plan.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listPlan(query) {
|
||||
return request({ url: '/mill/plan/list', method: 'get', params: query })
|
||||
}
|
||||
export function getPlan(id) {
|
||||
return request({ url: `/mill/plan/${id}`, method: 'get' })
|
||||
}
|
||||
export function addPlan(data) {
|
||||
return request({ url: '/mill/plan', method: 'post', data })
|
||||
}
|
||||
export function updatePlan(data) {
|
||||
return request({ url: '/mill/plan', method: 'put', data })
|
||||
}
|
||||
export function delPlan(id) {
|
||||
return request({ url: `/mill/plan/${id}`, method: 'delete' })
|
||||
}
|
||||
export function moveUpPlan(id) {
|
||||
return request({ url: `/mill/plan/moveUp/${id}`, method: 'put' })
|
||||
}
|
||||
export function moveDownPlan(id) {
|
||||
return request({ url: `/mill/plan/moveDown/${id}`, method: 'put' })
|
||||
}
|
||||
20
ruoyi-ui/src/api/mill/recipe.js
Normal file
20
ruoyi-ui/src/api/mill/recipe.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listRecipe(query) {
|
||||
return request({ url: '/mill/recipe/list', method: 'get', params: query })
|
||||
}
|
||||
export function listAllRecipe(query) {
|
||||
return request({ url: '/mill/recipe/listAll', method: 'get', params: query })
|
||||
}
|
||||
export function getRecipeDetail(id) {
|
||||
return request({ url: `/mill/recipe/${id}`, method: 'get' })
|
||||
}
|
||||
export function addRecipe(data) {
|
||||
return request({ url: '/mill/recipe', method: 'post', data })
|
||||
}
|
||||
export function updateRecipe(data) {
|
||||
return request({ url: '/mill/recipe', method: 'put', data })
|
||||
}
|
||||
export function delRecipe(ids) {
|
||||
return request({ url: `/mill/recipe/${ids}`, method: 'delete' })
|
||||
}
|
||||
@@ -179,6 +179,32 @@ export const constantRoutes = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/mill',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: 'process',
|
||||
component: () => import('@/views/mill/process'),
|
||||
name: 'MillProcess',
|
||||
meta: { title: '工艺管理', icon: '' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/mill',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: 'plan',
|
||||
component: () => import('@/views/mill/plan'),
|
||||
name: 'MillPlan',
|
||||
meta: { title: '生产计划', icon: '' }
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
// 动态路由,基于用户权限动态去加载
|
||||
|
||||
485
ruoyi-ui/src/views/mill/plan.vue
Normal file
485
ruoyi-ui/src/views/mill/plan.vue
Normal file
@@ -0,0 +1,485 @@
|
||||
<template>
|
||||
<div class="plan-page">
|
||||
|
||||
<!-- 上方:轧制队列 -->
|
||||
<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="bottom-section">
|
||||
|
||||
<!-- 左侧:轧制工艺 -->
|
||||
<div class="pass-panel">
|
||||
<div class="section-header">
|
||||
<span>轧制工艺</span>
|
||||
<span v-if="selectedPlan" 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>
|
||||
</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>
|
||||
|
||||
<!-- 新增/修改对话框 -->
|
||||
<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="12">
|
||||
<el-form-item label="工艺方案" prop="recipeId">
|
||||
<el-select v-model="form.recipeId" filterable 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="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="采料厚度" 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="inMatWidth">
|
||||
<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>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listPlan, getPlan, addPlan, updatePlan, delPlan, moveUpPlan, moveDownPlan } from '@/api/mill/plan'
|
||||
import { listAllRecipe, getRecipeDetail } from '@/api/mill/recipe'
|
||||
|
||||
const emptyForm = () => ({
|
||||
id: null, inMatNo: '', alloyNo: '', recipeId: null, recipeNo: '',
|
||||
outThick: '', inMatThick: '', inMatWidth: '', inMatLength: '',
|
||||
inMatWeight: '', inMatOd: '', inMatId: '', remark: ''
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'MillPlan',
|
||||
data() {
|
||||
return {
|
||||
planList: [],
|
||||
selectedPlan: null,
|
||||
passList: [],
|
||||
recipeOptions: [],
|
||||
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' }],
|
||||
recipeId: [{ required: true, message: '请选择工艺方案', trigger: 'change' }],
|
||||
outThick: [{ required: true, message: '请输入成品厚度', trigger: 'blur' }],
|
||||
inMatThick:[{ required: true, message: '请输入采料厚度', trigger: 'blur' }],
|
||||
inMatWidth:[{ required: true, message: '请输入采料宽度', trigger: 'blur' }],
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogTitle() { return this.isNew ? '新增钢卷' : '修改钢卷' },
|
||||
currentCoil() {
|
||||
return this.planList.find(p => p.prodStatus === '1') || {}
|
||||
},
|
||||
nextCoil() {
|
||||
const idx = this.planList.findIndex(p => p.prodStatus === '1')
|
||||
return idx >= 0 && idx + 1 < this.planList.length ? this.planList[idx + 1] : (this.planList[0] || {})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadList()
|
||||
listAllRecipe({}).then(res => { this.recipeOptions = res.data || [] })
|
||||
},
|
||||
methods: {
|
||||
loadList() {
|
||||
const params = { inMatNo: this.query.inMatNo }
|
||||
if (this.query.hideFinished) params.prodStatus = '!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 || []
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.query = { inMatNo: '', dateRange: null, hideFinished: false }
|
||||
this.loadList()
|
||||
},
|
||||
handleQueueSelect(row) {
|
||||
this.selectedPlan = row
|
||||
if (!row) { this.passList = []; return }
|
||||
if (row.recipeId) {
|
||||
getRecipeDetail(row.recipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
} else {
|
||||
this.passList = []
|
||||
}
|
||||
},
|
||||
handleAdd() {
|
||||
this.isNew = true
|
||||
this.form = emptyForm()
|
||||
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 }
|
||||
const api = this.isNew ? addPlan : updatePlan
|
||||
api(this.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.dialogVisible = false
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDelete() {
|
||||
this.$confirm(`确定删除钢卷「${this.selectedPlan.inMatNo}」?`, '提示', { type: 'warning' }).then(() => {
|
||||
delPlan(this.selectedPlan.id).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.selectedPlan = null
|
||||
this.passList = []
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleMoveUp() {
|
||||
moveUpPlan(this.selectedPlan.id).then(() => this.loadList())
|
||||
},
|
||||
handleMoveDown() {
|
||||
moveDownPlan(this.selectedPlan.id).then(() => this.loadList())
|
||||
},
|
||||
onRecipeChange(recipeId) {
|
||||
const r = this.recipeOptions.find(x => x.id === recipeId)
|
||||
if (r) {
|
||||
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
|
||||
}
|
||||
},
|
||||
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] || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.plan-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 84px);
|
||||
background: #f0f2f5;
|
||||
padding: 8px 12px;
|
||||
box-sizing: border-box;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* ── 通用 section header ── */
|
||||
.section-header {
|
||||
background: #1c2b3a;
|
||||
color: #ecf0f1;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
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: #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 {
|
||||
flex: 1;
|
||||
::v-deep .el-table__row.alt-row td { background: #f7f9fc !important; }
|
||||
}
|
||||
|
||||
.calc-val {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: 600;
|
||||
color: #1d4e89;
|
||||
}
|
||||
|
||||
/* 右侧操作区 */
|
||||
.op-panel {
|
||||
width: 260px;
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #dde1e6;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.query-form {
|
||||
padding: 10px 12px 4px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.op-buttons {
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
|
||||
.el-button { width: 100%; justify-content: flex-start; }
|
||||
}
|
||||
|
||||
/* ── 底部状态栏 ── */
|
||||
.footer-bar {
|
||||
background: #1c2b3a;
|
||||
border-radius: 3px;
|
||||
padding: 6px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/* ── 状态标签 ── */
|
||||
.status-wait { color: #7f8c8d; }
|
||||
.status-rolling { color: #d68910; font-weight: 700; }
|
||||
.status-done { color: #2471a3; }
|
||||
.status-err { color: #c0392b; font-weight: 700; }
|
||||
</style>
|
||||
432
ruoyi-ui/src/views/mill/process.vue
Normal file
432
ruoyi-ui/src/views/mill/process.vue
Normal file
@@ -0,0 +1,432 @@
|
||||
<template>
|
||||
<div class="process-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="search-bar">
|
||||
<el-input v-model="searchKey" placeholder="方案号/合金号" size="mini" clearable
|
||||
prefix-icon="el-icon-search" @input="loadList" />
|
||||
</div>
|
||||
|
||||
<!-- 列表 -->
|
||||
<div class="recipe-list">
|
||||
<div v-for="r in recipeList" :key="r.id"
|
||||
:class="['recipe-item', { active: selectedId === r.id }]"
|
||||
@click="handleSelect(r)">
|
||||
<div class="recipe-item__no">{{ r.recipeNo }}</div>
|
||||
<div class="recipe-item__info">
|
||||
<span>{{ r.alloyNo }}</span>
|
||||
<span>{{ r.inThick }} → {{ r.outThick }} mm</span>
|
||||
<span>{{ r.passCount }} 道次</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="recipeList.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>
|
||||
|
||||
<template v-else>
|
||||
<!-- 顶部操作栏 -->
|
||||
<div class="detail-header">
|
||||
<span>{{ isNew ? '新建工艺方案' : form.recipeNo }}</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" 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="recipe-form">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="方案记录号" prop="recipeNo">
|
||||
<el-input v-model="form.recipeNo" :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="4">
|
||||
<el-form-item label="原料厚度" prop="inThick">
|
||||
<el-input v-model="form.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="form.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="成品宽度" prop="outWidth">
|
||||
<el-input v-model="form.outWidth"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<!-- 道次详情 -->
|
||||
<div class="pass-section">
|
||||
<div class="pass-header">
|
||||
<span>道次参数</span>
|
||||
<div class="btn-group">
|
||||
<el-button size="mini" icon="el-icon-plus" @click="addPass">增加道次</el-button>
|
||||
<el-button size="mini" icon="el-icon-minus" @click="removeLastPass" :disabled="passList.length===0">删除末道</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table :data="passList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass" height="calc(100vh - 340px)">
|
||||
<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)" width="100" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.inThick" size="mini" @blur="calcPass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口厚度(mm)" width="100" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.outThick" size="mini" @blur="calcPass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="宽度(mm)" width="90" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.width" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="轧制力(kN)" width="90" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.rollForce" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口张力(kN)" width="95" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.inTension" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口张力(kN)" width="95" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.outTension" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最高速度(m/min)" width="110" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.maxSpeed" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口单位张力" width="100" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.inUnitTension" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口单位张力" width="100" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.outUnitTension" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<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-column label="备注" min-width="100">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.remark" size="mini" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listRecipe, getRecipeDetail, addRecipe, updateRecipe, delRecipe } from '@/api/mill/recipe'
|
||||
|
||||
const emptyPass = (no) => ({
|
||||
passNo: no, inThick: '', outThick: '', width: '',
|
||||
rollForce: '', inTension: '', outTension: '',
|
||||
maxSpeed: '', inUnitTension: '', outUnitTension: '',
|
||||
reduction: '', totalReduction: '', remark: ''
|
||||
})
|
||||
|
||||
const emptyForm = () => ({
|
||||
id: null, recipeNo: '', alloyNo: '', passCount: 0,
|
||||
inThick: '', outThick: '', outWidth: '', status: '0', remark: ''
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'MillProcess',
|
||||
data() {
|
||||
return {
|
||||
searchKey: '',
|
||||
recipeList: [],
|
||||
selectedId: null,
|
||||
isNew: false,
|
||||
form: emptyForm(),
|
||||
passList: [],
|
||||
rules: {
|
||||
recipeNo: [{ required: true, message: '请输入方案记录号', trigger: 'blur' }],
|
||||
alloyNo: [{ required: true, message: '请输入合金号', trigger: 'blur' }],
|
||||
inThick: [{ required: true, message: '请输入原料厚度', trigger: 'blur' }],
|
||||
outThick: [{ required: true, message: '请输入成品厚度', trigger: 'blur' }],
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() { this.loadList() },
|
||||
methods: {
|
||||
loadList() {
|
||||
listRecipe({ recipeNo: this.searchKey, alloyNo: this.searchKey }).then(res => {
|
||||
this.recipeList = res.rows || []
|
||||
})
|
||||
},
|
||||
handleSelect(r) {
|
||||
this.selectedId = r.id
|
||||
this.isNew = false
|
||||
getRecipeDetail(r.id).then(res => {
|
||||
this.form = { ...res.data }
|
||||
this.passList = res.data.passList || []
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.isNew = true
|
||||
this.selectedId = null
|
||||
this.form = emptyForm()
|
||||
this.passList = []
|
||||
},
|
||||
handleSave() {
|
||||
this.$refs.formRef.validate(valid => {
|
||||
if (!valid) return
|
||||
this.form.passList = this.passList
|
||||
this.form.passCount = this.passList.length
|
||||
const api = this.isNew ? addRecipe : updateRecipe
|
||||
api(this.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.loadList()
|
||||
this.isNew = false
|
||||
})
|
||||
})
|
||||
},
|
||||
handleReset() {
|
||||
if (this.isNew) { this.form = emptyForm(); this.passList = [] }
|
||||
else this.handleSelect({ id: this.selectedId })
|
||||
},
|
||||
handleDelete() {
|
||||
this.$confirm('确定删除该方案?', '提示', { type: 'warning' }).then(() => {
|
||||
delRecipe([this.form.id]).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.form = emptyForm(); this.passList = []
|
||||
this.selectedId = null; this.isNew = false
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
},
|
||||
addPass() {
|
||||
this.passList.push(emptyPass(this.passList.length + 1))
|
||||
},
|
||||
removeLastPass() {
|
||||
if (this.passList.length) this.passList.pop()
|
||||
},
|
||||
calcPass(row) {
|
||||
const inT = parseFloat(row.inThick) || 0
|
||||
const outT = parseFloat(row.outThick) || 0
|
||||
row.reduction = outT > 0 ? (inT - outT).toFixed(3) : ''
|
||||
// 累计总压下量
|
||||
let total = 0
|
||||
const base = parseFloat(this.form.inThick) || 0
|
||||
for (const p of this.passList) {
|
||||
const pOut = parseFloat(p.outThick) || 0
|
||||
if (base > 0 && pOut > 0) {
|
||||
total = parseFloat((base - pOut).toFixed(3))
|
||||
p.totalReduction = total
|
||||
}
|
||||
}
|
||||
},
|
||||
passRowClass({ rowIndex }) {
|
||||
return rowIndex % 2 === 0 ? '' : 'alt-row'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.process-page {
|
||||
display: flex;
|
||||
height: calc(100vh - 84px);
|
||||
gap: 0;
|
||||
background: #f0f2f5;
|
||||
padding: 10px 12px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ── 左侧面板 ── */
|
||||
.left-panel {
|
||||
width: 220px;
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #dde1e6;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-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;
|
||||
}
|
||||
|
||||
.recipe-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.recipe-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; }
|
||||
|
||||
&__no {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #1c2b3a;
|
||||
}
|
||||
&__info {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
font-size: 11px;
|
||||
color: #7f8c8d;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.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; }
|
||||
|
||||
.recipe-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;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #1c2b3a;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pass-table {
|
||||
flex: 1;
|
||||
|
||||
::v-deep .el-table__row.alt-row td {
|
||||
background: #f7f9fc !important;
|
||||
}
|
||||
::v-deep .el-input__inner {
|
||||
text-align: right;
|
||||
padding: 0 4px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.calc-val {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: 600;
|
||||
color: #1d4e89;
|
||||
}
|
||||
</style>
|
||||
95
sql/mill_tables.sql
Normal file
95
sql/mill_tables.sql
Normal file
@@ -0,0 +1,95 @@
|
||||
-- ============================================================
|
||||
-- 冷轧双机架二级控制系统业务表
|
||||
-- ============================================================
|
||||
|
||||
-- ----------------------------
|
||||
-- 1. 工艺方案主表
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mill_process_recipe`;
|
||||
CREATE TABLE `mill_process_recipe` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`recipe_no` varchar(30) NOT NULL COMMENT '方案记录号/方案名称',
|
||||
`alloy_no` varchar(24) NOT NULL COMMENT '合金号(钢种)',
|
||||
`pass_count` int(4) NOT NULL DEFAULT 0 COMMENT '道次数量',
|
||||
`in_thick` decimal(9,3) NOT NULL DEFAULT 0.000 COMMENT '原料厚度(mm)',
|
||||
`out_thick` decimal(9,3) NOT NULL DEFAULT 0.000 COMMENT '成品厚度(mm)',
|
||||
`out_width` decimal(10,3) NOT NULL DEFAULT 0.000 COMMENT '成品宽度(mm)',
|
||||
`status` char(1) NOT NULL DEFAULT '0' COMMENT '状态 0-正常 1-停用',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
`del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志 0-存在 2-删除',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_recipe_no` (`recipe_no`),
|
||||
KEY `idx_alloy_no` (`alloy_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工艺方案主表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 2. 工艺方案道次详情表
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mill_process_pass`;
|
||||
CREATE TABLE `mill_process_pass` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`recipe_id` bigint(20) NOT NULL COMMENT '方案ID',
|
||||
`pass_no` int(4) NOT NULL COMMENT '道次号',
|
||||
`in_thick` decimal(9,3) NOT NULL DEFAULT 0.000 COMMENT '入口厚度(mm)',
|
||||
`out_thick` decimal(9,3) NOT NULL DEFAULT 0.000 COMMENT '出口厚度(mm)',
|
||||
`width` decimal(10,3) NOT NULL DEFAULT 0.000 COMMENT '宽度(mm)',
|
||||
`roll_force` decimal(10,1) NOT NULL DEFAULT 0.0 COMMENT '轧制力(kN)',
|
||||
`in_tension` decimal(10,1) NOT NULL DEFAULT 0.0 COMMENT '入口张力(kN)',
|
||||
`out_tension` decimal(10,1) NOT NULL DEFAULT 0.0 COMMENT '出口张力(kN)',
|
||||
`max_speed` decimal(10,1) NOT NULL DEFAULT 0.0 COMMENT '最高速度(m/min)',
|
||||
`in_unit_tension` decimal(8,2) NOT NULL DEFAULT 0.00 COMMENT '入口单位张力(N/mm²)',
|
||||
`out_unit_tension` decimal(8,2) NOT NULL DEFAULT 0.00 COMMENT '出口单位张力(N/mm²)',
|
||||
`reduction` decimal(8,2) NOT NULL DEFAULT 0.00 COMMENT '道次压下量(mm)',
|
||||
`total_reduction` decimal(8,2) NOT NULL DEFAULT 0.00 COMMENT '累计总压下量(mm)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
`del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志 0-存在 2-删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_recipe_id` (`recipe_id`),
|
||||
KEY `idx_recipe_pass` (`recipe_id`, `pass_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工艺方案道次详情表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 3. 生产计划表(轧制队列)
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mill_production_plan`;
|
||||
CREATE TABLE `mill_production_plan` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`plan_no` varchar(30) NOT NULL COMMENT '计划号',
|
||||
`mat_seq_no` varchar(3) DEFAULT '' COMMENT 'L3序号',
|
||||
`unit_code` varchar(4) DEFAULT '' COMMENT '机组代码',
|
||||
`plan_type` char(1) DEFAULT '' COMMENT '计划类型',
|
||||
`plan_status` char(1) NOT NULL DEFAULT '0' COMMENT '计划状态 0-待生产 1-生产中 2-完成 3-撤销',
|
||||
`prod_status` varchar(20) DEFAULT '' COMMENT '生产状态(Rolling/NextCoil/Idle等)',
|
||||
`sort_no` int(6) NOT NULL DEFAULT 0 COMMENT '队列排序号',
|
||||
`in_mat_no` varchar(20) NOT NULL COMMENT '入口钢卷号',
|
||||
`in_mat_thick` decimal(9,3) DEFAULT 0.000 COMMENT '入口厚度(mm)',
|
||||
`in_mat_width` decimal(10,3) DEFAULT 0.000 COMMENT '入口宽度(mm)',
|
||||
`in_mat_wt` decimal(8,0) DEFAULT 0 COMMENT '入口重量(kg)',
|
||||
`in_mat_len` decimal(12,3) DEFAULT 0.000 COMMENT '入口长度(m)',
|
||||
`in_mat_in_dia` decimal(8,2) DEFAULT 0.00 COMMENT '入口内径(mm)',
|
||||
`in_mat_dia` decimal(8,2) DEFAULT 0.00 COMMENT '入口外径(mm)',
|
||||
`pono` varchar(10) DEFAULT '' COMMENT '炉号',
|
||||
`sg_sign` varchar(24) DEFAULT '' COMMENT '钢种',
|
||||
`out_mat_no` varchar(20) DEFAULT '' COMMENT '出口材料号',
|
||||
`out_thick` decimal(9,3) DEFAULT 0.000 COMMENT '成品厚度(mm)',
|
||||
`recipe_id` bigint(20) DEFAULT NULL COMMENT '绑定工艺方案ID',
|
||||
`recipe_no` varchar(30) DEFAULT '' COMMENT '绑定工艺方案号',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
`del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志 0-存在 2-删除',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_plan_no` (`plan_no`),
|
||||
KEY `idx_plan_status` (`plan_status`),
|
||||
KEY `idx_sort_no` (`sort_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产计划表(轧制队列)';
|
||||
Reference in New Issue
Block a user