Compare commits

...

6 Commits

Author SHA1 Message Date
朱昊天
73ede33466 样式优化 2026-06-17 02:11:05 +08:00
朱昊天
2798133412 Merge remote-tracking branch 'origin/master' 2026-06-16 13:57:19 +08:00
朱昊天
8ea6894552 工艺管理
修复“重置导致选中丢失”
修复“新增保存后不会停留在新方案”
修复“搜索后左右不同步”
生产计划
定位生产计划页 plan.vue 的查询参数、日期范围、完成按钮与方案下拉逻辑
修复日期范围筛选:前端按后端约定写入 queryParams.params.beginTime/endTime
修复“不显示生产完成”筛选:前后端新增 excludeDone 过滤并落到 SQL 条件
修复完成计划幂等:后端避免重复插入实绩;前端对已完成禁用按钮
生产绩效
修复“明细信息显示旧数据”
修复“点击表格行只看明细但不能直接修改/删除
修复“时间字段时分秒丢失”
 修复“补录/修改表单无校验”
2026-06-16 13:56:58 +08:00
6acb7b4b40 refactor(mill): 优化轧辊备用管理的数据查询和状态更新逻辑
- 修改 MesRollInfoMapper 中条件更新状态方法的参数命名,提升可读性
- 更新 MesRollStandbyMapper 查询接口返回类型为 MesRollStandbyVo
- 重构 MesRollStandbyMapper XML 映射文件中的查询语句,增加位置标签字段
- 将清空操作从物理删除改为逻辑删除,保留数据记录
- 在 MesRollStandbyVo 中新增 positionLabel、remark 和 createTime 字段
- 调整控制器注解配置,移除权限校验并简化接口定义
2026-06-12 10:26:47 +08:00
21a1d339d5 Merge remote-tracking branch 'origin/master' 2026-06-09 17:28:39 +08:00
c47da2f443 fix(mill): 优化换辊记录查询逻辑
- 修改selectCurrentStateByStand方法实现各辊位独立获取最新非空记录
- 更新selectLatestByStandAndPosition方法支持按辊位类型条件查询
- 添加删除标记过滤确保只查询有效数据
- 优化SQL查询结构提升部分换辊场景的数据准确性
- 调整查询条件顺序增强查询性能
- 修正注释描述以准确反映新的查询逻辑
2026-06-09 17:28:29 +08:00
21 changed files with 576 additions and 443 deletions

View File

@@ -104,14 +104,12 @@ public class MesRollStandbyController extends BaseController
} }
/** /**
* 清空指定机架所有备辊,同时回退轧辊状态 * 清空指定产线+机架的全部下批轧辊
* DELETE /mill/standby/clear?lineId=xxx&standNo=1%23 * DELETE /mill/standby/clear?lineId=xxx&standNo=1%23
*/ */
@PreAuthorize("@ss.hasPermi('mill:standby:remove')") @Log(title = "下批轧辊", businessType = BusinessType.DELETE)
@Log(title = "下批轧辊(待换上)", businessType = BusinessType.DELETE)
@DeleteMapping("/clear") @DeleteMapping("/clear")
public AjaxResult clearByStand(@RequestParam Long lineId, @RequestParam String standNo) public AjaxResult clear(Long lineId, @RequestParam String standNo) {
{
return toAjax(mesRollStandbyService.clearByStand(lineId, standNo)); return toAjax(mesRollStandbyService.clearByStand(lineId, standNo));
} }
} }

View File

@@ -14,10 +14,14 @@ public class MesRollStandbyVo {
private String rollNo; private String rollNo;
private String rollType; private String rollType;
private String position; private String position;
/** 辊位中文标签(上支撑辊/上工作辊/下工作辊/下支撑辊) */
private String positionLabel;
private BigDecimal diameter; private BigDecimal diameter;
private BigDecimal roughness; private BigDecimal roughness;
private BigDecimal crown; private BigDecimal crown;
private Date readyTime; private Date readyTime;
private String remark;
private Date createTime;
public Long getStandbyId() { return standbyId; } public Long getStandbyId() { return standbyId; }
public void setStandbyId(Long standbyId) { this.standbyId = standbyId; } public void setStandbyId(Long standbyId) { this.standbyId = standbyId; }
@@ -37,6 +41,9 @@ public class MesRollStandbyVo {
public String getPosition() { return position; } public String getPosition() { return position; }
public void setPosition(String position) { this.position = position; } public void setPosition(String position) { this.position = position; }
public String getPositionLabel() { return positionLabel; }
public void setPositionLabel(String positionLabel) { this.positionLabel = positionLabel; }
public BigDecimal getDiameter() { return diameter; } public BigDecimal getDiameter() { return diameter; }
public void setDiameter(BigDecimal diameter) { this.diameter = diameter; } public void setDiameter(BigDecimal diameter) { this.diameter = diameter; }
@@ -48,4 +55,10 @@ public class MesRollStandbyVo {
public Date getReadyTime() { return readyTime; } public Date getReadyTime() { return readyTime; }
public void setReadyTime(Date readyTime) { this.readyTime = readyTime; } public void setReadyTime(Date readyTime) { this.readyTime = readyTime; }
public String getRemark() { return remark; }
public void setRemark(String remark) { this.remark = remark; }
public Date getCreateTime() { return createTime; }
public void setCreateTime(Date createTime) { this.createTime = createTime; }
} }

View File

@@ -126,18 +126,18 @@ public class MillProductionActual extends BaseEntity
private String customer; private String customer;
/** 上线时间 */ /** 上线时间 */
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "上线时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "上线时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date onlineTime; private Date onlineTime;
/** 开始时间 */ /** 开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date startTime; private Date startTime;
/** 结束时间 */ /** 结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date endTime; private Date endTime;
/** 机组号 */ /** 机组号 */

View File

@@ -36,10 +36,9 @@ public interface MesRollInfoMapper {
int updateCurrentDia(@Param("rollId") Long rollId, @Param("currentDia") BigDecimal currentDia); int updateCurrentDia(@Param("rollId") Long rollId, @Param("currentDia") BigDecimal currentDia);
/** /**
* 条件更新轧辊状态 — 仅当当前状态为 oldStatus 时才更新为 newStatus * 条件更新仅当当前状态等于 onlyIfStatus 时才更新(用于避免误覆盖已 Online 的辊)
* 用于清空备辊时安全回退:避免把已上机的轧辊状态改错
*/ */
int updateStatusByRollNoIfStatus(@Param("rollNo") String rollNo, int updateStatusByRollNoIfStatus(@Param("rollNo") String rollNo,
@Param("newStatus") String newStatus, @Param("status") String status,
@Param("oldStatus") String oldStatus); @Param("onlyIfStatus") String onlyIfStatus);
} }

