Compare commits

..

2 Commits

Author SHA1 Message Date
75a2623d8b config: 更新生产环境和预发布环境页面标题
- 将生产环境页面标题从"科伦普冷轧涂镀数智运营一体化平台"改为"MES一体化平台"
- 将预发布环境页面标题从"科伦普冷轧涂镀数智运营一体化平台"改为"MES一体化平台"
2026-03-09 16:58:25 +08:00
5d046be15b docs(app): 更新应用名称为MES一体化平台
- 将VUE_APP_TITLE从"科伦普冷轧涂镀数智运营一体化平台"更改为"MES一体化平台"
- 修改Greeting组件中的平台描述为"欢迎使用MES数智一体化平台"
- 将favicon链接从png格式更改为ico格式
- 替换index.vue中的关于页面内容为MES平台相关介绍
- 更新登录页面中的平台描述和公司信息
- 修改侧边栏Logo组件中的平台标题为"MES一体化平台"
- 注释掉dashboard demo组件中的全屏功能代码
2026-03-09 16:27:47 +08:00
122 changed files with 604 additions and 8308 deletions

View File

@@ -1,55 +0,0 @@
package com.klp.aps.controller;
import com.klp.aps.domain.dto.ApsQuickSheetQueryReq;
import com.klp.aps.domain.dto.ApsQuickSheetSaveReq;
import com.klp.aps.domain.vo.ApsQuickSheetRowVo;
import com.klp.aps.service.ApsQuickSheetService;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.R;
import com.klp.common.helper.LoginHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequiredArgsConstructor
@RestController
@RequestMapping("/aps/quick-sheet")
public class ApsQuickSheetController extends BaseController {
private final ApsQuickSheetService quickSheetService;
@GetMapping("/list")
public R<List<ApsQuickSheetRowVo>> list(@Validated ApsQuickSheetQueryReq req) {
return R.ok(quickSheetService.queryList(req));
}
@GetMapping("/preset")
public R<List<ApsQuickSheetRowVo>> preset(@RequestParam(value = "lineId", required = false) Long lineId) {
String salesman = LoginHelper.getNickName();
return R.ok(quickSheetService.buildPresetRows(lineId, salesman));
}
@PostMapping("/save")
public R<Void> save(@Validated @RequestBody ApsQuickSheetSaveReq req) {
quickSheetService.saveRows(req, getUsername());
return R.ok();
}
@GetMapping("/export")
public void export(@Validated ApsQuickSheetQueryReq req, javax.servlet.http.HttpServletResponse response) {
quickSheetService.exportExcel(req, response);
}
@PostMapping("/delete")
public R<Void> delete(@RequestParam("quickSheetId") Long quickSheetId) {
quickSheetService.deleteById(quickSheetId, getUsername());
return R.ok();
}
}

View File

@@ -1,20 +0,0 @@
package com.klp.aps.domain.dto;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
@Data
public class ApsQuickSheetQueryReq {
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
private Long lineId;
private String customerName;
}

View File

@@ -1,35 +0,0 @@
package com.klp.aps.domain.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.List;
@Data
public class ApsQuickSheetSaveReq {
@NotEmpty(message = "rows 不能为空")
private List<Row> rows;
@Data
public static class Row {
private Long quickSheetId;
private Long lineId;
private String lineName;
private String planCode;
private String orderCode;
private String customerName;
private String salesman;
private String productName;
private String rawMaterialId;
private String rawCoilNos;
private String rawLocation;
private String rawPackaging;
private String rawEdgeReq;
private String rawCoatingType;
private String rawNetWeight;
private String planQty;
private String startTime;
private String endTime;
}
}

View File

@@ -1,35 +0,0 @@
package com.klp.aps.domain.entity;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
public class ApsQuickSheetEntity {
private Long quickSheetId;
private LocalDate planDate;
private Long lineId;
private String lineName;
private String planCode;
private String orderCode;
private String customerName;
private String salesman;
private String productName;
private String rawMaterialId;
private String rawCoilNos;
private String rawLocation;
private String rawPackaging;
private String rawEdgeReq;
private String rawCoatingType;
private BigDecimal rawNetWeight;
private BigDecimal planQty;
private LocalDateTime startTime;
private LocalDateTime endTime;
private String createBy;
private String updateBy;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private Integer delFlag;
}

View File

@@ -1,28 +0,0 @@
package com.klp.aps.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class ApsQuickSheetRowVo {
private Long quickSheetId;
private Long lineId;
private String lineName;
private String planCode;
private String orderCode;
private String customerName;
private String salesman;
private String productName;
private String rawMaterialId;
private String rawCoilNos;
private String rawLocation;
private String rawPackaging;
private String rawEdgeReq;
private String rawCoatingType;
private BigDecimal rawNetWeight;
private BigDecimal planQty;
private LocalDateTime startTime;
private LocalDateTime endTime;
}

View File

@@ -1,73 +0,0 @@
package com.klp.aps.mapper;
import com.klp.aps.domain.vo.ApsQuickSheetRowVo;
import com.klp.aps.domain.dto.ApsQuickSheetQueryReq;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface ApsQuickSheetMapper {
List<ApsQuickSheetRowVo> selectList(ApsQuickSheetQueryReq req);
@Select("SELECT COUNT(1) FROM aps_quick_sheet WHERE del_flag = 0 AND plan_date = #{planDate}")
int countToday(@Param("planDate") java.time.LocalDate planDate);
@Select("SELECT quick_sheet_id FROM aps_quick_sheet WHERE plan_code = #{planCode} AND del_flag = 0 LIMIT 1")
Long selectIdByPlanCode(@Param("planCode") String planCode);
@org.apache.ibatis.annotations.Insert("INSERT INTO aps_quick_sheet (line_id, line_name, plan_date, plan_code, order_code, customer_name, salesman, product_name, raw_material_id, raw_coil_nos, raw_location, raw_packaging, raw_edge_req, raw_coating_type, raw_net_weight, plan_qty, start_time, end_time, create_by, update_by, create_time, update_time, del_flag) "
+ "VALUES (#{lineId}, #{lineName}, #{planDate}, #{planCode}, #{orderCode}, #{customerName}, #{salesman}, #{productName}, #{rawMaterialId}, #{rawCoilNos}, #{rawLocation}, #{rawPackaging}, #{rawEdgeReq}, #{rawCoatingType}, #{rawNetWeight}, #{planQty}, #{startTime}, #{endTime}, #{createBy}, #{updateBy}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 0)")
int insertRow(@Param("lineId") Long lineId,
@Param("lineName") String lineName,
@Param("planDate") java.time.LocalDate planDate,
@Param("planCode") String planCode,
@Param("orderCode") String orderCode,
@Param("customerName") String customerName,
@Param("salesman") String salesman,
@Param("productName") String productName,
@Param("rawMaterialId") String rawMaterialId,
@Param("rawCoilNos") String rawCoilNos,
@Param("rawLocation") String rawLocation,
@Param("rawPackaging") String rawPackaging,
@Param("rawEdgeReq") String rawEdgeReq,
@Param("rawCoatingType") String rawCoatingType,
@Param("rawNetWeight") java.math.BigDecimal rawNetWeight,
@Param("planQty") java.math.BigDecimal planQty,
@Param("startTime") java.time.LocalDateTime startTime,
@Param("endTime") java.time.LocalDateTime endTime,
@Param("createBy") String createBy,
@Param("updateBy") String updateBy);
@org.apache.ibatis.annotations.Update("UPDATE aps_quick_sheet SET line_id = #{lineId}, line_name = #{lineName}, plan_code = #{planCode}, order_code = #{orderCode}, customer_name = #{customerName}, salesman = #{salesman}, product_name = #{productName}, raw_material_id = #{rawMaterialId}, raw_coil_nos = #{rawCoilNos}, raw_location = #{rawLocation}, raw_packaging = #{rawPackaging}, raw_edge_req = #{rawEdgeReq}, raw_coating_type = #{rawCoatingType}, raw_net_weight = #{rawNetWeight}, plan_qty = #{planQty}, start_time = #{startTime}, end_time = #{endTime}, update_by = #{updateBy}, update_time = CURRENT_TIMESTAMP WHERE quick_sheet_id = #{id}")
int updateRow(@Param("id") Long id,
@Param("lineId") Long lineId,
@Param("lineName") String lineName,
@Param("planCode") String planCode,
@Param("orderCode") String orderCode,
@Param("customerName") String customerName,
@Param("salesman") String salesman,
@Param("productName") String productName,
@Param("rawMaterialId") String rawMaterialId,
@Param("rawCoilNos") String rawCoilNos,
@Param("rawLocation") String rawLocation,
@Param("rawPackaging") String rawPackaging,
@Param("rawEdgeReq") String rawEdgeReq,
@Param("rawCoatingType") String rawCoatingType,
@Param("rawNetWeight") java.math.BigDecimal rawNetWeight,
@Param("planQty") java.math.BigDecimal planQty,
@Param("startTime") java.time.LocalDateTime startTime,
@Param("endTime") java.time.LocalDateTime endTime,
@Param("updateBy") String updateBy);
@org.apache.ibatis.annotations.Update("UPDATE aps_quick_sheet SET del_flag = 1, update_by = #{updateBy}, update_time = CURRENT_TIMESTAMP WHERE quick_sheet_id = #{id}")
int deleteRow(@Param("id") Long id, @Param("updateBy") String updateBy);
@org.apache.ibatis.annotations.Update("UPDATE aps_quick_sheet SET del_flag = 1, update_by = #{updateBy}, update_time = CURRENT_TIMESTAMP WHERE quick_sheet_id = #{id}")
int softDelete(@Param("id") Long id,
@Param("updateBy") String updateBy);
@org.apache.ibatis.annotations.Update("UPDATE aps_quick_sheet SET del_flag = 1, update_by = #{updateBy}, update_time = CURRENT_TIMESTAMP WHERE quick_sheet_id = #{id}")
int deleteById(@Param("id") Long id, @Param("updateBy") String updateBy);
}

View File

@@ -1,20 +0,0 @@
package com.klp.aps.service;
import com.klp.aps.domain.dto.ApsQuickSheetQueryReq;
import com.klp.aps.domain.dto.ApsQuickSheetSaveReq;
import com.klp.aps.domain.vo.ApsQuickSheetRowVo;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface ApsQuickSheetService {
List<ApsQuickSheetRowVo> queryList(ApsQuickSheetQueryReq req);
void saveRows(ApsQuickSheetSaveReq req, String operator);
List<ApsQuickSheetRowVo> buildPresetRows(Long lineId, String salesman);
void exportExcel(ApsQuickSheetQueryReq req, HttpServletResponse response);
void deleteById(Long id, String operator);
}

View File