View File

@@ -2,6 +2,7 @@ package com.ruoyi.mill.mapper;
import java.util.List; import java.util.List;
import com.ruoyi.mill.domain.MesRollStandby; import com.ruoyi.mill.domain.MesRollStandby;
import com.ruoyi.mill.domain.MesRollStandbyVo;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
/** /**
@@ -67,7 +68,7 @@ public interface MesRollStandbyMapper
* @param standNo 机架号 * @param standNo 机架号
* @return 备辊列表 (VO) * @return 备辊列表 (VO)
*/ */
public List<MesRollStandby> selectByStand(@Param("lineId") Long lineId, @Param("standNo") String standNo); public List<MesRollStandbyVo> selectByStand(@Param("lineId") Long lineId, @Param("standNo") String standNo);
/** /**
* 清空指定机架的所有备辊记录 * 清空指定机架的所有备辊记录

View File

@@ -27,6 +27,14 @@ public interface MillProductionActualMapper
*/ */
public List<MillProductionActual> selectMillProductionActualList(MillProductionActual millProductionActual); public List<MillProductionActual> selectMillProductionActualList(MillProductionActual millProductionActual);
/**
* 查询某计划是否已生成实绩
*
* @param planId 计划ID
* @return 数量
*/
public int countByPlanId(Long planId);
/** /**
* 新增轧线生产实绩 * 新增轧线生产实绩
* *

View File

@@ -11,6 +11,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.mill.mapper.MesRollStandbyMapper; import com.ruoyi.mill.mapper.MesRollStandbyMapper;
import com.ruoyi.mill.domain.MesRollStandby; import com.ruoyi.mill.domain.MesRollStandby;
import com.ruoyi.mill.domain.MesRollStandbyVo;
import com.ruoyi.mill.service.IMesRollStandbyService; import com.ruoyi.mill.service.IMesRollStandbyService;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
@@ -113,9 +114,9 @@ public class MesRollStandbyServiceImpl implements IMesRollStandbyService
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Boolean clearByStand(Long lineId, String standNo) { public Boolean clearByStand(Long lineId, String standNo) {
// 先查出所有辊号再清空 // 先查出所有辊号再清空
List<MesRollStandby> list = mesRollStandbyMapper.selectByStand(lineId, standNo); List<MesRollStandbyVo> list = mesRollStandbyMapper.selectByStand(lineId, standNo);
int rows = mesRollStandbyMapper.clearByStand(lineId, standNo); int rows = mesRollStandbyMapper.clearByStand(lineId, standNo);
for (MesRollStandby vo : list) { for (MesRollStandbyVo vo : list) {
if (StringUtils.isNotBlank(vo.getRollNo())) { if (StringUtils.isNotBlank(vo.getRollNo())) {
// 只有仍处于 Standby 状态时才回退为 Offline换辊后已变 Online 的不动) // 只有仍处于 Standby 状态时才回退为 Offline换辊后已变 Online 的不动)
rollInfoMapper.updateStatusByRollNoIfStatus(vo.getRollNo(), "Offline", "Standby"); rollInfoMapper.updateStatusByRollNoIfStatus(vo.getRollNo(), "Offline", "Standby");

View File

@@ -96,28 +96,32 @@ public class MillProductionPlanServiceImpl implements IMillProductionPlanService
throw new RuntimeException("计划不存在: " + planId); throw new RuntimeException("计划不存在: " + planId);
} }
// 2. 更新计划状态为完成(2) // 2. 更新计划状态为完成(幂等)
plan.setProdStatus("Done"); if (!"Done".equals(plan.getProdStatus())) {
plan.setUpdateBy(SecurityUtils.getUsername()); plan.setProdStatus("Done");
int updateResult = planMapper.update(plan); plan.setUpdateBy(SecurityUtils.getUsername());
if (updateResult <= 0) { int updateResult = planMapper.update(plan);
throw new RuntimeException("更新计划状态失败"); if (updateResult <= 0) {
throw new RuntimeException("更新计划状态失败");
}
} }
// 3. 创建生产实绩记录 // 3. 创建生产实绩记录(幂等)
MillProductionActual actual = new MillProductionActual(); if (actualMapper.countByPlanId(planId) <= 0) {
actual.setPlanId(plan.getPlanId()); MillProductionActual actual = new MillProductionActual();
actual.setPlanNo(plan.getPlanNo()); actual.setPlanId(plan.getPlanId());
actual.setEntryMatId(plan.getInMatNo()); // 来料卷号 = 生产计划钢卷号 actual.setPlanNo(plan.getPlanNo());
actual.setSteelGrade(plan.getAlloyNo()); // 钢种 actual.setEntryMatId(plan.getInMatNo());
actual.setStatus("已完成"); // 实绩状态:已完成 actual.setSteelGrade(plan.getAlloyNo());
actual.setEndTime(new Date()); // 结束时间 actual.setStatus("已完成");
actual.setCreateBy(SecurityUtils.getUsername()); actual.setEndTime(new Date());
actual.setDelFlag("0"); // 正常状态 actual.setCreateBy(SecurityUtils.getUsername());
actual.setDelFlag("0");
int actualResult = actualMapper.insertMillProductionActual(actual); int actualResult = actualMapper.insertMillProductionActual(actual);
if (actualResult <= 0) { if (actualResult <= 0) {
throw new RuntimeException("创建生产实绩记录失败"); throw new RuntimeException("创建生产实绩记录失败");
}
} }
return 1; return 1;

View File

@@ -148,33 +148,34 @@
</foreach> </foreach>
</delete> </delete>
<!-- 查询指定机架当前各辊位状态(最近一次换辊记录) --> <!-- 组合查询各辊位当前实际在机状态(每个位置独立取最新非空记录) -->
<select id="selectCurrentStateByStand" resultType="map"> <select id="selectCurrentStateByStand" resultType="map">
SELECT change_time AS changeTime, SELECT
upper_wr_no AS upperWrNo, (SELECT upper_wr_no FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if> AND upper_wr_no IS NOT NULL AND upper_wr_no != '' ORDER BY change_time DESC, change_id DESC LIMIT 1) AS upperWrNo,
upper_wr_dia AS upperWrDia, (SELECT upper_wr_dia FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if> AND upper_wr_no IS NOT NULL AND upper_wr_no != '' ORDER BY change_time DESC, change_id DESC LIMIT 1) AS upperWrDia,
lower_wr_no AS lowerWrNo, (SELECT lower_wr_no FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if> AND lower_wr_no IS NOT NULL AND lower_wr_no != '' ORDER BY change_time DESC, change_id DESC LIMIT 1) AS lowerWrNo,
lower_wr_dia AS lowerWrDia, (SELECT lower_wr_dia FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if> AND lower_wr_no IS NOT NULL AND lower_wr_no != '' ORDER BY change_time DESC, change_id DESC LIMIT 1) AS lowerWrDia,
upper_br_no AS upperBrNo, (SELECT upper_br_no FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if> AND upper_br_no IS NOT NULL AND upper_br_no != '' ORDER BY change_time DESC, change_id DESC LIMIT 1) AS upperBrNo,
upper_br_dia AS upperBrDia, (SELECT upper_br_dia FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if> AND upper_br_no IS NOT NULL AND upper_br_no != '' ORDER BY change_time DESC, change_id DESC LIMIT 1) AS upperBrDia,
lower_br_no AS lowerBrNo, (SELECT lower_br_no FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if> AND lower_br_no IS NOT NULL AND lower_br_no != '' ORDER BY change_time DESC, change_id DESC LIMIT 1) AS lowerBrNo,
lower_br_dia AS lowerBrDia (SELECT lower_br_dia FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if> AND lower_br_no IS NOT NULL AND lower_br_no != '' ORDER BY change_time DESC, change_id DESC LIMIT 1) AS lowerBrDia,
FROM mes_roll_change (SELECT MAX(change_time) FROM mes_roll_change WHERE stand_no = #{standNo} AND del_flag = 0 <if test="lineId != null">AND line_id = #{lineId}</if>) AS changeTime
WHERE line_id = #{lineId} AND stand_no = #{standNo}
ORDER BY change_id DESC
LIMIT 1
</select> </select>
<!-- 查询指定机架+辊位最新换辊记录 --> <!-- 辊位最新非空换辊记录(支持部分换辊) -->
<select id="selectLatestByStandAndPosition" resultMap="MesRollChangeResult"> <select id="selectLatestByStandAndPosition" resultMap="MesRollChangeResult">
<include refid="selectMesRollChangeVo"/> SELECT change_id, line_id, change_no, change_time, stand_no, operator,
WHERE line_id = #{lineId} AND stand_no = #{standNo} AND del_flag = 0 upper_wr_no, upper_wr_dia, lower_wr_no, lower_wr_dia,
AND ( upper_br_no, upper_br_dia, lower_br_no, lower_br_dia
(#{posType} = 'upperWr' AND upper_wr_no IS NOT NULL) FROM mes_roll_change
OR (#{posType} = 'lowerWr' AND lower_wr_no IS NOT NULL) WHERE del_flag = 0 AND stand_no = #{standNo}
OR (#{posType} = 'upperBr' AND upper_br_no IS NOT NULL) <if test="lineId != null">AND line_id = #{lineId}</if>
OR (#{posType} = 'lowerBr' AND lower_br_no IS NOT NULL) <choose>
) <when test="posType == 'upperWr'">AND upper_wr_no IS NOT NULL AND upper_wr_no != ''</when>
<when test="posType == 'lowerWr'">AND lower_wr_no IS NOT NULL AND lower_wr_no != ''</when>
<when test="posType == 'upperBr'">AND upper_br_no IS NOT NULL AND upper_br_no != ''</when>
<when test="posType == 'lowerBr'">AND lower_br_no IS NOT NULL AND lower_br_no != ''</when>
</choose>
ORDER BY change_time DESC, change_id DESC ORDER BY change_time DESC, change_id DESC
LIMIT 1 LIMIT 1
</select> </select>

View File

@@ -171,13 +171,10 @@
WHERE del_flag = 0 AND roll_id = #{rollId} WHERE del_flag = 0 AND roll_id = #{rollId}
</update> </update>
<!-- 条件更新轧辊状态 — 仅当当前状态为 oldStatus 时才更新 -->
<update id="updateStatusByRollNoIfStatus"> <update id="updateStatusByRollNoIfStatus">
UPDATE mes_roll_info UPDATE mes_roll_info
SET status = #{newStatus}, update_time = NOW() SET status = #{status}, update_time = NOW()
WHERE del_flag = 0 WHERE del_flag = 0 AND roll_no = #{rollNo} AND status = #{onlyIfStatus}
AND roll_no = #{rollNo}
AND status = #{oldStatus}
</update> </update>
</mapper> </mapper>

View File

@@ -118,13 +118,33 @@
</foreach> </foreach>
</delete> </delete>
<select id="selectByStand" resultMap="MesRollStandbyResult"> <select id="selectByStand" resultType="com.ruoyi.mill.domain.MesRollStandbyVo">
<include refid="selectMesRollStandbyVo"/> SELECT
where line_id = #{lineId} and stand_no = #{standNo} standby_id, line_id, stand_no, roll_no, roll_type, position,
CASE
WHEN roll_type = 'BR' AND position = 'UP' THEN '上支撑辊'
WHEN roll_type = 'WR' AND position = 'UP' THEN '上工作辊'
WHEN roll_type = 'WR' AND position = 'DOWN' THEN '下工作辊'
WHEN roll_type = 'BR' AND position = 'DOWN' THEN '下支撑辊'
ELSE CONCAT(position, roll_type)
END AS position_label,
diameter, roughness, crown, ready_time, remark, create_time
FROM mes_roll_standby
WHERE del_flag = 0
AND stand_no = #{standNo}
<if test="lineId != null">AND line_id = #{lineId}</if>
ORDER BY
FIELD(roll_type, 'BR', 'WR', 'WR', 'BR'),
FIELD(position, 'UP', 'UP', 'DOWN', 'DOWN')
</select> </select>
<delete id="clearByStand"> <!-- 逻辑删除指定产线+机架所有下批轧辊(清空) -->
delete from mes_roll_standby <update id="clearByStand">
where line_id = #{lineId} and stand_no = #{standNo} UPDATE mes_roll_standby
</delete> SET del_flag = 1
WHERE del_flag = 0
AND stand_no = #{standNo}
<if test="lineId != null">AND line_id = #{lineId}</if>
</update>
</mapper> </mapper>

View File

@@ -29,12 +29,22 @@
SELECT <include refid="cols"/> SELECT <include refid="cols"/>
FROM mill_process_recipe FROM mill_process_recipe
WHERE del_flag = '0' WHERE del_flag = '0'
<if test="recipeNo != null and recipeNo != ''"> <choose>
AND recipe_no LIKE CONCAT('%', #{recipeNo}, '%') <when test="recipeNo != null and recipeNo != '' and alloyNo != null and alloyNo != '' and recipeNo == alloyNo">
</if> AND (
<if test="alloyNo != null and alloyNo != ''"> recipe_no LIKE CONCAT('%', #{recipeNo}, '%')
AND alloy_no LIKE CONCAT('%', #{alloyNo}, '%') OR alloy_no LIKE CONCAT('%', #{alloyNo}, '%')
</if> )
</when>
<otherwise>
<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>
</otherwise>
</choose>
<if test="status != null and status != ''"> <if test="status != null and status != ''">
AND status = #{status} AND status = #{status}
</if> </if>

View File

@@ -101,6 +101,10 @@
where actual_id = #{actualId} where actual_id = #{actualId}
</select> </select>
<select id="countByPlanId" parameterType="Long" resultType="int">
select count(1) from mill_production_actual where plan_id = #{planId} and del_flag = '0'
</select>
<insert id="insertMillProductionActual" parameterType="MillProductionActual" useGeneratedKeys="true" keyProperty="actualId"> <insert id="insertMillProductionActual" parameterType="MillProductionActual" useGeneratedKeys="true" keyProperty="actualId">
insert into mill_production_actual insert into mill_production_actual
<trim prefix="(" suffix=")" suffixOverrides=","> <trim prefix="(" suffix=")" suffixOverrides=",">

View File

@@ -48,6 +48,9 @@
<if test="planStatus != null and planStatus != ''"> <if test="planStatus != null and planStatus != ''">
AND plan_status = #{planStatus} AND plan_status = #{planStatus}
</if> </if>
<if test="params != null and (params.excludeDone == true or params.excludeDone == 'true')">
AND prod_status != 'Done'
</if>
<if test="params != null and params.beginTime != null and params.beginTime != ''"> <if test="params != null and params.beginTime != null and params.beginTime != ''">
AND DATE(create_time) >= #{params.beginTime} AND DATE(create_time) >= #{params.beginTime}
</if> </if>

View File

@@ -89,9 +89,9 @@
} }
.el-menu-item.is-active { .el-menu-item.is-active {
background-color: #1d4e89 !important; background-color: rgba(93, 173, 226, 0.24) !important;
color: #ffffff !important; color: #ffffff !important;
border-left: 3px solid #5dade2; border-left: 3px solid #85c1e9;
} }
& .nest-menu .el-submenu>.el-submenu__title, & .nest-menu .el-submenu>.el-submenu__title,

View File

@@ -7,7 +7,9 @@
<router-link v-else key="expand" class="sidebar-logo-link" to="/"> <router-link v-else key="expand" class="sidebar-logo-link" to="/">
<div class="sidebar-logo-inner"> <div class="sidebar-logo-inner">
<img v-if="logo" :src="logo" class="sidebar-logo" /> <img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1> <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">
<span v-for="(line, index) in titleLines" :key="index" class="sidebar-title-line">{{ line }}</span>
</h1>
</div> </div>
</router-link> </router-link>
</transition> </transition>
@@ -32,6 +34,12 @@ export default {
}, },
sideTheme() { sideTheme() {
return this.$store.state.settings.sideTheme return this.$store.state.settings.sideTheme
},
titleLines() {
if (this.title === '科伦普冷轧双机架控制平台') {
return ['科伦普冷轧', '双机架控制平台']
}
return [this.title]
} }
}, },
data() { data() {
@@ -72,10 +80,14 @@ export default {
text-decoration: none; text-decoration: none;
& .sidebar-logo-inner { & .sidebar-logo-inner {
display: flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 10px; gap: 10px;
width: auto;
max-width: calc(100% - 20px);
margin: 0 auto;
transform: translate(-6px, 5px);
} }
& .sidebar-logo { & .sidebar-logo {
@@ -87,19 +99,26 @@ export default {
} }
& .sidebar-title { & .sidebar-title {
display: inline-block; display: block;
margin: 0; margin: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #fff; color: #fff;
font-weight: 700; font-weight: 700;
line-height: 56px; font-size: 13px;
font-size: 15px;
font-family: Avenir, Helvetica Neue, Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif; font-family: Avenir, Helvetica Neue, Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
vertical-align: middle; vertical-align: middle;
letter-spacing: 0.5px; letter-spacing: 0.2px;
text-align: center;
max-width: 150px;
}
& .sidebar-title-line {
display: block;
line-height: 18px;
white-space: nowrap; white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 140px;
} }
} }

View File

@@ -1,328 +1,329 @@
<template> <template>
<div id="tags-view-container" class="tags-view-container"> <div id="tags-view-container" class="tags-view-container">
<scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll"> <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
<router-link <router-link
v-for="tag in visitedViews" v-for="tag in visitedViews"
ref="tag" ref="tag"
:key="tag.path" :key="tag.path"
:class="isActive(tag)?'active':''" :class="isActive(tag)?'active':''"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
tag="span" tag="span"
class="tags-view-item" class="tags-view-item"
:style="activeStyle(tag)" :style="activeStyle(tag)"
@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''" @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
@contextmenu.prevent.native="openMenu(tag,$event)" @contextmenu.prevent.native="openMenu(tag,$event)"
> >
{{ tag.title }} {{ tag.title }}
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
</router-link> </router-link>
</scroll-pane> </scroll-pane>
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"> <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 刷新页面</li> <li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 刷新页面</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 关闭当前</li> <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 关闭当前</li>
<li @click="closeOthersTags"><i class="el-icon-circle-close"></i> 关闭其他</li> <li @click="closeOthersTags"><i class="el-icon-circle-close"></i> 关闭其他</li>
<li v-if="!isFirstView()" @click="closeLeftTags"><i class="el-icon-back"></i> 关闭左侧</li> <li v-if="!isFirstView()" @click="closeLeftTags"><i class="el-icon-back"></i> 关闭左侧</li>
<li v-if="!isLastView()" @click="closeRightTags"><i class="el-icon-right"></i> 关闭右侧</li> <li v-if="!isLastView()" @click="closeRightTags"><i class="el-icon-right"></i> 关闭右侧</li>
<li @click="closeAllTags(selectedTag)"><i class="el-icon-circle-close"></i> 全部关闭</li> <li @click="closeAllTags(selectedTag)"><i class="el-icon-circle-close"></i> 全部关闭</li>
</ul> </ul>
</div> </div>
</template> </template>
<script> <script>
import ScrollPane from './ScrollPane' import ScrollPane from './ScrollPane'
import path from 'path' import path from 'path'
export default { export default {
components: { ScrollPane }, components: { ScrollPane },
data() { data() {
return { return {
visible: false, visible: false,
top: 0, top: 0,
left: 0, left: 0,
selectedTag: {}, selectedTag: {},
affixTags: [] affixTags: []
} }
}, },
computed: { computed: {
visitedViews() { visitedViews() {
return this.$store.state.tagsView.visitedViews return this.$store.state.tagsView.visitedViews
}, },
routes() { routes() {
return this.$store.state.permission.routes return this.$store.state.permission.routes
}, },
theme() { theme() {
return this.$store.state.settings.theme; return this.$store.state.settings.theme;
} }
}, },
watch: { watch: {
$route() { $route() {
this.addTags() this.addTags()
this.moveToCurrentTag() this.moveToCurrentTag()
}, },
visible(value) { visible(value) {
if (value) { if (value) {
document.body.addEventListener('click', this.closeMenu) document.body.addEventListener('click', this.closeMenu)
} else { } else {
document.body.removeEventListener('click', this.closeMenu) document.body.removeEventListener('click', this.closeMenu)
} }
} }
}, },
mounted() { mounted() {
this.initTags() this.initTags()
this.addTags() this.addTags()
}, },
methods: { methods: {
isActive(route) { isActive(route) {
return route.path === this.$route.path return route.path === this.$route.path
}, },
activeStyle(tag) { activeStyle(tag) {
if (!this.isActive(tag)) return {}; if (!this.isActive(tag)) return {};
return { return {
"background-color": this.theme, "background-color": "rgba(93, 173, 226, 0.16)",
"border-color": this.theme "border-color": "#85c1e9",
}; "color": "#2f5d84"
}, };
isAffix(tag) { },
return tag.meta && tag.meta.affix isAffix(tag) {
}, return tag.meta && tag.meta.affix
isFirstView() { },
try { isFirstView() {
return this.selectedTag.fullPath === '/index' || this.selectedTag.fullPath === this.visitedViews[1].fullPath try {
} catch (err) { return this.selectedTag.fullPath === '/index' || this.selectedTag.fullPath === this.visitedViews[1].fullPath
return false } catch (err) {
} return false
}, }
isLastView() { },
try { isLastView() {
return this.selectedTag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath try {
} catch (err) { return this.selectedTag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath
return false } catch (err) {
} return false
}, }
filterAffixTags(routes, basePath = '/') { },
let tags = [] filterAffixTags(routes, basePath = '/') {
routes.forEach(route => { let tags = []
if (route.meta && route.meta.affix) { routes.forEach(route => {
const tagPath = path.resolve(basePath, route.path) if (route.meta && route.meta.affix) {
tags.push({ const tagPath = path.resolve(basePath, route.path)
fullPath: tagPath, tags.push({
path: tagPath, fullPath: tagPath,
name: route.name, path: tagPath,
meta: { ...route.meta } name: route.name,
}) meta: { ...route.meta }
} })
if (route.children) { }
const tempTags = this.filterAffixTags(route.children, route.path) if (route.children) {
if (tempTags.length >= 1) { const tempTags = this.filterAffixTags(route.children, route.path)
tags = [...tags, ...tempTags] if (tempTags.length >= 1) {
} tags = [...tags, ...tempTags]
} }
}) }
return tags })
}, return tags
initTags() { },
const affixTags = this.affixTags = this.filterAffixTags(this.routes) initTags() {
for (const tag of affixTags) { const affixTags = this.affixTags = this.filterAffixTags(this.routes)
// Must have tag name for (const tag of affixTags) {
if (tag.name) { // Must have tag name
this.$store.dispatch('tagsView/addVisitedView', tag) if (tag.name) {
} this.$store.dispatch('tagsView/addVisitedView', tag)
} }
}, }
addTags() { },
const { name } = this.$route addTags() {
if (name) { const { name } = this.$route
this.$store.dispatch('tagsView/addView', this.$route) if (name) {
} this.$store.dispatch('tagsView/addView', this.$route)
}, }
moveToCurrentTag() { },
const tags = this.$refs.tag moveToCurrentTag() {
this.$nextTick(() => { const tags = this.$refs.tag
for (const tag of tags) { this.$nextTick(() => {
if (tag.to.path === this.$route.path) { for (const tag of tags) {
this.$refs.scrollPane.moveToTarget(tag) if (tag.to.path === this.$route.path) {
// when query is different then update this.$refs.scrollPane.moveToTarget(tag)
if (tag.to.fullPath !== this.$route.fullPath) { // when query is different then update
this.$store.dispatch('tagsView/updateVisitedView', this.$route) if (tag.to.fullPath !== this.$route.fullPath) {
} this.$store.dispatch('tagsView/updateVisitedView', this.$route)
break }
} break
} }
}) }
}, })
refreshSelectedTag(view) { },
this.$tab.refreshPage(view); refreshSelectedTag(view) {
if (this.$route.meta.link) { this.$tab.refreshPage(view);
this.$store.dispatch('tagsView/delIframeView', this.$route) if (this.$route.meta.link) {
} this.$store.dispatch('tagsView/delIframeView', this.$route)
}, }
closeSelectedTag(view) { },
this.$tab.closePage(view).then(({ visitedViews }) => { closeSelectedTag(view) {
if (this.isActive(view)) { this.$tab.closePage(view).then(({ visitedViews }) => {
this.toLastView(visitedViews, view) if (this.isActive(view)) {
} this.toLastView(visitedViews, view)
}) }
}, })
closeRightTags() { },
this.$tab.closeRightPage(this.selectedTag).then(visitedViews => { closeRightTags() {
if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) { this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {
this.toLastView(visitedViews) if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
} this.toLastView(visitedViews)
}) }
}, })
closeLeftTags() { },
this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => { closeLeftTags() {
if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) { this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {
this.toLastView(visitedViews) if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
} this.toLastView(visitedViews)
}) }
}, })
closeOthersTags() { },
this.$router.push(this.selectedTag.fullPath).catch(()=>{}); closeOthersTags() {
this.$tab.closeOtherPage(this.selectedTag).then(() => { this.$router.push(this.selectedTag.fullPath).catch(()=>{});
this.moveToCurrentTag() this.$tab.closeOtherPage(this.selectedTag).then(() => {
}) this.moveToCurrentTag()
}, })
closeAllTags(view) { },
this.$tab.closeAllPage().then(({ visitedViews }) => { closeAllTags(view) {
if (this.affixTags.some(tag => tag.path === this.$route.path)) { this.$tab.closeAllPage().then(({ visitedViews }) => {
return if (this.affixTags.some(tag => tag.path === this.$route.path)) {
} return
this.toLastView(visitedViews, view) }
}) this.toLastView(visitedViews, view)
}, })
toLastView(visitedViews, view) { },
const latestView = visitedViews.slice(-1)[0] toLastView(visitedViews, view) {
if (latestView) { const latestView = visitedViews.slice(-1)[0]
this.$router.push(latestView.fullPath) if (latestView) {
} else { this.$router.push(latestView.fullPath)
// now the default is to redirect to the home page if there is no tags-view, } else {
// you can adjust it according to your needs. // now the default is to redirect to the home page if there is no tags-view,
if (view.name === 'Dashboard') { // you can adjust it according to your needs.
// to reload home page if (view.name === 'Dashboard') {
this.$router.replace({ path: '/redirect' + view.fullPath }) // to reload home page
} else { this.$router.replace({ path: '/redirect' + view.fullPath })
this.$router.push('/') } else {
} this.$router.push('/')
} }
}, }
openMenu(tag, e) { },
const menuMinWidth = 105 openMenu(tag, e) {
const offsetLeft = this.$el.getBoundingClientRect().left // container margin left const menuMinWidth = 105
const offsetWidth = this.$el.offsetWidth // container width const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
const maxLeft = offsetWidth - menuMinWidth // left boundary const offsetWidth = this.$el.offsetWidth // container width
const left = e.clientX - offsetLeft + 15 // 15: margin right const maxLeft = offsetWidth - menuMinWidth // left boundary
const left = e.clientX - offsetLeft + 15 // 15: margin right
if (left > maxLeft) {
this.left = maxLeft if (left > maxLeft) {
} else { this.left = maxLeft
this.left = left } else {
} this.left = left
}
this.top = e.clientY
this.visible = true this.top = e.clientY
this.selectedTag = tag this.visible = true
}, this.selectedTag = tag
closeMenu() { },
this.visible = false closeMenu() {
}, this.visible = false
handleScroll() { },
this.closeMenu() handleScroll() {
} this.closeMenu()
} }
} }
</script> }
</script>
<style lang="scss" scoped>
.tags-view-container { <style lang="scss" scoped>
height: 34px; .tags-view-container {
width: 100%; height: 34px;
background: #fff; width: 100%;
border-bottom: 1px solid #d8dce5; background: #fff;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04); border-bottom: 1px solid #d8dce5;
.tags-view-wrapper { box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
.tags-view-item { .tags-view-wrapper {
display: inline-block; .tags-view-item {
position: relative; display: inline-block;
cursor: pointer; position: relative;
height: 26px; cursor: pointer;
line-height: 26px; height: 26px;
border: 1px solid #d8dce5; line-height: 26px;
color: #495060; border: 1px solid #d8dce5;
background: #fff; color: #495060;
padding: 0 8px; background: #fff;
font-size: 12px; padding: 0 8px;
margin-left: 5px; font-size: 12px;
margin-top: 4px; margin-left: 5px;
&:first-of-type { margin-top: 4px;
margin-left: 15px; &:first-of-type {
} margin-left: 15px;
&:last-of-type { }
margin-right: 15px; &:last-of-type {
} margin-right: 15px;
&.active { }
background-color: #42b983; &.active {
color: #fff; background-color: rgba(93, 173, 226, 0.16);
border-color: #42b983; color: #2f5d84;
&::before { border-color: #85c1e9;
content: ''; &::before {
background: #fff; content: '';
display: inline-block; background: #85c1e9;
width: 8px; display: inline-block;
height: 8px; width: 8px;
border-radius: 50%; height: 8px;
position: relative; border-radius: 50%;
margin-right: 2px; position: relative;
} margin-right: 2px;
} }
} }
} }
.contextmenu { }
margin: 0; .contextmenu {
background: #fff; margin: 0;
z-index: 3000; background: #fff;
position: absolute; z-index: 3000;
list-style-type: none; position: absolute;
padding: 5px 0; list-style-type: none;
border-radius: 4px; padding: 5px 0;
font-size: 12px; border-radius: 4px;
font-weight: 400; font-size: 12px;
color: #333; font-weight: 400;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); color: #333;
li { box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
margin: 0; li {
padding: 7px 16px; margin: 0;
cursor: pointer; padding: 7px 16px;
&:hover { cursor: pointer;
background: #eee; &:hover {
} background: #eee;
} }
} }
} }
</style> }
</style>
<style lang="scss">
//reset element css of el-icon-close <style lang="scss">
.tags-view-wrapper { //reset element css of el-icon-close
.tags-view-item { .tags-view-wrapper {
.el-icon-close { .tags-view-item {
width: 16px; .el-icon-close {
height: 16px; width: 16px;
vertical-align: 2px; height: 16px;
border-radius: 50%; vertical-align: 2px;
text-align: center; border-radius: 50%;
transition: all .3s cubic-bezier(.645, .045, .355, 1); text-align: center;
transform-origin: 100% 50%; transition: all .3s cubic-bezier(.645, .045, .355, 1);
&:before { transform-origin: 100% 50%;
transform: scale(.6); &:before {
display: inline-block; transform: scale(.6);
vertical-align: -3px; display: inline-block;
} vertical-align: -3px;
&:hover { }
background-color: #b4bccc; &:hover {
color: #fff; background-color: #b4bccc;
} color: #fff;
} }
} }
} }
</style> }
</style>

View File

@@ -195,7 +195,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
background: #1c2b3a; background: #2b4358;
color: #ecf0f1; color: #ecf0f1;
padding: 0 16px; padding: 0 16px;
height: 36px; height: 36px;
@@ -215,10 +215,10 @@ export default {
} }
} }
.system-name { font-weight: 700; font-size: 13px; letter-spacing: .5px; } .system-name { font-weight: 700; font-size: 13px; letter-spacing: .5px; }
.divider { color: #4a6275; } .divider { color: #89a0b4; }
.unit-tag { background: #1d4e89; padding: 1px 8px; border-radius: 2px; font-size: 11px; } .unit-tag { background: rgba(133, 193, 233, 0.20); color: #eef7ff; padding: 1px 8px; border-radius: 2px; font-size: 11px; }
.sys-status { font-size: 11px; &.online { color: #7fb3d3; } } .sys-status { font-size: 11px; &.online { color: #abd4ee; } }
.clock { font-family: 'Courier New', monospace; font-size: 12px; color: #aab7c4; } .clock { font-family: 'Courier New', monospace; font-size: 12px; color: #c4d3de; }
/* ── KPI 卡片 ── */ /* ── KPI 卡片 ── */
.kpi-row { margin-bottom: 12px; } .kpi-row { margin-bottom: 12px; }
@@ -262,7 +262,7 @@ export default {
overflow: hidden; overflow: hidden;
&__header { &__header {
background: #1c2b3a; background: #2b4358;
color: #ecf0f1; color: #ecf0f1;
padding: 7px 12px; padding: 7px 12px;
display: flex; display: flex;
@@ -294,7 +294,7 @@ export default {
.stand-badge { .stand-badge {
font-size: 11px; padding: 2px 8px; font-size: 11px; padding: 2px 8px;
border-radius: 2px; font-weight: 600; border-radius: 2px; font-weight: 600;
&.running { background: #1d4e89; color: #fff; } &.running { background: rgba(133, 193, 233, 0.20); color: #eef7ff; }
&.stopped { background: #c0392b; color: #fff; } &.stopped { background: #c0392b; color: #fff; }
} }

View File

@@ -96,7 +96,7 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table v-loading="loading" :data="actualList" @selection-change="handleSelectionChange" @row-click="handleRowClick" highlight-current-row> <el-table ref="actualTable" v-loading="loading" :data="actualList" row-key="actualId" @selection-change="handleSelectionChange" @row-click="handleRowClick" highlight-current-row>
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="成品卷号" align="center" prop="exitMatId" /> <el-table-column label="成品卷号" align="center" prop="exitMatId" />
<el-table-column label="来料卷号" align="center" prop="entryMatId" /> <el-table-column label="来料卷号" align="center" prop="entryMatId" />
@@ -108,9 +108,9 @@
<el-table-column label="成品厚度" align="center" prop="exitThickness" /> <el-table-column label="成品厚度" align="center" prop="exitThickness" />
<el-table-column label="成品宽度" align="center" prop="exitWidth" /> <el-table-column label="成品宽度" align="center" prop="exitWidth" />
<el-table-column label="实际重量" align="center" prop="actualWeight" /> <el-table-column label="实际重量" align="center" prop="actualWeight" />
<el-table-column label="上线时间" align="center" prop="onlineTime" width="120"> <el-table-column label="上线时间" align="center" prop="onlineTime" width="170">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ parseTime(scope.row.onlineTime, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.onlineTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column label="状态" align="center" prop="status" /> --> <!-- <el-table-column label="状态" align="center" prop="status" /> -->
@@ -476,6 +476,9 @@ export default {
}, },
form: {}, form: {},
rules: { rules: {
exitMatId: [{ required: true, message: '请输入成品卷号', trigger: 'blur' }],
entryMatId: [{ required: true, message: '请输入来料卷号', trigger: 'blur' }],
planNo: [{ required: true, message: '请输入计划号', trigger: 'blur' }],
} }
}; };
}, },
@@ -486,9 +489,17 @@ export default {
getList() { getList() {
this.loading = true; this.loading = true;
listActual(this.queryParams).then(response => { listActual(this.queryParams).then(response => {
this.actualList = response.rows; this.actualList = response.rows || [];
this.total = response.total; this.total = response.total;
this.loading = false; this.loading = false;
this.ids = [];
this.single = true;
this.multiple = true;
if (this.$refs.actualTable) this.$refs.actualTable.clearSelection();
if (this.currentRow && this.currentRow.actualId != null) {
const updated = this.actualList.find(r => r.actualId === this.currentRow.actualId);
this.currentRow = updated || null;
}
}); });
}, },
cancel() { cancel() {
@@ -549,6 +560,11 @@ export default {
}, },
resetQuery() { resetQuery() {
this.resetForm("queryForm"); this.resetForm("queryForm");
this.currentRow = null;
this.ids = [];
this.single = true;
this.multiple = true;
if (this.$refs.actualTable) this.$refs.actualTable.clearSelection();
this.handleQuery(); this.handleQuery();
}, },
handleSelectionChange(selection) { handleSelectionChange(selection) {
@@ -558,6 +574,10 @@ export default {
}, },
handleRowClick(row) { handleRowClick(row) {
this.currentRow = row; this.currentRow = row;
if (this.$refs.actualTable) {
this.$refs.actualTable.clearSelection();
this.$refs.actualTable.toggleRowSelection(row, true);
}
}, },
handleAdd() { handleAdd() {
this.reset(); this.reset();
@@ -600,6 +620,8 @@ export default {
this.$modal.confirm('是否确认删除轧线生产实绩编号为"' + actualIds + '"的数据项?').then(function() { this.$modal.confirm('是否确认删除轧线生产实绩编号为"' + actualIds + '"的数据项?').then(function() {
return delActual(actualIds); return delActual(actualIds);
}).then(() => { }).then(() => {
const deleted = String(actualIds).split(',').map(v => Number(v));
if (this.currentRow && deleted.includes(Number(this.currentRow.actualId))) this.currentRow = null;
this.getList(); this.getList();
this.$modal.msgSuccess("删除成功"); this.$modal.msgSuccess("删除成功");
}).catch(() => {}); }).catch(() => {});

View File

@@ -173,7 +173,7 @@
<div class="op-btn-group"> <div class="op-btn-group">
<el-button size="mini" type="primary" icon="el-icon-plus" @click="handleAdd">钢卷增加</el-button> <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" icon="el-icon-edit" :disabled="!selectedPlan" @click="handleEdit">修改</el-button>
<el-button size="mini" icon="el-icon-document" :disabled="!selectedPlan" @click="handleFinish">完成</el-button> <el-button size="mini" icon="el-icon-document" :disabled="!selectedPlan || selectedPlan.prodStatus === 'Done'" @click="handleFinish">完成</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" :disabled="!selectedPlan" @click="handleDelete">删除</el-button> <el-button size="mini" type="danger" icon="el-icon-delete" :disabled="!selectedPlan" @click="handleDelete">删除</el-button>
</div> </div>
<div class="op-btn-sep"></div> <div class="op-btn-sep"></div>
@@ -404,11 +404,24 @@ export default {
}, },
methods: { methods: {
refreshRecipeOptions() { refreshRecipeOptions() {
listAllRecipe({}).then(res => { this.recipeOptions = res.data || [] }) listAllRecipe({}).then(res => {
const all = res.data || []
const keepIds = new Set()
if (this.selectedPlan && this.selectedPlan.recipeId) keepIds.add(this.selectedPlan.recipeId)
if (this.form && this.form.recipeId) keepIds.add(this.form.recipeId)
if (this.selectRecipeId) keepIds.add(this.selectRecipeId)
const visible = all.filter(r => !String(r.recipeNo || '').startsWith('__'))
all.forEach(r => {
if (keepIds.has(r.recipeId) && !visible.some(x => x.recipeId === r.recipeId)) visible.push(r)
})
this.recipeOptions = visible
})
}, },
handleFinish() { handleFinish() {
const planId = this.selectedPlan.planId const planId = this.selectedPlan && this.selectedPlan.planId
if (!planId) return this.$message.warning('请先选择钢卷') if (!planId) return this.$message.warning('请先选择钢卷')
if (this.selectedPlan.prodStatus === 'Done') return this.$message.info('该计划已完成')
finishPlan(planId).then(res => { finishPlan(planId).then(res => {
if (res.code === 200) { if (res.code === 200) {
this.$message.success('完成成功') this.$message.success('完成成功')
@@ -419,12 +432,13 @@ export default {
}) })
}, },
loadList() { loadList() {
const params = { inMatNo: this.query.inMatNo } const params = { inMatNo: this.query.inMatNo, params: {} }
if (this.query.hideFinished) params.Idle = 'Idle' if (this.query.hideFinished) params.params.excludeDone = true
if (this.query.dateRange && this.query.dateRange.length === 2) { if (this.query.dateRange && this.query.dateRange.length === 2) {
params.beginTime = this.query.dateRange[0] params.params.beginTime = this.query.dateRange[0]
params.endTime = this.query.dateRange[1] params.params.endTime = this.query.dateRange[1]
} }
if (!Object.keys(params.params).length) delete params.params
listPlan(params).then(res => { this.planList = res.data || [] }) listPlan(params).then(res => { this.planList = res.data || [] })
}, },
resetQuery() { resetQuery() {

View File

@@ -175,7 +175,7 @@ const emptyPass = (no) => ({
}) })
const emptyForm = () => ({ const emptyForm = () => ({
id: null, recipeNo: '', alloyNo: '', passCount: 0, recipeId: null, recipeNo: '', alloyNo: '', passCount: 0,
inThick: '', outThick: '', outWidth: '', status: '0', remark: '' inThick: '', outThick: '', outWidth: '', status: '0', remark: ''
}) })
@@ -200,16 +200,29 @@ export default {
mounted() { this.loadList() }, mounted() { this.loadList() },
methods: { methods: {
loadList() { loadList() {
listRecipe({ recipeNo: this.searchKey, alloyNo: this.searchKey }).then(res => { return listRecipe({ recipeNo: this.searchKey, alloyNo: this.searchKey }).then(res => {
this.recipeList = res.rows || [] const list = res.rows || []
this.recipeList = list
if (this.isNew) return
if (this.selectedId != null && !list.some(item => item.recipeId === this.selectedId)) {
this.clearSelection()
}
}) })
}, },
clearSelection() {
this.selectedId = null
this.isNew = false
this.form = emptyForm()
this.passList = []
if (this.$refs.formRef) this.$refs.formRef.clearValidate()
},
handleSelect(r) { handleSelect(r) {
this.selectedId = r.recipeId this.selectedId = r.recipeId
this.isNew = false this.isNew = false
getRecipeDetail(r.recipeId).then(res => { getRecipeDetail(r.recipeId).then(res => {
this.form = { ...res.data } this.form = { ...res.data }
this.passList = res.data.passList || [] this.passList = res.data.passList || []
if (this.$refs.formRef) this.$refs.formRef.clearValidate()
}) })
}, },
handleAdd() { handleAdd() {
@@ -217,6 +230,7 @@ export default {
this.selectedId = null this.selectedId = null
this.form = emptyForm() this.form = emptyForm()
this.passList = [] this.passList = []
if (this.$refs.formRef) this.$refs.formRef.clearValidate()
}, },
handleSave() { handleSave() {
this.$refs.formRef.validate(valid => { this.$refs.formRef.validate(valid => {
@@ -224,23 +238,27 @@ export default {
this.form.passList = this.passList this.form.passList = this.passList
this.form.passCount = this.passList.length this.form.passCount = this.passList.length
const api = this.isNew ? addRecipe : updateRecipe const api = this.isNew ? addRecipe : updateRecipe
api(this.form).then(() => { api(this.form).then((res) => {
this.$message.success('保存成功') this.$message.success('保存成功')
this.loadList() const targetId = this.isNew ? res.data : this.form.recipeId
this.isNew = false this.isNew = false
this.loadList().then(() => {
if (targetId != null) this.handleSelect({ recipeId: targetId })
else this.clearSelection()
})
}) })
}) })
}, },
handleReset() { handleReset() {
if (this.isNew) { this.form = emptyForm(); this.passList = [] } if (this.isNew) { this.form = emptyForm(); this.passList = [] }
else this.handleSelect({ id: this.selectedId }) else if (this.selectedId != null) this.handleSelect({ recipeId: this.selectedId })
else this.clearSelection()
}, },
handleDelete() { handleDelete() {
this.$confirm('确定删除该方案?', '提示', { type: 'warning' }).then(() => { this.$confirm('确定删除该方案?', '提示', { type: 'warning' }).then(() => {
delRecipe([this.form.recipeId]).then(() => { delRecipe([this.form.recipeId]).then(() => {
this.$message.success('删除成功') this.$message.success('删除成功')
this.form = emptyForm(); this.passList = [] this.clearSelection()
this.selectedId = null; this.isNew = false
this.loadList() this.loadList()
}) })
}) })