@@ -1,214 +0,0 @@
package com.klp.aps.service.impl;
import com.klp.aps.domain.dto.ApsQuickSheetSaveReq;
import com.klp.aps.domain.vo.ApsQuickSheetRowVo;
import com.klp.aps.mapper.ApsQuickSheetMapper;
import com.klp.aps.service.ApsQuickSheetService;
import com.klp.common.exception.ServiceException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
@RequiredArgsConstructor
@Service
public class ApsQuickSheetServiceImpl implements ApsQuickSheetService {
private final ApsQuickSheetMapper quickSheetMapper;
private static final DateTimeFormatter DATE_CODE = DateTimeFormatter.ofPattern("yyyyMMdd");
@Override
public List<ApsQuickSheetRowVo> queryList(com.klp.aps.domain.dto.ApsQuickSheetQueryReq req) {
return quickSheetMapper.selectList(req);
}
@Override
public void saveRows(ApsQuickSheetSaveReq req, String operator) {
if (req == null || req.getRows() == null) {
throw new ServiceException("保存数据不能为空");
}
for (ApsQuickSheetSaveReq.Row row : req.getRows()) {
if (row == null) continue;
Long id = row.getQuickSheetId();
Long lineId = row.getLineId();
String lineName = row.getLineName();
String planCode = row.getPlanCode();
String orderCode = row.getOrderCode();
String customerName = row.getCustomerName();
String salesman = row.getSalesman();
String productName = row.getProductName();
String rawMaterialId = row.getRawMaterialId();
String rawCoilNos = row.getRawCoilNos();
String rawLocation = row.getRawLocation();
String rawPackaging = row.getRawPackaging();
String rawEdgeReq = row.getRawEdgeReq();
String rawCoatingType = row.getRawCoatingType();
BigDecimal rawNetWeight = parseQty(row.getRawNetWeight());
BigDecimal planQty = parseQty(row.getPlanQty());
LocalDateTime startTime = parseTime(row.getStartTime());
LocalDateTime endTime = parseTime(row.getEndTime());
boolean hasAny = lineId != null || isNotBlank(lineName) || isNotBlank(planCode) || isNotBlank(orderCode)
|| isNotBlank(customerName) || isNotBlank(salesman) || isNotBlank(productName)
|| isNotBlank(rawMaterialId) || isNotBlank(rawCoilNos) || isNotBlank(rawLocation)
|| isNotBlank(rawPackaging) || isNotBlank(rawEdgeReq) || isNotBlank(rawCoatingType)
|| rawNetWeight != null || planQty != null || startTime != null || endTime != null;
if (!hasAny) {
continue;
}
if (id == null) {
if (!isNotBlank(planCode)) {
planCode = buildPlanCode();
}
quickSheetMapper.insertRow(lineId, lineName, LocalDate.now(), planCode, orderCode, customerName, salesman, productName,
rawMaterialId, rawCoilNos, rawLocation, rawPackaging, rawEdgeReq, rawCoatingType, rawNetWeight, planQty, startTime, endTime, operator, operator);
} else {
quickSheetMapper.updateRow(id, lineId, lineName, planCode, orderCode, customerName, salesman, productName,
rawMaterialId, rawCoilNos, rawLocation, rawPackaging, rawEdgeReq, rawCoatingType, rawNetWeight, planQty, startTime, endTime, operator);
}
}
}
@Override
public List<ApsQuickSheetRowVo> buildPresetRows(Long lineId, String salesman) {
List<ApsQuickSheetRowVo> rows = new ArrayList<>();
LocalDateTime now = LocalDateTime.now();
LocalDateTime end = now.plusHours(1);
for (int i = 0; i < 3; i++) {
ApsQuickSheetRowVo row = new ApsQuickSheetRowVo();
row.setLineId(lineId);
row.setLineName(lineId == null ? null : ("产线" + lineId));
row.setSalesman(salesman);
row.setPlanQty(BigDecimal.ZERO);
row.setStartTime(now);
row.setEndTime(end);
row.setPlanCode(buildPlanCode());
rows.add(row);
}
return rows;
}
@Override
public void exportExcel(com.klp.aps.domain.dto.ApsQuickSheetQueryReq req, javax.servlet.http.HttpServletResponse response) {
List<ApsQuickSheetRowVo> rows = queryList(req);
try (org.apache.poi.ss.usermodel.Workbook wb = new org.apache.poi.xssf.usermodel.XSSFWorkbook()) {
org.apache.poi.ss.usermodel.Sheet sheet = wb.createSheet("快速排产表");
int r = 0;
org.apache.poi.ss.usermodel.Row title = sheet.createRow(r++);
title.setHeightInPoints(36f);
org.apache.poi.ss.usermodel.Cell t0 = title.createCell(0);
t0.setCellValue("快速排产表Excel录入");
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(0, 0, 0, 14));
org.apache.poi.ss.usermodel.CellStyle titleStyle = wb.createCellStyle();
titleStyle.setAlignment(org.apache.poi.ss.usermodel.HorizontalAlignment.CENTER);
titleStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
org.apache.poi.xssf.usermodel.XSSFFont titleFont = ((org.apache.poi.xssf.usermodel.XSSFWorkbook) wb).createFont();
titleFont.setBold(true);
titleFont.setFontHeightInPoints((short) 15);
titleStyle.setFont(titleFont);
t0.setCellStyle(titleStyle);
String[] headers = new String[]{
"产线", "计划号", "订单号", "客户", "业务员", "产品",
"原料钢卷", "原料卷号", "钢卷位置", "包装要求", "切边要求", "镀层种类",
"原料净重", "计划数量", "开始时间", "结束时间"
};
org.apache.poi.ss.usermodel.Row head = sheet.createRow(r++);
for (int i = 0; i < headers.length; i++) {
head.createCell(i).setCellValue(headers[i]);
}
if (rows != null) {
for (ApsQuickSheetRowVo row : rows) {
org.apache.poi.ss.usermodel.Row rr = sheet.createRow(r++);
int cc = 0;
rr.createCell(cc++).setCellValue(nvl(row.getLineName(), row.getLineId()));
rr.createCell(cc++).setCellValue(nvl(row.getPlanCode(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getOrderCode(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getCustomerName(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getSalesman(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getProductName(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawMaterialId(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawCoilNos(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawLocation(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawPackaging(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawEdgeReq(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawCoatingType(), ""));
rr.createCell(cc++).setCellValue(row.getRawNetWeight() == null ? "" : row.getRawNetWeight().toPlainString());
rr.createCell(cc++).setCellValue(row.getPlanQty() == null ? "" : row.getPlanQty().toPlainString());
rr.createCell(cc++).setCellValue(row.getStartTime() == null ? "" : row.getStartTime().toString());
rr.createCell(cc++).setCellValue(row.getEndTime() == null ? "" : row.getEndTime().toString());
}
}
for (int i = 0; i < headers.length; i++) {
sheet.autoSizeColumn(i, true);
int w = sheet.getColumnWidth(i);
sheet.setColumnWidth(i, Math.min(Math.max(w, 3000), 12000));
}
String filename = "aps_quick_sheet_" + System.currentTimeMillis() + ".xlsx";
String encoded = java.net.URLEncoder.encode(filename, java.nio.charset.StandardCharsets.UTF_8.name());
response.setCharacterEncoding(java.nio.charset.StandardCharsets.UTF_8.name());
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encoded);
try (javax.servlet.ServletOutputStream os = response.getOutputStream()) {
wb.write(os);
os.flush();
}
} catch (java.io.IOException e) {
throw new ServiceException("导出失败:" + e.getMessage());
}
}
private String buildPlanCode() {
LocalDate today = LocalDate.now();
int seq = quickSheetMapper.countToday(today) + 1;
return today.format(DATE_CODE) + String.format("%03d", seq);
}
private String nvl(Object v, Object fallback) {
if (v == null) return String.valueOf(fallback);
String s = String.valueOf(v);
return s == null ? String.valueOf(fallback) : s;
}
@Override
public void deleteById(Long id, String operator) {
if (id == null) return;
quickSheetMapper.deleteRow(id, operator);
}
private BigDecimal parseQty(String val) {
if (val == null || val.trim().isEmpty()) return null;
try {
return new BigDecimal(val.trim());
} catch (Exception e) {
return null;
}
}
private boolean isNotBlank(String val) {
return val != null && !val.trim().isEmpty();
}
private LocalDateTime parseTime(String val) {
if (val == null || val.trim().isEmpty()) return null;
String v = val.trim();
if (v.length() == 16) v = v + ":00";
try {
return LocalDateTime.parse(v, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
} catch (Exception e) {
return null;
}
}
}

View File

@@ -1,44 +0,0 @@
<?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.klp.aps.mapper.ApsQuickSheetMapper">
<select id="selectList" parameterType="com.klp.aps.domain.dto.ApsQuickSheetQueryReq" resultType="com.klp.aps.domain.vo.ApsQuickSheetRowVo">
SELECT
quick_sheet_id AS quickSheetId,
line_id AS lineId,
line_name AS lineName,
plan_code AS planCode,
order_code AS orderCode,
customer_name AS customerName,
salesman,
product_name AS productName,
raw_material_id AS rawMaterialId,
raw_coil_nos AS rawCoilNos,
raw_location AS rawLocation,
raw_packaging AS rawPackaging,
raw_edge_req AS rawEdgeReq,
raw_coating_type AS rawCoatingType,
raw_net_weight AS rawNetWeight,
plan_qty AS planQty,
start_time AS startTime,
end_time AS endTime
FROM aps_quick_sheet
WHERE del_flag = 0
<if test="startDate != null">
AND start_time <![CDATA[>=]]> CONCAT(#{startDate}, ' 00:00:00')
</if>
<if test="endDate != null">
AND start_time <![CDATA[<=]]> CONCAT(#{endDate}, ' 23:59:59')
</if>
<if test="lineId != null">
AND line_id = #{lineId}
</if>
<if test="customerName != null and customerName != ''">
AND customer_name LIKE CONCAT('%', #{customerName}, '%')
</if>
ORDER BY quick_sheet_id DESC
</select>
</mapper>

View File

@@ -7,13 +7,10 @@ import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -35,7 +32,7 @@ import java.util.concurrent.TimeUnit;
@Slf4j
@RequiredArgsConstructor
@Component
public class AcidOeeMonthTask implements ApplicationRunner {
public class AcidOeeMonthTask {
/** Redis 缓存 key 模板:当月 OEE 汇总(酸轧线) */
private static final String SUMMARY_KEY_PATTERN = "oee:report:month:summary:%s:SY";
@@ -51,13 +48,10 @@ public class AcidOeeMonthTask implements ApplicationRunner {
private final StringRedisTemplate stringRedisTemplate;
/**
* 项目启动完成后计算一次当月酸轧 OEE 汇总并写入 Redis。
* 使用 ApplicationRunner 在 Spring Boot 启动完成后执行。
* 使用 @Async 异步执行,不阻塞项目启动。
* 项目启动完成后立即计算一次当月酸轧 OEE 汇总并写入 Redis。
*/
@Async
@Override
public void run(ApplicationArguments args) throws Exception {
@PostConstruct
public void init() {
try {
computeCurrentMonth("startup");
} catch (Exception e) {

View File

@@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = 科伦普冷轧涂镀数智运营一体化平台
VUE_APP_TITLE = MES一体化平台
# 开发环境配置
ENV = 'development'

View File

@@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = 科伦普冷轧涂镀数智运营一体化平台
VUE_APP_TITLE = MES一体化平台
# 生产环境配置
ENV = 'production'

View File

@@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = 科伦普冷轧涂镀数智运营一体化平台
VUE_APP_TITLE = MES一体化平台
# 开发环境配置
ENV = 'development'

View File

@@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.png">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style>

View File

@@ -1,42 +0,0 @@
import request from '@/utils/request'
export function fetchQuickSheetList(params) {
return request({
url: '/aps/quick-sheet/list',
method: 'get',
params
})
}
export function fetchQuickSheetPreset(params) {
return request({
url: '/aps/quick-sheet/preset',
method: 'get',
params
})
}
export function saveQuickSheet(data) {
return request({
url: '/aps/quick-sheet/save',
method: 'post',
data
})
}
export function exportQuickSheet(params) {
return request({
url: '/aps/quick-sheet/export',
method: 'get',
params,
responseType: 'blob'
})
}
export function deleteQuickSheetRow(quickSheetId) {
return request({
url: '/aps/quick-sheet/delete',
method: 'post',
params: { quickSheetId }
})
}

View File

@@ -27,16 +27,3 @@ export function delOss(ossId) {
})
}
/**
* 上传文件
*/
export function uploadFile(file) {
const form = new FormData()
form.append('file', file)
return request({
url: '/system/oss/upload',
method: 'post',
data: form,
})
}

View File

@@ -42,16 +42,3 @@ export function delApproval(approvalId) {
method: 'delete'
})
}
/**
* 撤销审批
*/
export function withdrawApproval(approvalId) {
return request({
url: '/wms/approval/cancel',
method: 'post',
params: {
approvalId: approvalId
}
})
}

View File

@@ -1,5 +1,4 @@
import request from '@/utils/request'
import { tansParams } from "@/utils/klp";
// 查询钢卷物料表列表
export function listMaterialCoil(query) {
@@ -203,14 +202,13 @@ export function cancelExportCoil(coilId) {
}
// 检查入场钢卷号或当前钢卷号是否合法(是否存在)
export function checkCoilNo({ currentCoilNo, enterCoilNo, coilId, supplierCoilNo }) {
export function checkCoilNo({ currentCoilNo, enterCoilNo, coilId }) {
return request({
url: '/wms/materialCoil/checkCoilNoDuplicate',
method: 'get',
params: {
currentCoilNo,
enterCoilNo,
supplierCoilNo,
coilId
}
})
@@ -254,19 +252,15 @@ export function restoreMaterialCoil(coilId) {
/**
* 开始分条,锁定钢卷
*/
export function startSpecialSplit(coilId, actionType) {
export function startSpecialSplit(coilId) {
if (!coilId) {
return Promise.reject(new Error('coilId is required'))
}
if (!actionType) {
return Promise.reject(new Error('actionType is required'))
}
return request({
url: '/wms/materialCoil/specialSplit/start',
method: 'post',
params: {
coilId,
actionType
coilId
}
})
}
@@ -351,18 +345,4 @@ export function categoryWidthStatistics() {
url: '/wms/materialCoil/statistics/categoryWidthStatistics',
method: 'get',
})
}
/**
* 导出钢卷的全部字段
*/
export function exportCoilWithAll(data) {
return request({
url: '/wms/materialCoil/exportAll',
method: 'post',
data: data,
transformRequest: [(params) => { return tansParams(params) }],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob'
})
}

View File

@@ -42,16 +42,3 @@ export function delCoilStatisticsSummary(summaryId) {
method: 'delete'
})
}
// 检查今天是否已经创建过该类型的透视表
// 如果已经创建过返回该透视表的id
// 如果没有创建过返回null
export function checkCoilStatisticsSummaryExist(statType) {
return request({
url: '/wms/coilStatisticsSummary/checkToday',
method: 'get',
params: {
statType
}
})
}

View File

@@ -1,64 +0,0 @@
import request from '@/utils/request'
// 查询员工异动(入职/离职)列表
export function listEmployeeChange(query) {
return request({
url: '/wms/employeeChange/list',
method: 'get',
params: query
})
}
// 查询员工异动(入职/离职)详细
export function getEmployeeChange(changeId) {
return request({
url: '/wms/employeeChange/' + changeId,
method: 'get'
})
}
// 新增员工异动(入职/离职)
export function addEmployeeChange(data) {
return request({
url: '/wms/employeeChange',
method: 'post',
data: data
})
}
// 修改员工异动(入职/离职)
export function updateEmployeeChange(data) {
return request({
url: '/wms/employeeChange',
method: 'put',
data: data
})
}
// 删除员工异动(入职/离职)
export function delEmployeeChange(changeId) {
return request({
url: '/wms/employeeChange/' + changeId,
method: 'delete'
})
}
// 员工入职
export function employeeEntry(data) {
return request({
url: '/wms/employeeChange/entry',
method: 'post',
data: data
})
}
/**
* 员工离职
*/
export function employeeLeave(data) {
return request({
url: '/wms/employeeChange/leave',
method: 'post',
data: data
})
}

View File

@@ -1,23 +1,5 @@
import request from '@/utils/request'
function parseDate(date) {
// 修复1参数名和内部变量名冲突改用tempDate
// 修复2如果传入的date为空/无效,默认使用当前时间
const tempDate = date ? new Date(date) : new Date();
// 获取年、月、日、时、分、秒(补零处理,确保是两位数)
const year = tempDate.getFullYear();
// 月份从0开始所以要+1不足两位补0
const month = String(tempDate.getMonth() + 1).padStart(2, '0');
const day = String(tempDate.getDate()).padStart(2, '0');
const hours = String(tempDate.getHours()).padStart(2, '0');
const minutes = String(tempDate.getMinutes()).padStart(2, '0');
const seconds = String(tempDate.getSeconds()).padStart(2, '0');
// 格式化为YYYY-mm-dd HH:mm:ss并返回
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 查询钢卷待操作列表
export function listPendingAction(query) {
return request({
@@ -27,31 +9,6 @@ export function listPendingAction(query) {
})
}
// 查询钢卷待操作列表(包含已删除记录)
// includeDeleted: 0=不包含已删除(默认), 1=包含已删除记录, 2=仅查询已删除记录
export function listPendingActionWithDeleted(query) {
return request({
url: '/wms/coilPendingAction/list',
method: 'get',
params: {
...query,
includeDeleted: 1
}
})
}
// 仅查询已删除的钢卷待操作列表
export function listDeletedPendingAction(query) {
return request({
url: '/wms/coilPendingAction/list',
method: 'get',
params: {
...query,
includeDeleted: 2
}
})
}
// 查询钢卷待操作详细
export function getPendingAction(actionId) {
return request({
@@ -62,37 +19,19 @@ export function getPendingAction(actionId) {
// 新增钢卷待操作
export function addPendingAction(data) {
const payload = { ...data }
if (payload.processTime) {
payload.processTime = parseDate(payload.processTime)
}
if (payload.completeTime) {
payload.completeTime = parseDate(payload.completeTime)
}
return request({
url: '/wms/coilPendingAction',
method: 'post',
data: payload
data: data
})
}
// 修改钢卷待操作
export function updatePendingAction(data) {
const payload = { ...data }
if (payload.processTime) {
payload.processTime = parseDate(payload.processTime)
}
if (payload.completeTime) {
payload.completeTime = parseDate(payload.completeTime)
}
if (payload.scanTime) {
// 扫码日期格式化为yyyy-MM-dd'T'HH:mm:ss.SSSX
payload.scanTime = parseDate(payload.scanTime).replace(' ', 'T') + '.000Z'
}
return request({
url: '/wms/coilPendingAction',
method: 'put',
data: payload
data: data
})
}
@@ -145,12 +84,3 @@ export function exportPendingAction(query) {
})
}
/**
* 还原被删除的钢卷
*/
export function restorePendingAction(actionId) {
return request({
url: `/wms/coilPendingAction/restore/${actionId}`,
method: 'put'
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -18,9 +18,9 @@
</div>
<el-dialog title="选择钢卷" :visible.sync="dialogVisible" :width="dialogWidth" :close-on-click-modal="false"
@close="handleClose" append-to-body :fullscreen="orderBy">
@close="handleClose" append-to-body>
<!-- 搜索区域 -->
<el-form v-if="!rangeMode" inline :model="queryParams" class="search-form">
<el-form v-if="!rangeMode" :model="queryParams" class="search-form">
<!-- <el-form-item label="类型">
<el-select v-model="queryParams.selectType" placeholder="请选择类型" size="small">
<el-option label="成品" value="product" />
@@ -62,13 +62,12 @@
</el-form-item>
<el-form-item label="实际库区" v-if="orderBy">
<actual-warehouse-select v-model="queryParams.actualWarehouseId" placeholder="请选择实际库区" canSelectLevel2
canSelectDisabled :clearInput="false" clearable />
canSelectDisabled />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
<el-checkbox style="margin-left: 10px;" v-model="showCoilMap" size="small">显示钢卷地图</el-checkbox>
</el-form-item>
</el-form>
@@ -78,7 +77,6 @@
<!-- 自定义列 -->
<el-table-column v-for="column in renderColumns" :label="column.label" :align="column.align" :prop="column.prop"
:width="column.width" :show-overflow-tooltip="column.showOverflowTooltip" />
<el-table-column v-if="orderBy" label="品质" prop="qualityStatus"></el-table-column>
<el-table-column v-if="orderBy" label="切边" prop="trimmingRequirement"></el-table-column>
<el-table-column v-if="orderBy" label="包装" prop="packagingRequirement"></el-table-column>
</el-table>
@@ -95,7 +93,6 @@
<!-- 自定义列 -->
<el-table-column v-for="column in renderColumns" :label="column.label" :align="column.align"
:prop="column.prop" :width="column.width" :show-overflow-tooltip="column.showOverflowTooltip" />
<el-table-column v-if="orderBy" label="品质" prop="qualityStatus"></el-table-column>
<el-table-column v-if="orderBy" label="切边" prop="trimmingRequirement"></el-table-column>
<el-table-column v-if="orderBy" label="包装" prop="packagingRequirement"></el-table-column>
</el-table>
@@ -108,7 +105,6 @@
<el-table v-if="multiple && selectedCoils.length > 0" :data="selectedCoils">
<el-table-column v-for="column in renderColumns" :label="column.label" :align="column.align" :prop="column.prop"
:width="column.width" :show-overflow-tooltip="column.showOverflowTooltip" />
<el-table-column v-if="orderBy" label="品质" prop="qualityStatus"></el-table-column>
<el-table-column label="操作" width="50">
<template slot-scope="scope">
@@ -121,42 +117,23 @@
<el-button type="primary" @click="handleConfirm">确认选择</el-button>
<el-button @click="handleClose">取消</el-button>
</div>
<!-- 一个可以拖拽和调节大小的浮层 -->
<DragResizeBox v-if="showCoilMap" @size-change="handleSizeChange" storageKey="coil-map">
<div style="height: 100%; width: 100%; overflow-y: scroll; display: flex; background-color: #fff;">
<div style="min-width: 150px; position: sticky; top: 0;" v-loading="treeLoading">
<el-tree ref="warehouseTreeRef" :data="warehouseTree" :props="treeProps" node-key="actualWarehouseId"
@node-click="handleNodeClick" :expand-on-click-node="false" highlight-current class="warehouse-tree">
</el-tree>
</div>
<warehouse-bird-mini ref="warehouseBirdMini" v-loading="warehouseLoading" :warehouseList="warehouseList" :id="selectedNodeId"
:canToggle="false" :canRelease="false" />
</div>
</DragResizeBox>
</el-dialog>
</div>
</template>
<script>
import { listMaterialCoil } from '@/api/wms/coil';
import { listActualWarehouse } from "@/api/wms/actualWarehouse";
import { treeActualWarehouseTwoLevel } from "@/api/wms/actualWarehouse";
import MemoInput from '@/components/MemoInput/index.vue';
import MutiSelect from '@/components/MutiSelect/index.vue';
import { defaultColumns } from './data';
import ActualWarehouseSelect from '@/components/KLPService/ActualWarehouseSelect/index.vue';
import WarehouseBirdMini from '@/views/wms/warehouse/components/WarehouseBirdMini.vue';
import DragResizeBox from '@/components/DragResizeBox/index.vue';
export default {
name: 'CoilSelector',
components: {
MemoInput,
MutiSelect,
ActualWarehouseSelect,
WarehouseBirdMini,
DragResizeBox
ActualWarehouseSelect
},
dicts: ['coil_itemname', 'coil_material', 'coil_manufacturer'],
props: {
@@ -223,7 +200,6 @@ export default {
},
data() {
return {
showCoilMap: false,
loading: false,
coilList: [],
total: 0,
@@ -247,12 +223,6 @@ export default {
columns: defaultColumns,
currentTab: 'my',
selectedCoils: [],
warehouseList: [],
selectedNodeId: null,
warehouseLoading: false,
warehouseTree: [],
treeProps: { label: "actualWarehouseName", children: "children" },
treeLoading: false,
};
},
computed: {
@@ -334,56 +304,8 @@ export default {
if (this.initialCoil) {
this.selectedCoil = this.initialCoil;
}
if (this.orderBy) {
this.getWarehouseTree();
}
},
methods: {
// 获取库位列表
getWarehouseList(parentId) {
this.warehouseLoading = true;
return listActualWarehouse({ parentId })
.then((res) => { this.warehouseList = res.data || []; this.warehouseLoading = false; })
.catch((err) => {
this.$message.error("获取库位数据失败:" + err.message);
this.warehouseList = [];
this.warehouseLoading = false;
});
},
handleNodeClick(data) {
console.log('data', data);
if (data.actualWarehouseType != 2) {
return;
}
this.selectedNodeId = data.actualWarehouseId;
this.getWarehouseList(data.actualWarehouseId);
},
// 获取树形数据
getWarehouseTree() {
this.treeLoading = true;
treeActualWarehouseTwoLevel()
.then((res) => { this.warehouseTree = res.data || []; })
.catch((err) => { this.$message.error("获取仓库树形数据失败:" + err.message); })
.finally(() => { this.treeLoading = false; });
},
// 处理大小变化
handleSizeChange(size) {
console.log('size', size);
this.$refs.warehouseBirdMini.resize();
},
// 处理实际库区选择变化
handleWarehouseChange(val) {
console.log('val', val);
if (!val) {
this.selectedNodeId = null;
this.warehouseList = [];
return;
}
if (val.pathIds.length == 2) {
this.selectedNodeId = val;
this.getWarehouseList(val.id);
}
},
// 动态生成表格行类名 - 综合处理选中、禁用等状态
getRowClassName({ row }) {
const classNames = [];
@@ -617,6 +539,13 @@ export default {
margin-top: 4px;
}
.search-form {
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 16px;
}
::v-deep .el-dialog__body {
padding: 20px;
max-height: calc(100vh - 200px);

View File

@@ -1,301 +0,0 @@
<template>
<div class="drag-resize-container" ref="containerRef">
<!-- 可拖拽调整的元素 -->
<div
class="draggable-element"
ref="elementRef"
:style="{
left: `${position.x}px`,
top: `${position.y}px`,
width: `${size.width}px`,
height: `${size.height}px`
}"
@mousedown="startDrag"
>
<!-- 元素内容区 -->
<div class="element-content">
<slot>可拖拽调整的元素</slot>
</div>
<!-- 右下角调整大小的控制点 -->
<div class="resize-handle" @mousedown="startResize"></div>
</div>
</div>
</template>
<script>
export default {
name: 'DragResizeBox',
props: {
// 初始位置
initPosition: {
type: Object,
default: () => ({ x: 100, y: 100 })
},
// 初始尺寸
initSize: {
type: Object,
default: () => ({ width: 200, height: 150 })
},
// 移除容器尺寸限制保留prop但默认值改为屏幕尺寸
containerSize: {
type: Object,
default: () => ({
width: window.innerWidth,
height: window.innerHeight
})
},
// 元素最小尺寸
minSize: {
type: Object,
default: () => ({ width: 100, height: 80 })
},
// 用于localStorage存储的唯一标识
storageKey: {
type: String,
default: ''
}
},
data() {
return {
// 当前位置
position: { x: 0, y: 0 },
// 当前尺寸
size: { width: 0, height: 0 },
// 拖拽状态
isDragging: false,
// 调整大小状态
isResizing: false,
// 鼠标初始位置
startMouse: { x: 0, y: 0 },
// 元素初始状态
startState: { x: 0, y: 0, width: 0, height: 0 }
};
},
mounted() {
// 初始化位置和尺寸优先从localStorage读取
this.initFromStorage();
// 监听全局鼠标移动和松开事件
document.addEventListener('mousemove', this.handleMouseMove);
document.addEventListener('mouseup', this.handleMouseUp);
// 监听窗口大小变化,更新屏幕尺寸
window.addEventListener('resize', this.updateScreenSize);
},
beforeDestroy() {
// 移除全局事件监听,防止内存泄漏
document.removeEventListener('mousemove', this.handleMouseMove);
document.removeEventListener('mouseup', this.handleMouseUp);
window.removeEventListener('resize', this.updateScreenSize);
},
methods: {
/**
* 从localStorage初始化位置和尺寸
* 有key时优先读取存储值无则使用props传入的初始值
*/
initFromStorage() {
if (this.storageKey) {
try {
const storageKey = `dnd-ps-${this.storageKey}`;
const storedData = localStorage.getItem(storageKey);
if (storedData) {
const { position, size } = JSON.parse(storedData);
// 验证存储的数据是否合法,防止异常值
const isValidPosition = position && typeof position.x === 'number' && typeof position.y === 'number';
const isValidSize = size && typeof size.width === 'number' && typeof size.height === 'number';
if (isValidPosition && isValidSize) {
// 使用存储的位置和尺寸(确保不小于最小尺寸)
this.position = {
x: Math.max(0, position.x),
y: Math.max(0, position.y)
};
this.size = {
width: Math.max(this.minSize.width, size.width),
height: Math.max(this.minSize.height, size.height)
};
return;
}
}
} catch (error) {
console.warn('读取拖拽元素存储数据失败,使用默认值:', error);
}
}
// 无存储数据或存储异常时使用props初始值
this.position = { ...this.initPosition };
this.size = { ...this.initSize };
},
/**
* 将当前位置和尺寸保存到localStorage
*/
saveToStorage() {
if (this.storageKey) {
try {
const storageKey = `dnd-ps-${this.storageKey}`;
const saveData = {
position: { ...this.position },
size: { ...this.size },
updateTime: new Date().getTime()
};
console.log('saveData', saveData);
localStorage.setItem(storageKey, JSON.stringify(saveData));
// 触发存储成功事件
this.$emit('save-success', saveData);
} catch (error) {
console.error('保存拖拽元素数据失败:', error);
this.$emit('save-fail', error);
}
}
},
/**
* 更新屏幕尺寸(窗口大小变化时)
*/
updateScreenSize() {
this.containerSize = {
width: window.innerWidth,
height: window.innerHeight
};
},
/**
* 开始拖拽(移动位置)
*/
startDrag(e) {
// 阻止事件冒泡,避免和调整大小冲突
if (e.target.classList.contains('resize-handle')) return;
this.isDragging = true;
// 记录鼠标初始位置
this.startMouse = { x: e.clientX, y: e.clientY };
// 记录元素初始位置
this.startState = {
x: this.position.x,
y: this.position.y,
width: this.size.width,
height: this.size.height
};
// 更改鼠标样式
document.body.style.cursor = 'move';
},
/**
* 开始调整大小
*/
startResize(e) {
e.stopPropagation(); // 阻止事件冒泡
this.isResizing = true;
// 记录鼠标初始位置
this.startMouse = { x: e.clientX, y: e.clientY };
// 记录元素初始尺寸
this.startState = {
x: this.position.x,
y: this.position.y,
width: this.size.width,
height: this.size.height
};
// 更改鼠标样式
document.body.style.cursor = 'se-resize';
},
/**
* 处理鼠标移动
*/
handleMouseMove(e) {
if (this.isDragging) {
// 计算鼠标移动的偏移量
const dx = e.clientX - this.startMouse.x;
const dy = e.clientY - this.startMouse.y;
// 核心修改:移除容器边界限制,仅限制不超出屏幕左侧/顶部(右侧/底部可任意移动)
this.position.x = Math.max(0, this.startState.x + dx);
this.position.y = Math.max(0, this.startState.y + dy);
// 触发位置变化事件
this.$emit('position-change', { ...this.position });
}
if (this.isResizing) {
// 计算鼠标移动的偏移量
const dx = e.clientX - this.startMouse.x;
const dy = e.clientY - this.startMouse.y;
// 调整大小仅限制最小尺寸,不限制屏幕边界
this.size.width = Math.max(this.minSize.width, this.startState.width + dx);
this.size.height = Math.max(this.minSize.height, this.startState.height + dy);
// 触发尺寸变化事件
this.$emit('size-change', { ...this.size });
}
},
/**
* 处理鼠标松开
*/
handleMouseUp() {
// 重置状态
this.isDragging = false;
this.isResizing = false;
// 恢复鼠标样式
document.body.style.cursor = 'default';
// 保存当前状态到localStorage有key时
this.saveToStorage();
// 触发结束事件
this.$emit('drag-end', { position: { ...this.position }, size: { ...this.size } });
}
}
};
</script>
<style scoped>
/* 容器样式:改为全屏且无视觉样式 */
.drag-resize-container {
position: fixed; /* 固定定位覆盖整个屏幕 */
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none; /* 容器不拦截鼠标事件,不影响页面其他元素 */
box-sizing: border-box;
}
/* 可拖拽元素样式fixed定位确保基于屏幕移动 */
.draggable-element {
position: fixed;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
user-select: none; /* 禁止文本选中 */
box-sizing: border-box;
overflow: hidden;
pointer-events: auto; /* 元素本身响应鼠标事件 */
z-index: 9999; /* 确保元素在最上层 */
background-color: #ffffff; /* 添加背景色,提升可视性 */
}
/* 元素内容区 */
.element-content {
height: calc(100% - 20px);
padding: 10px;
cursor: move;
}
/* 调整大小控制点 */
.resize-handle {
position: absolute;
right: 0;
bottom: 0;
width: 20px;
height: 20px;
background-color: #1e88e5;
cursor: se-resize;
border-top-left-radius: 4px;
}
/* 控制点hover效果 */
.resize-handle:hover {
background-color: #1976d2;
}
</style>

View File

@@ -1,119 +0,0 @@
<template>
<div class="file-list-container">
<el-table
:data="fileList"
border
size="small"
v-loading="loading"
style="width: 100%;"
>
<el-table-column
label="文件名"
prop="originalName"
min-width="200"
>
<template slot-scope="scope">
<i class="el-icon-document" style="margin-right: 8px;"></i>
{{ scope.row.originalName }}
</template>
</el-table-column>
<el-table-column
label="操作"
width="100"
align="center"
>
<template slot-scope="scope">
<el-button
type="text"
icon="el-icon-download"
@click="downloadFile(scope.row)"
size="small"
>
下载
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 空数据提示 -->
<div v-if="fileList.length === 0 && !loading" class="empty-tip">
<el-empty description="暂无文件数据"></el-empty>
</div>
</div>
</template>
<script>
import { listByIds } from "@/api/system/oss";
export default {
name: "FileList",
props: {
ossIds: {
type: String,
default: '',
},
},
data() {
return {
fileList: [],
loading: false // 加载状态
}
},
watch: {
ossIds: {
handler(val) {
if (val) {
this.getFileList();
} else {
this.fileList = []; // 清空文件列表
}
},
immediate: true,
}
},
methods: {
async getFileList() {
if (!this.ossIds) return;
this.loading = true;
try {
let res = await listByIds(this.ossIds);
this.fileList = res.data || [];
} catch (error) {
this.$message.error('获取文件列表失败:' + (error.message || '未知错误'));
this.fileList = [];
} finally {
this.loading = false;
}
},
// 文件下载方法
downloadFile(file) {
if (!file || !file.ossId) {
this.$message.warning('文件下载地址不存在');
return;
}
this.$download.oss(file.ossId);
}
}
}
</script>
<style scoped>
.file-list-container {
width: 100%;
min-height: 100px;
}
.empty-tip {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}
::v-deep .el-table {
--el-table-header-text-color: #606266;
--el-table-row-hover-bg-color: #f5f7fa;
}
</style>

View File

@@ -30,18 +30,6 @@
<span class="label">净重</span>
<span class="value">{{ netWeight }}</span>
</div>
<div class="info-item" v-if="length">
<span class="label">长度</span>
<span class="value">{{ length }}</span>
</div>
<div class="info-item" v-if="actualLength">
<span class="label">实测长度</span>
<span class="value">{{ actualLength }}</span>
</div>
<div class="info-item" v-if="actualWidth">
<span class="label">实测宽度</span>
<span class="value">{{ actualWidth }}</span>
</div>
<div class="info-item">
<span class="label">厂家卷号</span>
<span class="value">{{ supplierCoilNo }}</span>

View File

@@ -35,7 +35,7 @@ export default {
},
data() {
return {
title: '科伦普一体化平台',
title: 'MES一体化平台',
logo: logoImg
}
}

View File

@@ -1,748 +0,0 @@
<template>
<div class="aps-quick-sheet excel-theme">
<div class="sheet-toolbar">
<div class="sheet-actions">
<el-button size="small" icon="el-icon-refresh" @click="loadRows">刷新</el-button>
<el-button size="small" type="primary" icon="el-icon-finished" :loading="saving" @click="saveAll">保存</el-button>
<el-button size="small" icon="el-icon-plus" @click="addRow">新增行</el-button>
<el-button size="small" icon="el-icon-download" @click="exportCsv">导出</el-button>
<el-date-picker
v-model="filter.range"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
size="small"
style="width: 240px"
@change="onFilterChange"
/>
</div>
<div class="preset-bar">
<span class="preset-title">预设方案</span>
<el-button
v-for="line in lineOptions"
:key="line.lineId"
size="mini"
plain
@click="applyPreset(line)"
>
{{ line.lineName || line.lineCode || ('产线' + line.lineId) }}
</el-button>
</div>
</div>
<div class="sheet-body">
<el-table
v-loading="loading"
:data="displayRows"
border
size="mini"
class="excel-table"
>
<el-table-column label="序号" width="60" align="center">
<template slot-scope="scope">
{{ ((pager.pageNum - 1) * pager.pageSize) + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column
v-for="col in flatColumns"
:key="col.prop || col.label"
:label="col.label"
:prop="col.prop"
:width="col.width"
:min-width="col.minWidth"
:align="col.align || 'center'"
:show-overflow-tooltip="col.showOverflowTooltip !== false"
>
<template slot-scope="scope">
<template v-if="col.prop === 'rawMaterialId'">
<el-button
size="mini"
type="text"
class="coil-picker-btn"
@click="openCoilPicker(scope.row)"
>
{{ scope.row.rawCoilNos || '选择原料钢卷' }}
</el-button>
</template>
<template v-else-if="isTimeField(col.prop)">
<el-date-picker
v-model="scope.row[col.prop]"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
size="mini"
style="width: 100%"
@change="onCellChange(scope.row)"
@input="onCellChange(scope.row)"
/>
</template>
<template v-else>
<el-autocomplete
v-if="col.prop === 'lineName'"
v-model="scope.row[col.prop]"
size="mini"
clearable
:fetch-suggestions="queryLineHistory"
@select="onLineHistorySelect(scope.row)"
@input="onLineHistoryInput(scope.row)"
/>
<el-input
v-else
v-model="scope.row[col.prop]"
size="mini"
clearable
@input="onCellChange(scope.row)"
/>
</template>
</template>
</el-table-column>
<el-table-column label="操作" width="70" fixed="right" align="center">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="clearRow(scope.row)">清空</el-button>
</template>
</el-table-column>
</el-table>
<div class="pager-wrap">
<el-pagination
small
background
layout="prev, pager, next, total"
:current-page.sync="pager.pageNum"
:page-size="pager.pageSize"
:total="totalRows"
/>
</div>
</div>
<div v-if="missingRows.length" class="missing-tip">
<div v-for="msg in missingRows" :key="msg" class="missing-item">{{ msg }}</div>
</div>
<el-dialog title="选择原料钢卷" :visible.sync="coilPicker.visible" width="1280px" append-to-body>
<el-form :inline="true" size="small" class="coil-picker-form">
<el-form-item label="库区">
<el-select v-model="coilPicker.selectedWarehouseId" clearable filterable placeholder="全部库区" style="width: 220px" @change="onCoilFilterChange">
<el-option
v-for="w in coilPicker.warehouseOptions"
:key="w.actualWarehouseId"
:label="w.actualWarehouseName"
:value="w.actualWarehouseId"
/>
</el-select>
</el-form-item>
<el-form-item label="入场钢卷号">
<el-input v-model="coilPicker.enterCoilNo" clearable placeholder="支持模糊" style="width: 170px" @keyup.enter.native="searchCoils" />
</el-form-item>
<el-form-item label="当前钢卷号">
<el-input v-model="coilPicker.currentCoilNo" clearable placeholder="支持模糊" style="width: 170px" @keyup.enter.native="searchCoils" />
</el-form-item>
<el-form-item label="厂家">
<el-input v-model="coilPicker.manufacturer" clearable placeholder="支持模糊" style="width: 170px" @keyup.enter.native="searchCoils" />
</el-form-item>
<el-form-item>
<el-button size="mini" type="primary" @click="searchCoils">查询</el-button>
</el-form-item>
</el-form>
<div class="coil-stack-wrap" v-loading="coilPicker.loading">
<el-empty v-if="!coilColumnKeys.length" description="暂无可选原料钢卷" :image-size="60" />
<div v-else class="coil-bird-wrap">
<div class="coil-legend">
<span class="legend-item"><i class="dot layer1" />一层</span>
<span class="legend-item"><i class="dot layer2" />二层</span>
<span class="legend-item"><i class="dot occupied" />已占用</span>
</div>
<div class="coil-grid-scroll">
<div class="coil-col-ruler">
<div class="ruler-empty" />
<div v-for="col in coilColumnKeys" :key="`ruler-${col}`" class="ruler-col">{{ col }}</div>
</div>
<div class="coil-grid-main">
<div class="coil-row-ruler">
<div v-for="row in coilMaxRow" :key="`row-${row}`" class="ruler-row">{{ row }}</div>
</div>
<div class="coil-grid-columns">
<div v-for="col in coilColumnKeys" :key="`col-${col}`" class="coil-col-pair">
<div class="coil-layer">
<div
v-for="row in coilMaxRow"
:key="`l1-${col}-${row}`"
class="coil-cell layer1"
:class="{ occupied: !!(getCoilCell(col, row, 1) && getCoilCell(col, row, 1).rawMaterialId) }"
@click="selectCoilCell(col, row, 1)"
>
<template v-if="getCoilCell(col, row, 1)">
<div class="line1" :title="getCoilCell(col, row, 1).rawLocation">{{ getCoilCell(col, row, 1).rawLocation }}</div>
<div class="line2" :title="getCoilCell(col, row, 1).rawMaterialCode">{{ getCoilCell(col, row, 1).rawMaterialCode || '-' }}</div>
</template>
<template v-else>-</template>
</div>
</div>
<div class="coil-layer layer2-shift">
<div
v-for="row in (coilMaxRow - 1)"
:key="`l2-${col}-${row}`"
class="coil-cell layer2"
:class="{ occupied: !!(getCoilCell(col, row, 2) && getCoilCell(col, row, 2).rawMaterialId) }"
@click="selectCoilCell(col, row, 2)"
>
<template v-if="getCoilCell(col, row, 2)">
<div class="line1" :title="getCoilCell(col, row, 2).rawLocation">{{ getCoilCell(col, row, 2).rawLocation }}</div>
<div class="line2" :title="getCoilCell(col, row, 2).rawMaterialCode">{{ getCoilCell(col, row, 2).rawMaterialCode || '-' }}</div>
</template>
<template v-else>-</template>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="coil-picker-foot"> {{ coilPicker.total || 0 }} 条钢卷按库位分布展示</div>
</el-dialog>
</div>
</template>
<script>
import { fetchQuickSheetList, fetchQuickSheetPreset, saveQuickSheet, exportQuickSheet, deleteQuickSheetRow } from '@/api/aps/quickSheet'
import { listProductionLine } from '@/api/wms/productionLine'
import { getMaterialCoilLocationGrid } from '@/api/wms/coil'
import { treeActualWarehouseTwoLevel } from '@/api/wms/actualWarehouse'
import { getTemplateByKey } from './sheets/templates'
import { saveAs } from 'file-saver'
export default {
name: 'ApsQuickSheet',
data() {
return {
loading: false,
saving: false,
rows: [],
lineOptions: [],
lineHistory: [],
dirtyIds: new Set(),
autoSaveTimer: null,
templateKey: 'unified',
filter: {
range: []
},
pager: {
pageNum: 1,
pageSize: 25
},
coilPicker: {
visible: false,
loading: false,
currentRow: null,
selectedWarehouseId: undefined,
enterCoilNo: '',
currentCoilNo: '',
manufacturer: '',
warehouseOptions: [],
coilGrid: {},
total: 0
}
}
},
computed: {
currentTemplate() {
return getTemplateByKey(this.templateKey)
},
flatColumns() {
const res = []
const loop = (cols) => {
;(cols || []).forEach(c => {
if (c.children && c.children.length) loop(c.children)
else res.push(c)
})
}
loop(this.currentTemplate.columns || [])
return res
},
displayRows() {
const [startAfter, endBefore] = this.filter.range || []
const filtered = this.rows.filter(r => {
if (!r.startTime) return true
const d = String(r.startTime).slice(0, 10)
if (startAfter && d < startAfter) return false
if (endBefore && d > endBefore) return false
return true
})
const start = (this.pager.pageNum - 1) * this.pager.pageSize
const page = filtered.slice(start, start + this.pager.pageSize)
if (page.length < this.pager.pageSize) {
return page.concat(this.buildEmptyRows(this.pager.pageSize - page.length))
}
return page
},
totalRows() {
const [startAfter, endBefore] = this.filter.range || []
return this.rows.filter(r => {
if (!r.startTime) return true
const d = String(r.startTime).slice(0, 10)
if (startAfter && d < startAfter) return false
if (endBefore && d > endBefore) return false
return true
}).length
},
missingRows() {
return this.collectMissing(this.displayRows)
},
coilColumnKeys() {
const keys = Object.keys(this.coilPicker.coilGrid || {})
return keys.map(v => Number(v)).filter(v => !Number.isNaN(v)).sort((a, b) => a - b)
},
coilMaxRow() {
let max = 0
Object.values(this.coilPicker.coilGrid || {}).forEach(col => {
const l1 = col.layer1 || []
const l2 = col.layer2 || []
;[...l1, ...l2].forEach(item => {
const row = Number(item._row || 0)
if (row > max) max = row
})
})
return max || 1
}
},
created() {
const today = new Date()
const start = `${today.getFullYear()}-${`${today.getMonth() + 1}`.padStart(2, '0')}-${`${today.getDate()}`.padStart(2, '0')}`
this.filter.range = [start, '']
this.loadRows()
this.loadLines()
},
beforeDestroy() {
if (this.autoSaveTimer) clearTimeout(this.autoSaveTimer)
},
methods: {
async loadLines() {
const res = await listProductionLine({ pageNum: 1, pageSize: 1000 })
this.lineOptions = res.rows || []
},
async loadRows() {
this.loading = true
try {
const res = await fetchQuickSheetList()
this.rows = (res.data || []).map(r => this.normalizeRow(r))
this.lineHistory = this.rows
.map(r => r.lineName)
.filter(v => v && v.trim())
.filter((v, i, arr) => arr.indexOf(v) === i)
} finally {
this.loading = false
}
},
buildEmptyRows(count) {
return Array.from({ length: count }).map(() => this.buildEmptyRow())
},
async applyPreset(line) {
if (!line || !line.lineId) return
const res = await fetchQuickSheetPreset({ lineId: line.lineId })
const preset = res.data || []
if (!preset.length) return
const targetRow = this.rows.find(r => !r.lineId && !r.lineName) || this.buildEmptyRow()
const base = this.normalizeRow(preset[0])
Object.keys(base).forEach(k => {
if (k === 'quickSheetId') return
targetRow[k] = base[k]
})
targetRow.lineId = line.lineId
targetRow.lineName = line.lineName || line.lineCode || ''
if (!this.rows.includes(targetRow)) {
this.rows.push(targetRow)
}
if (this.rows.length < 25) {
this.rows = this.rows.concat(this.buildEmptyRows(25 - this.rows.length))
}
this.markDirty(targetRow)
this.scheduleAutoSave()
},
async loadWarehouseOptions() {
const res = await treeActualWarehouseTwoLevel()
const tree = res.data || []
const leaf = []
tree.forEach(p => {
;(p.children || []).forEach(c => {
leaf.push({
actualWarehouseId: c.actualWarehouseId,
actualWarehouseName: `${p.actualWarehouseName || ''}/${c.actualWarehouseName || ''}`
})
})
})
this.coilPicker.warehouseOptions = leaf
},
async loadCoilsByWarehouse() {
if (!this.coilPicker.selectedWarehouseId) {
this.coilPicker.coilGrid = {}
this.coilPicker.total = 0
return
}
this.coilPicker.loading = true
try {
const gridRes = await getMaterialCoilLocationGrid({
itemType: 'raw_material',
actualWarehouseId: this.coilPicker.selectedWarehouseId,
enterCoilNo: this.coilPicker.enterCoilNo || undefined,
currentCoilNo: this.coilPicker.currentCoilNo || undefined,
manufacturer: this.coilPicker.manufacturer || undefined
})
const data = gridRes.data || {}
const warehouses = data.warehouses || []
const coils = (data.coils || []).map(item => ({
rawMaterialId: item.coilId,
rawMaterialCode: item.currentCoilNo || item.enterCoilNo || item.coilNo || '',
rawMaterialName: item.itemName || item.materialName || '',
specification: item.specification || '',
coilWeight: item.netWeight,
packageType: item.packagingRequirement || item.packageType,
edgeType: item.trimmingRequirement || item.edgeType,
zincLayer: item.coatingType || item.zincLayer,
surfaceTreatmentDesc: item.surfaceTreatmentDesc,
actualWarehouseId: item.actualWarehouseId,
actualWarehouseName: item.actualWarehouseName || '未分配库位',
rawLocation: item.actualWarehouseName || '未分配库位'
}))
this.coilPicker.total = coils.length
const coilByWarehouseId = {}
coils.forEach(c => {
if (c.actualWarehouseId && !coilByWarehouseId[c.actualWarehouseId]) {
coilByWarehouseId[c.actualWarehouseId] = c
}
})
const grid = {}
warehouses.forEach(w => {
const code = String(w.actualWarehouseCode || '')
const m = code.match(/^([A-Za-z0-9]{3})([^-]+)-(\d{2})-(\d+)$/)
if (!m) return
const col = Number(m[2])
const row = Number(m[3])
const layer = Number(m[4])
if (!grid[col]) grid[col] = { layer1: [], layer2: [] }
const coil = coilByWarehouseId[w.actualWarehouseId] || null
const cell = {
_col: col,
_row: row,
_layer: layer,
actualWarehouseId: w.actualWarehouseId,
actualWarehouseCode: w.actualWarehouseCode,
rawLocation: w.actualWarehouseName || w.actualWarehouseCode,
...(coil || {})
}
if (layer === 1) grid[col].layer1.push(cell)
else if (layer === 2) grid[col].layer2.push(cell)
})
Object.keys(grid).forEach(k => {
grid[k].layer1.sort((a, b) => Number(a._row) - Number(b._row))
grid[k].layer2.sort((a, b) => Number(a._row) - Number(b._row))
})
this.coilPicker.coilGrid = grid
} finally {
this.coilPicker.loading = false
}
},
searchCoils() {
this.loadCoilsByWarehouse()
},
onCoilFilterChange() {
this.loadCoilsByWarehouse()
},
openCoilPicker(row) {
this.coilPicker.currentRow = row
this.coilPicker.visible = true
this.loadWarehouseOptions().then(() => {
if (!this.coilPicker.selectedWarehouseId && this.coilPicker.warehouseOptions.length) {
this.coilPicker.selectedWarehouseId = this.coilPicker.warehouseOptions[0].actualWarehouseId
}
this.loadCoilsByWarehouse()
})
},
getCoilCell(col, row, layer) {
const c = this.coilPicker.coilGrid[col]
if (!c) return null
const list = layer === 1 ? (c.layer1 || []) : (c.layer2 || [])
return list.find(i => Number(i._row) === Number(row)) || null
},
selectCoilCell(col, row, layer) {
const item = this.getCoilCell(col, row, layer)
if (!item) return
if (!item.rawMaterialId) {
this.$message.warning('该库位当前无钢卷')
return
}
this.pickRawMaterial(item)
},
pickRawMaterial(item) {
const row = this.coilPicker.currentRow
if (!row) return
this.$set(row, 'rawMaterialId', item.rawMaterialId)
this.$set(row, 'rawCoilNos', item.rawMaterialCode || '')
this.$set(row, 'rawNetWeight', item.coilWeight != null ? item.coilWeight : '')
this.$set(row, 'rawPackaging', item.packageType || '')
this.$set(row, 'rawEdgeReq', item.edgeType || '')
this.$set(row, 'rawCoatingType', item.zincLayer || item.surfaceTreatmentDesc || '')
this.$set(row, 'rawLocation', item.rawLocation || '')
this.coilPicker.visible = false
this.onCellChange(row)
},
onCellChange(row) {
if (row && !this.rows.includes(row)) {
this.rows.push(row)
}
this.markDirty(row)
this.scheduleAutoSave()
},
queryLineHistory(query, cb) {
const list = this.lineHistory || []
const q = (query || '').trim().toLowerCase()
const res = list
.filter(item => !q || String(item).toLowerCase().includes(q))
.map(item => ({ value: item }))
cb(res)
},
onLineHistoryInput(row) {
if (!row) return
if (row.lineId && row.lineName && row.lineName.trim() !== String(row.lineName).trim()) {
row.lineId = null
}
this.onCellChange(row)
},
onLineHistorySelect(row) {
return () => {
this.onCellChange(row)
}
},
onFilterChange() {
this.pager.pageNum = 1
},
normalizeRow(row) {
const base = this.buildEmptyRow()
Object.keys(base).forEach(k => {
if (row && row[k] !== undefined && row[k] !== null) base[k] = row[k]
})
const idVal = row ? (row.quickSheetId !== undefined && row.quickSheetId !== null ? row.quickSheetId : row.id) : null
base.quickSheetId = idVal != null ? idVal : null
return base
},
buildEmptyRow() {
const row = { quickSheetId: null }
this.flatColumns.forEach(col => {
if (!col.prop) return
row[col.prop] = ''
})
return row
},
isRowEmpty(row) {
if (!row) return true
return !this.flatColumns.some(col => col.prop && row[col.prop])
},
isTimeField(prop) {
return prop === 'startTime' || prop === 'endTime'
},
markDirty(row) {
if (!row) return
if (!row._tmpId) row._tmpId = Math.random().toString(36).slice(2)
this.dirtyIds.add(row._tmpId)
},
async clearRow(row) {
if (!row) return
if (!row.quickSheetId) {
this.flatColumns.forEach(col => {
if (!col.prop) return
row[col.prop] = ''
})
row.quickSheetId = null
return
}
await deleteQuickSheetRow(row.quickSheetId)
this.flatColumns.forEach(col => {
if (!col.prop) return
row[col.prop] = ''
})
row.quickSheetId = null
},
scheduleAutoSave() {
if (this.autoSaveTimer) clearTimeout(this.autoSaveTimer)
this.autoSaveTimer = setTimeout(() => {
this.saveAll(true)
}, 800)
},
async saveAll(isAuto = false, payload) {
const rows = payload && payload.rows
? payload.rows
: this.rows.filter(r => r && r._tmpId && this.dirtyIds.has(r._tmpId))
.map(r => ({
...r,
quickSheetId: r.quickSheetId || null
}))
if (!rows.length) {
if (!isAuto) this.$message.warning('暂无可保存数据')
return
}
const missing = this.collectMissing(rows)
if (missing.length && !isAuto) {
this.$message.warning(`必填项未填写:${missing.join('')}`)
return
}
this.saving = true
try {
await saveQuickSheet({ rows })
if (!isAuto) this.$message.success('保存成功')
rows.forEach(r => {
if (r._tmpId) this.dirtyIds.delete(r._tmpId)
})
} finally {
this.saving = false
}
},
addRow() {
this.rows.push(this.buildEmptyRow())
if (this.rows.length < this.pager.pageSize) {
this.rows = this.rows.concat(this.buildEmptyRows(this.pager.pageSize - this.rows.length))
}
},
onFilterChange() {
this.pager.pageNum = 1
},
exportCsv() {
this.loading = true
exportQuickSheet()
.then(blob => {
const filename = `quick_sheet_${new Date().getTime()}.xlsx`
saveAs(new Blob([blob], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }), filename)
})
.finally(() => {
this.loading = false
})
},
addRow() {
this.rows.unshift(this.buildEmptyRow())
this.pager.pageNum = 1
},
collectMissing(rows) {
const msgs = []
rows.forEach((row, idx) => {
if (this.isRowEmpty(row)) return
const line = idx + 1
const missing = []
if (!row.lineName && !row.lineId) missing.push('产线')
if (!row.planCode) missing.push('计划号')
if (!row.startTime) missing.push('开始时间')
if (!row.endTime) missing.push('结束时间')
if (missing.length) {
msgs.push(`${line}行缺少${missing.join('、')}`)
}
})
return msgs
}
}
}
</script>
<style scoped lang="scss">
.aps-quick-sheet {
padding: 8px;
background: #f7f9fc;
}
.sheet-toolbar,
.sheet-body {
border: 1px solid #eef2f7;
border-radius: 8px;
background: #fff;
}
.sheet-toolbar {
margin-bottom: 8px;
padding: 8px 12px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.sheet-actions { display: flex; gap: 8px; }
.preset-bar { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #667085; }
.preset-title { font-weight: 600; color: #475467; }
::v-deep .excel-table {
border: 1px solid #edf1f7;
}
::v-deep .excel-table th.el-table__cell {
background: #fafbfe;
color: #5d6b82;
font-weight: 600;
border-right: 1px solid #edf1f7;
border-bottom: 1px solid #edf1f7;
padding: 4px 0;
}
::v-deep .excel-table td.el-table__cell {
border-right: 1px solid #f0f2f6;
border-bottom: 1px solid #f0f2f6;
padding: 1px 2px;
}
::v-deep .excel-table .el-table__row:hover > td {
background-color: #f7faff !important;
}
::v-deep .el-input__inner {
border-radius: 0;
height: 26px;
line-height: 26px;
border: none;
box-shadow: none;
background: transparent;
}
::v-deep .el-input__inner:focus {
border: none;
box-shadow: inset 0 0 0 1px #4a90e2;
background: #fff;
}
.missing-tip {
margin-top: 8px;
padding: 8px 12px;
background: #fff7e6;
border: 1px solid #ffd591;
border-radius: 6px;
font-size: 12px;
color: #d46b08;
}
.missing-item {
line-height: 1.6;
}
.coil-picker-btn {
padding: 0;
}
.coil-bird-wrap { border: 1px solid #ebeef5; border-radius: 6px; padding: 8px; }
.coil-legend { display: flex; gap: 14px; font-size: 12px; color: #606266; margin-bottom: 8px; }
.legend-item { display: inline-flex; align-items: center; gap: 4px; }
.dot { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }
.dot.layer1 { background: #fff3e0; border: 1px solid #f5d7a1; }
.dot.layer2 { background: #e8f5e9; border: 1px solid #b7ddb9; }
.dot.occupied { background: #f6f8fb; border: 1px solid #d7dde5; }
.coil-grid-scroll { overflow: auto; max-height: 460px; }
.coil-col-ruler { display: flex; min-width: max-content; }
.ruler-empty { width: 28px; flex: none; }
.ruler-col { width: 138px; text-align: center; font-size: 12px; color: #606266; }
.coil-grid-main { display: flex; min-width: max-content; }
.coil-row-ruler { width: 28px; display: flex; flex-direction: column; }
.ruler-row { height: 56px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #909399; }
.coil-grid-columns { display: flex; gap: 8px; }
.coil-col-pair { display: grid; grid-template-columns: 1fr 1fr; width: 180px; border: 1px solid #eef2f7; border-radius: 4px; overflow: visible; }
.coil-layer { display: flex; flex-direction: column; }
.coil-layer.layer2-shift { margin-top: 28px; }
.coil-cell { height: 56px; border-bottom: 1px solid #eef2f7; border-right: 1px solid #eef2f7; padding: 4px; font-size: 11px; color: #909399; display: flex; align-items: center; justify-content: center; text-align: center; cursor: pointer; }
.coil-cell.layer1 { background: #fff3e0; color: #e67e22; }
.coil-cell.layer2 { background: #e8f5e9; color: #2e8b57; border-right: none; }
.coil-cell.occupied { font-weight: 600; }
.coil-cell .line1 { width: 100%; font-size: 11px; line-height: 1.1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.coil-cell .line2 { width: 100%; font-size: 11px; line-height: 1.1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.coil-picker-foot { margin-top: 8px; text-align: right; color: #909399; font-size: 12px; }
</style>

View File

@@ -1,225 +0,0 @@
<template>
<div class="aps-quick-sheet-preview excel-theme">
<div class="sheet-toolbar">
<div class="sheet-actions">
<el-date-picker
v-model="filter.range"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
size="small"
style="width: 240px"
@change="onFilterChange"
/>
<el-select v-model="filter.lineId" clearable filterable size="small" placeholder="产线" style="width: 160px" @change="onFilterChange">
<el-option v-for="line in lineOptions" :key="line.lineId" :label="line.lineName || line.lineCode || ('产线' + line.lineId)" :value="line.lineId" />
</el-select>
<el-input v-model="filter.customer" size="small" clearable placeholder="客户" style="width: 160px" @input="onFilterChange" />
<el-button size="small" icon="el-icon-refresh" @click="loadRows">刷新</el-button>
<el-button size="small" icon="el-icon-download" @click="exportExcel">导出</el-button>
</div>
</div>
<div class="sheet-body">
<el-table
v-loading="loading"
:data="displayRows"
border
size="mini"
class="excel-table"
>
<el-table-column label="序号" width="60" align="center">
<template slot-scope="scope">
{{ ((pager.pageNum - 1) * pager.pageSize) + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column
v-for="col in flatColumns"
:key="col.prop || col.label"
:label="col.label"
:prop="col.prop"
:width="col.width"
:min-width="col.minWidth"
:align="col.align || 'center'"
:show-overflow-tooltip="col.showOverflowTooltip !== false"
/>
</el-table>
<div class="pager-wrap">
<el-pagination
small
background
layout="prev, pager, next, total"
:current-page.sync="pager.pageNum"
:page-size="pager.pageSize"
:total="totalRows"
/>
</div>
</div>
</div>
</template>
<script>
import { fetchQuickSheetList, exportQuickSheet } from '@/api/aps/quickSheet'
import { listProductionLine } from '@/api/wms/productionLine'
import { getTemplateByKey } from './sheets/templates'
import { saveAs } from 'file-saver'
export default {
name: 'ApsQuickSheetPreview',
data() {
return {
loading: false,
rows: [],
lineOptions: [],
filter: {
range: [],
lineId: null,
customer: ''
},
pager: {
pageNum: 1,
pageSize: 25
}
}
},
computed: {
currentTemplate() {
return getTemplateByKey('unified')
},
flatColumns() {
const res = []
const loop = (cols) => {
;(cols || []).forEach(c => {
if (c.children && c.children.length) loop(c.children)
else res.push(c)
})
}
loop(this.currentTemplate.columns || [])
return res
},
filteredRows() {
const [startAfter, endBefore] = this.filter.range || []
const lineName = (this.filter.lineName || '').trim()
const customer = (this.filter.customer || '').trim().toLowerCase()
return this.rows.filter(r => {
if (startAfter || endBefore) {
const d = r.startTime ? String(r.startTime).slice(0, 10) : ''
if (startAfter && d && d < startAfter) return false
if (endBefore && d && d > endBefore) return false
}
if (lineName && r.lineName !== lineName) return false
if (customer) {
const txt = String(r.customerName || '').toLowerCase()
if (!txt.includes(customer)) return false
}
return true
})
},
displayRows() {
const start = (this.pager.pageNum - 1) * this.pager.pageSize
return this.filteredRows.slice(start, start + this.pager.pageSize)
},
totalRows() {
return this.filteredRows.length
}
},
created() {
const today = new Date()
const start = `${today.getFullYear()}-${`${today.getMonth() + 1}`.padStart(2, '0')}-${`${today.getDate()}`.padStart(2, '0')}`
this.filter.range = [start, '']
this.loadRows()
this.loadLines()
},
methods: {
async loadLines() {
const res = await listProductionLine({ pageNum: 1, pageSize: 1000 })
this.lineOptions = res.rows || []
},
async loadRows() {
this.loading = true
try {
const params = this.buildQueryParams()
const res = await fetchQuickSheetList(params)
this.rows = (res.data || []).map(r => ({ ...r }))
} finally {
this.loading = false
}
},
onFilterChange() {
this.pager.pageNum = 1
this.loadRows()
},
exportExcel() {
const params = this.buildQueryParams()
exportQuickSheet(params)
.then(blob => {
const filename = `quick_sheet_preview_${new Date().getTime()}.xlsx`
saveAs(new Blob([blob], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }), filename)
})
},
buildQueryParams() {
const [startDate, endDate] = this.filter.range || []
return {
startDate: startDate || undefined,
endDate: endDate || undefined,
lineId: this.filter.lineId || undefined,
customerName: this.filter.customer || undefined
}
}
}
}
</script>
<style scoped lang="scss">
.aps-quick-sheet-preview {
padding: 8px;
background: #f7f9fc;
}
.sheet-toolbar {
margin-bottom: 8px;
padding: 8px;
border: 1px solid #eef2f7;
border-radius: 8px;
background: #fff;
}
.sheet-actions {
display: flex;
gap: 8px;
align-items: center;
flex-wrap: wrap;
}
.sheet-body {
border: 1px solid #eef2f7;
border-radius: 8px;
background: #fff;
padding: 6px;
}
::v-deep .excel-table {
border: 1px solid #edf1f7;
}
::v-deep .excel-table th.el-table__cell {
background: #fafbfe;
color: #5d6b82;
font-weight: 600;
border-right: 1px solid #edf1f7;
border-bottom: 1px solid #edf1f7;
padding: 4px 0;
}
::v-deep .excel-table td.el-table__cell {
border-right: 1px solid #f0f2f6;
border-bottom: 1px solid #f0f2f6;
padding: 1px 2px;
}
.pager-wrap {
margin-top: 8px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -15,7 +15,7 @@ export const APS_SHEET_TEMPLATES = [
key: 'unified',
name: '统一排产表',
columns: [
{ label: '产线', prop: 'lineName', minWidth: 140 },
{ label: '产线', prop: 'lineName', minWidth: 120 },
{ label: '计划号', prop: 'planCode', minWidth: 140 },
{ label: '订单号', prop: 'orderCode', minWidth: 140 },
{ label: '客户', prop: 'customerName', minWidth: 140 },

View File

@@ -3,7 +3,7 @@
<img :src="avatar" class="user-avatar" alt="头像" />
<div class="greeting-text">
<div class="greeting-title">{{ greeting }}{{ name }}</div>
<div class="greeting-desc">欢迎使用科伦普冷轧涂渡数智一体化平台</div>
<div class="greeting-desc">欢迎使用MES数智一体化平台</div>
</div>
</div>
</template>

View File

@@ -12,10 +12,10 @@ export default {
components: { Home },
mounted() {
// 确保容器DOM已渲染后对容器执行全屏
this.$nextTick(() => {
this.enterFullscreen()
this.addFullscreenListener()
})
// this.$nextTick(() => {
// this.enterFullscreen()
// this.addFullscreenListener()
// })
},
beforeDestroy() {
// 移除监听,避免内存泄漏
@@ -60,7 +60,7 @@ export default {
!document.mozFullScreenElement &&
!document.webkitFullscreenElement &&
!document.msFullscreenElement
if (isExit) {
// 退出全屏后返回上一页
this.$router.back()
@@ -91,4 +91,4 @@ export default {
height: 100%;
/* 可根据需要添加其他样式(如背景色等) */
}
</style>
</style>

View File

@@ -1,68 +1,71 @@
<template>
<div class="dashboard-editor-container">
<img src="http://kelunpuzhonggong.com/upload/img/20250427091033.jpg" alt="">
<div class="aboutus">
<el-row :gutter="30">
<!-- 左栏 -->
<el-col :span="12" :xs="24">
<div class="aboutus-title">
<h2>关于我们</h2>
<p>ABOUT US</p>
</div>
<div class="aboutus-left">
<p class="aboutus-desc">
嘉祥科伦普重工有限公司是山东省重点工程项目是济宁市工程之一也是科伦普产品结构调整重要的工程项目工程采用了外方技术总负责关键设备整体引进点采集成国内技术总成自主创新单体设备引进等多种建设方案保证了技术先进和人才的培养确保工程投产后达产达效
</p>
<p class="aboutus-desc">
科伦普冷轧重工有限公司是设计年产量150万吨能向广大用户提供热轧酸洗热轧镀锌冷硬罩式退火冷轧镀锌铝锌合金锌铝合金锌铝镁镀铬等各大类产品产品覆盖东北华北华东华南等地区
</p>
</div>
<!-- <div class="dashboard-editor-container">-->
<!-- <img src="http://kelunpuzhonggong.com/upload/img/20250427091033.jpg" alt="">-->
<!-- -->
<!-- <div class="aboutus">-->
<!-- <el-row :gutter="30">-->
<!-- &lt;!&ndash; 左栏 &ndash;&gt;-->
<!-- <el-col :span="12" :xs="24">-->
<!-- <div class="aboutus-title">-->
<!-- <h2>关于我们</h2>-->
<!-- <p>ABOUT US</p>-->
<!-- </div>-->
<!-- <div class="aboutus-left">-->
<!-- <p class="aboutus-desc">-->
<!-- MES一体化平台是面向制造企业车间执行层的生产信息化管理系统为企业提供包括制造数据管理计划排程管理生产调度管理库存管理质量管理人力资源管理工作中心管理等多项企业管理功能-->
<!-- </p>-->
<!-- <p class="aboutus-desc">-->
<!-- 平台通过互联网技术实现企业数字化转型提高生产效率降低成本提升产品质量实现精益化生产管理帮助企业实现智能制造目标-->
<!-- </p>-->
<!-- </div>-->
<statistic-group />
</el-col>
<!-- <statistic-group />-->
<!-- </el-col>-->
<!-- 右栏 -->
<el-col :span="12" :xs="24">
<img src="http://kelunpuzhonggong.com/upload/img/20251015103934.jpg" alt="">
<!-- <div class="aboutus-right">
<p class="aboutus-detail">
嘉祥科伦普重工有限公司成立于2017年8月注册资金33100万元主要经营高铁设备配件制造与销售模具制造与销售新材料技术研发高性能有色金属及合金材料销售机械零件零部件加工与销售金属材料制造与销售锌铝镁新材料等目前公司拥有10余项具有自主知识产权的发明专利技术综合技术水平达国内领先2024年公司主导产品国内市场占有率约占85%2024年总资产5.98亿元净资产4.49亿元收入3.95亿元公司现有员工238人研究与试验发展人员57人其中专职研究与试验发展人员52人外聘专家5人
</p>
<p class="aboutus-detail">
2024年公司新建科伦普合金新材料研发项目占地290亩采用国内先进的镀层核心技术和热处理工艺专业生产锌铝镁板材和镀铬板材致力于打造国内工艺链条最完善产品型号最丰富的涂镀新材料生产企业全部投产后可实现新增销售收入80亿元利税4.7亿元带动就业约500人项目主要生产的冷轧板锌铝镁涂层板镀铬涂层板镀锡涂层板等产品涵盖0.08MM-6.0MM区间60多种产品是国内单个企业产品种类最多的项目产品因其防锈耐氧化耐腐蚀高电导高稳定的优秀特性广泛应用于建筑结构件汽车制造轻工家电食品包装医疗器械电子通讯航空航天领域
</p>
</div> -->
</el-col>
</el-row>
</div>
<!-- &lt;!&ndash; 右栏 &ndash;&gt;-->
<!-- <el-col :span="12" :xs="24">-->
<!-- <img src="http://kelunpuzhonggong.com/upload/img/20251015103934.jpg" alt="">-->
<!-- &lt;!&ndash; <div class="aboutus-right">-->
<!-- <p class="aboutus-detail">-->
<!-- 嘉祥科伦普重工有限公司成立于2017年8月注册资金33100万元主要经营高铁设备配件制造与销售模具制造与销售新材料技术研发高性能有色金属及合金材料销售机械零件零部件加工与销售金属材料制造与销售锌铝镁新材料等目前公司拥有10余项具有自主知识产权的发明专利技术综合技术水平达国内领先2024年公司主导产品国内市场占有率约占85%2024年总资产5.98亿元净资产4.49亿元收入3.95亿元公司现有员工238人研究与试验发展人员57人其中专职研究与试验发展人员52人外聘专家5人-->
<!-- </p>-->
<!-- <p class="aboutus-detail">-->
<!-- 2024年公司新建科伦普合金新材料研发项目占地290亩采用国内先进的镀层核心技术和热处理工艺专业生产锌铝镁板材和镀铬板材致力于打造国内工艺链条最完善产品型号最丰富的涂镀新材料生产企业全部投产后可实现新增销售收入80亿元利税4.7亿元带动就业约500人项目主要生产的冷轧板锌铝镁涂层板镀铬涂层板镀锡涂层板等产品涵盖0.08MM-6.0MM区间60多种产品是国内单个企业产品种类最多的项目产品因其防锈耐氧化耐腐蚀高电导高稳定的优秀特性广泛应用于建筑结构件汽车制造轻工家电食品包装医疗器械电子通讯航空航天领域-->
<!-- </p>-->
<!-- </div> &ndash;&gt;-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- </div>-->
<!-- <div>
<statistic-group />
</div> -->
<!-- <AllApplications />
<el-row :gutter="10">
<el-col :span="18">
<el-empty description="办公模块定制开发中"></el-empty>
</el-col>
<el-col :span="6">
<mini-calendar />
</el-col>
</el-row> -->
</div>
<!-- &lt;!&ndash; <div>-->
<!-- <statistic-group />-->
<!-- </div> &ndash;&gt;-->
<!-- -->
<!-- &lt;!&ndash; <AllApplications /> -->
<!-- <el-row :gutter="10">-->
<!-- <el-col :span="18">-->
<!-- <el-empty description="办公模块定制开发中"></el-empty>-->
<!-- </el-col>-->
<!-- <el-col :span="6">-->
<!-- <mini-calendar />-->
<!-- </el-col>-->
<!-- </el-row> &ndash;&gt;-->
<!-- </div>-->
<Dashboard />
</template>
<script>
import StatisticGroup from '@/components/HomeModules/StatisticGroup.vue'
// import AllApplications from '@/components/HomeModules/AllApplications.vue'
// import MiniCalendar from '@/components/HomeModules/MiniCalendar.vue'
import Dashboard from '@/views/dashboard/demo.vue'
export default {
export default {
name: 'Index',
components: {
// PanelGroup,
StatisticGroup,
Dashboard,
// AllApplications,
// MiniCalendar,
},
@@ -193,4 +196,4 @@ export default {
}
}
}
</style>
</style>

View File

@@ -3,15 +3,14 @@
<div class="login-box">
<div class="login-left">
<div class="login-title-welcome">
<img src="../assets/logo/logo.png" alt="logo" class="logo-img" />
<span class="login-title">欢迎使用科伦普冷轧涂镀数智一体化平台</span>
<!-- <img src="../assets/logo/logo.png" alt="logo" class="logo-img" />-->
<span class="login-title">欢迎使用MES一体化平台</span>
</div>
<p>
嘉祥科伦普重工有限公司是山东省重点工程项目是济宁市工程之一也是科伦普产品结构调整重要的工程项目工程采用了外方技术总负责关键设备整体引进点采集成国内技术总成自主创新单体设备引进等多种建设方
保证了技术先进和人才的培养确保工程投产后达产达效
MES一体化平台是面向制造企业车间执行层的生产信息化管理系统为企业提供包括制造数据管理计划排程管理生产调度管理库存管理质量管理人力资源管理工作中心管理等多项企业管理功能
</p>
<p>
科伦普冷轧重工有限公司是设计年产量150万 能向广大用户提供热轧酸洗热轧镀锌冷硬罩式退火冷轧镀锌铝锌合金锌铝合金锌铝镁镀铬等各大类产品产品覆盖东北华北华东华南等地区
平台通过互联网技术实现企业数字化转型提高生产效率降低成本提升产品质量实现精益化生产管理
</p>
</div>
@@ -300,4 +299,4 @@ $--metal-gradient-light: linear-gradient(145deg, #f5f5f550, #ffffff50);
color: $--color-text-secondary; // 浅灰色文字
}
}
</style>
</style>

View File

@@ -15,16 +15,6 @@
<!-- 搜索栏 -->
<el-form :model="materialQueryParams" ref="materialQueryForm" size="small" :inline="true" class="query-form">
<el-form-item label="钢卷类型" prop="dataType">
<el-select v-model="coilType" placeholder="请选择钢卷类型">
<el-option label="全部" value="all" />
<el-option label="当前钢卷" value="now" />
<el-option label="历史钢卷" value="history" />
<el-option label="已发货钢卷" value="trans" />
<el-option label="未入库钢卷" value="unIn" />
</el-select>
</el-form-item>
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="materialQueryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable
@keyup.enter.native="handleMaterialQuery" style="width: 150px;" />
@@ -33,14 +23,9 @@
<el-input v-model="materialQueryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
@keyup.enter.native="handleMaterialQuery" style="width: 150px;" />
</el-form-item>
<el-form-item label="逻辑库区" prop="warehouseId">
<warehouse-select v-model="materialQueryParams.warehouseId" placeholder="请选择逻辑库区" clearable
@keyup.enter.native="handleMaterialQuery" style="width: 150px;" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleMaterialQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetMaterialQuery">重置</el-button>
<el-button type="success" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-form-item>
</el-form>
@@ -150,14 +135,6 @@
<span class="param-label">长度</span>
<span class="param-value">{{ item.length }}</span>
</div>
<div class="param-row" v-if="item.actualLength">
<span class="param-label">实测长度</span>
<span class="param-value">{{ item.actualLength }}</span>
</div>
<div class="param-row" v-if="item.actualWidth">
<span class="param-label">实测宽度</span>
<span class="param-value">{{ item.actualWidth }}</span>
</div>
<div class="param-row" v-if="item.temperGrade">
<span class="param-label">调制度</span>
<span class="param-value">{{ item.temperGrade }}</span>
@@ -184,13 +161,11 @@
</div>
</div>
</div>
</div>
</div>
<i slot="reference" class="el-icon-setting param-icon"></i>
</el-popover>
<i class="el-icon-view param-icon" @click="handlePreviewLabel(item)" title="查看标签"></i>
<i class="el-icon-time param-icon" @click="handleTrace(item)" title="追溯"></i>
</div>
</div>
@@ -222,13 +197,9 @@
style="position: absolute; bottom: 10px; right: 10px;" type="success" icon="el-icon-refresh"
size="mini" @click="handleRestoreMaterial(item)" :loading="item.cancelling"
class="action-btn">回滚</el-button>
<el-button v-if="item.dataType == 10 && item.status == 0"
style="position: absolute; bottom: 10px; right: 10px;" type="success" icon="el-icon-refresh"
size="mini" @click="handleForceInMaterial(item)" :loading="item.cancelling"
class="action-btn">强制入库</el-button>
</div>
<div class="card-footer">
<div class="card-footer" v-if="item.dataType != 10">
<el-button type="primary" icon="el-icon-check" size="mini" @click="handleCorrectMaterial(item)"
:loading="item.picking" class="action-btn">修正</el-button>
<el-button type="danger" icon="el-icon-delete" size="mini" @click="hanleDeleteMaterial(item)"
@@ -288,7 +259,7 @@
<label-render :content="labelRender.data" :labelType="labelRender.type" />
</el-dialog>
<el-dialog :title="title" :visible.sync="correctVisible" width="600px">
<el-dialog title="钢卷信息修正" :visible.sync="correctVisible" width="600px">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="form.enterCoilNo" placeholder="请输入入场钢卷号" :disabled="form.coilId" />
@@ -360,14 +331,6 @@
<el-form-item label="长度" prop="length">
<el-input v-model="form.length" placeholder="请输入长度" />
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="form.actualLength" placeholder="请输入实测长度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth">
<el-input-number :controls="false" v-model="form.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="form.temperGrade" placeholder="请输入调制度" />
</el-form-item>
@@ -377,11 +340,11 @@
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="创建时间" prop="createTime" v-if="form.coilId">
<el-form-item label="创建时间" prop="createTime">
<el-date-picker v-model="form.createTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择创建时间" style="width: 100%;" />
</el-form-item>
<el-form-item label="创建人" prop="createBy" v-if="form.coilId">
<el-form-item label="创建人" prop="createBy">
<el-select v-model="form.createBy" placeholder="请选择创建人" style="width: 100%;" clearable filterable>
<el-option v-for="item in userList" :key="item.userName" :label="item.nickName" :value="item.userName" />
</el-select>
@@ -393,16 +356,11 @@
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 钢卷追溯对话框使用封装的组件 -->
<el-dialog title="钢卷追溯" :visible.sync="traceOpen" width="90%" append-to-body>
<coil-trace-result v-loading="traceLoading" :trace-result="traceResult"></coil-trace-result>
</el-dialog>
</div>
</template>
<script>
import { listMaterialCoil, getMaterialCoilTrace, updateMaterialCoilSimple, checkCoilNo, delMaterialCoil, restoreMaterialCoil, addMaterialCoil } from '@/api/wms/coil'
import { listMaterialCoil, updateMaterialCoilSimple, checkCoilNo, delMaterialCoil, restoreMaterialCoil } from '@/api/wms/coil'
import { listUser } from '@/api/system/user'
import { listPendingAction, startProcess, cancelAction, delPendingAction } from '@/api/wms/pendingAction'
import { parseTime } from '@/utils/klp'
@@ -414,7 +372,6 @@ import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import ProductSelect from "@/components/KLPService/ProductSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
import CoilTraceResult from "../panels/CoilTraceResult.vue";
export default {
name: 'DoPage',
@@ -437,16 +394,9 @@ export default {
ActualWarehouseSelect,
ProductSelect,
RawMaterialSelect,
CoilTraceResult,
},
data() {
return {
traceOpen: false,
traceLoading: false,
traceResult: null,
coilType: 'all',
title: '钢卷信息修正',
// 物料列表相关
materialLoading: false,
materialCoilList: [],
@@ -458,8 +408,7 @@ export default {
// dataType: 1,
// status: 0,
enterCoilNo: null,
currentCoilNo: null,
warehouseId: null,
currentCoilNo: null
},
labelRender: {
visible: false,
@@ -642,61 +591,6 @@ export default {
},
methods: {
parseTime,
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.correctVisible = true;
this.title = "添加钢卷物料";
},
/** 追溯按钮操作 */
handleTrace(row) {
this.traceOpen = true;
this.traceLoading = true;
this.traceResult = null; // 清空历史数据
getMaterialCoilTrace({
coilId: row.coilId,
currentCoilNo: row.currentCoilNo,
}).then(res => {
this.traceResult = res.data; // 将结果传递给组件
}).catch(err => {
console.error('溯源查询失败:', err);
this.$message.error('溯源查询失败,请重试');
}).finally(() => {
this.traceLoading = false;
});
},
// 表单重置
reset() {
this.form = {
coilId: undefined,
enterCoilNo: undefined,
currentCoilNo: undefined,
supplierCoilNo: undefined,
dataType: 1,
warehouseId: undefined,
nextWarehouseId: undefined,
qrcodeRecordId: undefined,
actualWarehouseId: undefined,
team: undefined,
hasMergeSplit: undefined,
parentCoilNos: undefined,
itemId: undefined,
itemType: undefined,
status: undefined,
remark: undefined,
delFlag: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined,
materialType: '原料',
temperGrade: undefined,
coatingType: undefined,
actualLength: undefined,
actualWidth: undefined,
};
this.resetForm("form");
},
getBorderStyle(row) {
// console.log(row);
// 已发货
@@ -781,39 +675,9 @@ export default {
})
})
},
handleForceInMaterial(row) {
this.$modal.confirm('是否要强制入库改钢卷?').then(_ => {
const loading = this.$loading({
lock: true,
text: '处理中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
updateMaterialCoilSimple({
...row,
dataType: 1,
}).then(_ => {
this.$modal.msgSuccess("强制入库成功");
this.getMaterialCoil();
}).finally(() => {
loading.close()
})
})
},
getMaterialCoil() {
this.materialLoading = true
const payload = { ...this.materialQueryParams }
if (this.coilType == 'now') {
payload.dataType = 1;
payload.status = 0;
} else if (this.coilType == 'history') {
payload.dataType = 0;
} else if (this.coilType == 'trans') {
payload.status = 1;
} else if (this.coilType == 'unIn') {
payload.dataType = 10;
}
listMaterialCoil(payload).then(response => {
listMaterialCoil(this.materialQueryParams).then(response => {
this.materialCoilList = response.rows || []
this.materialTotal = response.total || 0
this.materialLoading = false
@@ -863,8 +727,7 @@ export default {
handleCorrectMaterial(row) {
this.form = {
...row,
};
this.title = "钢卷信息修正";
}
this.correctVisible = true
},
cancel() {
@@ -878,25 +741,13 @@ export default {
return
}
this.buttonLoading = true;
if (this.form.coilId) {
// 更新
updateMaterialCoilSimple(this.form).then(_ => {
this.$modal.msgSuccess("修正成功");
this.correctVisible = false;
this.getMaterialCoil();
}).finally(() => {
this.buttonLoading = false;
});
} else {
// 新增
addMaterialCoil(this.form).then(_ => {
this.$modal.msgSuccess("新增成功");
this.correctVisible = false;
this.getMaterialCoil();
}).finally(() => {
this.buttonLoading = false;
});
}
updateMaterialCoilSimple(this.form).then(_ => {
this.$modal.msgSuccess("修正成功");
this.correctVisible = false;
this.getMaterialCoil();
}).finally(() => {
this.buttonLoading = false;
});
})
},
/** 删除按钮操作 */

View File

@@ -32,7 +32,6 @@
'镀锌工序': [
{value: '1988150263284953089', label: '镀锌原料库'},
{value: '1988150323162836993', label: '镀锌成品库'},
{value: '1988150487185289217', label: '镀锌纵剪分条原料库'},
],
'脱脂工序': [
{value: '1988150545175736322', label: '脱脂原料库'},
@@ -54,16 +53,9 @@
{value: '1988151076996706306', label: '镀铬原料库'},
{value: '1988151132361519105', label: '镀铬成品库'},
],
'纵剪分条工序': [
{value: '', label: '原料库'},
{value: '1988150210872930306', label: '酸连轧分条成品'},
{value: '1988150800092950529', label: '退火分条成品'},
{value: '1988150380649967617', label: '镀锌分条成品'},
{value: '1988151027466170370', label: '拉矫分条成品'},
],
}
if (this.actionType === '镀锌工序' || this.actionType === '脱脂工序' || this.actionType === '拉矫平整工序' || this.actionType === '双机架工序' || this.actionType === '镀铬工序' || this.actionType === '纵剪分条工序') {
if (this.actionType === '镀锌工序') {
this.useSpecialSplit = true
}
// 从map中获取默认的查询参数

View File

@@ -35,7 +35,7 @@
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="厂家原料卷号" prop="supplierCoilNo">
<el-form-item v-if="!form.coilId" label="厂家原料卷号" prop="supplierCoilNo">
<el-input v-model="form.supplierCoilNo" placeholder="请输入厂家原料卷号" />
</el-form-item>
</el-col>
@@ -457,29 +457,6 @@ export default {
// }, trigger: 'blur'
// },
],
supplierCoilNo: [
{ required: true, message: "厂家原料卷号不能为空", trigger: "blur" },
// 远程校验,检查钢卷号是否存在
{
validator: (rule, value, callback) => {
if (this.form.coilId) {
// 新增时触发校验
console.log('编辑时不触发校验');
callback();
} else {
checkCoilNo({ supplierCoilNo: value }).then(res => {
const { duplicateType } = res.data;
if (duplicateType === 'supplier' || duplicateType === 'both') {
// alert('厂家原料卷号重复,请重新输入');
callback(new Error('厂家原料卷号重复,请重新输入'));
} else {
callback();
}
})
}
}, trigger: 'blur'
},
],
materialType: [
{ required: true, message: "材料类型不能为空", trigger: "change" }
],
@@ -747,11 +724,11 @@ export default {
}
delPendingAction(row.actionId).then(response => {
this.$modal.msgSuccess("删除成功");
// delCoilWarehouseOperationLogByCoilId({
// coilId: row.coilId,
// operationType: 1,
// inOutType: 1
// })
delCoilWarehouseOperationLogByCoilId({
coilId: row.coilId,
operationType: 1,
inOutType: 1
})
this.getList();
}).finally(() => {
this.buttonLoading = false;

View File

@@ -1,759 +0,0 @@
<template>
<div class="app-container">
<!-- 搜索栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="钢卷号" prop="currentCoilNo">
<el-input v-model="queryParams.currentCoilNo" placeholder="请输入钢卷号" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="操作类型" prop="actionType">
<el-select v-model="queryParams.actionType" placeholder="请选择操作类型" clearable filterable>
<el-option v-for="item in dict.type.action_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<!-- <el-form-item label="只看待操作" prop="actionStatus">
<el-switch @change="switchActionStatus" v-model="queryParams.actionSwitch" />
</el-form-item> -->
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-refresh" size="mini" @click="handleRefresh"
:disabled="buttonLoading" v-loading="buttonLoading">刷新</el-button>
</el-col>
<el-col :span="3">
<el-checkbox v-model="rubbish" label="1" @change="getList">查看被删除操作</el-checkbox>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 -->
<el-table v-loading="loading" :data="actionList" @selection-change="handleSelectionChange"
:row-class-name="tableRowClassName">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="序号" type="index" width="60" align="center" /> -->
<el-table-column label="钢卷号" align="center" prop="currentCoilNo">
<template slot-scope="scope">
<coil-no :coil-no="scope.row.currentCoilNo"></coil-no>
</template>
</el-table-column>
<el-table-column label="操作类型" align="center" prop="actionType" width="160">
<template slot-scope="scope">
<span v-if="scope.row.actionType === 401">入库/收货操作</span>
<span v-else-if="scope.row.actionType === 402">发货操作</span>
<span v-else-if="scope.row.actionType === 403">移库操作</span>
<span v-else-if="scope.row.actionType === 404">通过库区编辑钢卷</span>
<span v-else-if="scope.row.actionType === 405">钢卷打包</span>
<dict-tag v-else :options='dict.type.action_type' :value="scope.row.actionType"></dict-tag>
</template>
</el-table-column>
<el-table-column label="操作状态" align="center" prop="actionStatus" width="120">
<template slot-scope="scope">
<el-select v-model="scope.row.actionStatus" placeholder="请选择操作状态" @change="handleStatusChange(scope.row)">
<el-option label="待处理" :value="0" />
<el-option label="处理中" :value="1" />
<el-option label="已完成" :value="2" />
<el-option label="已取消" :value="3" />
</el-select>
<!-- <el-tag v-if="scope.row.actionStatus === 0" type="info" size="small">待处理</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 1" type="warning" size="small">处理中</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 2" type="success" size="small">已完成</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 3" type="danger" size="small">已取消</el-tag> -->
</template>
</el-table-column>
<el-table-column label="优先级" align="center" prop="priority" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.priority === 0" type="info" size="mini">普通</el-tag>
<el-tag v-else-if="scope.row.priority === 1" type="warning" size="mini">重要</el-tag>
<el-tag v-else-if="scope.row.priority === 2" type="danger" size="mini">紧急</el-tag>
</template>
</el-table-column>
<el-table-column label="来源" align="center" prop="sourceType" width="80">
<template slot-scope="scope">
<el-tag v-if="scope.row.sourceType === 'scan'" type="success" size="mini">
<i class="el-icon-mobile"></i> 扫码
</el-tag>
<el-tag v-else type="info" size="mini">
<i class="el-icon-edit-outline"></i> 手动
</el-tag>
</template>
</el-table-column>
<el-table-column label="新增时间" align="center" prop="createTime" width="155" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建人" align="center" prop="createByName" width="100" />
<el-table-column label="操作人" align="center" prop="updateBy" width="100" />
<el-table-column label="完成时间" align="center" prop="completeTime" width="220" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-date-picker @change="handleProcessTimeChange(scope.row)" value-format="yyyy-MM-dd HH:mm:ss" style="width: 200px" v-model="scope.row.completeTime" type="datetime" placeholder="选择完成时间" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width" fixed="right">
<template slot-scope="scope">
<!-- 待处理状态显示操作按钮 -->
<!-- <template v-if="scope.row.actionStatus === 0">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="handleProcess(scope.row)"
v-loading="buttonLoading" :disabled="buttonLoading">操作</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
</template> -->
<!-- 处理中状态显示继续按钮 -->
<!-- <template v-else-if="scope.row.actionStatus === 1">
<el-button size="mini" type="warning" icon="el-icon-edit" @click="handleProcess(scope.row)"
:disabled="buttonLoading" v-loading="buttonLoading">继续</el-button>
<el-button size="mini" type="info" icon="el-icon-close" @click="handleCancel(scope.row)">取消</el-button>
</template> -->
<!-- 已完成或已取消状态显示删除按钮 -->
<template v-if="scope.row.actionStatus === 2 || scope.row.actionStatus === 3">
<el-button v-if="scope.row.delFlag == 0" size="mini" type="danger" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
<el-button v-if="scope.row.delFlag == 2" size="mini" type="success" icon="el-icon-refresh" @click="handleRestore(scope.row)">还原</el-button>
</template>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 添加或修改对话框 -->
<el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="钢卷" prop="coilId">
<coil-selector v-model="form.coilId" :use-trigger="true" @select="handleCoilSelect" />
</el-form-item>
<el-form-item label="操作类型" prop="actionType">
<div class="action-type-cards">
<!-- 分条操作区 -->
<div class="card-section" v-if="splitTypes.length > 0">
<div class="section-title">分条操作</div>
<div class="action-cards-row">
<div v-for="item in splitTypes" :key="item.value" class="action-card split-card"
:class="{ 'active': form.actionType == item.value }" @click="form.actionType = parseInt(item.value)">
<div class="card-icon">
<i :class="getActionIcon(item.value)"></i>
</div>
<div class="card-content">
<div class="card-title">{{ item.label }}</div>
<div class="card-desc">{{ item.remark || '钢卷分条操作' }}</div>
</div>
</div>
</div>
</div>
<!-- 其他操作区 -->
<div class="card-section" v-if="otherTypes.length > 0">
<div class="section-title">其他操作</div>
<div class="action-cards-row">
<div v-for="item in otherTypes" :key="item.value" class="action-card"
:class="{ 'active': form.actionType == item.value }" @click="form.actionType = parseInt(item.value)">
<div class="card-icon">
<i :class="getActionIcon(item.value)"></i>
</div>
<div class="card-content">
<div class="card-title">{{ item.label }}</div>
<div class="card-desc">{{ item.remark || '钢卷操作' }}</div>
</div>
</div>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-select v-model="form.priority" placeholder="请选择优先级">
<el-option label="普通" :value="0" />
<el-option label="重要" :value="1" />
<el-option label="紧急" :value="2" />
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm" :disabled="buttonLoading" v-loading="buttonLoading"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
listPendingAction,
getPendingAction,
delPendingAction,
addPendingAction,
updatePendingAction,
startProcess,
cancelAction,
restorePendingAction,
} from '@/api/wms/pendingAction';
import CoilSelector from '@/components/CoilSelector';
import CoilNo from '@/components/KLPService/Renderer/CoilNo.vue';
export default {
name: 'CoilActflow',
dicts: ['action_type'],
components: {
CoilSelector,
CoilNo
},
data() {
return {
// 遮罩层
loading: true,
buttonLoading: false,
rubbish: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 待操作列表数据
actionList: [],
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
currentCoilNo: null,
actionType: null,
actionStatus: null, // 默认查询待处理
priority: null
},
// 表单参数
form: {},
// 表单校验
rules: {
coilId: [
{ required: true, message: '请选择钢卷', trigger: 'blur' }
],
actionType: [
{ required: true, message: '请选择操作类型', trigger: 'change' }
]
},
// 钢卷选择器可见性
coilSelectorVisible: false
};
},
computed: {
// 分条操作列表100-199
splitTypes() {
if (!this.dict.type.action_type) return [];
return this.dict.type.action_type.filter(item => {
const value = parseInt(item.value);
return value >= 100 && value <= 199;
});
},
// 其他操作列表200-299等
otherTypes() {
if (!this.dict.type.action_type) return [];
return this.dict.type.action_type.filter(item => {
const value = parseInt(item.value);
return value < 100 || value > 199;
});
}
},
created() {
this.getList();
// 设置定时刷新(可选,用于移动端扫码后自动刷新)
this.startAutoRefresh();
},
beforeDestroy() {
// 清除定时器
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
}
},
methods: {
/** 查询待操作列表 */
getList() {
this.loading = true;
this.buttonLoading = true;
const payload = {
...this.queryParams,
includeDeleted: this.rubbish ? 2 : 0
}
listPendingAction(payload).then(response => {
console.log('response.rows', response.rows);
this.actionList = response.rows;
this.total = response.total;
this.buttonLoading = false;
this.loading = false;
});
},
switchActionStatus(value) {
console.log(value)
if (!value) {
this.queryParams.actionStatus = null;
} else {
this.queryParams.actionStatus = '-1';
}
this.getList()
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
actionId: null,
coilId: null,
currentCoilNo: null,
actionType: null,
actionStatus: null,
priority: 0,
sourceType: 'manual',
remark: null
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
handleStatusChange(row) {
// console.log(row)
updatePendingAction(row).then(response => {
this.$message.success('操作状态更新成功');
this.getList();
});
},
/** 还原按钮操作 */
handleRestore(row) {
const actionId = row.actionId;
this.$modal.confirm('是否确认还原该待操作记录?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
restorePendingAction(actionId).then(response => {
this.$message.success('还原成功');
this.getList();
});
});
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.actionId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加待操作';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const actionId = row.actionId || this.ids;
getPendingAction(actionId).then(response => {
this.form = response.data;
this.open = true;
this.title = '修改待操作';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.actionId != null) {
updatePendingAction(this.form).then(response => {
this.$message.success('修改成功');
this.open = false;
this.getList();
this.buttonLoading = false;
});
} else {
addPendingAction(this.form).then(response => {
this.$message.success('新增成功');
this.open = false;
this.getList();
this.buttonLoading = false;
});
}
}
});
},
/** 完成时间改变时触发 */
handleProcessTimeChange(row) {
console.log('完成时间改变:', row);
updatePendingAction(row).then(response => {
this.$message.success('更新成功');
});
},
/** 删除按钮操作 */
handleDelete(row) {
const actionIds = row.actionId || this.ids;
this.$confirm('是否确认删除该待操作记录?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return delPendingAction(actionIds);
}).then(() => {
this.getList();
this.$message.success('删除成功');
}).catch(() => { });
},
/** 处理操作 - 跳转到对应页面 */
handleProcess(row) {
console.log('=== 开始处理操作 ===');
console.log('待操作记录:', row);
console.log('操作类型:', row.actionType);
console.log('钢卷ID:', row.coilId);
this.buttonLoading = true;
this.$forceUpdate();
const actionType = parseInt(row.actionType);
// 特殊处理:发货和移库操作不需要跳转
if (actionType === 4 || actionType === 5 || actionType === 401 || actionType === 402) {
this.$message.info(actionType === 4 ? '发货操作已在移动端完成' : '移库操作已在移动端完成');
this.buttonLoading = false;
return;
}
// 根据操作类型跳转到不同页面
let path = '';
// 分条操作100-199
if (actionType >= 100 && actionType <= 199) {
path = '/wms/split';
}
// 合卷操作200-299
else if (actionType == 200) {
path = '/wms/merge';
}
else if (actionType < 100) {
path = '/wms/typing';
}
// 其他操作类型
else {
this.$message.error('特殊操作请到专门的页面进行处理');
this.buttonLoading = false;
return;
}
if (!path) {
this.$message.error('未知的操作类型: ' + row.actionType);
this.buttonLoading = false;
return;
}
// 更新状态为处理中
console.log('调用startProcessactionId:', row.actionId);
startProcess(row.actionId).then(response => {
console.log('开始处理响应:', response);
if (response.code !== 200) {
this.$message.error(response.msg || '更新状态失败');
return;
}
// 跳转并传递参数
console.log('准备跳转到:', path, '参数:', { coilId: row.coilId, actionId: row.actionId });
this.$router.push({
path: path,
query: {
coilId: row.coilId,
actionId: row.actionId
}
});
this.buttonLoading = false;
}).catch(error => {
console.error('更新状态失败:', error);
this.$message.error('更新状态失败: ' + (error.message || error));
}).finally(() => {
this.buttonLoading = false;
});
},
/** 取消操作 */
handleCancel(row) {
this.$confirm('是否确认取消该操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return cancelAction(row.actionId);
}).then(() => {
this.$message.success('操作已取消');
this.getList();
}).catch(() => { });
},
/** 刷新列表 */
handleRefresh() {
this.getList();
this.$message.success('刷新成功');
},
/** 自动刷新 */
startAutoRefresh() {
// 每30秒自动刷新一次用于移动端扫码后自动更新列表
this.refreshTimer = setInterval(() => {
// 只在查看待处理状态时自动刷新
this.getList();
}, 30000);
},
/** 表格行样式 */
tableRowClassName({ row }) {
if (row.priority === 2) {
return 'urgent-row';
} else if (row.priority === 1) {
return 'important-row';
}
return '';
},
/** 显示钢卷选择器 */
showCoilSelector() {
this.coilSelectorVisible = true;
},
/** 钢卷选择回调 */
handleCoilSelect(coil) {
this.form.coilId = coil.coilId;
this.form.currentCoilNo = coil.currentCoilNo;
},
/** 获取状态文本 */
getStatusText(status) {
const statusMap = {
0: '待处理',
1: '处理中',
2: '已完成',
3: '已取消'
};
return statusMap[status] || '未知';
},
/** 根据操作类型获取图标 */
getActionIcon(actionType) {
const value = parseInt(actionType);
const iconMap = {
1: 'el-icon-connection', // 合卷
2: 'el-icon-s-operation', // 分条
3: 'el-icon-edit', // 更新
4: 'el-icon-truck', // 发货
5: 'el-icon-s-grid', // 移库
101: 'el-icon-scissors', // 纵剪分条
102: 'el-icon-s-operation', // 横切分条
103: 'el-icon-s-unfold' // 开卷分条
};
return iconMap[value] || 'el-icon-s-operation';
}
}
};
</script>
<style scoped lang="scss">
.app-container {
::v-deep .urgent-row {
background: #fef0f0 !important;
}
::v-deep .important-row {
background: #fdf6ec !important;
}
// 优化按钮文字颜色
// 实心按钮:白色文字(在深色背景上清晰可见)
::v-deep .el-button--primary.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--danger.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--warning.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--info.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--success.el-button--mini:not(.is-plain) {
color: #fff;
}
// plain按钮同色系深色文字在浅色背景上
::v-deep .el-button--primary.el-button--mini.is-plain {
color: #409eff;
}
::v-deep .el-button--danger.el-button--mini.is-plain {
color: #f56c6c;
}
::v-deep .el-button--warning.el-button--mini.is-plain {
color: #e6a23c;
}
}
/* 操作类型卡片样式 */
.action-type-cards {
width: 100%;
.card-section {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
}
.section-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-left: 8px;
border-left: 3px solid #409eff;
}
// 分条操作区域的特殊样式
.card-section:first-child .section-title {
border-left-color: #e6a23c;
}
.action-cards-row {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 12px;
}
.action-card {
min-width: 0;
padding: 16px;
border: 2px solid #dcdfe6;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
background: #fff;
display: flex;
align-items: center;
gap: 12px;
&:hover {
border-color: #409eff;
box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.15);
transform: translateY(-2px);
}
&.active {
border-color: #409eff;
background: linear-gradient(135deg, #e3f2fd 0%, #f0f7ff 100%);
box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.3);
.card-icon {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
color: #fff;
}
.card-title {
color: #409eff;
font-weight: 600;
}
}
&.split-card {
&.active {
background: linear-gradient(135deg, #fff3e0 0%, #fff8f0 100%);
border-color: #e6a23c;
.card-icon {
background: linear-gradient(135deg, #e6a23c 0%, #f0ad4e 100%);
}
.card-title {
color: #e6a23c;
}
}
&:hover {
border-color: #e6a23c;
box-shadow: 0 2px 12px 0 rgba(230, 162, 60, 0.15);
}
}
}
.card-icon {
width: 48px;
height: 48px;
border-radius: 8px;
background: #f5f7fa;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: #909399;
transition: all 0.3s ease;
flex-shrink: 0;
}
.card-content {
flex: 1;
}
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-bottom: 4px;
transition: all 0.3s ease;
}
.card-desc {
font-size: 13px;
color: #909399;
line-height: 1.4;
}
}
</style>

View File

@@ -50,16 +50,10 @@ export const actionStrategies = {
handler: async (coil, action) => {
// 更新操作记录状态 actionStatus: 2
// 并行执行更新操作记录和更新钢卷状态
// 将日期格式化为yyyy-MM-dd HH:mm:ss
const completeTime = new Date()
function parseDate(date) {
return date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds()
}
await Promise.all([
updatePendingAction({
...action,
actionStatus: 2,
completeTime: parseDate(completeTime),
}),
updateMaterialCoilSimple({
...coil,

View File

@@ -189,18 +189,6 @@
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="targetCoil.actualLength" placeholder="请输入实测长度" type="number"
:step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth">
<el-input-number :controls="false" v-model="targetCoil.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="targetCoil.temperGrade" placeholder="请输入调制度" />
</el-form-item>
@@ -275,8 +263,6 @@ export default {
length: null,
temperGrade: '',
coatingType: '',
actualLength: undefined,
actualWidth: undefined,
},
buttonLoading: false,
loading: false,

View File

@@ -1,13 +0,0 @@
<template>
<div>
酸轧合卷
</div>
</template>
<script>
</script>
<style>
</style>

View File

@@ -114,7 +114,7 @@
Jiaxiang County,Jining City,Shandong Province</span>
<br />
<span>
TEL19053728822 19053728835
TEL0537-6625068 0537-6625067
</span>
</div>
<div class="contact-timestamp">

View File

@@ -1,291 +0,0 @@
<template>
<div class="label-container" :style="{ '--print-scale': printScale }">
<div class="material-label-grid">
<!-- 公司名称行 -->
<div class="grid-cell company-cell">嘉祥科伦普重工有限公司</div>
<!-- 第一行冷卷号热卷号 -->
<div class="grid-cell label-cell">冷卷号</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.currentCoilNo || '' }}</div>
</div>
<div class="grid-cell label-cell">热卷号</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.enterCoilNo || '' }}</div>
</div>
<!-- 第二行规格钢种 -->
<div class="grid-cell label-cell">规格</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.specification || '' }}</div>
</div>
<div class="grid-cell label-cell">钢种</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.material || '' }}</div>
</div>
<!-- 第三行净重下工序 -->
<div class="grid-cell label-cell">净重</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.netWeight || '' }}</div>
</div>
<div class="grid-cell label-cell">下工序</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.nextProcess || '冷轧' }}</div>
</div>
<!-- 第四行包装要求切边要求 -->
<div class="grid-cell label-cell">包装要求</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.packagingRequirement || '' }}</div>
</div>
<div class="grid-cell label-cell">切边要求</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.trimmingRequirement || '' }}</div>
</div>
<!-- 第五行班组代码二维码 -->
<div class="grid-cell label-cell">班组</div>
<div class="grid-cell value-cell">
<div class="nob" contenteditable>{{ content.team || '' }}</div>
</div>
<div class="grid-cell label-cell">代码</div>
<div class="grid-cell qrcode-cell">
<!-- 二维码容器 -->
<QRCode :content="content.qrcodeRecordId" :size="80"/>
</div>
<!-- 第六行生产日期 -->
<div class="grid-cell label-cell">生产日期</div>
<div class="grid-cell value-cell date-cell">
<div class="nob" contenteditable>{{ content.createTime || '' }}</div>
</div>
</div>
</div>
</template>
<script>
import QRCode from '@/components/QRCode/index.vue';
export default {
name: 'ZincRawTag',
components: {
QRCode
},
props: {
content: {
type: Object,
default: () => ({
currentCoilNo: '',
entryCoilNo: '',
specification: '',
material: '',
netWeight: '',
nextProcess: '',
packagingRequirements: '',
trimmingRequirements: '',
team: '',
createTime: '',
qrcodeRecordId: '',
})
},
paperWidthMm: {
type: Number,
default: 100
},
paperHeightMm: {
type: Number,
default: 80
}
},
data() {
return {
printScale: 1,
printMediaQuery: null
}
},
mounted() {
this.printMediaQuery = window.matchMedia('print');
this.printMediaQuery.addListener(this.handlePrintMediaChange);
window.addEventListener('beforeprint', this.handleBeforePrint);
window.addEventListener('afterprint', this.handleAfterPrint);
this.$nextTick(() => {
this.calculatePrintScale();
});
},
beforeDestroy() {
if (this.printMediaQuery) {
this.printMediaQuery.removeListener(this.handlePrintMediaChange);
}
window.removeEventListener('beforeprint', this.handleBeforePrint);
window.removeEventListener('afterprint', this.handleAfterPrint);
},
methods: {
handlePrintMediaChange(mq) {
mq.matches ? this.calculatePrintScale() : this.resetPrintScale();
},
handleBeforePrint() {
setTimeout(() => this.calculatePrintScale(), 100);
},
handleAfterPrint() {
this.resetPrintScale();
},
calculatePrintScale() {
this.$nextTick(() => {
const container = this.$el;
if (!container) return;
const dpi = 96;
const mmToPx = dpi / 25.4;
const paperWidthPx = this.paperWidthMm * mmToPx;
const paperHeightPx = this.paperHeightMm * mmToPx;
const marginPx = 2 * mmToPx;
const rect = container.getBoundingClientRect();
const contentWidth = rect.width || container.scrollWidth;
const contentHeight = rect.height || container.scrollHeight;
const availableWidth = paperWidthPx - marginPx * 2;
const availableHeight = paperHeightPx - marginPx * 2;
const scaleX = contentWidth > 0 ? availableWidth / contentWidth : 1;
const scaleY = contentHeight > 0 ? availableHeight / contentHeight : 1;
this.printScale = Math.min(scaleX, scaleY, 1);
container.style.setProperty('--print-scale', this.printScale);
container.style.setProperty('--paper-width', `${this.paperWidthMm}mm`);
container.style.setProperty('--paper-height', `${this.paperHeightMm}mm`);
});
},
resetPrintScale() {
this.printScale = 1;
if (this.$el) {
this.$el.style.setProperty('--print-scale', 1);
this.$el.style.removeProperty('--paper-width');
this.$el.style.removeProperty('--paper-height');
}
}
}
}
</script>
<style scoped>
.label-container {
width: 45em;
height: 25em;
padding: 16px;
font-family: "SimSun", serif;
box-sizing: border-box;
}
/* 核心Grid布局 */
.material-label-grid {
display: grid;
grid-template-columns: repeat(4, 1fr); /* 4列等宽 */
grid-auto-rows: 1fr; /* 行高自适应 */
width: 100%;
height: 100%;
border: 1px solid #333;
box-sizing: border-box;
}
.grid-cell {
border: 1px solid #333;
padding: 4px;
font-size: 20px;
box-sizing: border-box;
text-align: center;
word-break: break-all;
overflow-wrap: break-word;
display: flex;
align-items: center;
justify-content: center;
}
/* 公司名称单元格 */
.company-cell {
grid-column: span 4; /* 跨4列 */
font-size: 24px;
font-weight: bold;
/* background-color: #f5f5f5; */
}
/* 标签单元格(左) */
.label-cell {
/* background-color: #f5f5f5; */
font-weight: bold;
}
/* 值单元格 */
.value-cell {
text-align: center;
font-weight: bold;
}
.date-cell {
grid-column: span 2;
}
/* 二维码单元格跨2列+2行 */
.qrcode-cell {
grid-row: span 2; /* 跨2行 */
display: flex;
align-items: center;
justify-content: center;
}
.qrcode-container {
width: 80%;
height: 80%;
border: 1px dashed #999; /* 占位虚线 */
}
/* 内容可编辑区域 */
.nob {
width: 100%;
height: 100%;
border: none;
outline: none;
background: transparent;
text-align: center;
font-size: inherit;
word-break: break-all;
display: flex;
align-items: center;
justify-content: center;
}
/* 打印样式 */
@media print {
@page {
size: 100mm 80mm;
margin: 0 !important;
}
* {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
}
html,
body {
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
body>*:not(.label-container) {
display: none !important;
}
.label-container {
page-break-inside: avoid !important;
break-inside: avoid !important;
transform: scale(var(--print-scale, 1)) !important;
transform-origin: top left !important;
max-width: var(--paper-width, 100mm) !important;
max-height: var(--paper-height, 80mm) !important;
overflow: hidden !important;
}
}
</style>

View File

@@ -36,13 +36,7 @@
v-if="tagType === 'ge'"
:content="content"
:paperWidthMm="180"
:paperHeightMm="100"
/>
<TuoZhiTag
v-if="tagType === '6'"
:content="content"
:paperWidthMm="180"
:paperHeightMm="100"
:paperHeightMm="80"
/>
<!-- <SampleTagPreview v-if="labelType === '4'" :content="content" />
<ForgeTagPreview v-if="labelType === '5'" :content="content" />
@@ -67,8 +61,6 @@ import GalvanizedTag from './GalvanizedTag.vue';
import WhereTag from './WhereTag.vue';
import ZincRawTag from './ZincRawTag.vue';
import DuGeTag from './DuGeTag.vue';
import TuoZhiTag from './TuoZhiTag.vue';
// import SampleTagPreview from './SampleTagPreview.vue';
// import ForgeTagPreview from './ForgeTagPreview.vue';
@@ -83,7 +75,6 @@ export default {
WhereTag,
ZincRawTag,
DuGeTag,
TuoZhiTag,
// SampleTagPreview,
// ForgeTagPreview,
// SaltSprayTagPreview,
@@ -116,10 +107,6 @@ export default {
width: 180,
height: 100,
},
'6': {
width: 180,
height: 100,
},
}
}
},
@@ -154,12 +141,8 @@ export default {
handler(newVal) {
const { itemName, itemType, warehouseId } = newVal;
// 在镀锌颜料库的卷使用镀锌原料标签
if (itemType == 'raw_material' && (warehouseId == '1988150263284953089' || warehouseId == '1988150487185289217')) {
if (itemType == 'raw_material' && warehouseId == '1988150263284953089') {
this.labelType = '5';
}
// 脱脂原料库
else if (itemType == 'raw_material' && (warehouseId == '1988150545175736322')) {
this.labelType = '6';
} else if (itemType == 'raw_material') {
this.labelType = '2';
} else if (itemType == 'product' && itemName == '冷硬卷') {

View File

@@ -1,138 +0,0 @@
<template>
<div class="hot-zha-raw">
<!-- 使用 el-table 展示数据 -->
<el-table
v-loading="loading"
:data="processedData"
border
style="width: 100%;"
:header-cell-style="{background: '#f2f2f2', fontWeight: 600}"
>
<!-- 类别列 -->
<el-table-column
label="类别"
prop="category"
min-width="180"
align="left"
/>
<!-- 合并的净边表头 -->
<el-table-column
label="净边"
align="center"
>
<el-table-column
label="1000"
prop="width1000"
min-width="100"
align="center"
/>
<el-table-column
label="1200"
prop="width1200"
min-width="100"
align="center"
/>
<el-table-column
label="1220"
prop="width1220"
min-width="100"
align="center"
/>
<el-table-column
label="1250"
prop="width1250"
min-width="100"
align="center"
/>
</el-table-column>
<!-- 其他宽度及毛边列 -->
<el-table-column
label="其他宽度及毛边"
prop="otherWidth"
min-width="120"
align="center"
/>
<!-- 合计列 -->
<el-table-column
label="合计"
prop="total"
min-width="100"
align="center"
:cell-style="{fontWeight: 600, color: '#1890ff'}"
/>
</el-table>
<!-- 无数据提示el-table 自带空数据提示这里可保留统一样式 -->
<div v-if="!data || data.length === 0" class="empty-data">
暂无数据
</div>
</div>
</template>
<script>
export default {
name: 'HotZhaRaw',
props: {
data: {
type: Array,
default: () => []
}
},
data() {
return {
loading: false // 可根据实际需求控制加载状态
};
},
computed: {
processedData() {
if (!this.data || !Array.isArray(this.data)) {
return [];
}
console.log(this.data);
// 深拷贝避免修改原数据
return this.data;
}
},
methods: {
// el-table 专用的数字格式化方法
formatTableNumber(row, column) {
const num = row[column.prop];
if (num === null || num === undefined || num === '') return '0.000';
return Number(num).toFixed(3);
}
}
};
</script>
<style scoped>
.hot-zha-raw {
width: 100%;
min-height: 200px;
padding: 10px;
box-sizing: border-box;
}
.empty-data {
text-align: center;
padding: 40px;
color: #999;
font-size: 14px;
}
/* 覆盖 el-table 样式,保持视觉统一 */
:deep(.el-table) {
--el-table-header-text-color: #303133;
--el-table-row-hover-bg-color: #f8f9fa;
}
:deep(.el-table th) {
border-right: 1px solid #ddd;
}
:deep(.el-table td) {
border-right: 1px solid #ddd;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<div class="trim-statistics-table">
<el-table
:data="filteredTableData"
:data="tableData"
border
stripe
:span-method="objectSpanMethod"
@@ -15,7 +15,7 @@
align="center"
/>
<!-- 冷硬卷板净边料现货库存 独立表头组 -->
<!-- 冷硬卷板净边料现货库存 表头组 -->
<el-table-column
label="冷硬卷板净边料现货库存"
align="center"
@@ -27,19 +27,18 @@
<el-table-column label="数量(件)" prop="trimmedTotalCount" width="80" align="center" />
<el-table-column label="重量(吨)" prop="trimmedTotalWeight" width="80" align="center" />
</el-table-column>
<!-- 净边料独立宽度列合并后的分组 -->
<el-table-column
v-for="group in trimmedWidthGroups"
:key="'trimmed-' + group.key"
:label="group.label"
v-for="width in widthList"
:key="'trimmed-' + width"
:label="width"
align="center"
>
<el-table-column label="数量(件)" :prop="`trimmed_${group.key}_count`" width="80" align="center" />
<el-table-column label="重量(吨)" :prop="`trimmed_${group.key}_weight`" width="80" align="center" />
<el-table-column label="数量(件)" :prop="`trimmed_${width}_count`" width="80" align="center" />
<el-table-column label="重量(吨)" :prop="`trimmed_${width}_weight`" width="80" align="center" />
</el-table-column>
</el-table-column>
<!-- 冷硬卷板毛边料现货库存 独立表头组 -->
<!-- 冷硬卷板毛边料现货库存 表头组 -->
<el-table-column
label="冷硬卷板毛边料现货库存"
align="center"
@@ -51,15 +50,14 @@
<el-table-column label="数量(件)" prop="untrimmedTotalCount" width="80" align="center" />
<el-table-column label="重量(吨)" prop="untrimmedTotalWeight" width="80" align="center" />
</el-table-column>
<!-- 毛边料独立宽度列合并后的分组 -->
<el-table-column
v-for="group in untrimmedWidthGroups"
:key="'untrimmed-' + group.key"
:label="group.label"
v-for="width in widthList"
:key="'untrimmed-' + width"
:label="width"
align="center"
>
<el-table-column label="数量(件)" :prop="`untrimmed_${group.key}_count`" width="80" align="center" />
<el-table-column label="重量(吨)" :prop="`untrimmed_${group.key}_weight`" width="80" align="center" />
<el-table-column label="数量(件)" :prop="`untrimmed_${width}_count`" width="80" align="center" />
<el-table-column label="重量(吨)" :prop="`untrimmed_${width}_weight`" width="80" align="center" />
</el-table-column>
</el-table-column>
</el-table>
@@ -73,202 +71,69 @@ export default {
data: {
type: Array,
default: () => []
},
// 可配置的宽度分组规则(支持自定义)
widthGroupRules: {
type: Object,
default: () => ({
'1000系列': ['1000', '1000~1005', '1010/1015'],
'1200基础系列': ['1200/1202', '1200~1215'],
'1218基础系列': ['1218/1220', '1218~1235', '1210/1215'],
'1240系列': ['1240/1252'],
'1225系列': ['1225/1235'],
'1250+系列': ['1250~1265', '1260-1265']
})
}
},
computed: {
// ========== 净边料相关计算 ==========
// 提取净边料所有原始宽度
rawTrimmedWidths() {
const widthSet = new Set();
this.data?.forEach(item => {
item.trimmedList?.forEach(trimmed => {
if (trimmed.width) widthSet.add(trimmed.width);
});
});
return Array.from(widthSet);
// 定义表格中需要展示的宽度规格(与图片中一致)
widthList() {
return [
'1000', '1200/1202', '1218/1220', '1240/1252',
'1010/1015', '1210/1215', '1225/1235', '1260-1265',
'1000~1005', '1200~1215', '1218~1235', '1250~1265'
];
},
// 净边料宽度分组(合并相近宽度
trimmedWidthGroups() {
return this.generateWidthGroups(this.rawTrimmedWidths);
},
// ========== 毛边料相关计算 ==========
// 提取毛边料所有原始宽度
rawUntrimmedWidths() {
const widthSet = new Set();
this.data?.forEach(item => {
item.untrimmedList?.forEach(untrimmed => {
if (untrimmed.width) widthSet.add(untrimmed.width);
});
});
return Array.from(widthSet);
},
// 毛边料宽度分组(合并相近宽度)
untrimmedWidthGroups() {
return this.generateWidthGroups(this.rawUntrimmedWidths);
},
// 处理后的原始表格数据
// 处理后的数据(适配表格列结构
tableData() {
return this.data.map(item => {
const row = {
thickness: item.thickness,
trimmedTotalCount: 0,
trimmedTotalWeight: 0,
untrimmedTotalCount: 0,
untrimmedTotalWeight: 0
trimmedTotalCount: 0, // 净边料总计数量
trimmedTotalWeight: 0, // 净边料总计重量
untrimmedTotalCount: 0, // 毛边料总计数量
untrimmedTotalWeight: 0 // 毛边料总计重量
};
// 初始化净边料分组数据
this.trimmedWidthGroups?.forEach(group => {
row[`trimmed_${group.key}_count`] = 0;
row[`trimmed_${group.key}_weight`] = 0;
// 初始化所有宽度的数量和重量为0
this.widthList.forEach(width => {
row[`trimmed_${width}_count`] = 0;
row[`trimmed_${width}_weight`] = 0;
row[`untrimmed_${width}_count`] = 0;
row[`untrimmed_${width}_weight`] = 0;
});
// 初始化毛边料分组数据
this.untrimmedWidthGroups?.forEach(group => {
row[`untrimmed_${group.key}_count`] = 0;
row[`untrimmed_${group.key}_weight`] = 0;
// 处理净边料数据
item.trimmedList.forEach(trimmed => {
const widthKey = trimmed.width;
if (this.widthList.includes(widthKey)) {
row[`trimmed_${widthKey}_count`] = trimmed.coilCount;
row[`trimmed_${widthKey}_weight`] = trimmed.totalWeight;
// 累加总计
row.trimmedTotalCount += trimmed.coilCount;
row.trimmedTotalWeight = (Number(row.trimmedTotalWeight) + Number(trimmed.totalWeight)).toFixed(3);
}
});
// 处理边料数据(按分组求和)
item.trimmedList?.forEach(trimmed => {
const width = trimmed.width;
const count = Number(trimmed.coilCount) || 0;
const weight = Number(trimmed.totalWeight) || 0;
// 找到宽度所属的分组并累加
this.trimmedWidthGroups?.forEach(group => {
if (group.includesWidth(width)) {
row[`trimmed_${group.key}_count`] += count;
row[`trimmed_${group.key}_weight`] = (row[`trimmed_${group.key}_weight`] + weight).toFixed(3);
}
});
// 累加总计
row.trimmedTotalCount += count;
row.trimmedTotalWeight = (Number(row.trimmedTotalWeight) + weight).toFixed(3);
});
// 处理毛边料数据(按分组求和)
item.untrimmedList?.forEach(untrimmed => {
const width = untrimmed.width;
const count = Number(untrimmed.coilCount) || 0;
const weight = Number(untrimmed.totalWeight) || 0;
// 找到宽度所属的分组并累加
this.untrimmedWidthGroups?.forEach(group => {
if (group.includesWidth(width)) {
row[`untrimmed_${group.key}_count`] += count;
row[`untrimmed_${group.key}_weight`] = (row[`untrimmed_${group.key}_weight`] + weight).toFixed(3);
}
});
// 累加总计
row.untrimmedTotalCount += count;
row.untrimmedTotalWeight = (Number(row.untrimmedTotalWeight) + weight).toFixed(3);
// 处理边料数据
item.untrimmedList.forEach(untrimmed => {
const widthKey = untrimmed.width;
if (this.widthList.includes(widthKey)) {
row[`untrimmed_${widthKey}_count`] = untrimmed.coilCount;
row[`untrimmed_${widthKey}_weight`] = untrimmed.totalWeight;
// 累加总计
row.untrimmedTotalCount += untrimmed.coilCount;
row.untrimmedTotalWeight = (Number(row.untrimmedTotalWeight) + Number(untrimmed.totalWeight)).toFixed(3);
}
});
return row;
});
},
// 过滤掉全0的行
filteredTableData() {
return this.tableData.filter(row => {
let hasNonZeroData = false;
// 检查净边料总计
if (Number(row.trimmedTotalCount) > 0 || Number(row.trimmedTotalWeight) > 0) {
hasNonZeroData = true;
}
// 检查毛边料总计
if (Number(row.untrimmedTotalCount) > 0 || Number(row.untrimmedTotalWeight) > 0) {
hasNonZeroData = true;
}
// 检查净边料分组列
if (!hasNonZeroData) {
this.trimmedWidthGroups?.forEach(group => {
if (Number(row[`trimmed_${group.key}_count`]) > 0 || Number(row[`trimmed_${group.key}_weight`]) > 0) {
hasNonZeroData = true;
}
});
}
// 检查毛边料分组列
if (!hasNonZeroData) {
this.untrimmedWidthGroups?.forEach(group => {
if (Number(row[`untrimmed_${group.key}_count`]) > 0 || Number(row[`untrimmed_${group.key}_weight`]) > 0) {
hasNonZeroData = true;
}
});
}
return hasNonZeroData;
});
}
},
methods: {
// 生成宽度分组(核心方法
generateWidthGroups(rawWidths) {
const groups = [];
const usedWidths = new Set();
// 遍历分组规则,匹配原始宽度
Object.entries(this.widthGroupRules)?.forEach(([groupLabel, widthList]) => {
// 筛选出当前分组包含的原始宽度
const matchedWidths = rawWidths.filter(width => widthList.includes(width));
if (matchedWidths.length === 0) return;
// 创建分组对象
const groupKey = groupLabel.replace(/[^a-zA-Z0-9]/g, '_');
groups.push({
key: groupKey,
label: groupLabel,
widths: matchedWidths,
includesWidth: function(width) {
return this.widths.includes(width);
}
});
// 标记已使用的宽度
matchedWidths?.forEach(width => usedWidths.add(width));
});
// 处理未匹配到分组的宽度(单独成组)
rawWidths?.forEach(width => {
if (!usedWidths.has(width)) {
const groupKey = width.replace(/[^a-zA-Z0-9]/g, '_');
groups.push({
key: groupKey,
label: width,
widths: [width],
includesWidth: function(width) {
return this.widths.includes(width);
}
});
}
});
return groups;
},
// 合并表头的跨度方法
// 合并表头的跨度方法(可选,若需要合并行/列可扩展
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
// 可根据需求实现行/列合并逻辑,例如合并重复的厚度行
// 示例:若需合并相同厚度的行,可在此处返回 { rowspan: n, colspan: m }
return { rowspan: 1, colspan: 1 };
}
}

View File

@@ -51,14 +51,13 @@
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button icon="el-icon-download" size="mini" @click="handleNewExport" v-if="showNewExport">导出</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8" v-if="showControl">
<!-- <el-col :span="1.5">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-col> -->
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single"
@click="handleCheck">修正</el-button>
@@ -74,10 +73,6 @@
<el-button type="info" plain icon="el-icon-printer" size="mini" :disabled="multiple"
@click="handleBatchPrintLabel">批量打印标签</el-button>
</el-col>
<el-col :span="1.5" v-if="showOrderBy">
<el-checkbox v-model="queryParams.orderBy" v-loading="loading" @change="getList"
label="orderBy">按实际库区排序</el-checkbox>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@@ -182,8 +177,7 @@
<el-table-column label="关联订单" align="center" prop="relatedToOrder" v-if="showRelatedToOrder" width="150">
<template slot-scope="scope">
<el-switch @change="handleRelatedToOrderChange(scope.row)" v-model="scope.row.isRelatedToOrder"
:active-value="1" :inactive-value="0" />
<el-switch @change="handleRelatedToOrderChange(scope.row)" v-model="scope.row.isRelatedToOrder" :active-value="1" :inactive-value="0" />
</template>
</el-table-column>
@@ -340,14 +334,6 @@
<el-form-item label="长度" prop="length" v-if="showLength">
<el-input v-model="form.length" placeholder="请输入长度" />
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="form.actualLength" placeholder="请输入实测长度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth">
<el-input-number :controls="false" v-model="form.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="form.temperGrade" placeholder="请输入调制度" />
</el-form-item>
@@ -418,10 +404,9 @@ import {
exportCoil,
cancelExportCoil,
checkCoilNo,
returnCoil,
returnCoil
} from "@/api/wms/coil";
import { listBoundCoil } from "@/api/wms/deliveryWaybillDetail";
import { addPendingAction } from "@/api/wms/pendingAction";
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import QRCode from "../../print/components/QRCode.vue";
import * as XLSX from 'xlsx'
@@ -544,14 +529,6 @@ export default {
showRelatedToOrder: {
type: Boolean,
default: false,
},
showOrderBy: {
type: Boolean,
default: false,
},
showNewExport: {
type: Boolean,
default: false,
}
},
data() {
@@ -600,7 +577,6 @@ export default {
itemIds: undefined,
status: undefined,
updateTime: undefined,
orderBy: false,
...this.querys,
},
// 表单参数
@@ -713,9 +689,7 @@ export default {
{ label: '包装要求', prop: 'packagingRequirement' },
{ label: '厂家', prop: 'itemManufacturer' },
{ label: '调制度', prop: 'temperGrade' },
{ label: '镀层种类', prop: 'coatingType' },
{ label: '实测长度(m)', prop: 'actualLength' },
{ label: '实测宽度(m)', prop: 'actualWidth' },
{ label: '镀层种类', prop: 'coatingType' }
],
title: '详细信息'
},
@@ -813,31 +787,8 @@ export default {
handlePrintLabel(row) {
const item = row.itemType === 'product' ? row.product : row.rawMaterial;
const itemName = row.itemType === 'product' ? item?.productName || '' : item?.rawMaterialName || '';
const itemType = row.itemType || '';
const warehouseId = row.warehouseId || '';
// 在镀锌颜料库的卷使用镀锌原料标签
if (itemType == 'raw_material' && (warehouseId == '1988150263284953089' || warehouseId == '1988150487185289217')) {
this.labelRender.type = '5';
}
// 脱脂原料库
else if (itemType == 'raw_material' && (warehouseId == '1988150545175736322')) {
this.labelRender.type = '6';
}
else if (itemType == 'raw_material') {
this.labelRender.type = '2';
} else if (itemType == 'product' && itemName == '冷硬卷') {
this.labelRender.type = '3';
} else if (itemType == 'product' && itemName == '热轧卷板') {
this.labelRender.type = '3';
} else if (itemType == 'product' && itemName == '镀锌卷') {
this.labelRender.type = '4';
} else if (itemType == 'product' && itemName == '冷轧卷') {
this.labelRender.type = '3';
} else if (itemType == 'product' && itemName == '镀铬卷') {
this.labelRender.type = 'ge';
} else {
this.labelRender.type = '3';
}
this.labelRender.type = row.itemType === 'product' ? '3' : '2';
this.labelRender.data = {
...row,
itemName: itemName,
@@ -947,6 +898,12 @@ export default {
}
},
handleAbnormal(row) {
// this.$router.push({
// path: '/quality/detail',
// query: {
// coilId: row.coilId,
// }
// })
this.currentCoilId = row.coilId;
this.abnormalOpen = true;
},
@@ -1058,50 +1015,11 @@ export default {
handleExportCoil(row) {
exportCoil(row.coilId).then(response => {
this.$modal.msgSuccess("发货成功");
// 2. 插入一条已完成的待操作记录
addPendingAction({
coilId: row.coilId,
currentCoilNo: row.currentCoilNo,
actionType: 402, // 402=发货
actionStatus: 2, // 直接标记为完成状态
scanTime: new Date(),
// scanDevice: ,
priority: 0, // 0=普通
sourceType: 'scan',
warehouseId: row.warehouseId,
processTime: new Date(),
completeTime: new Date()
});
this.getList();
}).catch(error => {
this.$modal.msgError("发货失败");
});
},
async handleNewExport(row) {
this.loading = true
let coilIds = ''
const query = {
...this.queryParams,
selectType: 'product',
pageSize: 9999,
pageNum: 1,
}
if (this.showWaybill) {
const res = await listBoundCoil(query)
coilIds = res.rows.map(item => item.coilId).join(',')
this.loading = false
this.download('/wms/materialCoil/exportDelivery', {
coilIds,
}, 'coil.xlsx')
} else {
const { rows: coils } = await listMaterialCoil(query)
coilIds = coils.map(item => item.coilId).join(',')
this.loading = false
this.download('wms/materialCoil/exportAll', {
coilIds,
}, 'coil.xlsx')
}
},
handleCheck(row) {
this.isCheck = true;
this.loading = true;
@@ -1235,6 +1153,7 @@ export default {
...this.queryParams
}, `materialCoil_${new Date().getTime()}.xlsx`)
},
/** 批量打印标签按钮 */
handleBatchPrintLabel() {
if (!this.ids || this.ids.length === 0) {

View File

@@ -135,14 +135,6 @@
<span class="param-label">长度</span>
<span class="param-value">{{ item.length }}</span>
</div>
<div class="param-row" v-if="item.actualLength">
<span class="param-label">实测长度</span>
<span class="param-value">{{ item.actualLength }}</span>
</div>
<div class="param-row" v-if="item.actualWidth">
<span class="param-label">实测宽度</span>
<span class="param-value">{{ item.actualWidth }}</span>
</div>
<div class="param-row" v-if="item.temperGrade">
<span class="param-label">调制度</span>
<span class="param-value">{{ item.temperGrade }}</span>
@@ -207,7 +199,7 @@
</div>
<div class="card-footer">
<el-button v-if="useSpecialSplit" :style="splitButtonStyle" icon="el-icon-scissors" size="mini"
<el-button v-if="useSpecialSplit" type="success" icon="el-icon-scissors" size="mini"
@click="handleStartSplit(item)" :loading="buttonLoading" class="action-btn">加工</el-button>
<el-button v-else type="primary" icon="el-icon-check" size="mini" @click="handlePickMaterial(item)"
:loading="buttonLoading" class="action-btn">领料</el-button>
@@ -231,7 +223,7 @@
<div class="section-card action-section" v-if="useSpecialSplit" style="margin-bottom: 20px;"
v-loading="stepSpilt.loading">
<div class="section-header ">
<h3 class="section-title">进行中的{{ label }}</h3>
<h3 class="section-title">进行中的镀锌工序</h3>
<el-button size="mini" icon="el-icon-refresh" @click="getStepSplitList">刷新</el-button>
</div>
<div v-if="stepSpilt.list.length > 0" style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
@@ -306,7 +298,7 @@
</div>
</div>
<div v-else>
<el-empty :description="`暂无进行中的${label}`" />
<el-empty description="暂无进行中的镀锌工序" />
</div>
</div>
@@ -560,7 +552,7 @@ export default {
degree: null,
remark: null
},
tagSizeMap: {
tagSizeMap: {
'2': {
width: 100,
height: 80,
@@ -585,10 +577,6 @@ export default {
width: 180,
height: 100,
},
'6': {
width: 180,
height: 100,
},
},
stepSpilt: {
list: [],
@@ -610,48 +598,6 @@ export default {
})
return acidAction ? parseInt(acidAction.value) : null
},
splitButtonStyle() {
if (this.acidRollingActionType == 501) {
return {
backgroundColor: '#2cb867',
border: '1px solid #2cb867',
color: '#111'
}
} else if (this.acidRollingActionType == 502) {
return {
backgroundColor: 'purple',
border: '1px solid purple',
color: '#fff'
}
} else if (this.acidRollingActionType == 503) {
return {
backgroundColor: '#f56c6c',
border: '1px solid #f56c6c',
color: '#fff'
}
} else if (this.acidRollingActionType == 504) {
return {
backgroundColor: 'orange',
border: '1px solid orange',
color: '#111'
}
} else if (this.acidRollingActionType == 505) {
return {
// 青色
backgroundColor: 'blue',
border: '1px solid blue',
color: '#fff'
}
} else if (this.acidRollingActionType == 506) {
return {
backgroundColor: '#2bf',
border: '1px solid #2bf',
color: '#fff'
}
} else {
return {}
}
}
},
watch: {
// 监听字典数据加载当acidRollingActionType有值时自动加载待操作列表
@@ -677,12 +623,9 @@ export default {
},
currentTab: {
handler(newVal) {
if (newVal && newVal != 0) {
if (newVal) {
this.materialQueryParams.warehouseId = newVal
} else {
this.materialQueryParams.warehouseId = ''
}
this.getMaterialCoil()
},
immediate: true
@@ -696,11 +639,9 @@ export default {
if (this.acidRollingActionType) {
this.actionQueryParams.actionType = this.acidRollingActionType
this.getPendingAction()
if (this.useSpecialSplit) {
this.getStepSplitList()
}
}
})
this.getStepSplitList()
},
mounted() {
// 确保在mounted时也尝试加载字典数据可能此时才加载完成
@@ -720,14 +661,9 @@ export default {
const itemType = row.itemType || '';
const warehouseId = row.warehouseId || '';
// 在镀锌颜料库的卷使用镀锌原料标签
if (itemType == 'raw_material' && (warehouseId == '1988150263284953089' || warehouseId == '1988150487185289217')) {
if (itemType == 'raw_material' && warehouseId == '1988150263284953089') {
this.labelRender.type = '5';
}
// 脱脂原料库
else if (itemType == 'raw_material' && (warehouseId == '1988150545175736322')) {
this.labelRender.type = '6';
}
else if (itemType == 'raw_material') {
} else if (itemType == 'raw_material') {
this.labelRender.type = '2';
} else if (itemType == 'product' && itemName == '冷硬卷') {
this.labelRender.type = '3';
@@ -754,11 +690,7 @@ export default {
getStepSplitList() {
this.stepSpilt.loading = true
if (!this.acidRollingActionType) {
this.$message.error(`未找到${this.label}操作类型,请检查字典配置`)
return
}
listPendingAction({ actionType: this.acidRollingActionType, actionStatus: 0 }).then(response => {
listPendingAction({ actionType: 501, actionStatus: 0 }).then(response => {
this.stepSpilt.list = response.rows || []
this.stepSpilt.loading = false
})
@@ -1023,7 +955,7 @@ export default {
try {
await this.$modal.confirm('是否确认领料开始分步加工操作?')
this.stepSpilt.loading = true
await startSpecialSplit(row.coilId, this.acidRollingActionType);
await startSpecialSplit(row.coilId);
// await addPendingAction({
// coilId: row.coilId,
// currentCoilNo: row.currentCoilNo,

View File

@@ -135,14 +135,6 @@
<el-form-item label="长度" prop="length">
<el-input v-model="splitForm.length" placeholder="请输入长度" type="number" />
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="splitForm.actualLength" placeholder="请输入实测长度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth">
<el-input-number :controls="false" v-model="splitForm.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="splitForm.temperGrade" placeholder="请输入调制度" />
</el-form-item>
@@ -259,8 +251,6 @@ export default {
grossWeight: '',
netWeight: '',
length: '',
actualLength: '',
actualWidth: '',
temperGrade: '',
coatingType: '',
remark: '',

View File

@@ -17,9 +17,6 @@
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" class="add-btn">
新增
</el-button>
<el-button type="primary" plain icon="el-icon-refresh" size="mini" @click="getList" class="add-btn">
刷新
</el-button>
</div>
<!-- 自定义列表替代表格 -->
@@ -35,16 +32,11 @@
<!-- 内容区域 -->
<div class="item-content">
<el-tag type="info">{{ item.statType }}</el-tag>
<div style="display: flex; flex-direction: column;">
<div style="display: flex;">
<!-- 双击后变成输入框输入框失去焦点触发更新 -->
<div class="value">
{{ item.title }}
<el-icons title="本次汇总保存了汇总时使用的钢卷明细" v-if="item.attachmentInfo" class="el-icon-link"></el-icons>
</div>
<div>
<span class="value" style="margin-right: 5px;">{{ item.createBy }}</span>
<span class="value">{{ item.createTime }}</span>
</div>
<div class="value">{{ item.title }}</div>
<!-- <span class="value">{{ item.createTime }}</span>
<span class="value">{{ item.createBy }}</span> -->
</div>
</div>
@@ -63,10 +55,12 @@
<!-- 添加或修改钢卷生产统计对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<div v-for="item in tableType" :key="item.statType" @click="handleCreate(item)" class="type-item">
<div class="type-title">{{ item.title }}</div>
<div class="type-desc">{{ item.description }}</div>
</div>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<div v-for="item in tableType" :key="item.statType" @click="handleCreate(item)" class="type-item">
<div class="type-title">{{ item.title }}</div>
<div class="type-desc">{{ item.description }}</div>
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
@@ -269,7 +263,6 @@ export default {
.item-content {
flex: 1;
display: flex;
align-items: flex-start;
gap: 5px;
}

View File

@@ -5,53 +5,32 @@
<LeftList ref="leftList" @add="handleAdd" @select="handleSelect" />
</el-col>
<el-col :span="18" style="position: relative;">
<ul style="float: right; position: absolute; right: 0; top: 0; z-index: 100;">
<li v-show="currentRow.attachmentInfo" @click="handleDownload(currentRow)"><el-button
icon="el-icon-download">下载明细</el-button></li>
</ul>
<el-col :span="18">
<div style="height: calc(100vh - 124px); overflow-y: scroll; overflow-x: hidden;">
<div v-if="currentRow.summaryId">
<Preview :data="currentRow.statJson" :statType="currentRow.statType" />
</div>
<div v-else>
<div>
<el-empty description="请点击左侧列表查看或创建透视表" />
</div>
<div>钢卷生产统计详情</div>
</div>
</div>
</el-col>
</el-row>
<el-dialog v-loading="previewLoading" title="效果预览" :visible.sync="previewOpen" width="80vw" append-to-body>
<div>
<el-button type="primary" @click="handleSave" :loading="buttonLoading">保存</el-button>
<!-- <el-button type="primary" @click="handleDetail" :loading="buttonLoading">查看明细</el-button> -->
<el-checkbox style="margin-left: 10px;" v-model="saveDetail"
label="orderBy">保存透视表时保存明细勾选后在保存时会消耗更长的时间且会占用更多内存和存储</el-checkbox>
</div>
<div style="height: calc(100vh - 300px); overflow-y: scroll; overflow-x: hidden;">
<div v-if="liveData">
<Preview :data="liveData" :statType="form.statType" />
</div>
<div v-else>
<div>
<el-empty description="未知的透视表" />
</div>
</div>
</div>
<el-dialog v-loading="previewLoading" title="效果预览" :visible.sync="previewOpen" width="100vw" fullscreen append-to-body>
<Preview :data="liveData" :statType="form.statType" />
<el-button type="primary" @click="handleSave">保存</el-button>
</el-dialog>
</div>
</template>
<script>
import { getCoilStatisticsSummary, delCoilStatisticsSummary, addCoilStatisticsSummary, updateCoilStatisticsSummary, checkCoilStatisticsSummaryExist } from "@/api/wms/coilStatisticsSummary";
import { getCoilStatisticsSummary, delCoilStatisticsSummary, addCoilStatisticsSummary, updateCoilStatisticsSummary } from "@/api/wms/coilStatisticsSummary";
import LeftList from "./components/LeftList.vue";
import Preview from "@/views/wms/coil/panels/Perspective/index.vue";
import { listRawMaterialPerspective } from "@/api/wms/rawMaterial";
import { uploadFile } from "@/api/system/oss";
import { listCoilTrimStatistics, categoryWidthStatistics, listMaterialCoil, exportCoilWithAll } from "@/api/wms/coil";
import { listCoilTrimStatistics, categoryWidthStatistics } from "@/api/wms/coil";
export default {
name: "CoilStatisticsSummary",
@@ -88,7 +67,6 @@ export default {
title: undefined,
statType: undefined,
},
saveDetail: false,
// 表单参数
form: {},
// 表单校验
@@ -100,7 +78,19 @@ export default {
currentRow: {},
};
},
created() {
this.getList();
},
methods: {
/** 查询钢卷生产统计列表 */
getList() {
this.loading = true;
listCoilStatisticsSummary(this.queryParams).then(response => {
this.coilStatisticsSummaryList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
@@ -140,39 +130,9 @@ export default {
};
},
/** 新增按钮操作 */
async handleAdd(form) {
this.form = form;
// 先检查今天是否已经创建过该类型的透视表
const {data: existingSummary} = await checkCoilStatisticsSummaryExist(form.statType);
// 如果已经创建过
if (existingSummary) {
// 先提示是否继续创建
try {
await this.$confirm('该类型已存在透视表,是否继续创建?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
} catch (error) {
return;
}
// 如果要继续创建,则提示是否要覆盖已经存在的透视表
try {
await this.$confirm('是否覆盖已存在的透视表?', '提示', {
confirmButtonText: '删除并重新创建',
cancelButtonText: '保留已有透视表',
type: 'warning'
});
delCoilStatisticsSummary(existingSummary).then(() => {
this.$modal.msgSuccess("删除成功");
this.getList();
});
} catch (error) {
}
}
handleAdd(form) {
this.previewOpen = true;
this.form = form;
if (form.statType == '热轧原料') {
this.previewLoading = true;
listRawMaterialPerspective().then(response => {
@@ -223,97 +183,19 @@ export default {
}
this.previewLoading = false;
},
async handleSave() {
const loading = this.$loading({
lock: true,
text: '保存中...',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
this.buttonLoading = true;
const { data: summary } = await addCoilStatisticsSummary({
...this.form,
statJson: JSON.stringify(this.liveData)
})
if (this.saveDetail) {
// 获取原始数据组装coilIds
let coilIds = ''
if (this.form.statType == '热轧原料') {
const { rows: coils } = await listMaterialCoil({
pageNum: 1,
pageSize: 9999,
selectType: 'raw_material',
dataType: 1,
status: 0,
itemName: '热轧卷板',
itemType: 'raw_material',
})
coilIds = coils.map(item => item.coilId).join(',')
} else if (this.form.statType == '冷硬卷板') {
const { rows: coils1 } = await listMaterialCoil({
pageNum: 1,
pageSize: 9999,
selectType: 'raw_material',
dataType: 1,
status: 0,
itemName: '冷硬卷',
itemType: 'raw_material',
})
const { rows: coils2 } = await listMaterialCoil({
pageNum: 1,
pageSize: 9999,
selectType: 'product',
dataType: 1,
status: 0,
itemName: '冷硬卷',
itemType: 'product',
})
coilIds = coils1.concat(coils2).map(item => item.coilId).join(',')
} else if (this.form.statType == '汇总') {
const { rows: coils } = await listMaterialCoil({
pageNum: 1,
pageSize: 9999,
dataType: 1,
status: 0,
})
coilIds = coils.map(item => item.coilId).join(',')
}
// 使用exportCoilWithAll接口传入coilIds获取二进制文件数据
const response = await exportCoilWithAll({
coilIds: coilIds,
})
const file = new Blob([response], { type: 'application/vnd.ms-excel' })
const fileName = this.form.statType + '明细.xlsx'
// 通过new File构建出excel文件
const excelFile = new File([file], fileName, { type: 'application/vnd.ms-excel' })
console.log(excelFile)
// 上传文件到minio
const uploadResponse = await uploadFile(excelFile)
console.log(uploadResponse)
// 关联附件信息
await updateCoilStatisticsSummary({
...summary,
attachmentInfo: uploadResponse.data.ossId,
});
}
handleSave() {
addCoilStatisticsSummary({
...this.form,
statJson: JSON.stringify(this.liveData)
}).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.previewOpen = false;
this.liveData = [];
this.form = {};
this.$refs.leftList.getList();
} finally {
}).finally(() => {
this.buttonLoading = false;
loading.close();
}
},
handleDownload(row) {
this.$download.oss(row.attachmentInfo)
});
},
/** 修改按钮操作 */
handleUpdate(row) {

View File

@@ -29,8 +29,7 @@ export default {
showStatus: true,
hideType: true,
showLength: true,
canExportAll: true,
showOrderBy: true,
canExportAll: true
}
}
}

View File

@@ -193,18 +193,6 @@
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="item.actualLength" placeholder="请输入实测长度" type="number"
:step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth">
<el-input-number :controls="false" v-model="item.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="item.temperGrade" placeholder="请输入调制度" />
</el-form-item>
@@ -287,8 +275,6 @@ export default {
length: undefined,
temperGrade: '',
coatingType: '',
actualLength: undefined,
actualWidth: undefined,
}
],
loading: false,
@@ -473,8 +459,6 @@ export default {
trimmingRequirement: '',
temperGrade: '',
coatingType: '',
actualLength: undefined,
actualWidth: undefined,
});
},

View File

@@ -157,21 +157,14 @@
<el-form-item label="净重(t)" prop="netWeight">
<el-input-number :precision="3" :controls="false" v-model="updateForm.netWeight" placeholder="请输入净重"
type="number" :step="0.001">
type="number" :step="0.01">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="updateForm.actualLength" placeholder="请输入实测长度" type="number"
:step="0.001">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth">
<el-input-number :controls="false" v-model="updateForm.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.001">
<el-form-item label="长度(m)" prop="length">
<el-input-number :controls="false" v-model="updateForm.length" placeholder="请输入长度" type="number"
:step="0.01">
<template slot="append"></template>
</el-input-number>
</el-form-item>
@@ -290,8 +283,6 @@ export default {
length: undefined,
temperGrade: '',
coatingType: '',
actualLength: undefined,
actualWidth: undefined,
},
rules: {
currentCoilNo: [

View File

@@ -1,9 +1,5 @@
<template>
<el-tabs class="app-container" v-model="activeTab">
<el-tab-pane label="次品" name="third">
<BasePage :qrcode="qrcode" :querys="query3" :labelType="labelType" :hideWarehouseQuery="hideWarehouseQuery"
:hideType="hideType" />
</el-tab-pane>
<el-tab-pane label="待收卷" name="second">
<BasePage :qrcode="qrcode" :querys="querys2" :labelType="labelType" :hideWarehouseQuery="hideWarehouseQuery"
:hideType="hideType" />
@@ -25,7 +21,7 @@ export default {
data() {
return {
qrcode: false,
activeTab: 'third',
activeTab: 'second',
querys: {
dataType: 1,
status: 0,
@@ -38,10 +34,6 @@ export default {
nextWarehouseId: '2019583429955104769', // 废品仓
// materialType: '废品'
},
query3: {
dataType: 1,
OnlyScrap: true,
},
hideWarehouseQuery: true,
showAbnormal: true,
labelType: '2',

View File

@@ -2,7 +2,6 @@
<BasePage
:qrcode="qrcode"
:showWaybill="showWaybill"
:showNewExport="showNewExport"
:querys="querys" :labelType="labelType" :showStatus="showStatus" :hideType="hideType" :showControl="showControl" :showExportTime="showExportTime" />
</template>
@@ -28,7 +27,6 @@ export default {
hideType: false,
showExportTime: false,
showWaybill: true,
showNewExport: true,
}
}
}

View File

@@ -1,38 +0,0 @@
<template>
<BasePage :qrcode="qrcode"
:querys="querys"
:labelType="labelType"
:showStatus="showStatus"
:hideType="hideType"
:showLength="showLength"
:canExportAll="canExportAll"
/>
</template>
<script>
import BasePage from '@/views/wms/coil/panels/base.vue';
export default {
components: {
BasePage
},
data() {
return {
qrcode: false,
querys: {
dataType: 1,
materialType: '成品',
itemType: 'product',
status: 0,
orderBy: true
},
labelType: '3',
showStatus: true,
hideType: true,
showLength: true,
canExportAll: true,
showOrderBy: false,
}
}
}
</script>

View File

@@ -264,7 +264,6 @@ export default {
rawMaterialFactory: coil.manufacturer,
coilNo: coil.currentCoilNo,
specification: coil.specification,
settlementType: '卷重结算',
material: coil.material,
quantity: 1,
weight: coil.netWeight,
@@ -279,7 +278,7 @@ export default {
productName: undefined,
edgeType: undefined,
packaging: undefined,
settlementType: '卷重结算',
settlementType: undefined,
rawMaterialFactory: undefined,
coilNo: undefined,
specification: undefined,
@@ -359,7 +358,6 @@ export default {
coilId: coil.coilId,
productName: coil.itemName,
edgeType: coil.trimmingRequirement,
settlementType: '卷重结算',
packaging: coil.packagingRequirement,
rawMaterialFactory: coil.manufacturer,
coilNo: coil.currentCoilNo,

View File

@@ -34,8 +34,8 @@
<div class="editable-input transparent-input" contenteditable>{{ localWaybill.principal }}</div>
</div>
<div class="header-right">
<span class="label">订单号</span>
<div class="editable-input transparent-input" contenteditable>{{ localWaybill.orderId ? localWaybill.orderCode : localWaybill.principalPhone }}</div>
<span class="label">电话</span>
<div class="editable-input transparent-input" contenteditable>{{ localWaybill.principalPhone }}</div>
</div>
<div class="header-right">
<span class="label">合同号</span>
@@ -239,8 +239,6 @@ export default {
handler(newVal) {
if (newVal) {
this.localWaybill = {
orderId: newVal.orderId || '',
orderCode: newVal.orderCode || '',
consigneeUnit: newVal.consigneeUnit || '',
senderUnit: newVal.senderUnit || '',
deliveryYear: this.getYearFromDate(newVal.deliveryTime) || '',
@@ -501,12 +499,12 @@ export default {
[
`负责人:${this.localWaybill.principal || ''}`,
undefined, undefined,
`订单号${this.localWaybill.orderId ? this.localWaybill.orderCode : this.localWaybill.principalPhone || ''}`,
`电话${this.localWaybill.principalPhone || ''}`,
undefined, undefined,
`合同号:${this.localWaybill.contractCode || ''}`,
undefined, undefined,
`车牌:${this.localWaybill.licensePlate || ''}`
], // 负责人/订单号/合同号/车牌行r=2
], // 负责人/电话/合同号/车牌行r=2
["品名", '切边', '包装', '仓库位置', '结算', '原料厂家', '卷号', '规格', '材质', '重量(t)', '单价', '备注'], // 表格表头r=3
];
@@ -560,7 +558,7 @@ export default {
{ s: { c: 4, r: headerRow1Idx }, e: { c: 7, r: headerRow1Idx } }, // 日期E2-H2
{ s: { c: 8, r: headerRow1Idx }, e: { c: 11, r: headerRow1Idx } }, // 发货单位I2-L2
{ s: { c: 0, r: headerRow2Idx }, e: { c: 2, r: headerRow2Idx } }, // 负责人A3-C3
{ s: { c: 3, r: headerRow2Idx }, e: { c: 5, r: headerRow2Idx } }, // 订单号D3-F3
{ s: { c: 3, r: headerRow2Idx }, e: { c: 5, r: headerRow2Idx } }, // 电话D3-F3
{ s: { c: 6, r: headerRow2Idx }, e: { c: 8, r: headerRow2Idx } }, // 合同号G3-I3
{ s: { c: 9, r: headerRow2Idx }, e: { c: 11, r: headerRow2Idx } }, // 车牌J3-L3
{ s: { c: 0, r: remarkRowIdx }, e: { c: 11, r: remarkRowIdx } }, // 备注跨列合并A*_L*
@@ -749,9 +747,9 @@ export default {
date: `${this.localWaybill.deliveryYear || ''}${this.localWaybill.deliveryMonth || ''}${this.localWaybill.deliveryDay || ''}`,
sender: `发货单位:${this.localWaybill.senderUnit || ''}`
};
const header2 = { // 负责人+订单号+合同号+车牌
const header2 = { // 负责人+电话+合同号+车牌
principal: `负责人:${this.localWaybill.principal || ''}`,
phone: `订单号${this.localWaybill.orderId ? this.localWaybill.orderCode : this.localWaybill.principalPhone || ''}`,
phone: `电话${this.localWaybill.principalPhone || ''}`,
contract: `合同号:${this.localWaybill.contractCode || ''}`,
license: `车牌:${this.localWaybill.licensePlate || ''}`
};
@@ -799,7 +797,7 @@ export default {
worksheet.getCell(`G${rowIdx}`).value = header2.contract;
worksheet.getCell(`J${rowIdx}`).value = header2.license;
worksheet.mergeCells(`A${rowIdx}:C${rowIdx}`); // 负责人A3-C3
worksheet.mergeCells(`D${rowIdx}:F${rowIdx}`); // 订单号D3-F3
worksheet.mergeCells(`D${rowIdx}:F${rowIdx}`); // 电话D3-F3
worksheet.mergeCells(`G${rowIdx}:I${rowIdx}`); // 合同号G3-I3
worksheet.mergeCells(`J${rowIdx}:L${rowIdx}`); // 车牌J3-L3
// 3.4 表格表头第4行

File diff suppressed because it is too large Load Diff

View File

@@ -43,20 +43,13 @@
<el-table-column label="车牌" align="center" prop="licensePlate" width="100" />
<el-table-column label="收货单位" align="center" prop="consigneeUnit" />
<!-- <el-table-column label="发货单位" align="center" prop="senderUnit" /> -->
<el-table-column label="订单编号" align="center" prop="orderNo">
<template slot-scope="scope">
<span v-if="scope.row.orderId">{{ scope.row.orderCode }}</span>
<span v-else>{{ scope.row.principalPhone }}</span>
</template>
</el-table-column>
<el-table-column label="订单编号" align="center" prop="orderNo" />
<el-table-column label="发货时间" align="center" prop="deliveryTime" width="100">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.deliveryTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="负责人" align="center" prop="principal" width="60" />
<el-table-column label="备注" align="center" prop="remark" width="100" show-overflow-tooltip/>
<!-- <el-table-column label="负责人电话" align="center" prop="principalPhone" width="100" /> -->
<el-table-column label="完成状态" align="center" prop="status" width="120">
<template slot-scope="scope">
@@ -72,8 +65,6 @@
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-view"
@click.stop="handlePrint(scope.row)">打印发货单</el-button>
<el-button size="mini" type="text" icon="el-icon-view"
@click.stop="handlePrintSimple(scope.row)">简单打印</el-button>
<el-button size="mini" type="text" icon="el-icon-copy"
@click.stop="handleCopy(scope.row)">复制新增</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" :disabled="scope.row.status === 1"
@@ -118,12 +109,9 @@
<el-form-item label="负责人" prop="principal">
<el-input v-model="form.principal" placeholder="请输入负责人" />
</el-form-item>
<el-form-item label="订单编号" prop="principalPhone" v-if="!form.orderId">
<el-input v-model="form.principalPhone" placeholder="请输入订单编号"/>
</el-form-item>
<el-form-item label="订单编号" prop="principalPhone" v-else title="当前发货单已绑定订单">
<el-input v-model="form.orderCode" placeholder="请输入订单编号" readonly disabled/>
</el-form-item>
<!-- <el-form-item label="负责人电话" prop="principalPhone">
<el-input v-model="form.principalPhone" placeholder="请输入负责人电话" />
</el-form-item> -->
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
@@ -136,8 +124,7 @@
<!-- 打印发货单对话框 -->
<el-dialog title="打印发货单" :visible.sync="printDialogVisible" width="1000px" append-to-body center>
<WayBill v-if="printType === 0" :waybill="currentWaybill" :waybillDetails="currentWaybillDetails" />
<WayBill2 v-else :waybill="currentWaybill" :waybillDetails="currentWaybillDetails" />
<WayBill :waybill="currentWaybill" :waybillDetails="currentWaybillDetails" />
</el-dialog>
</div>
</template>
@@ -151,8 +138,6 @@ import MemoInput from "@/components/MemoInput";
import DeliveryWaybillDetail from "../components/detailTable.vue";
import WayBill from "../components/wayBill.vue";
import PlanList from "../components/planList.vue";
import WayBill2 from "../components/wayBill2.vue";
export default {
name: "DeliveryWaybill",
@@ -160,8 +145,7 @@ export default {
MemoInput,
DeliveryWaybillDetail,
WayBill,
PlanList,
WayBill2
PlanList
},
data() {
return {
@@ -188,8 +172,6 @@ export default {
currentWaybillDetails: [],
// 弹出层标题
title: "",
// 打印类型
printType: 0,
// 是否显示弹出层
open: false,
// 查询参数
@@ -356,10 +338,7 @@ export default {
const waybillId = row.waybillId || this.ids
getDeliveryWaybill(waybillId).then(response => {
this.loading = false;
this.form = {
...response.data,
orderCode: row.orderCode
};
this.form = response.data;
this.open = true;
this.title = "修改发货单";
});
@@ -430,65 +409,6 @@ export default {
/** 打印发货单 */
handlePrint(row) {
this.loading = true;
this.printType = 0;
// 获取发货单明细
listDeliveryWaybillDetail({
waybillId: row.waybillId,
pageNum: 1,
pageSize: 1000 // 获取所有明细
}).then(response => {
// 处理字段映射确保与wayBill组件使用的字段名一致
this.currentWaybillDetails = response.rows.map(item => ({
coilId: item.coilId,
productName: item.productName,
edgeType: item.edgeType,
packageType: item.packaging, // 映射packaging到packageType
settlementType: item.settlementType,
rawMaterialFactory: item.rawMaterialFactory,
coilNumber: item.coilNo, // 映射coilNo到coilNumber
specification: item.specification,
material: item.material,
quantity: item.quantity,
weight: item.weight,
unitPrice: item.unitPrice || '',
// 单价为空时,显示为空字符串
remark: item.remark
}));
const coils = this.currentWaybillDetails.map(item => item.coilId).join(',');
if (coils) {
listCoilByIds(coils).then(response => {
// 取前三位, 然后去抽后用;连接
// 设置当前发货单
const actualWahouseNames = [...new Set(response.rows.filter(item => Boolean(item.actualWarehouseName)).map(item => item.actualWarehouseName.slice(0, 3)))].join(';');
this.currentWaybill = {
...row,
pickupLocation: actualWahouseNames || '',
};
this.currentWaybillDetails = this.currentWaybillDetails.map(item => {
const actualWarehouseName = response.rows.find(detail => detail.coilId === item.coilId)?.actualWarehouseName || '';
return {
...item,
actualWarehouseName: actualWarehouseName,
};
});
});
}
this.currentWaybill = {
...row,
};
this.printDialogVisible = true;
this.loading = false;
}).catch(error => {
console.error('获取发货单明细失败:', error);
this.$modal.msgError('获取发货单明细失败');
this.loading = false;
});
},
/** 打印发货单 */
handlePrintSimple(row) {
this.loading = true;
this.printType = 1;
// 获取发货单明细
listDeliveryWaybillDetail({
waybillId: row.waybillId,

View File

@@ -8,7 +8,7 @@
</template>
<!-- 左侧是新增表单 -->
<el-form ref="form" :model="form" :rules="rules" label-width="80px" v-loading="loading">
<el-form-item v-if="!form.outId" label="审批部门" prop="deptId">
<el-form-item label="审批部门" prop="deptId">
<el-select v-model="form.deptId" placeholder="请选择审批部门" filterable @change="getDeptLeader">
<el-option v-for="item in deptOptions" :key="item.deptId"
:label="item.deptName + '(' + (item.leaderNickName || '无负责人') + ')'" :value="item.deptId"></el-option>
@@ -63,13 +63,13 @@
<el-button style="float: right;" icon="el-icon-refresh" @click="getList">刷新</el-button>
</template>
<el-table v-loading="loading" :data="leaveRequestList">
<el-table-column prop="approvalStatus" label="审批状态" align="center">
<!-- <el-table-column prop="approvalStatus" label="审批状态" align="center">
<template slot-scope="scope">
<el-tag :type="getStatusTagType(scope.row.approvalStatus)">
{{ getStatusText(scope.row.approvalStatus) }}
</el-tag>
</template>
</el-table-column>
</el-table-column> -->
<el-table-column label="外出类型" align="center" prop="outType">
<template slot-scope="scope">
<dict-tag :options="dict.type.hrm_out_type" :value="scope.row.outType" />
@@ -104,8 +104,8 @@
@click="handlePrint(scope.row)">打印</el-button>
<el-button icon="el-icon-edit" size="mini" @click="handleEdit(scope.row)"
v-if="scope.row.approvalStatus === '待审批'">修改</el-button>
<el-button icon="el-icon-delete" size="mini" @click="handleWithdraw(scope.row)"
v-if="scope.row.approvalStatus === '待审批'">撤回</el-button>
<!-- <el-button icon="el-icon-delete" size="mini" @click="handleWithdraw(scope.row)"
v-if="scope.row.approvalStatus === '待审批'">撤回</el-button> -->
</template>
</el-table-column>
</el-table>
@@ -121,7 +121,7 @@
<script>
import { getOutRequest, addOutRequest, updateOutRequest } from "@/api/wms/outRequest";
import { listApproval, updateApproval, withdrawApproval } from "@/api/wms/approval"
import { listApproval, updateApproval } from "@/api/wms/approval"
import { listDept } from "@/api/wms/dept"
import FileUpload from '@/components/FileUpload'
import EmployeeSelector from '@/components/EmployeeSelector'
@@ -324,8 +324,10 @@ export default {
handleWithdraw(row) {
this.$modal.confirm('是否确认撤回外出申请编号为"' + row.applyId + '"的数据项?').then(() => {
this.loading = true;
// 撤销审批
return withdrawApproval(row.approvalId)
return updateApproval({
approvalId: row.approvalId,
approvalStatus: '已撤销'
});
}).then(() => {
this.loading = false;
this.getList();

View File

@@ -8,7 +8,7 @@
</template>
<!-- 左侧是新增表单 -->
<el-form ref="form" :model="form" :rules="rules" label-width="80px" v-loading="loading">
<el-form-item label="审批部门" prop="deptId" v-if="!form.leaveId">
<el-form-item label="审批部门" prop="deptId">
<el-select v-model="form.deptId" placeholder="请选择审批部门" filterable @change="getDeptLeader">
<el-option v-for="item in deptOptions" :key="item.deptId"
:label="item.deptName + '(' + (item.leaderNickName || '无负责人') + ')'" :value="item.deptId"></el-option>
@@ -29,8 +29,14 @@
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<span style="font-weight: 600;">请假时段 {{ index + 1 }}</span>
<!-- 只有多行时显示删除按钮 -->
<el-button v-if="form.list.length > 1" type="text" icon="el-icon-delete" size="mini"
@click="removeLeaveItem(index)" style="color: #f56c6c;">删除</el-button>
<el-button
v-if="form.list.length > 1"
type="text"
icon="el-icon-delete"
size="mini"
@click="removeLeaveItem(index)"
style="color: #f56c6c;"
>删除</el-button>
</div>
<!-- 注意prop需要指定数组索引支持嵌套校验 -->
<el-form-item label="开始时间" :prop="`list[${index}].startTime`" :rules="rules.listItem.startTime">
@@ -73,9 +79,7 @@
</el-form-item>
</el-form>
<div style="text-align: center;">
<el-button type="primary" @click="handleSubmit" v-loading="buttonLoading">{{ form.leaveId ? '更新申请' :
'批量提交申请'
}}</el-button>
<el-button type="primary" @click="handleSubmit" v-loading="buttonLoading">{{ form.leaveId ? '更新申请' : '批量提交申请' }}</el-button>
<el-button @click="handleReset">重置表单</el-button>
</div>
</el-card>
@@ -103,8 +107,7 @@
<el-table-column label="审批情况" align="center" prop="approverName">
<template slot-scope="scope">
<!-- 每行一个不要出现换行将英文映射成中文 -->
<el-tag v-for="task in scope.row.tasks" :key="task.taskId" :type="getTaskStatusTagType(task.taskStatus)"
style="margin-right: 8px;">
<el-tag v-for="task in scope.row.tasks" :key="task.taskId" :type="getTaskStatusTagType(task.taskStatus)" style="margin-right: 8px;">
<!-- taskStatus包括pending, approved, rejected, 根据状态设置不同的标签类型 -->
{{ task.approverName }} {{ getTaskStatusText(task.taskStatus) }}
</el-tag>
@@ -130,7 +133,7 @@
<el-table-column label="操作" align="center" width="160">
<template slot-scope="scope" v-if="scope.row.approvalStatus === '待审批'">
<el-button icon="el-icon-edit" size="mini" @click="handleEdit(scope.row)">修改</el-button>
<el-button icon="el-icon-delete" size="mini" @click="handleWithdraw(scope.row)">撤回</el-button>
<!-- <el-button icon="el-icon-delete" size="mini" @click="handleWithdraw(scope.row)">撤回</el-button> -->
</template>
</el-table-column>
</el-table>
@@ -144,7 +147,7 @@
<script>
import { getLeaveRequest, addLeaveRequest, updateLeaveRequest } from "@/api/wms/leaveRequest";
import { listApproval, updateApproval, withdrawApproval } from "@/api/wms/approval"
import { listApproval, updateApproval } from "@/api/wms/approval"
import { listDept } from "@/api/wms/dept"
import FileUpload from '@/components/FileUpload'
import EmployeeSelector from '@/components/EmployeeSelector'
@@ -304,8 +307,7 @@ export default {
endTime: data.endTime,
leaveShift: data.leaveShift,
leaveDays: data.leaveDays,
leaveReason: data.leaveReason,
oldApprovalType: data.approvalType,
leaveReason: data.leaveReason
}]
};
});
@@ -325,7 +327,7 @@ export default {
this.buttonLoading = true;
const { list, ...commonFields } = this.form; // 拆分公共字段和时段列表
let successCount = 0;
let failCount = 0;
let failCount = 0;
const failReasons = [];
// 2. 循环处理每个时段,逐个发送请求
@@ -340,23 +342,21 @@ export default {
leaveDays: item.leaveDays,
leaveReason: item.leaveReason,
// 生成单条记录的标题
leaveTitle: `${commonFields.applicantName}-${commonFields.leaveType}-时段${i + 1}-${item.startTime}-${item.leaveReason || ''}`,
leaveTitle: `${commonFields.applicantName}-${commonFields.leaveType}-时段${i+1}-${item.startTime}-${item.leaveReason || ''}`,
approvalType: approvalType,
};
try {
if (commonFields.leaveId != null) {
if (singleRequestData.oldApprovalType !== approvalType) {
this.$message.warning('请假时长变动过大,请撤销后重新发起');
failCount++;
continue;
}
await updateLeaveRequest({ ...singleRequestData, leaveId: commonFields.leaveId });
successCount++;
// 编辑模式:仅支持修改单条(因为后端是单条记录)
if (list.length > 1) {
this.$message.warning('编辑模式仅支持单条修改,已自动取第一行数据');
await updateLeaveRequest({ ...singleRequestData, leaveId: commonFields.leaveId });
successCount++;
break; // 编辑时只处理第一条
} else {
await updateLeaveRequest({ ...singleRequestData, leaveId: commonFields.leaveId });
successCount++;
}
} else {
// 新增模式:批量提交多条
@@ -365,23 +365,19 @@ export default {
}
} catch (error) {
failCount++;
failReasons.push(`时段${i + 1}提交失败:${error.message || '未知错误'}`);
failReasons.push(`时段${i+1}提交失败:${error.message || '未知错误'}`);
// 失败后继续提交下一条,不中断批量操作
continue;
}
}
// 3. 提交完成后反馈结果
console.log(commonFields.leaveId);
if (commonFields.leaveId == null) {
if (failCount === 0) {
this.$modal.msgSuccess(`批量提交成功!共提交${successCount}请假申请`);
} else {
this.$modal.msgWarning(`批量提交完成!成功${successCount}条,失败${failCount}\n失败原因${failReasons.join('')}`);
}
if (failCount === 0) {
this.$modal.msgSuccess(`批量提交成功!共提交${successCount}条请假申请`);
} else {
this.$modal.msgWarning(`批量提交完成!成功${successCount},失败${failCount}\n失败原因${failReasons.join('')}`);
}
// 4. 刷新列表并重置表单
this.getList();
this.reset();
@@ -394,8 +390,10 @@ export default {
handleWithdraw(row) {
this.$modal.confirm('是否确认撤回请假申请编号为"' + row.applyId + '"的数据项?').then(() => {
this.loading = true;
// 撤销审批
return withdrawApproval(row.approvalId)
return updateApproval({
approvalId: row.approvalId,
approvalStatus: '已撤销'
});
}).then(() => {
this.loading = false;
this.getList();

View File

@@ -1,32 +1,53 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="60px">
<el-form-item label="部门" prop="deptId">
<el-select v-model="queryParams.deptId" placeholder="请选择部门" clearable @keyup.enter.native="handleQuery">
<el-option v-for="item in deptList" :value="item.deptName" :label="item.deptName" :key="item.deptId" />
</el-select>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="部门" prop="dept">
<el-input
v-model="queryParams.dept"
placeholder="请输入部门"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" clearable @keyup.enter.native="handleQuery" />
<el-input
v-model="queryParams.name"
placeholder="请输入姓名"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="queryParams.idCard" placeholder="请输入身份证号" clearable @keyup.enter.native="handleQuery" />
<el-input
v-model="queryParams.idCard"
placeholder="请输入身份证号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model="queryParams.age" placeholder="请输入年龄" clearable @keyup.enter.native="handleQuery" />
<el-input
v-model="queryParams.age"
placeholder="请输入年龄"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-select v-model="queryParams.gender" placeholder="请选择性别" clearable @change="handleQuery">
<el-option label="男" value="男" />
<el-option label="女" value="女" />
</el-select>
<!-- <el-input v-model="queryParams.gender" placeholder="请输入性别" clearable @keyup.enter.native="handleQuery" /> -->
<el-input
v-model="queryParams.gender"
placeholder="请输入性别"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="学历" prop="education">
<el-select v-model="queryParams.education" placeholder="请选择学历" clearable @change="handleQuery">
<el-option v-for="item in dict.type.hrm_employee_education" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
<el-input
v-model="queryParams.education"
placeholder="请输入学历"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@@ -36,25 +57,49 @@
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">入职</el-button>
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single"
@click="handleUpdate">修改</el-button>
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete">删除</el-button>
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="employeeInfoList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键ID" align="center" prop="infoId" v-if="false" />
<el-table-column label="主键ID" align="center" prop="infoId" v-if="false"/>
<el-table-column label="部门" align="center" prop="dept" />
<el-table-column label="岗位工种" align="center" prop="jobType" />
<el-table-column label="姓名" align="center" prop="name" />
@@ -71,208 +116,95 @@
</el-table-column>
<el-table-column label="紧急联系人" align="center" prop="emergencyContact" />
<el-table-column label="关系" align="center" prop="relationship" />
<el-table-column label="紧急联系电话" align="center" prop="emergencyContactPhone" />
<el-table-column label="紧急联系电话" align="center" prop="emergencyContactPhone" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="在职状态" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.isLeave === 0 ? 'success' : 'danger'">
{{ scope.row.isLeave === 0 ? '在职' : '已离职' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
<el-button v-if="scope.row.isLeave === 0" size="mini" type="text" icon="el-icon-switch-button"
@click="handleResignation(scope.row)">离职</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改员工信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- 公司内信息 -->
<el-card class="mb-4" shadow="never">
<template slot="header">
<div class="card-header">
<span>在职信息</span>
</div>
</template>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="部门" prop="deptId">
<!-- <el-input v-model="form.dept" placeholder="请输入部门" /> -->
<el-select v-model="form.deptId" placeholder="请选择部门">
<el-option v-for="item in deptList" :value="item.deptName" :label="item.deptName"
:key="item.deptId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="岗位工种" prop="jobType">
<el-input v-model="form.jobType" placeholder="请输入岗位工种" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入职时间" prop="entryTime">
<el-date-picker clearable v-model="form.entryTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择入职时间" style="width: 100%;">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<!-- 员工个人信息 -->
<el-card class="mb-4" shadow="never">
<template slot="header">
<div class="card-header">
<span>员工信息</span>
</div>
</template>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="form.idCard" placeholder="请输入身份证号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="年龄" prop="age">
<el-input v-model="form.age" placeholder="请输入年龄" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="性别" prop="gender">
<!-- <el-input v-model="form.gender" placeholder="请输入性别" /> -->
<el-radio-group v-model="form.gender" size="small" mode="button">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学历" prop="education">
<!-- <el-input v-model="form.education" placeholder="请输入学历" /> -->
<el-select v-model="form.education" placeholder="请选择学历">
<el-option v-for="item in dict.type.hrm_employee_education" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系电话" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="家庭住址" prop="homeAddress">
<el-input v-model="form.homeAddress" placeholder="请输入家庭住址" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<!-- 紧急联系信息 -->
<el-card class="mb-4" shadow="never">
<template slot="header">
<div class="card-header">
<span>紧急联系信息</span>
</div>
</template>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="紧急联系人" prop="emergencyContact">
<el-input v-model="form.emergencyContact" placeholder="请输入紧急联系人" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="关系" prop="relationship">
<el-input v-model="form.relationship" placeholder="请输入关系" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="紧急联系电话" prop="emergencyContactPhone">
<el-input v-model="form.emergencyContactPhone" placeholder="请输入紧急联系人电话" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<!-- 备注和附件 -->
<!-- <el-card class="mb-4" shadow="hover">
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
<el-col :span="24" v-if="!form.infoId">
<el-form-item label="附件" prop="attachment">
<file-upload v-model="attachment"></file-upload>
</el-form-item>
</el-col>
</el-row>
</el-card> -->
<el-form-item label="部门" prop="dept">
<el-input v-model="form.dept" placeholder="请输入部门" />
</el-form-item>
<el-form-item label="岗位工种" prop="jobType">
<el-input v-model="form.jobType" placeholder="请输入岗位工种" />
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="form.idCard" placeholder="请输入身份证号" />
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model="form.age" placeholder="请输入年龄" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-input v-model="form.gender" placeholder="请输入性别" />
</el-form-item>
<el-form-item label="学历" prop="education">
<el-input v-model="form.education" placeholder="请输入学历" />
</el-form-item>
<el-form-item label="家庭住址" prop="homeAddress">
<el-input v-model="form.homeAddress" placeholder="请输入家庭住址" />
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系电话" />
</el-form-item>
<el-form-item label="入职时间" prop="entryTime">
<el-date-picker clearable
v-model="form.entryTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择入职时间">
</el-date-picker>
</el-form-item>
<el-form-item label="紧急联系人" prop="emergencyContact">
<el-input v-model="form.emergencyContact" placeholder="请输入紧急联系人" />
</el-form-item>
<el-form-item label="关系" prop="relationship">
<el-input v-model="form.relationship" placeholder="请输入关系" />
</el-form-item>
<el-form-item label="紧急联系人电话" prop="emergencyContactPhone">
<el-input v-model="form.emergencyContactPhone" placeholder="请输入紧急联系人电话" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 员工离职对话框 -->
<el-dialog :title="resignationTitle" :visible.sync="resignationOpen" width="500px" append-to-body>
<el-form ref="resignationForm" :model="resignationForm" :rules="resignationRules" label-width="80px">
<el-form-item label="员工姓名" prop="name">
<el-input v-model="resignationForm.name" disabled />
</el-form-item>
<el-form-item label="异动类型" prop="changeType">
<el-input v-model="resignationForm.changeType" disabled />
</el-form-item>
<el-form-item label="离职时间" prop="changeTime">
<el-date-picker clearable v-model="resignationForm.changeTime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择离职时间" />
</el-form-item>
<el-form-item label="离职原因" prop="changeReason" required>
<el-input v-model="resignationForm.changeReason" type="textarea" placeholder="请输入离职原因" />
</el-form-item>
<el-form-item label="负责人" prop="changeHandler">
<el-input v-model="resignationForm.changeHandler" disabled />
</el-form-item>
<el-form-item label="附件" prop="attachment">
<file-upload v-model="resignationAttachment"></file-upload>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="resignationForm.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitResignation"> </el-button>
<el-button @click="cancelResignation"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listEmployeeInfo, getEmployeeInfo, delEmployeeInfo, updateEmployeeInfo } from "@/api/wms/employeeInfo";
import { listDept } from "@/api/wms/dept";
import { employeeEntry, employeeLeave } from '@/api/wms/employeeChange'
import { listEmployeeInfo, getEmployeeInfo, delEmployeeInfo, addEmployeeInfo, updateEmployeeInfo } from "@/api/wms/employeeInfo";
export default {
name: "EmployeeInfo",
@@ -314,46 +246,11 @@ export default {
form: {},
// 表单校验
rules: {
},
// 附件
attachment: undefined,
// 部门列表
deptList: [],
// 离职对话框相关
resignationTitle: "员工离职",
resignationOpen: false,
resignationForm: {
infoId: undefined,
name: undefined,
changeType: "离职",
changeTime: undefined,
changeReason: undefined,
changeHandler: undefined,
remark: undefined
},
resignationRules: {
changeTime: [
{
required: true,
message: "请选择离职时间",
trigger: "change"
}
],
changeReason: [
{
required: true,
message: "请输入离职原因",
trigger: "blur"
}
]
},
resignationAttachment: undefined
}
};
},
dicts: ['hrm_employee_education'],
created() {
this.getList();
this.getDeptList();
},
methods: {
/** 查询员工信息列表 */
@@ -365,11 +262,6 @@ export default {
this.loading = false;
});
},
getDeptList() {
listDept().then(response => {
this.deptList = response.data;
});
},
// 取消按钮
cancel() {
this.open = false;
@@ -415,14 +307,14 @@ export default {
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.infoId)
this.single = selection.length !== 1
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "员工入职";
this.title = "添加员工信息";
},
/** 修改按钮操作 */
handleUpdate(row) {
@@ -450,14 +342,8 @@ export default {
this.buttonLoading = false;
});
} else {
employeeEntry({
changeType: 0,
changeTime: this.form.entryTime,
changeHandler: this.$store.getters.nickName,
attachment: this.attachment,
...this.form
}).then(response => {
this.$modal.msgSuccess("员工入职成功");
addEmployeeInfo(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
@@ -487,64 +373,6 @@ export default {
this.download('wms/employeeInfo/export', {
...this.queryParams
}, `employeeInfo_${new Date().getTime()}.xlsx`)
},
/** 离职按钮操作 */
handleResignation(row) {
// 获取北京时间UTC+8
const now = new Date();
const formattedDate = this.parseTime(now, '{y}-{m}-{d} {h}:{i}:{s}')
this.resignationForm = {
infoId: row.infoId,
name: row.name,
changeType: "离职",
changeTime: formattedDate,
changeReason: undefined,
changeHandler: this.$store.getters.nickName,
remark: undefined
};
this.resignationAttachment = undefined;
this.resignationOpen = true;
},
/** 取消离职按钮操作 */
cancelResignation() {
this.resignationOpen = false;
this.resignationForm = {
infoId: undefined,
name: undefined,
changeType: "1",
changeTime: undefined,
changeReason: undefined,
changeHandler: undefined,
remark: undefined
};
this.resignationAttachment = undefined;
this.resetForm("resignationForm");
},
/** 提交离职表单 */
submitResignation() {
this.$refs["resignationForm"].validate(valid => {
if (valid) {
this.$modal.confirm('是否确认提交员工离职申请?').then(() => {
this.buttonLoading = true;
employeeLeave({
changeType: 1,
changeTime: this.resignationForm.changeTime,
changeReason: this.resignationForm.changeReason,
changeHandler: this.resignationForm.changeHandler,
attachment: this.resignationAttachment,
remark: this.resignationForm.remark,
infoId: this.resignationForm.infoId
}).then(response => {
this.$modal.msgSuccess("员工离职成功");
this.resignationOpen = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
});
}
});
}
}
};

View File

@@ -40,32 +40,39 @@
<div class="custom-tabs-nav">
<div
class="custom-tabs-item"
:class="{ active: queryParams.taskStatus === undefined || queryParams.taskStatus === '' }"
@click="handleTabClick('taskStatus', '')"
:class="{ active: queryParams.approvalStatus === undefined || queryParams.approvalStatus === '' }"
@click="handleTabClick('approvalStatus', '')"
>
全部
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.taskStatus === 'pending' }"
@click="handleTabClick('taskStatus', 'pending')"
:class="{ active: queryParams.approvalStatus === '待审批' }"
@click="handleTabClick('approvalStatus', '待审批')"
>
待审批
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.taskStatus === 'approved' }"
@click="handleTabClick('taskStatus', 'approved')"
:class="{ active: queryParams.approvalStatus === '已同意' }"
@click="handleTabClick('approvalStatus', '已同意')"
>
已同意
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.taskStatus === 'rejected' }"
@click="handleTabClick('taskStatus', 'rejected')"
:class="{ active: queryParams.approvalStatus === '已驳回' }"
@click="handleTabClick('approvalStatus', '已驳回')"
>
已驳回
</div>
<div
class="custom-tabs-item"
:class="{ active: queryParams.approvalStatus === '已撤销' }"
@click="handleTabClick('approvalStatus', '已撤销')"
>
已撤回
</div>
</div>
</div>
@@ -103,13 +110,6 @@
{{ scope.row.endTime ? formatTime(scope.row.endTime) : '-' }}
</template>
</el-table-column>
<el-table-column prop="taskStatus" label="整体状态" align="center">
<template slot-scope="scope">
<el-tag :type="getInstStatusTagType(scope.row.approvalStatus)">
{{ getInstStatusText(scope.row.approvalStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="taskStatus" label="审批状态" align="center">
<template slot-scope="scope">
<el-tag :type="getStatusTagType(scope.row.taskStatus)">
@@ -127,7 +127,7 @@
详情
</el-button>
<el-button
v-if="scope.row.taskStatus === 'pending'"
v-if="scope.row.approvalStatus === '待审批'"
size="small"
icon="el-icon-check"
@click="handleApprove(scope.row)"
@@ -136,7 +136,7 @@
同意
</el-button>
<el-button
v-if="scope.row.taskStatus === 'pending'"
v-if="scope.row.approvalStatus === '待审批'"
size="small"
icon="el-icon-close"
@click="handleReject(scope.row)"
@@ -182,9 +182,6 @@
<el-descriptions-item label="请假天数">{{ currentDetail.leaveDays || '-' }}</el-descriptions-item>
<el-descriptions-item label="请假原因">{{ currentDetail.leaveReason || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ currentDetail.remark || '-' }}</el-descriptions-item>
<el-descriptions-item label="附件">
<FileList :ossIds="currentDetail.attachmentUrls" />
</el-descriptions-item>
</el-descriptions>
</div>
@@ -199,9 +196,6 @@
<el-descriptions-item label="外出地点">{{ currentDetail.outPlace || '-' }}</el-descriptions-item>
<el-descriptions-item label="外出原因">{{ currentDetail.outReason || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ currentDetail.remark || '-' }}</el-descriptions-item>
<el-descriptions-item label="附件">
<FileList :ossIds="currentDetail.attachmentUrls" />
</el-descriptions-item>
</el-descriptions>
</div>
@@ -214,14 +208,9 @@
<script>
import { listApprovalTask, rejectApprovalTask, resolveApprovalTask } from '@/api/wms/approvalTask'
import FileList from '@/components/FileList/index.vue'
export default {
name: 'TodoList',
components: {
FileList,
},
data() {
return {
// 查询参数
@@ -380,27 +369,6 @@ export default {
return this.parseTime(time, '{y}-{m}-{d} {h}')
},
// 获取审批状态对应的标签类型
getInstStatusTagType(status) {
const typeMap = {
'待审批': 'warning',
'已同意': 'success',
'已驳回': 'danger',
'已撤销': 'info',
}
return typeMap[status] || 'default'
},
// 获取审批状态的中文文本
getInstStatusText(status) {
const textMap = {
'待审批': '待审批',
'已同意': '已同意',
'已驳回': '已驳回',
'已撤销': '已撤销',
}
return textMap[status] || '未知状态'
},
// 获取审批状态对应的标签类型
getStatusTagType(status) {
const typeMap = {

View File

@@ -318,7 +318,7 @@ export default {
const res1 = await listPendingAction({
actionStatus: 2,
actionType: 11, // 酸轧工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -328,7 +328,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -339,7 +339,7 @@ export default {
const res1 = await listPendingAction({
actionStatus: 2,
actionType: 11, // 酸轧工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -349,7 +349,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -394,7 +394,7 @@ export default {
const res1 = await listPendingAction({
actionStatus: 2,
actionType: 11, // 酸轧工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -404,7 +404,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -323,7 +323,7 @@ export default {
const res1 = await listPendingAction({
actionStatus: 2,
actionType: 11, // 酸轧工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -333,7 +333,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -186,7 +186,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 11, // 酸轧工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -196,7 +196,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -304,7 +304,7 @@ export default {
const res1 = await listPendingAction({
actionStatus: 2,
actionType: 501, // 镀锌工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -314,7 +314,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -325,7 +325,7 @@ export default {
const res1 = await listPendingAction({
actionStatus: 2,
actionType: 501, // 镀锌工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -335,7 +335,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -381,7 +381,7 @@ export default {
const res1 = await listPendingAction({
actionStatus: 2,
actionType: 501, // 镀锌工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -391,7 +391,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -307,7 +307,7 @@ export default {
const res1 = await listPendingAction({
actionStatus: 2,
actionType: 501, // 镀锌工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -317,7 +317,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -186,7 +186,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 501, // 镀锌工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,
@@ -196,7 +196,7 @@ export default {
warehouseId: this.queryParams.planId,
// actionType: 401,
actionType: 120, // 分条工序
pageSize: 9999,
pageSize: 999,
pageNum: 1,
startTime: this.queryParams.byCreateTimeStart,
endTime: this.queryParams.byCreateTimeEnd,

View File

@@ -1,405 +0,0 @@
<template>
<div class="bird-container">
<!-- 图例 -->
<div class="legend-container">
<div class="legend-item">
<div class="legend-color layer-1"></div>
<span class="legend-text">一层</span>
</div>
<div class="legend-item">
<div class="legend-color layer-2"></div>
<span class="legend-text">二层</span>
</div>
<div class="legend-item">
<div class="legend-color occupied"></div>
<span class="legend-text">已占用</span>
</div>
<div class="legend-item">
<div class="legend-color error"></div>
<span class="legend-text">异常</span>
</div>
</div>
<!-- 分列库位容器 -->
<div class="layers-container">
<!-- 无数据提示 -->
<div class="empty-tip" v-if="Object.keys(columns).length === 0 && warehouseList.length > 0">
暂无解析到有效的库位分列数据
</div>
<div class="empty-tip" v-else-if="warehouseList.length === 0">
<el-empty description="暂无库位数据"></el-empty>
</div>
<warehouse-interlaced ref="warehouseInterlaced" v-else="warehouseList.length" :id="id" :columns="columns" :canToggle="canToggle"
:canRelease="canRelease" @split-warehouse="handleSplitWarehouse" @merge-warehouse="handleMergeWarehouse"
@release-warehouse="handleReleaseWarehouse" />
</div>
</div>
</template>
<script>
import WarehouseInterlaced from './WarehouseInterlaced.vue';
export default {
name: "WarehouseBirdMini",
components: { WarehouseInterlaced },
props: {
// 原始库位列表
warehouseList: {
type: Array,
default: () => []
},
id: {
type: String,
default: ''
},
canToggle: {
default: true,
type: Boolean
},
canRelease: {
default: false,
type: Boolean
}
},
data() {
return {
// 分列库位数据核心修改从layers改为columns
columns: {},
// 统计信息(适配分列逻辑)
statistics: {
total: 0,
columnCount: 0,
columnDetail: {},
// 占用情况
// 每一列每一层的总数和已占用数量
layerDetail: {}
},
tableData: []
};
},
watch: {
// 监听库位列表变化,重新构建分列数据
warehouseList: {
immediate: true,
handler(newVal) {
this.buildWarehouseBox(newVal);
}
}
},
methods: {
// 处理分列数据调整
resize() {
this.$refs.warehouseInterlaced?.handleResize();
},
handleSplitWarehouse(warehouse) {
this.$emit('split-warehouse', warehouse);
},
// 1. 转换layerDetail为表格所需的数组格式
formatTableData() {
const layerDetail = this.statistics.layerDetail;
this.tableData = Object.keys(layerDetail).map(column => {
const layer1 = layerDetail[column].layer1;
const layer2 = layerDetail[column].layer2;
return {
column: column, // 列号
// 第一层数据
layer1_total: layer1.total,
layer1_occupied: layer1.occupied,
layer1_free: layer1.free,
// 第二层数据
layer2_total: layer2.total,
layer2_occupied: layer2.occupied,
layer2_free: layer2.free,
// 该列总计
column_total: layer1.total + layer2.total,
column_occupied: layer1.occupied + layer2.occupied,
column_free: layer1.free + layer2.free
};
});
},
handleMergeWarehouse(warehouse) {
this.$emit('merge-warehouse', warehouse);
},
handleReleaseWarehouse(warehouse) {
this.$emit('release-warehouse', warehouse);
},
/**
* 解析第三级库位编码
* 新规则:
* 1. 前三位:数字或字母的任意组合
* 2. column从第五位开始到第一个"-"为止(支持多位数)
* 3. 保留 row两位数字、layer数字的解析规则
*/
parseWarehouseCode(code) {
if (!code) return null;
// 新正则表达式解析规则
// ^([A-Za-z0-9]{3}) 匹配前3位数字/字母)
// . 匹配第4位任意单个字符
// ([^-]+) 匹配column到第一个"-"为止至少1位
// -(\d{2}) 匹配row两位数字
// -(\d+) 匹配layer一位或多位数字
const reg = /^([A-Za-z0-9]{3})([^-]+)-(\d{2})-(\d+)$/;
const match = code.match(reg);
if (!match) {
console.warn(`库位编码解析失败:${code},格式不符合规范`);
return null;
}
return {
level: 3,
warehousePrefix: match[1], // 前三位(数字/字母替代原warehouseFirst/warehouseSecond
warehouseFirst: match[1].slice(0, 2), // 前三位的前两个字符
warehouseSecond: match[1].slice(2, 3), // 前三位的第三个字符
column: Number(match[2]), // 第五位到第一个"-"的内容(多位数)
row: Number(match[3]), // 两位数字的行号
layer: match[4] // 层级数字(可多位数)
};
},
/**
* 解析第四级库位编码格式为F2A1-X01-1
*/
parseWarehouseCodeFourth(code) {
if (!code) return null;
const reg = /^([A-Za-z0-9]{3})([^-]+)-X(\d{2})-(\d+)$/;
const match = code.match(reg);
if (!match) {
console.warn(`库位编码解析失败:${code},格式不符合规范`);
return null;
}
// console.log('match:', match);
return {
level: 4,
warehousePrefix: match[1],
warehouseFirst: match[1].slice(0, 2), // 前三位的前两个字符
warehouseSecond: match[1].slice(2, 3), // 前三位的第三个字符
// warehouseSecond: match[2],
column: Number(match[2]),
row: Number(match[3]),
layer: match[4],
};
},
buildWarehouseBox(list) {
const columnMap = {}; // 按列分组的核心对象
const statistics = {
total: list.length,
columnCount: 0,
columnDetail: {},
// 占用情况:每一列每一层的总数、已占用、未占用数量
layerDetail: {}
};
// 1. 按列分组每列内部分为layer1和layer2两个数组
list.forEach((warehouse) => {
let codeInfo = {}
if (warehouse.actualWarehouseType == 4) {
codeInfo = this.parseWarehouseCodeFourth(warehouse.actualWarehouseCode);
} else {
codeInfo = this.parseWarehouseCode(warehouse.actualWarehouseCode);
}
if (!codeInfo) return;
const { layer, row, column } = codeInfo;
warehouse.parsedInfo = codeInfo;
// 初始化列数据结构每列包含layer1、layer2数组以及最大行号
if (!columnMap[column]) {
columnMap[column] = {
maxRow: 0,
layer1: [], // 第一层库位数组
layer2: [], // 第二层库位数组
total: 0 // 该列总库位数
};
}
// 更新列的最大行号
columnMap[column].maxRow = Math.max(columnMap[column].maxRow, row);
// 根据层数将库位放入对应数组
if (layer === '1' || layer === 1) {
columnMap[column].layer1.push(warehouse);
} else if (layer === '2' || layer === 2) {
columnMap[column].layer2.push(warehouse);
}
// 更新该列总库位数
columnMap[column].total = columnMap[column].layer1.length + columnMap[column].layer2.length;
});
// 2. 对每列的两层数据分别按行号排序
Object.keys(columnMap).forEach((column) => {
const columnData = columnMap[column];
// 按行号排序(保证展示顺序正确)
columnData.layer1.sort((a, b) => a.parsedInfo.row - b.parsedInfo.row);
columnData.layer2.sort((a, b) => a.parsedInfo.row - b.parsedInfo.row);
});
// 3. 更新统计信息(适配分列逻辑)
statistics.columnCount = Object.keys(columnMap).length;
Object.keys(columnMap).forEach((column) => {
const columnData = columnMap[column];
// 列维度总数量
statistics.columnDetail[column] = columnData.total;
// ========== 新增layerDetail 层级统计逻辑 ==========
// 初始化当前列的层级统计结构
statistics.layerDetail[column] = {
layer1: {
total: 0, // 该层总库位数
occupied: 0, // 已占用isEnabled=0
free: 0 // 未占用isEnabled=1
},
layer2: {
total: 0,
occupied: 0,
free: 0
}
};
// 统计第一层
const layer1Data = columnData.layer1;
statistics.layerDetail[column].layer1.total = layer1Data.length;
statistics.layerDetail[column].layer1.occupied = layer1Data.filter(item => item.isEnabled === 0).length;
statistics.layerDetail[column].layer1.free = layer1Data.filter(item => item.isEnabled === 1).length;
// 统计第二层
const layer2Data = columnData.layer2;
statistics.layerDetail[column].layer2.total = layer2Data.length;
statistics.layerDetail[column].layer2.occupied = layer2Data.filter(item => item.isEnabled === 0).length;
statistics.layerDetail[column].layer2.free = layer2Data.filter(item => item.isEnabled === 1).length;
});
// 4. 赋值到响应式数据
this.columns = columnMap;
this.statistics = statistics;
this.formatTableData();
},
/**
* 打开初始化弹窗(透传至根组件)
*/
openInitDialog() {
this.$emit('open-init-dialog');
}
},
};
</script>
<style scoped lang="scss">
.bird-container {
width: 100%;
height: 100%;
}
// 统计卡片样式
.statistics-card {
margin-bottom: 16px;
.statistics-item {
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
.label {
color: #606266;
font-size: 14px;
}
.value {
color: #303133;
font-size: 14px;
font-weight: 500;
margin-left: 8px;
}
}
}
// 图例样式
.legend-container {
display: flex;
align-items: center;
margin-bottom: 16px;
padding: 8px 12px;
background: #f8f9fa;
border-radius: 4px;
.legend-item {
display: flex;
align-items: center;
margin-right: 24px;
&:last-child {
margin-right: 0;
}
.legend-color {
width: 16px;
height: 16px;
border-radius: 2px;
margin-right: 8px;
border: 1px solid #e6e6e6;
}
.normal {
background-color: #ffffff;
}
.layer-1 {
background-color: #fff3e0;
}
.layer-2 {
background-color: #e8f5e9;
}
.occupied {
background-color: #fafafa;
}
.error {
background-color: #fdecea;
}
.legend-text {
font-size: 14px;
color: #606266;
}
}
}
// 分列容器样式
.layers-container {
display: flex;
.layer-section {
flex: 1;
max-width: 50%;
margin-bottom: 24px;
}
.empty-tip {
text-align: center;
padding: 32px;
color: #909399;
font-size: 14px;
background: #fff;
border-radius: 8px;
.empty-text {
margin-bottom: 16px;
}
}
}
</style>

View File

@@ -125,7 +125,7 @@ export default {
canRelease: {
default: false,
type: Boolean
},
}
},
data() {
return {

View File

@@ -224,17 +224,4 @@ public class WmsActualWarehouseController extends BaseController {
return AjaxResult.error("库区释放失败: " + e.getMessage());
}
}
/**
* 修正已生成库位的排序号(交错排序)
*
* @param parentId 父库位ID
*/
@Log(title = "修正库位排序号", businessType = BusinessType.UPDATE)
@PutMapping("/fixSortNo/{parentId}")
public R<Integer> fixSortNo(@PathVariable Long parentId) {
int count = iWmsActualWarehouseService.fixSortNoByParentId(parentId);
return R.ok(count);
}
}

View File

@@ -142,18 +142,4 @@ public class WmsApprovalController extends BaseController {
public R<List<WmsApprovalTaskVo>> getTasks(@PathVariable Long approvalId) {
return R.ok(iWmsApprovalTaskService.queryByApprovalId(approvalId));
}
/**
* 撤销审批
*
* @param approvalId 审批ID
*/
@Log(title = "撤销审批", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/cancel")
public R<Map<String, Object>> cancelApproval(
@NotNull(message = "审批ID不能为空")
@RequestParam Long approvalId) {
return R.ok(iWmsApprovalService.cancelApproval(approvalId));
}
}

View File

@@ -106,7 +106,7 @@ public class WmsCoilPendingActionController extends BaseController {
*/
@Log(title = "钢卷待操作", businessType = BusinessType.UPDATE)
@PutMapping("/status/{actionId}/{status}")
public R<Void> updateStatus(@PathVariable("actionId") Long actionId,
public R<Void> updateStatus(@PathVariable("actionId") Long actionId,
@PathVariable("status") Integer status) {
return toAjax(iWmsCoilPendingActionService.updateStatus(actionId, status));
}
@@ -138,15 +138,6 @@ public class WmsCoilPendingActionController extends BaseController {
return toAjax(iWmsCoilPendingActionService.cancelAction(actionId));
}
/**
* 还原操作(将已删除的记录恢复为正常状态)
*/
@Log(title = "钢卷待操作", businessType = BusinessType.UPDATE)
@PutMapping("/restore/{actionId}")
public R<Void> restoreAction(@PathVariable("actionId")@NotNull Long actionId) {
return toAjax(iWmsCoilPendingActionService.restoreAction(actionId));
}
/**
* 计算理论节拍回归默认近6个月并返回散点+拟合线
*/

View File

@@ -71,8 +71,8 @@ public class WmsCoilStatisticsSummaryController extends BaseController {
@Log(title = "钢卷生产统计汇总(数据透视结果持久化)", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<WmsCoilStatisticsSummaryVo> add(@Validated(AddGroup.class) @RequestBody WmsCoilStatisticsSummaryBo bo) {
return R.ok(iWmsCoilStatisticsSummaryService.insertByBo(bo));
public R<Void> add(@Validated(AddGroup.class) @RequestBody WmsCoilStatisticsSummaryBo bo) {
return toAjax(iWmsCoilStatisticsSummaryService.insertByBo(bo));
}
/**
@@ -96,15 +96,4 @@ public class WmsCoilStatisticsSummaryController extends BaseController {
@PathVariable Long[] summaryIds) {
return toAjax(iWmsCoilStatisticsSummaryService.deleteWithValidByIds(Arrays.asList(summaryIds), true));
}
/**
* 检查当天是否存在指定类型的统计记录
*
* @param statType 统计类型
* @return 存在的记录ID不存在则返回null
*/
@GetMapping("/checkToday")
public R<Long> checkTodayExists(@RequestParam String statType) {
return R.ok(iWmsCoilStatisticsSummaryService.checkExistsByStatTypeToday(statType));
}
}

View File

@@ -1,119 +0,0 @@
package com.klp.controller;
import java.util.List;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.klp.common.annotation.RepeatSubmit;
import com.klp.common.annotation.Log;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.domain.R;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.domain.vo.WmsEmployeeChangeVo;
import com.klp.domain.bo.WmsEmployeeChangeBo;
import com.klp.service.IWmsEmployeeChangeService;
import com.klp.common.core.page.TableDataInfo;
/**
* 员工异动(入职/离职)
*
* @author klp
* @date 2026-03-14
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/wms/employeeChange")
public class WmsEmployeeChangeController extends BaseController {
private final IWmsEmployeeChangeService iWmsEmployeeChangeService;
/**
* 查询员工异动(入职/离职)列表
*/
@GetMapping("/list")
public TableDataInfo<WmsEmployeeChangeVo> list(WmsEmployeeChangeBo bo, PageQuery pageQuery) {
return iWmsEmployeeChangeService.queryPageList(bo, pageQuery);
}
/**
* 导出员工异动(入职/离职)列表
*/
@Log(title = "员工异动(入职/离职)", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(WmsEmployeeChangeBo bo, HttpServletResponse response) {
List<WmsEmployeeChangeVo> list = iWmsEmployeeChangeService.queryList(bo);
ExcelUtil.exportExcel(list, "员工异动(入职/离职)", WmsEmployeeChangeVo.class, response);
}
/**
* 获取员工异动(入职/离职)详细信息
*
* @param changeId 主键
*/
@GetMapping("/{changeId}")
public R<WmsEmployeeChangeVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long changeId) {
return R.ok(iWmsEmployeeChangeService.queryById(changeId));
}
/**
* 新增员工异动(入职/离职)
*/
@Log(title = "员工异动(入职/离职)", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody WmsEmployeeChangeBo bo) {
return toAjax(iWmsEmployeeChangeService.insertByBo(bo));
}
/**
* 修改员工异动(入职/离职)
*/
@Log(title = "员工异动(入职/离职)", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody WmsEmployeeChangeBo bo) {
return toAjax(iWmsEmployeeChangeService.updateByBo(bo));
}
/**
* 删除员工异动(入职/离职)
*
* @param changeIds 主键串
*/
@Log(title = "员工异动(入职/离职)", businessType = BusinessType.DELETE)
@DeleteMapping("/{changeIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] changeIds) {
return toAjax(iWmsEmployeeChangeService.deleteWithValidByIds(Arrays.asList(changeIds), true));
}
/**
* 员工入职
*/
@Log(title = "员工入职", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/entry")
public R<Void> entry(@Validated(AddGroup.class) @RequestBody WmsEmployeeChangeBo bo) {
return toAjax(iWmsEmployeeChangeService.employeeEntry(bo));
}
/**
* 员工离职
*/
@Log(title = "员工离职", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/leave")
public R<Void> leave(@Validated(AddGroup.class) @RequestBody WmsEmployeeChangeBo bo) {
return toAjax(iWmsEmployeeChangeService.employeeLeave(bo));
}
}

View File

@@ -1,15 +1,13 @@
package com.klp.controller;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Arrays;
import java.util.stream.Collectors;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.klp.domain.vo.*;
import com.klp.domain.vo.WmsMaterialCoilExportVo;
import com.klp.domain.vo.WmsMaterialCoilDeliveryExportVo;
import com.klp.domain.vo.WmsMaterialCoilLocationGridVo;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
@@ -24,6 +22,7 @@ import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.domain.vo.WmsMaterialCoilVo;
import com.klp.domain.bo.WmsMaterialCoilBo;
import com.klp.domain.vo.dashboard.CoilTrimStatisticsVo;
import com.klp.domain.vo.dashboard.CategoryWidthStatisticsVo;
@@ -67,7 +66,7 @@ public class WmsMaterialCoilController extends BaseController {
}
/**
* 导出钢卷物料表列表(精简字段版本)
* 导出钢卷物料表列表(完整字段版本)
*/
@Log(title = "钢卷物料表", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@@ -75,16 +74,6 @@ public class WmsMaterialCoilController extends BaseController {
List<WmsMaterialCoilExportVo> list = iWmsMaterialCoilService.queryExportList(bo);
ExcelUtil.exportExcel(list, "钢卷物料表", WmsMaterialCoilExportVo.class, response);
}
/**
* 导出钢卷物料表列表(完整字段版本)
* 导出全部字段
*/
@Log(title = "钢卷物料表", businessType = BusinessType.EXPORT)
@PostMapping("/exportAll")
public void exportSimple(WmsMaterialCoilBo bo, HttpServletResponse response) {
List<WmsMaterialCoilAllExportVo> list = iWmsMaterialCoilService.queryExportListAll(bo);
ExcelUtil.exportExcel(list, "钢卷物料表", WmsMaterialCoilAllExportVo.class, response);
}
/**
* 导出发货报表(按 coilIds联查发货单明细/主表/发货计划)
@@ -296,23 +285,19 @@ public class WmsMaterialCoilController extends BaseController {
* 检查钢卷号是否重复
* 前端传入入场钢卷号和当前钢卷号,返回哪个钢卷号重复
*
* @param coilId 钢卷ID修改时传入用于排除自身
* @param enterCoilNo 入场钢卷号
* @param currentCoilNo 当前钢卷号
* @param supplierCoilNo 厂家原料卷号
* @return 返回结果,包含:
* - duplicateType: "enter" (入场钢卷号重复), "current" (当前钢卷号重复), "supplier" (厂家原料卷号重复), "both" (都重复), "none" (都不重复)
* - duplicateType: "enter" (入场钢卷号重复), "current" (当前钢卷号重复), "both" (都重复), "none" (都不重复)
* - enterCoilNoDuplicate: 入场钢卷号是否重复
* - currentCoilNoDuplicate: 当前钢卷号是否重复
* - supplierCoilNoDuplicate: 厂家原料卷号是否重复
*/
@GetMapping("/checkCoilNoDuplicate")
public R<Map<String, Object>> checkCoilNoDuplicate(
@RequestParam(required = false) Long coilId,
@RequestParam(required = false) String enterCoilNo,
@RequestParam(required = false) String currentCoilNo,
@RequestParam(required = false) String supplierCoilNo) {
Map<String, Object> result = iWmsMaterialCoilService.checkCoilNoDuplicate(coilId, enterCoilNo, currentCoilNo, supplierCoilNo);
@RequestParam(required = false) String currentCoilNo) {
Map<String, Object> result = iWmsMaterialCoilService.checkCoilNoDuplicate(coilId,enterCoilNo, currentCoilNo);
return R.ok(result);
}
@@ -375,12 +360,9 @@ public class WmsMaterialCoilController extends BaseController {
@PostMapping("/specialSplit/start")
public R<Long> startSpecialSplit(
@NotNull(message = "钢卷ID不能为空")
@RequestParam Long coilId,
@NotNull(message = "操作类型不能为空")
@RequestParam Integer actionType
) {
@RequestParam Long coilId) {
try {
Boolean result = iWmsMaterialCoilService.startSpecialSplit(coilId, actionType);
Boolean result = iWmsMaterialCoilService.startSpecialSplit(coilId);
if (Boolean.TRUE.equals(result)) {
return R.ok();
}

View File

@@ -46,7 +46,4 @@ public class WmsCoilStatisticsSummary extends BaseEntity {
@TableLogic
private Long delFlag;
// 新增附件字段
private String attachmentInfo;
}

View File

@@ -1,63 +0,0 @@
package com.klp.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 员工异动(入职/离职)对象 wms_employee_change
*
* @author klp
* @date 2026-03-14
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("wms_employee_change")
public class WmsEmployeeChange extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 异动记录主键ID
*/
@TableId(value = "change_id")
private Long changeId;
/**
* 关联员工信息表的主键ID
*/
private Long infoId;
/**
* 异动类型0=入职1=离职
*/
private Integer changeType;
/**
* 异动时间(入职/离职时间)
*/
private Date changeTime;
/**
* 异动原因(离职必填,入职可选)
*/
private String changeReason;
/**
* 负责人
*/
private String changeHandler;
/**
* 附件
*/
private String attachment;
/**
* 逻辑删除标识0=正常1=已删
*/
@TableLogic
private Integer delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -82,10 +82,6 @@ public class WmsEmployeeInfo extends BaseEntity {
* 紧急联系人电话
*/
private String emergencyContactPhone;
/**
* 社保类型(三险/五险)
*/
private String socialInsuranceType;
/**
* 逻辑删除标识0=正常1=已删
*/
@@ -96,6 +92,4 @@ public class WmsEmployeeInfo extends BaseEntity {
*/
private String remark;
// 是否离职
private Integer isLeave;
}

View File

@@ -160,15 +160,5 @@ public class WmsMaterialCoil extends BaseEntity {
// 父钢卷id
private String parentCoilId;
/**
* 实测长度
*/
private BigDecimal actualLength;
/**
* 实测宽度
*/
private BigDecimal actualWidth;
}

View File

@@ -89,13 +89,13 @@ public class WmsCoilPendingActionBo extends BaseEntity {
/**
* 处理时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX", timezone = "GMT+8")
private Date processTime;
/**
* 完成时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX", timezone = "GMT+8")
private Date completeTime;
//开始时间和结束时间
@@ -109,10 +109,5 @@ public class WmsCoilPendingActionBo extends BaseEntity {
//备注
private String remark;
/**
* 是否包含已删除记录0=不包含1=包含已删除2=仅查询已删除)
*/
private Integer includeDeleted;
}

View File

@@ -42,8 +42,5 @@ public class WmsCoilStatisticsSummaryBo extends BaseEntity {
*/
private String remark;
// 新增附件字段
private String attachmentInfo;
}

View File

@@ -1,142 +0,0 @@
package com.klp.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 员工异动(入职/离职)业务对象 wms_employee_change
*
* @author klp
* @date 2026-03-14
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class WmsEmployeeChangeBo extends BaseEntity {
/**
* 异动记录主键ID
*/
private Long changeId;
/**
* 关联员工信息表的主键ID
*/
private Long infoId;
/**
* 异动类型0=入职1=离职
*/
private Integer changeType;
/**
* 异动时间(入职/离职时间)
*/
private Date changeTime;
/**
* 异动原因(离职必填,入职可选)
*/
private String changeReason;
/**
* 负责人
*/
private String changeHandler;
/**
* 附件
*/
private String attachment;
/**
* 备注
*/
private String remark;
/**
* 序号
*/
private Long serialNumber;
/**
* 部门
*/
private String dept;
/**
* 岗位工种
*/
private String jobType;
/**
* 姓名
*/
private String name;
/**
* 身份证号
*/
private String idCard;
/**
* 年龄
*/
private Long age;
/**
* 性别(男/女)
*/
private String gender;
/**
* 学历
*/
private String education;
/**
* 家庭住址
*/
private String homeAddress;
/**
* 联系电话
*/
private String phone;
/**
* 入职时间
*/
private Date entryTime;
/**
* 紧急联系人
*/
private String emergencyContact;
/**
* 关系
*/
private String relationship;
/**
* 紧急联系人电话
*/
private String emergencyContactPhone;
/**
* 社保类型(三险/五险)
*/
private String socialInsuranceType;
// infoRemart
private String infoRemark;
}

View File

@@ -94,19 +94,10 @@ public class WmsEmployeeInfoBo extends BaseEntity {
*/
private String emergencyContactPhone;
/**
* 社保类型(三险/五险)
*/
private String socialInsuranceType;
/**
* 备注
*/
private String remark;
// 是否离职
private Integer isLeave;
}

View File

@@ -260,15 +260,5 @@ public class WmsMaterialCoilBo extends BaseEntity {
// 已绑定钢卷列表中,未发货(status=0)的排在前面
@TableField(exist = false)
private Boolean statusFirst;
/**
* 实测长度
*/
private BigDecimal actualLength;
/**
* 实测宽度
*/
private BigDecimal actualWidth;
}

View File

@@ -200,6 +200,7 @@ public class WmsCoilPendingActionVo extends BaseEntity implements Serializable {
private String actualWarehouseName;
private Integer delFlag;
}

View File

@@ -4,7 +4,6 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.klp.common.annotation.ExcelDictFormat;
import com.klp.common.convert.ExcelDictConvert;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
@@ -16,7 +15,7 @@ import lombok.Data;
*/
@Data
@ExcelIgnoreUnannotated
public class WmsCoilStatisticsSummaryVo extends BaseEntity {
public class WmsCoilStatisticsSummaryVo {
private static final long serialVersionUID = 1L;
@@ -53,7 +52,5 @@ public class WmsCoilStatisticsSummaryVo extends BaseEntity {
@ExcelProperty(value = "备注")
private String remark;
// 新增附件字段
private String attachmentInfo;
}

View File

@@ -1,82 +0,0 @@
package com.klp.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.klp.common.annotation.ExcelDictFormat;
import com.klp.common.convert.ExcelDictConvert;
import com.klp.domain.WmsEmployeeInfo;
import lombok.Data;
/**
* 员工异动(入职/离职)视图对象 wms_employee_change
*
* @author klp
* @date 2026-03-14
*/
@Data
@ExcelIgnoreUnannotated
public class WmsEmployeeChangeVo {
private static final long serialVersionUID = 1L;
/**
* 异动记录主键ID
*/
@ExcelProperty(value = "异动记录主键ID")
private Long changeId;
/**
* 关联员工信息表的主键ID
*/
@ExcelProperty(value = "关联员工信息表的主键ID")
private Long infoId;
/**
* 异动类型0=入职1=离职
*/
@ExcelProperty(value = "异动类型0=入职1=离职")
private Integer changeType;
/**
* 异动时间(入职/离职时间)
*/
@ExcelProperty(value = "异动时间", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "入=职/离职时间")
private Date changeTime;
/**
* 异动原因(离职必填,入职可选)
*/
@ExcelProperty(value = "异动原因", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "离=职必填,入职可选")
private String changeReason;
/**
* 负责人
*/
@ExcelProperty(value = "负责人")
private String changeHandler;
/**
* 附件
*/
@ExcelProperty(value = "附件")
private String attachment;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 员工信息
*/
private WmsEmployeeInfo wmsEmployeeInfo;
}

View File

@@ -112,11 +112,6 @@ public class WmsEmployeeInfoVo {
@ExcelProperty(value = "紧急联系人电话")
private String emergencyContactPhone;
/**
* 社保类型(三险/五险)
*/
private String socialInsuranceType;
/**
* 备注
*/
@@ -124,6 +119,4 @@ public class WmsEmployeeInfoVo {
private String remark;
// 是否离职
private Integer isLeave;
}

View File

@@ -1,193 +0,0 @@
package com.klp.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.klp.common.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 钢卷物料导出VO
*
* @author klp
* @date 2025-11-27
*/
@Data
@ExcelIgnoreUnannotated
public class WmsMaterialCoilAllExportVo {
/**
* 类型(成品/原料)
*/
@ExcelProperty(value = "类型")
private String itemTypeDesc;
/**
* 逻辑库区
*/
@ExcelProperty(value = "逻辑库区")
private String warehouseName;
/**
* 实际库区
*/
@ExcelProperty(value = "实际库区")
private String actualWarehouseName;
/**
* 入场卷号
*/
@ExcelProperty(value = "入场卷号")
private String enterCoilNo;
/**
* 厂家卷号
*/
@ExcelProperty(value = "厂家卷号")
private String supplierCoilNo;
/**
* 成品卷号
*/
@ExcelProperty(value = "成品卷号")
private String currentCoilNo;
/**
* 日期
*/
@ExcelProperty(value = "日期")
private Date createTime;
/**
* 发货时间(仅临时存储,不导出)
*/
@ExcelProperty(value = "发货时间")
private Date exportTime;
// 发货人
@ExcelProperty(value = "发货人")
private String exportBy;
/**
* 重量kg
*/
@ExcelProperty(value = "重量")
private BigDecimal netWeight;
// 班组
private String team;
/**
* 用途
*/
@ExcelProperty(value = "用途")
private String purpose;
/**
* 切边要求
*/
@ExcelProperty(value = "切边要求")
private String trimmingRequirement;
/**
* 包装种类
*/
@ExcelProperty(value = "包装种类")
private String packagingRequirement;
/**
* 产品状态
*/
@ExcelProperty(value = "产品质量")
private String qualityStatus;
/**
* 打包状态
*/
@ExcelProperty(value = "打包状态")
private String packingStatus;
/**
* 库存状态
*/
@ExcelProperty(value = "库存状态")
private String statusDesc;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 名称
*/
@ExcelProperty(value = "名称")
private String itemName;
@ExcelProperty(value = "长度")
private BigDecimal length;
/**
* 规格
*/
@ExcelProperty(value = "规格")
private String specification;
/**
* 材质
*/
@ExcelProperty(value = "材质")
private String material;
/**
* 厂家
*/
@ExcelProperty(value = "厂家")
private String manufacturer;
/**
* 表面处理
*/
@ExcelProperty(value = "表面处理")
private String surfaceTreatmentDesc;
/**
* 锌层
*/
@ExcelProperty(value = "锌层")
private String zincLayer;
/**
* 物品ID
*/
@ExcelProperty(value = "物品ID")
private Long itemId;
/**
* 更新时间(仅临时存储,不导出,用于发货时间为空时兜底)
*/
private Date updateTime;
// 数据类型
@Excel(name = "数据类型", readConverterExp = "0=历史,1=当前")
private Integer dataType;
// 调制度
@ExcelProperty(value = "调制度")
private String temperGrade;
// 镀层种类
@ExcelProperty(value = "镀层种类")
private String coatingType;
// 业务用途
@ExcelProperty(value = "业务用途")
private String businessPurpose;
// 是否与订单相关 readConverterExp
@Excel(name = "是否与订单相关", readConverterExp = "0=否,1=是")
private Integer isRelatedToOrder;
}

View File

@@ -2,7 +2,6 @@ package com.klp.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.klp.common.annotation.Excel;
import com.klp.common.annotation.ExcelDictFormat;
import com.klp.common.convert.ExcelDictConvert;
import lombok.Data;
@@ -175,13 +174,4 @@ public class WmsMaterialCoilExportVo {
private String temperGrade;
// 镀层种类
private String coatingType;
// 班组
private String team;
// 业务用途
private String businessPurpose;
// 是否与订单相关 readConverterExp
private Integer isRelatedToOrder;
}

View File

@@ -429,17 +429,5 @@ public class WmsMaterialCoilVo extends BaseEntity {
* 明细单价
*/
private BigDecimal bindDetailUnitPrice;
/**
* 实测长度
*/
@ExcelProperty(value = "实测长度")
private BigDecimal actualLength;
/**
* 实测宽度
*/
@ExcelProperty(value = "实测宽度")
private BigDecimal actualWidth;
}

View File

@@ -16,22 +16,5 @@ import org.apache.ibatis.annotations.Param;
public interface WmsCoilPendingActionMapper extends BaseMapperPlus<WmsCoilPendingActionMapper, WmsCoilPendingAction, WmsCoilPendingActionVo> {
Page<WmsCoilPendingActionVo> selectVoPagePlus(Page<Object> build,@Param("ew") QueryWrapper<WmsCoilPendingAction> lqw);
/**
* 更新删除标志(绕过@TableLogic注解限制)
* @param actionId 操作ID
* @param delFlag 删除标志(0=正常,1=已删除)
* @return 更新行数
*/
int updateDelFlag(@Param("actionId") Long actionId, @Param("delFlag") Integer delFlag);
/**
* 根据操作ID和删除标志查询记录(包含已删除记录)
* @param actionId 操作ID
* @param delFlag 删除标志(0=正常,1=已删除)
* @return 待操作记录
*/
WmsCoilPendingAction selectByActionIdAndDelFlag(@Param("actionId") Long actionId, @Param("delFlag") Integer delFlag);
}

Some files were not shown because too many files have changed in this diff Show More