Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X
This commit is contained in:
@@ -76,6 +76,16 @@ public class ApsPlanDetailController extends BaseController {
|
||||
return toAjax(iApsPlanDetailService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量新增排产单明细
|
||||
*/
|
||||
@Log(title = "排产单明细", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/batch")
|
||||
public R<Void> batchAdd(@Validated(AddGroup.class) @RequestBody List<ApsPlanDetailBo> boList) {
|
||||
return toAjax(iApsPlanDetailService.insertBatchByBo(boList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改排产单明细
|
||||
*/
|
||||
|
||||
@@ -226,5 +226,9 @@ public class ApsPlanDetailBo extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 排产日期(字符串格式,例如 '2025-12-29')
|
||||
*/
|
||||
private String detailDate;
|
||||
|
||||
}
|
||||
|
||||
@@ -184,6 +184,10 @@ public class ApsPlanDetail extends BaseEntity {
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 排产日期(字符串格式,例如 '2025-12-29')
|
||||
*/
|
||||
private String detailDate;
|
||||
/**
|
||||
* 删除标记(0正常 1删除)
|
||||
*/
|
||||
|
||||
@@ -261,6 +261,12 @@ public class ApsPlanDetailVo {
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 排产日期(字符串格式,例如 '2025-12-29')
|
||||
*/
|
||||
@ExcelProperty(value = "排产日期")
|
||||
private String detailDate;
|
||||
|
||||
/**
|
||||
* 技术附件
|
||||
*/
|
||||
|
||||
@@ -43,6 +43,11 @@ public interface IApsPlanDetailService {
|
||||
*/
|
||||
Boolean insertByBo(ApsPlanDetailBo bo);
|
||||
|
||||
/**
|
||||
* 批量新增排产单明细
|
||||
*/
|
||||
Boolean insertBatchByBo(List<ApsPlanDetailBo> boList);
|
||||
|
||||
/**
|
||||
* 修改排产单明细
|
||||
*/
|
||||
|
||||
@@ -101,6 +101,7 @@ public class ApsPlanDetailServiceImpl implements IApsPlanDetailService {
|
||||
qw.eq(StringUtils.isNotBlank(bo.getSampleReq()), "d.sample_req", bo.getSampleReq());
|
||||
qw.eq(bo.getStartTime() != null, "d.start_time", bo.getStartTime());
|
||||
qw.eq(bo.getEndTime() != null, "d.end_time", bo.getEndTime());
|
||||
qw.eq(StringUtils.isNotBlank(bo.getDetailDate()), "d.detail_date", bo.getDetailDate());
|
||||
//根据创建时间倒叙
|
||||
qw.orderByDesc("d.create_time");
|
||||
return qw;
|
||||
@@ -168,6 +169,7 @@ public class ApsPlanDetailServiceImpl implements IApsPlanDetailService {
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getSampleReq()), ApsPlanDetail::getSampleReq, bo.getSampleReq());
|
||||
lqw.eq(bo.getStartTime() != null, ApsPlanDetail::getStartTime, bo.getStartTime());
|
||||
lqw.eq(bo.getEndTime() != null, ApsPlanDetail::getEndTime, bo.getEndTime());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDetailDate()), ApsPlanDetail::getDetailDate, bo.getDetailDate());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@@ -185,6 +187,16 @@ public class ApsPlanDetailServiceImpl implements IApsPlanDetailService {
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量新增排产单明细
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertBatchByBo(List<ApsPlanDetailBo> boList) {
|
||||
List<ApsPlanDetail> list = BeanUtil.copyToList(boList, ApsPlanDetail.class);
|
||||
list.forEach(this::validEntityBeforeSave);
|
||||
return baseMapper.insertBatch(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改排产单明细
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
<result property="startTime" column="start_time"/>
|
||||
<result property="endTime" column="end_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="detailDate" column="detail_date"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Excel相关处理
|
||||
@@ -149,6 +150,33 @@ public class ExcelUtil {
|
||||
builder.doWrite(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel(仅导出指定列)
|
||||
*
|
||||
* @param list 导出数据集合
|
||||
* @param sheetName 工作表的名称
|
||||
* @param clazz 实体类
|
||||
* @param includeColumnFieldNames 需要导出的字段名集合(Java字段名,非Excel列名)
|
||||
* @param response 响应体
|
||||
*/
|
||||
public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz,
|
||||
Set<String> includeColumnFieldNames,
|
||||
HttpServletResponse response) {
|
||||
try {
|
||||
resetResponse(sheetName, response);
|
||||
ServletOutputStream os = response.getOutputStream();
|
||||
EasyExcel.write(os, clazz)
|
||||
.autoCloseStream(false)
|
||||
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
|
||||
.registerConverter(new ExcelBigNumberConvert())
|
||||
.includeColumnFieldNames(includeColumnFieldNames)
|
||||
.sheet(sheetName)
|
||||
.doWrite(list);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("导出Excel异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单表多数据模板导出 模板格式为 {.属性}
|
||||
*
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.klp.mes.eqp.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.mes.eqp.domain.vo.EqpEquipmentInspectionApprovalVo;
|
||||
import com.klp.mes.eqp.domain.bo.EqpEquipmentInspectionApprovalBo;
|
||||
import com.klp.mes.eqp.service.IEqpEquipmentInspectionApprovalService;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 设备巡检审批(按产线+时间范围审批)
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-05-29
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/eqp/equipmentInspectionApproval")
|
||||
public class EqpEquipmentInspectionApprovalController extends BaseController {
|
||||
|
||||
private final IEqpEquipmentInspectionApprovalService iEqpEquipmentInspectionApprovalService;
|
||||
|
||||
/**
|
||||
* 查询设备巡检审批(按产线+时间范围审批)列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<EqpEquipmentInspectionApprovalVo> list(EqpEquipmentInspectionApprovalBo bo, PageQuery pageQuery) {
|
||||
return iEqpEquipmentInspectionApprovalService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出设备巡检审批(按产线+时间范围审批)列表
|
||||
*/
|
||||
@Log(title = "设备巡检审批(按产线+时间范围审批)", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(EqpEquipmentInspectionApprovalBo bo, HttpServletResponse response) {
|
||||
List<EqpEquipmentInspectionApprovalVo> list = iEqpEquipmentInspectionApprovalService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "设备巡检审批(按产线+时间范围审批)", EqpEquipmentInspectionApprovalVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备巡检审批(按产线+时间范围审批)详细信息
|
||||
*
|
||||
* @param approvalId 主键
|
||||
*/
|
||||
@GetMapping("/{approvalId}")
|
||||
public R<EqpEquipmentInspectionApprovalVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long approvalId) {
|
||||
return R.ok(iEqpEquipmentInspectionApprovalService.queryById(approvalId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
@Log(title = "设备巡检审批(按产线+时间范围审批)", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody EqpEquipmentInspectionApprovalBo bo) {
|
||||
return toAjax(iEqpEquipmentInspectionApprovalService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
@Log(title = "设备巡检审批(按产线+时间范围审批)", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody EqpEquipmentInspectionApprovalBo bo) {
|
||||
return toAjax(iEqpEquipmentInspectionApprovalService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备巡检审批(按产线+时间范围审批)
|
||||
*
|
||||
* @param approvalIds 主键串
|
||||
*/
|
||||
@Log(title = "设备巡检审批(按产线+时间范围审批)", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{approvalIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] approvalIds) {
|
||||
return toAjax(iEqpEquipmentInspectionApprovalService.deleteWithValidByIds(Arrays.asList(approvalIds), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.klp.mes.eqp.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;
|
||||
|
||||
/**
|
||||
* 设备巡检审批(按产线+时间范围审批)对象 eqp_equipment_inspection_approval
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-05-29
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("eqp_equipment_inspection_approval")
|
||||
public class EqpEquipmentInspectionApproval extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
/**
|
||||
* 审批ID 主键
|
||||
*/
|
||||
@TableId(value = "approval_id")
|
||||
private Long approvalId;
|
||||
/**
|
||||
* 产线ID(对应你刚改的bigint类型)
|
||||
*/
|
||||
private Long productionLine;
|
||||
/**
|
||||
* 巡检开始时间
|
||||
*/
|
||||
private Date insStartTime;
|
||||
/**
|
||||
* 巡检结束时间
|
||||
*/
|
||||
private Date insEndTime;
|
||||
/**
|
||||
* 申请人
|
||||
*/
|
||||
private String applyUser;
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
private Date applyTime;
|
||||
/**
|
||||
* 审批状态 1=待审批 2=已通过 3=已驳回 4=已撤销
|
||||
*/
|
||||
private Integer approvalStatus;
|
||||
/**
|
||||
* 审批人
|
||||
*/
|
||||
private String approvalUser;
|
||||
/**
|
||||
* 审批时间
|
||||
*/
|
||||
private Date approvalTime;
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String approvalOpinion;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 删除标识 0正常 2删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Long delFlag;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.klp.mes.eqp.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;
|
||||
|
||||
/**
|
||||
* 设备巡检审批(按产线+时间范围审批)业务对象 eqp_equipment_inspection_approval
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-05-29
|
||||
*/
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class EqpEquipmentInspectionApprovalBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 审批ID 主键
|
||||
*/
|
||||
private Long approvalId;
|
||||
|
||||
/**
|
||||
* 产线ID(对应你刚改的bigint类型)
|
||||
*/
|
||||
private Long productionLine;
|
||||
|
||||
/**
|
||||
* 巡检开始时间
|
||||
*/
|
||||
private Date insStartTime;
|
||||
|
||||
/**
|
||||
* 巡检结束时间
|
||||
*/
|
||||
private Date insEndTime;
|
||||
|
||||
/**
|
||||
* 申请人
|
||||
*/
|
||||
private String applyUser;
|
||||
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 审批状态 1=待审批 2=已通过 3=已驳回 4=已撤销
|
||||
*/
|
||||
private Integer approvalStatus;
|
||||
|
||||
/**
|
||||
* 审批人
|
||||
*/
|
||||
private String approvalUser;
|
||||
|
||||
/**
|
||||
* 审批时间
|
||||
*/
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String approvalOpinion;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.klp.mes.eqp.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 lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* 设备巡检审批(按产线+时间范围审批)视图对象 eqp_equipment_inspection_approval
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-05-29
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class EqpEquipmentInspectionApprovalVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 审批ID 主键
|
||||
*/
|
||||
@ExcelProperty(value = "审批ID 主键")
|
||||
private Long approvalId;
|
||||
|
||||
/**
|
||||
* 产线ID(对应你刚改的bigint类型)
|
||||
*/
|
||||
@ExcelProperty(value = "产线ID", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "对=应你刚改的bigint类型")
|
||||
private Long productionLine;
|
||||
|
||||
/**
|
||||
* 巡检开始时间
|
||||
*/
|
||||
@ExcelProperty(value = "巡检开始时间")
|
||||
private Date insStartTime;
|
||||
|
||||
/**
|
||||
* 巡检结束时间
|
||||
*/
|
||||
@ExcelProperty(value = "巡检结束时间")
|
||||
private Date insEndTime;
|
||||
|
||||
/**
|
||||
* 申请人
|
||||
*/
|
||||
@ExcelProperty(value = "申请人")
|
||||
private String applyUser;
|
||||
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
@ExcelProperty(value = "申请时间")
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 审批状态 1=待审批 2=已通过 3=已驳回 4=已撤销
|
||||
*/
|
||||
@ExcelProperty(value = "审批状态 1=待审批 2=已通过 3=已驳回 4=已撤销")
|
||||
private Integer approvalStatus;
|
||||
|
||||
/**
|
||||
* 审批人
|
||||
*/
|
||||
@ExcelProperty(value = "审批人")
|
||||
private String approvalUser;
|
||||
|
||||
/**
|
||||
* 审批时间
|
||||
*/
|
||||
@ExcelProperty(value = "审批时间")
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
@ExcelProperty(value = "审批意见")
|
||||
private String approvalOpinion;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.klp.mes.eqp.mapper;
|
||||
|
||||
import com.klp.mes.eqp.domain.EqpEquipmentInspectionApproval;
|
||||
import com.klp.mes.eqp.domain.vo.EqpEquipmentInspectionApprovalVo;
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 设备巡检审批(按产线+时间范围审批)Mapper接口
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-05-29
|
||||
*/
|
||||
public interface EqpEquipmentInspectionApprovalMapper extends BaseMapperPlus<EqpEquipmentInspectionApprovalMapper, EqpEquipmentInspectionApproval, EqpEquipmentInspectionApprovalVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.klp.mes.eqp.service;
|
||||
|
||||
import com.klp.mes.eqp.domain.EqpEquipmentInspectionApproval;
|
||||
import com.klp.mes.eqp.domain.vo.EqpEquipmentInspectionApprovalVo;
|
||||
import com.klp.mes.eqp.domain.bo.EqpEquipmentInspectionApprovalBo;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备巡检审批(按产线+时间范围审批)Service接口
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-05-29
|
||||
*/
|
||||
public interface IEqpEquipmentInspectionApprovalService {
|
||||
|
||||
/**
|
||||
* 查询设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
EqpEquipmentInspectionApprovalVo queryById(Long approvalId);
|
||||
|
||||
/**
|
||||
* 查询设备巡检审批(按产线+时间范围审批)列表
|
||||
*/
|
||||
TableDataInfo<EqpEquipmentInspectionApprovalVo> queryPageList(EqpEquipmentInspectionApprovalBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询设备巡检审批(按产线+时间范围审批)列表
|
||||
*/
|
||||
List<EqpEquipmentInspectionApprovalVo> queryList(EqpEquipmentInspectionApprovalBo bo);
|
||||
|
||||
/**
|
||||
* 新增设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
Boolean insertByBo(EqpEquipmentInspectionApprovalBo bo);
|
||||
|
||||
/**
|
||||
* 修改设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
Boolean updateByBo(EqpEquipmentInspectionApprovalBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除设备巡检审批(按产线+时间范围审批)信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.klp.mes.eqp.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.klp.common.helper.LoginHelper;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.klp.mes.eqp.domain.bo.EqpEquipmentInspectionApprovalBo;
|
||||
import com.klp.mes.eqp.domain.vo.EqpEquipmentInspectionApprovalVo;
|
||||
import com.klp.mes.eqp.domain.EqpEquipmentInspectionApproval;
|
||||
import com.klp.mes.eqp.mapper.EqpEquipmentInspectionApprovalMapper;
|
||||
import com.klp.mes.eqp.service.IEqpEquipmentInspectionApprovalService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 设备巡检审批(按产线+时间范围审批)Service业务层处理
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-05-29
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class EqpEquipmentInspectionApprovalServiceImpl implements IEqpEquipmentInspectionApprovalService {
|
||||
|
||||
private final EqpEquipmentInspectionApprovalMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
@Override
|
||||
public EqpEquipmentInspectionApprovalVo queryById(Long approvalId){
|
||||
return baseMapper.selectVoById(approvalId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备巡检审批(按产线+时间范围审批)列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<EqpEquipmentInspectionApprovalVo> queryPageList(EqpEquipmentInspectionApprovalBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<EqpEquipmentInspectionApproval> lqw = buildQueryWrapper(bo);
|
||||
Page<EqpEquipmentInspectionApprovalVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备巡检审批(按产线+时间范围审批)列表
|
||||
*/
|
||||
@Override
|
||||
public List<EqpEquipmentInspectionApprovalVo> queryList(EqpEquipmentInspectionApprovalBo bo) {
|
||||
LambdaQueryWrapper<EqpEquipmentInspectionApproval> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<EqpEquipmentInspectionApproval> buildQueryWrapper(EqpEquipmentInspectionApprovalBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<EqpEquipmentInspectionApproval> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getProductionLine() != null, EqpEquipmentInspectionApproval::getProductionLine, bo.getProductionLine());
|
||||
lqw.eq(bo.getInsStartTime() != null, EqpEquipmentInspectionApproval::getInsStartTime, bo.getInsStartTime());
|
||||
lqw.eq(bo.getInsEndTime() != null, EqpEquipmentInspectionApproval::getInsEndTime, bo.getInsEndTime());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplyUser()), EqpEquipmentInspectionApproval::getApplyUser, bo.getApplyUser());
|
||||
lqw.eq(bo.getApplyTime() != null, EqpEquipmentInspectionApproval::getApplyTime, bo.getApplyTime());
|
||||
lqw.eq(bo.getApprovalStatus() != null, EqpEquipmentInspectionApproval::getApprovalStatus, bo.getApprovalStatus());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApprovalUser()), EqpEquipmentInspectionApproval::getApprovalUser, bo.getApprovalUser());
|
||||
lqw.eq(bo.getApprovalTime() != null, EqpEquipmentInspectionApproval::getApprovalTime, bo.getApprovalTime());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApprovalOpinion()), EqpEquipmentInspectionApproval::getApprovalOpinion, bo.getApprovalOpinion());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(EqpEquipmentInspectionApprovalBo bo) {
|
||||
EqpEquipmentInspectionApproval add = BeanUtil.toBean(bo, EqpEquipmentInspectionApproval.class);
|
||||
add.setApplyUser(LoginHelper.getNickName());
|
||||
add.setApplyTime(new Date());
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setApprovalId(add.getApprovalId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(EqpEquipmentInspectionApprovalBo bo) {
|
||||
EqpEquipmentInspectionApproval update = BeanUtil.toBean(bo, EqpEquipmentInspectionApproval.class);
|
||||
if (bo.getApprovalStatus() != null && (bo.getApprovalStatus() == 2 || bo.getApprovalStatus() == 3)) {
|
||||
update.setApprovalUser(LoginHelper.getNickName());
|
||||
update.setApprovalTime(new Date());
|
||||
}
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(EqpEquipmentInspectionApproval entity){
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除设备巡检审批(按产线+时间范围审批)
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,10 @@ public class QcInspectionTask extends BaseEntity {
|
||||
* 附件路径(多个用英文逗号分隔)
|
||||
*/
|
||||
private String attachmentFiles;
|
||||
/**
|
||||
* 厂家卷号集合,多个使用英文逗号分隔
|
||||
*/
|
||||
private String supplierCoilNos;
|
||||
|
||||
/**
|
||||
* 删除标志(0=正常,1=已删除)
|
||||
|
||||
@@ -108,4 +108,9 @@ public class QcInspectionTaskBo extends BaseEntity {
|
||||
* 附件路径(多个用英文逗号分隔)
|
||||
*/
|
||||
private String attachmentFiles;
|
||||
|
||||
/**
|
||||
* 厂家卷号集合,多个使用英文逗号分隔
|
||||
*/
|
||||
private String supplierCoilNos;
|
||||
}
|
||||
|
||||
@@ -134,6 +134,11 @@ public class QcInspectionTaskVo {
|
||||
*/
|
||||
private String attachmentFiles;
|
||||
|
||||
/**
|
||||
* 厂家卷号集合,多个使用英文逗号分隔
|
||||
*/
|
||||
private String supplierCoilNos;
|
||||
|
||||
private List<WmsMaterialCoilVo> coilList;
|
||||
|
||||
|
||||
|
||||
@@ -136,6 +136,7 @@ public class QcInspectionTaskServiceImpl implements IQcInspectionTaskService {
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getResult()), QcInspectionTask::getResult, bo.getResult());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCoilIds()), QcInspectionTask::getCoilIds, bo.getCoilIds());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getEnterCoilNos()), QcInspectionTask::getEnterCoilNos, bo.getEnterCoilNos());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getSupplierCoilNos()), QcInspectionTask::getSupplierCoilNos, bo.getSupplierCoilNos());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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.mes.eqp.mapper.EqpEquipmentInspectionApprovalMapper">
|
||||
|
||||
<resultMap type="com.klp.mes.eqp.domain.EqpEquipmentInspectionApproval" id="EqpEquipmentInspectionApprovalResult">
|
||||
<result property="approvalId" column="approval_id"/>
|
||||
<result property="productionLine" column="production_line"/>
|
||||
<result property="insStartTime" column="ins_start_time"/>
|
||||
<result property="insEndTime" column="ins_end_time"/>
|
||||
<result property="applyUser" column="apply_user"/>
|
||||
<result property="applyTime" column="apply_time"/>
|
||||
<result property="approvalStatus" column="approval_status"/>
|
||||
<result property="approvalUser" column="approval_user"/>
|
||||
<result property="approvalTime" column="approval_time"/>
|
||||
<result property="approvalOpinion" column="approval_opinion"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -23,6 +23,7 @@
|
||||
<result property="attachmentFiles" column="attachment_files"/>
|
||||
<result property="coilIds" column="coil_ids"/>
|
||||
<result property="enterCoilNos" column="enter_coil_nos"/>
|
||||
<result property="supplierCoilNos" column="supplier_coil_nos"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
|
||||
@@ -26,6 +26,15 @@ export function addPlanDetail(data) {
|
||||
})
|
||||
}
|
||||
|
||||
// 批量新增排产单明细
|
||||
export function addPlanDetailBatch(data) {
|
||||
return request({
|
||||
url: '/aps/planDetail/batch',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改排产单明细
|
||||
export function updatePlanDetail(data) {
|
||||
return request({
|
||||
|
||||
39
klp-ui/src/api/mes/eqp/equipmentInspectionApproval.js
Normal file
39
klp-ui/src/api/mes/eqp/equipmentInspectionApproval.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listEquipmentInspectionApproval(query) {
|
||||
return request({
|
||||
url: '/eqp/equipmentInspectionApproval/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getEquipmentInspectionApproval(approvalId) {
|
||||
return request({
|
||||
url: '/eqp/equipmentInspectionApproval/' + approvalId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addEquipmentInspectionApproval(data) {
|
||||
return request({
|
||||
url: '/eqp/equipmentInspectionApproval',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateEquipmentInspectionApproval(data) {
|
||||
return request({
|
||||
url: '/eqp/equipmentInspectionApproval',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delEquipmentInspectionApproval(approvalId) {
|
||||
return request({
|
||||
url: '/eqp/equipmentInspectionApproval/' + approvalId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -489,3 +489,11 @@ export function listLightCoil(data) {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取可导出的列元数据
|
||||
export function getExportColumns() {
|
||||
return request({
|
||||
url: '/wms/materialCoil/exportColumns',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@@ -61,6 +61,14 @@ export function listBoundCoil(query) {
|
||||
})
|
||||
}
|
||||
|
||||
export function getBoundCoilStatisticsList(query) {
|
||||
return request({
|
||||
url: '/wms/deliveryWaybillDetail/statistics',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 按销售员查询订单明细的卷
|
||||
export function listDeliveryWaybillDetailBySaleman(principal) {
|
||||
return request({
|
||||
|
||||
@@ -79,6 +79,10 @@
|
||||
canSelectDisabled :clearInput="false" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark" v-if="orderBy">
|
||||
<el-input v-model="queryParams.remark" placeholder="请输入备注" clearable size="small" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
|
||||
<el-button v-if="multiple" type="primary" size="small" icon="el-icon-check"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<div>
|
||||
<el-button type="primary" plain @click="handleAdd">新增明细</el-button>
|
||||
<el-button type="success" plain @click="handleBatchAdd">批量新增</el-button>
|
||||
<el-button type="info" plain @click="handleImport">导入</el-button>
|
||||
<el-button type="danger" plain @click="handleBatchDelete"
|
||||
:disabled="selectedRows.length === 0">批量删除</el-button>
|
||||
<el-button type="warning" plain @click="handleBatchTransfer"
|
||||
@@ -60,6 +61,11 @@
|
||||
</el-table-column>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<el-table-column label="排产日期" align="center" prop="detailDate" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.detailDate" style="background-color: #fff3e6;" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单号" align="center" prop="orderCode" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.orderCode" style="background-color: #fff3e6;">
|
||||
@@ -491,16 +497,169 @@
|
||||
:loading="buttonLoading">确认新增</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 导入对话框 -->
|
||||
<el-dialog title="导入排产单明细" :visible.sync="importDialogVisible" width="900px" append-to-body
|
||||
:close-on-click-modal="false" @close="resetImportState">
|
||||
<div class="import-container">
|
||||
<el-steps :active="importStep" align-center finish-status="success">
|
||||
<el-step title="下载模板" description="下载并填写Excel模板" />
|
||||
<el-step title="上传文件" description="选择填好的文件" />
|
||||
<el-step title="校验数据" description="验证数据完整性" />
|
||||
<el-step title="开始导入" description="预览并确认导入" />
|
||||
</el-steps>
|
||||
|
||||
<div class="import-step-content">
|
||||
<!-- Step 0: 下载模板 -->
|
||||
<div v-show="importStep === 0" class="step-body">
|
||||
<div class="step-download">
|
||||
<i class="el-icon-download step-icon"></i>
|
||||
<p>请先下载Excel模板,按格式填写排产单明细数据</p>
|
||||
<el-button type="primary" icon="el-icon-download" @click="downloadTemplate">下载导入模板</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 1: 上传文件 -->
|
||||
<div v-show="importStep === 1" class="step-body">
|
||||
<div class="step-upload">
|
||||
<el-upload ref="importUpload" class="custom-upload" drag :auto-upload="false" :show-file-list="false"
|
||||
:on-change="handleImportFileChange" accept=".xlsx,.xls">
|
||||
<div class="upload-zone-body">
|
||||
<div class="upload-zone-icon">
|
||||
<i class="el-icon-upload2"></i>
|
||||
</div>
|
||||
<p class="upload-zone-title">将文件拖到此处,或<span>点击选择</span></p>
|
||||
<p class="upload-zone-tip">支持 .xlsx / .xls 格式</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div v-if="importFile" class="parse-result" :class="errorList.length > 0 ? 'parse-error' : 'parse-ok'">
|
||||
<div class="parse-result-header">
|
||||
<i :class="errorList.length > 0 ? 'el-icon-warning' : 'el-icon-circle-check'"></i>
|
||||
<span class="parse-result-filename">{{ importFile.name }}</span>
|
||||
<span class="parse-result-count">解析 {{ rawData.length }} 条数据</span>
|
||||
</div>
|
||||
<div v-if="errorList.length > 0" class="error-list">
|
||||
<el-table :data="errorList" border max-height="150">
|
||||
<el-table-column prop="rowNum" label="行号" width="80" />
|
||||
<el-table-column prop="errorMsg" label="错误信息" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: 校验数据 -->
|
||||
<div v-show="importStep === 2" class="step-body">
|
||||
<div class="step-validate">
|
||||
<p class="step-desc">点击下方按钮校验数据完整性,已解析 {{ rawData.length }} 条数据</p>
|
||||
<el-button type="success" icon="el-icon-check" @click="handleValidateData"
|
||||
:loading="validateLoading" size="medium" style="margin-bottom: 16px">
|
||||
校验数据
|
||||
</el-button>
|
||||
<div v-if="errorList.length > 0" class="error-list">
|
||||
<el-alert :title="'校验失败,共 ' + errorList.length + ' 条错误'" type="error" show-icon :closable="false" style="margin-bottom: 10px" />
|
||||
<el-table :data="errorList" border max-height="200">
|
||||
<el-table-column prop="rowNum" label="行号" width="80" />
|
||||
<el-table-column prop="errorMsg" label="错误信息" />
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-if="isValidated && errorList.length === 0" class="validate-ok">
|
||||
<el-alert title="数据校验通过!" type="success" show-icon :closable="false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: 预览并导入 -->
|
||||
<div v-show="importStep === 3" class="step-body">
|
||||
<div class="step-import-container">
|
||||
<div class="data-preview">
|
||||
<div class="section-title">数据预览(共 {{ tableData.length }} 条)</div>
|
||||
<el-table :data="tableData" border max-height="280" style="margin-top: 10px">
|
||||
<el-table-column type="index" label="#" width="50" />
|
||||
<el-table-column prop="detailDate" label="排产日期" width="100" />
|
||||
<el-table-column prop="contractCode" label="合同号" width="120" />
|
||||
<el-table-column prop="deliveryDate" label="交货期" width="100" />
|
||||
<el-table-column prop="customerName" label="客户名称" width="120" />
|
||||
<el-table-column prop="productName" label="产品名称" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="usageReq" label="客户用途" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="productMaterial" label="材质" width="80" />
|
||||
<el-table-column prop="rollingThick" label="成品厚度" width="80" />
|
||||
<el-table-column prop="productWidth" label="成品宽度" width="80" />
|
||||
<el-table-column prop="planWeight" label="数量(吨)" width="90" />
|
||||
<el-table-column prop="surfaceTreatment" label="表面处理" width="80" />
|
||||
<el-table-column prop="productPackaging" label="包装要求" width="80" />
|
||||
<el-table-column prop="remark" label="其他要求" width="120" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<div v-if="importStatus === 'processing'" class="import-progress">
|
||||
<el-progress :percentage="importProgress" />
|
||||
<p>正在导入:{{ importedCount }} / {{ totalCount }}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="importStatus === 'finished'" class="import-result">
|
||||
<el-alert :title="'导入完成!共成功导入 ' + importedCount + ' 条数据'" type="success" show-icon :closable="false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button v-if="importStep > 0" @click="importStep--" :disabled="importStatus === 'processing'">上一步</el-button>
|
||||
<el-button @click="importDialogVisible = false">关闭</el-button>
|
||||
<el-button v-if="importStep === 0" type="primary" @click="downloadTemplate">下载模板</el-button>
|
||||
<el-button v-if="importStep === 0" type="primary" @click="importStep = 1">已下载,下一步</el-button>
|
||||
<el-button v-if="importStep === 1" type="primary" @click="goValidateStep" :disabled="!importFile || rawData.length === 0">
|
||||
下一步
|
||||
</el-button>
|
||||
<el-button v-if="importStep === 2" type="primary" @click="goImportStep" :disabled="!isValidated || errorList.length > 0">
|
||||
下一步
|
||||
</el-button>
|
||||
<el-button v-if="importStep === 3 && importStatus !== 'finished'" type="primary" @click="startImport"
|
||||
:loading="importLoading">
|
||||
开始导入
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { updatePlanDetail, listPlanDetail, addPlanDetail, delPlanDetail } from "@/api/aps/planDetail";
|
||||
import * as XLSX from 'xlsx'
|
||||
import { updatePlanDetail, listPlanDetail, addPlanDetail, addPlanDetailBatch, delPlanDetail } from "@/api/aps/planDetail";
|
||||
import { getPlanSheet, listPlanSheet } from "@/api/aps/planSheet";
|
||||
import { listOrder } from '@/api/crm/order';
|
||||
import { listOrderItem } from '@/api/crm/orderItem'
|
||||
import PlanSheetList from "@/views/aps/planSheet/PlanSheetList.vue";
|
||||
|
||||
const TEMPLATE_HEADERS = [
|
||||
'排产日期', '合同号', '交货期', '业务员', '客户名称', '产品名称',
|
||||
'客户用途', '材质', '成品厚度', '成品宽度', '数量(吨)',
|
||||
'厚度范围', '宽度范围', '表面质量', '表面处理', '包装要求',
|
||||
'切边要求', '其他要求'
|
||||
]
|
||||
|
||||
const HEADER_MAP = {
|
||||
'排产日期': 'detailDate',
|
||||
'合同号': 'contractCode',
|
||||
'交货期': 'deliveryDate',
|
||||
'业务员': 'salesman',
|
||||
'客户名称': 'customerName',
|
||||
'产品名称': 'productName',
|
||||
'客户用途': 'usageReq',
|
||||
'材质': 'productMaterial',
|
||||
'成品厚度': 'rollingThick',
|
||||
'成品宽度': 'productWidth',
|
||||
'数量(吨)': 'planWeight',
|
||||
'厚度范围': 'markCoatThick',
|
||||
'宽度范围': 'productEdgeReq',
|
||||
'表面质量': 'coatingG',
|
||||
'表面处理': 'surfaceTreatment',
|
||||
'包装要求': 'productPackaging',
|
||||
'切边要求': 'widthReq',
|
||||
'其他要求': 'remark'
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "PlanSheet",
|
||||
dicts: ['sys_lines'],
|
||||
@@ -625,6 +784,20 @@ export default {
|
||||
selectedRows: [],
|
||||
// 是否批量操作(批量转单)
|
||||
isBatchTransfer: false,
|
||||
// 导入对话框
|
||||
importDialogVisible: false,
|
||||
importStep: 0,
|
||||
importFile: null,
|
||||
rawData: [],
|
||||
tableData: [],
|
||||
errorList: [],
|
||||
isValidated: false,
|
||||
importProgress: 0,
|
||||
importedCount: 0,
|
||||
totalCount: 0,
|
||||
importStatus: 'idle',
|
||||
validateLoading: false,
|
||||
importLoading: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
@@ -1166,6 +1339,218 @@ export default {
|
||||
this.$message.error('批量新增失败');
|
||||
});
|
||||
});
|
||||
},
|
||||
// 打开导入对话框
|
||||
handleImport() {
|
||||
this.importDialogVisible = true
|
||||
this.resetImportState()
|
||||
},
|
||||
// 重置导入状态
|
||||
resetImportState() {
|
||||
this.importStep = 0
|
||||
this.importFile = null
|
||||
this.rawData = []
|
||||
this.tableData = []
|
||||
this.errorList = []
|
||||
this.isValidated = false
|
||||
this.importProgress = 0
|
||||
this.importedCount = 0
|
||||
this.totalCount = 0
|
||||
this.importStatus = 'idle'
|
||||
this.validateLoading = false
|
||||
this.importLoading = false
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.importUpload) {
|
||||
this.$refs.importUpload.clearFiles()
|
||||
}
|
||||
})
|
||||
},
|
||||
// 跳转到校验步骤
|
||||
goValidateStep() {
|
||||
if (!this.importFile || this.rawData.length === 0) return
|
||||
this.importStep = 2
|
||||
},
|
||||
// 跳转到导入步骤
|
||||
goImportStep() {
|
||||
if (!this.isValidated || this.errorList.length > 0) return
|
||||
this.importStep = 3
|
||||
},
|
||||
// 下载导入模板
|
||||
downloadTemplate() {
|
||||
const templateData = [
|
||||
TEMPLATE_HEADERS,
|
||||
['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
|
||||
]
|
||||
const wb = XLSX.utils.book_new()
|
||||
const ws = XLSX.utils.aoa_to_sheet(templateData)
|
||||
ws['!cols'] = TEMPLATE_HEADERS.map(() => ({ wch: 14 }))
|
||||
XLSX.utils.book_append_sheet(wb, ws, '排产单明细')
|
||||
XLSX.writeFile(wb, '排产单明细导入模板.xlsx')
|
||||
},
|
||||
// 导入文件选择变化
|
||||
handleImportFileChange(file) {
|
||||
this.isValidated = false
|
||||
this.errorList = []
|
||||
this.tableData = []
|
||||
this.importStatus = 'idle'
|
||||
this.importFile = file.raw
|
||||
this.readExcel()
|
||||
},
|
||||
// 读取Excel文件内容
|
||||
readExcel() {
|
||||
if (!this.importFile) return
|
||||
try {
|
||||
const fileReader = new FileReader()
|
||||
fileReader.readAsArrayBuffer(this.importFile)
|
||||
fileReader.onload = (e) => {
|
||||
try {
|
||||
const data = new Uint8Array(e.target.result)
|
||||
const workbook = XLSX.read(data, { type: 'array' })
|
||||
const sheetName = workbook.SheetNames[0]
|
||||
const worksheet = workbook.Sheets[sheetName]
|
||||
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 })
|
||||
this.validateHeaders(jsonData[0])
|
||||
this.rawData = jsonData.slice(1).filter(row => row.some(cell => cell !== undefined && cell !== null && cell !== ''))
|
||||
this.formatExcel()
|
||||
if (this.errorList.length === 0) {
|
||||
this.importStatus = 'parsed'
|
||||
this.$message.success(`成功解析Excel,共读取到 ${this.rawData.length} 条数据`)
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorList = [{ rowNum: 0, errorMsg: '解析Excel失败:' + error.message }]
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorList = [{ rowNum: 0, errorMsg: '读取文件失败:' + error.message }]
|
||||
}
|
||||
},
|
||||
// 校验表头
|
||||
validateHeaders(headers) {
|
||||
if (headers.length !== TEMPLATE_HEADERS.length) {
|
||||
this.errorList.push({
|
||||
rowNum: 1,
|
||||
errorMsg: `表头列数不匹配,要求${TEMPLATE_HEADERS.length}列,实际${headers.length}列`
|
||||
})
|
||||
return
|
||||
}
|
||||
headers.forEach((header, index) => {
|
||||
if (String(header || '').trim() !== TEMPLATE_HEADERS[index]) {
|
||||
this.errorList.push({
|
||||
rowNum: 1,
|
||||
errorMsg: `第${index + 1}列表头错误,要求:"${TEMPLATE_HEADERS[index]}",实际:"${header}"`
|
||||
})
|
||||
}
|
||||
})
|
||||
if (this.errorList.length > 0) {
|
||||
this.$message.error('Excel表头格式不符合要求,请检查!')
|
||||
}
|
||||
},
|
||||
// 格式化Excel数据
|
||||
formatExcel() {
|
||||
this.tableData = []
|
||||
if (this.rawData.length === 0) return
|
||||
const currentMaxSeqNo = this.planDetailList.length > 0
|
||||
? Math.max(...this.planDetailList.map(item => parseInt(item.bizSeqNo) || 0))
|
||||
: 0
|
||||
this.rawData.forEach((row, index) => {
|
||||
const rowObj = { bizSeqNo: currentMaxSeqNo + index + 1 }
|
||||
TEMPLATE_HEADERS.forEach((header, colIndex) => {
|
||||
const field = HEADER_MAP[header]
|
||||
const cellValue = row[colIndex]
|
||||
if (cellValue !== undefined && cellValue !== null && cellValue !== '') {
|
||||
rowObj[field] = String(cellValue).trim()
|
||||
}
|
||||
})
|
||||
this.tableData.push(rowObj)
|
||||
})
|
||||
},
|
||||
// 校验数据
|
||||
handleValidateData() {
|
||||
if (this.validateLoading) return
|
||||
if (this.rawData.length === 0) {
|
||||
this.$message.warning('暂无数据可校验')
|
||||
return
|
||||
}
|
||||
this.validateLoading = true
|
||||
this.errorList = []
|
||||
try {
|
||||
this.tableData.forEach((row, i) => {
|
||||
const rowNum = i + 2
|
||||
if (!row.contractCode || row.contractCode.trim() === '') {
|
||||
this.errorList.push({ rowNum, errorMsg: '合同号不能为空' })
|
||||
}
|
||||
if (!row.customerName || row.customerName.trim() === '') {
|
||||
this.errorList.push({ rowNum, errorMsg: '客户名称不能为空' })
|
||||
}
|
||||
if (!row.productName || row.productName.trim() === '') {
|
||||
this.errorList.push({ rowNum, errorMsg: '产品名称不能为空' })
|
||||
}
|
||||
if (!row.productMaterial || row.productMaterial.trim() === '') {
|
||||
this.errorList.push({ rowNum, errorMsg: '材质不能为空' })
|
||||
}
|
||||
if (row.planWeight && isNaN(Number(row.planWeight))) {
|
||||
this.errorList.push({ rowNum, errorMsg: '数量(吨)必须是数字' })
|
||||
}
|
||||
})
|
||||
this.isValidated = true
|
||||
if (this.errorList.length > 0) {
|
||||
this.$message.error(`数据校验失败,共 ${this.errorList.length} 条错误`)
|
||||
} else {
|
||||
this.$message.success('数据校验通过,可以开始导入')
|
||||
this.importStep = 3
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorList.push({ rowNum: 0, errorMsg: '校验数据时发生错误:' + error.message })
|
||||
} finally {
|
||||
this.validateLoading = false
|
||||
}
|
||||
},
|
||||
// 开始导入
|
||||
startImport() {
|
||||
if (this.importLoading) return
|
||||
if (!this.isValidated) {
|
||||
this.$message.warning('请先校验数据')
|
||||
return
|
||||
}
|
||||
if (this.errorList.length > 0) {
|
||||
this.$message.warning('请先修正校验错误后再导入')
|
||||
return
|
||||
}
|
||||
if (this.tableData.length === 0) {
|
||||
this.$message.warning('暂无数据可导入')
|
||||
return
|
||||
}
|
||||
this.$confirm(`确认导入 ${this.tableData.length} 条排产单明细?`, '导入确认', {
|
||||
confirmButtonText: '确认导入',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.doImport()
|
||||
}).catch(() => {})
|
||||
},
|
||||
// 执行导入
|
||||
doImport() {
|
||||
this.importLoading = true
|
||||
this.importStatus = 'processing'
|
||||
this.totalCount = this.tableData.length
|
||||
this.importedCount = 0
|
||||
this.importProgress = 0
|
||||
const boList = this.tableData.map(row => ({
|
||||
...row,
|
||||
planSheetId: this.currentPlanSheetId
|
||||
}))
|
||||
addPlanDetailBatch(boList).then(() => {
|
||||
this.importedCount = this.totalCount
|
||||
this.importProgress = 100
|
||||
this.importStatus = 'finished'
|
||||
this.$message.success(`导入完成!共成功导入 ${this.importedCount} 条数据`)
|
||||
this.getList()
|
||||
}).catch(error => {
|
||||
this.importStatus = 'idle'
|
||||
this.$message.error('导入失败:' + (error.message || '未知错误'))
|
||||
}).finally(() => {
|
||||
this.importLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1259,4 +1644,211 @@ export default {
|
||||
margin-bottom: 15px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.import-container {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.import-step-content {
|
||||
margin-top: 24px;
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
.step-body {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.step-download {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.step-download .step-icon {
|
||||
font-size: 48px;
|
||||
color: #409eff;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.step-download p {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.step-upload {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.custom-upload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.custom-upload ::v-deep .el-upload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.custom-upload ::v-deep .el-upload-dragger {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding: 40px 20px;
|
||||
border: 2px dashed #dcdfe6;
|
||||
border-radius: 8px;
|
||||
background: #fafbfc;
|
||||
transition: all .3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.custom-upload ::v-deep .el-upload-dragger:hover {
|
||||
border-color: #409eff;
|
||||
background: #ecf5ff;
|
||||
}
|
||||
|
||||
.custom-upload ::v-deep .el-upload-dragger.is-dragover {
|
||||
border-color: #409eff;
|
||||
background: #ecf5ff;
|
||||
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.15);
|
||||
}
|
||||
|
||||
.upload-zone-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.upload-zone-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #ecf5ff 0%, #d9ecff 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.upload-zone-icon i {
|
||||
font-size: 28px;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.upload-zone-title {
|
||||
font-size: 15px;
|
||||
color: #606266;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.upload-zone-title span {
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.upload-zone-tip {
|
||||
font-size: 12px;
|
||||
color: #c0c4cc;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.parse-result {
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.parse-result-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 12px 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.parse-result-header i {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.parse-result-filename {
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.parse-result-count {
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.parse-result.parse-ok {
|
||||
border: 1px solid #b7eb8f;
|
||||
}
|
||||
|
||||
.parse-result.parse-ok .parse-result-header {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.parse-result.parse-ok i {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.parse-result.parse-error {
|
||||
border: 1px solid #ffa39e;
|
||||
}
|
||||
|
||||
.parse-result.parse-error .parse-result-header {
|
||||
background: #fff1f0;
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
.parse-result.parse-error i {
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
.step-validate {
|
||||
padding: 0 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.step-validate .step-desc {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.validate-ok {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.step-import-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.error-list {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.data-preview {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.import-progress {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.import-progress p {
|
||||
margin-top: 8px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.import-result {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
<el-button type="primary" size="mini" @click="showAddDetail=true">+ 明细列</el-button>
|
||||
<el-button size="mini" type="success" @click="openMetricPicker">+ 指标列</el-button>
|
||||
<el-button size="mini" plain @click="openMetricMgr">指标管理</el-button>
|
||||
<el-button size="mini" plain @click="openCopyCfg">复制配置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="allCols" border stripe size="mini" highlight-current-row @dragover.native.prevent @drop.native="onNativeDrop" @current-change="curIdx = allCols.indexOf($event)" @selection-change="selCol=$event">
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<div class="contract-tabs">
|
||||
<div v-if="orderId" class="tabs-content">
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane label="订单编辑" name="edit" v-hasPermi="['crm:order:edit']">
|
||||
<!-- <el-tab-pane label="订单编辑" name="edit" v-hasPermi="['crm:order:edit']">
|
||||
<div class="order-detail" v-if="activeTab === 'edit'">
|
||||
<el-descriptions title="订单明细" />
|
||||
<OrderDetail :orderId="currentOrder.orderId" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tab-pane> -->
|
||||
<el-tab-pane label="财务状态" name="finance" v-hasPermi="['crm:order:finance']">
|
||||
<div class="order-finance" v-if="activeTab === 'finance'">
|
||||
<!-- 财务状态内容 -->
|
||||
|
||||
251
klp-ui/src/views/mes/eqp/check/approval.vue
Normal file
251
klp-ui/src/views/mes/eqp/check/approval.vue
Normal file
@@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="产线">
|
||||
<el-select v-model="queryParams.productionLine" placeholder="请选择产线" clearable @change="handleQuery" style="width: 150px;">
|
||||
<el-option v-for="item in lineList" :key="item.lineId" :label="item.lineName" :value="item.lineId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="审批状态" prop="approvalStatus">
|
||||
<el-select v-model="queryParams.approvalStatus" placeholder="请选择状态" clearable @change="handleQuery" style="width: 120px;">
|
||||
<el-option label="待审批" :value="1" />
|
||||
<el-option label="已通过" :value="2" />
|
||||
<el-option label="已驳回" :value="3" />
|
||||
<el-option label="已撤销" :value="4" />
|
||||
</el-select>
|
||||
</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" v-if="!readonly">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="approvalList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" v-if="!readonly" />
|
||||
<el-table-column label="产线" align="center" prop="productionLine" width="100">
|
||||
<template slot-scope="scope">
|
||||
{{ getLineName(scope.row.productionLine) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="巡检开始时间" align="center" prop="insStartTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.insStartTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="巡检结束时间" align="center" prop="insEndTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.insEndTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请人" align="center" prop="applyUser" width="100" />
|
||||
<el-table-column label="申请时间" align="center" prop="applyTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.applyTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批状态" align="center" prop="approvalStatus" width="90">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.approvalStatus === 1" type="warning">待审批</el-tag>
|
||||
<el-tag v-else-if="scope.row.approvalStatus === 2" type="success">已通过</el-tag>
|
||||
<el-tag v-else-if="scope.row.approvalStatus === 3" type="danger">已驳回</el-tag>
|
||||
<el-tag v-else-if="scope.row.approvalStatus === 4" type="info">已撤销</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批人" align="center" prop="approvalUser" width="100" />
|
||||
<el-table-column label="审批时间" align="center" prop="approvalTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.approvalTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批意见" align="center" prop="approvalOpinion" show-overflow-tooltip />
|
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" width="280" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleDetail(scope.row)">详情</el-button>
|
||||
<el-button v-if="scope.row.approvalStatus === 1" size="mini" type="text" icon="el-icon-check" @click="handleApprove(scope.row)">通过</el-button>
|
||||
<el-button v-if="scope.row.approvalStatus === 1" size="mini" type="text" icon="el-icon-close" @click="handleReject(scope.row)">驳回</el-button>
|
||||
<el-button v-if="scope.row.approvalStatus === 1 || scope.row.approvalStatus === 4" 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"
|
||||
/>
|
||||
|
||||
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="500px" append-to-body>
|
||||
<el-form ref="dialogForm" :model="dialogForm" :rules="dialogRules" label-width="80px">
|
||||
<el-form-item label="审批意见" prop="approvalOpinion">
|
||||
<el-input v-model="dialogForm.approvalOpinion" type="textarea" rows="3" placeholder="请输入审批意见" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitApproval">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listEquipmentInspectionApproval, delEquipmentInspectionApproval, updateEquipmentInspectionApproval } from "@/api/mes/eqp/equipmentInspectionApproval";
|
||||
import { listProductionLine } from "@/api/wms/productionLine";
|
||||
|
||||
export default {
|
||||
name: "EquipmentInspectionApproval",
|
||||
props: {
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
defaultStatus: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
buttonLoading: false,
|
||||
loading: true,
|
||||
ids: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
showSearch: true,
|
||||
total: 0,
|
||||
approvalList: [],
|
||||
dialogTitle: "",
|
||||
dialogVisible: false,
|
||||
approvalAction: "",
|
||||
currentRow: null,
|
||||
lineList: [],
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
productionLine: undefined,
|
||||
approvalStatus: this.defaultStatus,
|
||||
},
|
||||
dialogForm: {
|
||||
approvalOpinion: "",
|
||||
},
|
||||
dialogRules: {},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.loadLineList();
|
||||
},
|
||||
methods: {
|
||||
async loadLineList() {
|
||||
try {
|
||||
const res = await listProductionLine({ pageSize: 999 });
|
||||
if (res.rows) this.lineList = res.rows;
|
||||
this.getList();
|
||||
} catch (e) { console.error('加载产线列表失败', e); }
|
||||
},
|
||||
getLineName(lineId) {
|
||||
const found = this.lineList.find(l => l.lineId === lineId);
|
||||
return found ? found.lineName : '';
|
||||
},
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listEquipmentInspectionApproval(this.queryParams).then(response => {
|
||||
this.approvalList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.approvalId);
|
||||
this.single = selection.length !== 1;
|
||||
this.multiple = !selection.length;
|
||||
},
|
||||
formatQueryDate(date) {
|
||||
if (!date) return '';
|
||||
const d = new Date(date);
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
||||
},
|
||||
handleDetail(row) {
|
||||
this.$router.push({
|
||||
path: '/eqp/day',
|
||||
query: {
|
||||
productionLine: row.productionLine,
|
||||
startDate: this.formatQueryDate(row.insStartTime),
|
||||
endDate: this.formatQueryDate(row.insEndTime),
|
||||
}
|
||||
});
|
||||
},
|
||||
handleApprove(row) {
|
||||
this.currentRow = row;
|
||||
this.approvalAction = 'approve';
|
||||
this.dialogTitle = "审批通过";
|
||||
this.dialogForm.approvalOpinion = "";
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
handleReject(row) {
|
||||
this.currentRow = row;
|
||||
this.approvalAction = 'reject';
|
||||
this.dialogTitle = "审批驳回";
|
||||
this.dialogForm.approvalOpinion = "";
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
submitApproval() {
|
||||
this.$refs["dialogForm"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
const status = this.approvalAction === 'approve' ? 2 : 3;
|
||||
updateEquipmentInspectionApproval({
|
||||
approvalId: this.currentRow.approvalId,
|
||||
approvalStatus: status,
|
||||
approvalOpinion: this.dialogForm.approvalOpinion,
|
||||
}).then(() => {
|
||||
const msg = this.approvalAction === 'approve' ? '审批通过' : '已驳回';
|
||||
this.$modal.msgSuccess(msg);
|
||||
this.dialogVisible = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
handleDelete(row) {
|
||||
const approvalIds = row.approvalId || this.ids;
|
||||
this.$modal.confirm('是否确认删除审批记录编号为"' + approvalIds + '"的数据项?').then(() => {
|
||||
this.loading = true;
|
||||
return delEquipmentInspectionApproval(approvalIds);
|
||||
}).then(() => {
|
||||
this.loading = false;
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -8,12 +8,16 @@
|
||||
@change="handleQuery" style="width: 260px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产线">
|
||||
<dict-select v-model="productionLine" dict-type="sys_lines" placeholder="请选择产线"
|
||||
clearable @change="handleQuery" style="width: 150px;" />
|
||||
<el-select v-model="productionLine" placeholder="请选择产线" clearable @change="handleQuery" style="width: 150px;">
|
||||
<el-option v-for="item in lineList" :key="item.lineId" :label="item.lineName" :value="item.lineId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item v-hasPermi="['mes:eqp:submit']">
|
||||
<el-button type="success" icon="el-icon-s-promotion" @click="handleSubmitForApproval">送检</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
|
||||
@@ -105,17 +109,26 @@
|
||||
<script>
|
||||
import { listEquipmentPart } from "@/api/mes/eqp/equipmentPart";
|
||||
import { listEquipmentInspectionRecord } from "@/api/mes/eqp/equipmentInspectionRecord";
|
||||
import { listProductionLine } from "@/api/wms/productionLine";
|
||||
import { addEquipmentInspectionApproval } from "@/api/mes/eqp/equipmentInspectionApproval";
|
||||
|
||||
export default {
|
||||
name: "DailyInspectionReport",
|
||||
dicts: ['sys_lines'],
|
||||
data() {
|
||||
const d = new Date();
|
||||
const today = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
||||
const routeQuery = this.$route && this.$route.query || {};
|
||||
const hasRouteQuery = !!(routeQuery.productionLine || (routeQuery.startDate && routeQuery.endDate));
|
||||
return {
|
||||
loading: false,
|
||||
dateRange: [this.getToday(), this.getToday()],
|
||||
productionLine: '酸轧线',
|
||||
dateRange: (routeQuery.startDate && routeQuery.endDate)
|
||||
? [routeQuery.startDate, routeQuery.endDate]
|
||||
: [today, today],
|
||||
productionLine: routeQuery.productionLine ? Number(routeQuery.productionLine) : 2,
|
||||
lineList: [],
|
||||
partList: [],
|
||||
records: [],
|
||||
hasRouteQuery,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -125,6 +138,10 @@ export default {
|
||||
partName: cl.partName || p.inspectPart,
|
||||
})));
|
||||
},
|
||||
selectedLineName() {
|
||||
const found = this.lineList.find(l => l.lineId === this.productionLine);
|
||||
return found ? found.lineName : '';
|
||||
},
|
||||
tableData() {
|
||||
const recordMap = {};
|
||||
this.records.forEach(r => {
|
||||
@@ -227,13 +244,14 @@ export default {
|
||||
this.loading = true;
|
||||
try {
|
||||
const partParams = {};
|
||||
if (this.productionLine) partParams.productionLine = this.productionLine;
|
||||
const productionLine = this.productionLine;
|
||||
if (productionLine) partParams.productionLine = productionLine;
|
||||
const recordParams = {
|
||||
startInspectTime: this.dateRange[0] + ' 00:00:00',
|
||||
endInspectTime: this.dateRange[1] + ' 23:59:59',
|
||||
pageSize: 9999,
|
||||
};
|
||||
if (this.productionLine) recordParams.productionLine = this.productionLine;
|
||||
if (productionLine) recordParams.productionLine = productionLine;
|
||||
const [partRes, recordRes] = await Promise.all([
|
||||
listEquipmentPart(partParams),
|
||||
listEquipmentInspectionRecord(recordParams),
|
||||
@@ -246,9 +264,43 @@ export default {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
handleSubmitForApproval() {
|
||||
if (!this.dateRange || this.dateRange.length !== 2) {
|
||||
this.$modal.msgWarning("请选择时间段");
|
||||
return;
|
||||
}
|
||||
if (!this.productionLine) {
|
||||
this.$modal.msgWarning("请选择产线");
|
||||
return;
|
||||
}
|
||||
this.$modal.confirm('确认将该时间段"' + this.dateRange[0] + '至' + this.dateRange[1] + '"的巡检日报提交审批吗?').then(() => {
|
||||
this.loading = true;
|
||||
return addEquipmentInspectionApproval({
|
||||
productionLine: this.productionLine,
|
||||
insStartTime: this.dateRange[0] + ' 00:00:00',
|
||||
insEndTime: this.dateRange[1] + ' 23:59:59',
|
||||
});
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess("送检成功");
|
||||
this.loading = false;
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
async loadLineList() {
|
||||
try {
|
||||
const res = await listProductionLine({ pageSize: 999 });
|
||||
if (res.rows) this.lineList = res.rows;
|
||||
if (!this.hasRouteQuery && this.lineList.length > 0) {
|
||||
const suanYa = this.lineList.find(l => l.lineName === '酸轧线');
|
||||
this.productionLine = suanYa ? suanYa.lineId : this.lineList[0].lineId;
|
||||
}
|
||||
this.handleQuery();
|
||||
} catch (e) { console.error('加载产线列表失败', e); }
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.handleQuery();
|
||||
this.loadLineList();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<dict-select v-model="sharedQueryParams.productionLine" dict-type="sys_lines" placeholder="请选择产线" renderType="radio"
|
||||
clearable kisv @change="handleQuery" />
|
||||
<el-radio-group v-model="sharedQueryParams.productionLine" @change="handleQuery" size="small" style="margin-bottom: 10px;">
|
||||
<el-radio-button v-for="item in lineList" :key="item.lineId" :label="item.lineId">{{ item.lineName }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
|
||||
<DragResizePanel direction="horizontal" :initialSize="500" :minSize="350"
|
||||
style="height: calc(100vh - 164px); margin-top: 10px;">
|
||||
@@ -132,7 +133,9 @@
|
||||
<el-dialog :title="partTitle" :visible.sync="partOpen" width="500px" append-to-body>
|
||||
<el-form ref="partForm" :model="partForm" :rules="partRules" label-width="80px">
|
||||
<el-form-item label="产线" prop="productionLine">
|
||||
<dict-select v-model="partForm.productionLine" dict-type="sys_lines" kisv placeholder="请选择产线" />
|
||||
<el-select v-model="partForm.lineId" placeholder="请选择产线" style="width: 100%;">
|
||||
<el-option v-for="item in lineList" :key="item.lineId" :label="item.lineName" :value="item.lineId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="产线段" prop="lineSection">
|
||||
<el-input v-model="partForm.lineSection" placeholder="请输入产线段" />
|
||||
@@ -206,20 +209,21 @@ import html2canvas from 'html2canvas';
|
||||
import { PDFDocument } from 'pdf-lib';
|
||||
import { listEquipmentPart, getEquipmentPart, delEquipmentPart, addEquipmentPart, updateEquipmentPart } from "@/api/mes/eqp/equipmentPart";
|
||||
import { listEquipmentChecklist, getEquipmentChecklist, delEquipmentChecklist, addEquipmentChecklist, updateEquipmentChecklist } from "@/api/mes/eqp/equipmentChecklist";
|
||||
import { listProductionLine } from '@/api/wms/productionLine'
|
||||
|
||||
export default {
|
||||
name: "EquipmentPartChecklist",
|
||||
components: { DragResizePanel, QRCode },
|
||||
dicts: ['sys_lines'],
|
||||
data() {
|
||||
return {
|
||||
showSearch: true,
|
||||
|
||||
// Shared query params (productionLine & lineSection)
|
||||
sharedQueryParams: {
|
||||
productionLine: '酸轧线',
|
||||
lineId: null,
|
||||
lineSection: undefined
|
||||
},
|
||||
lineList: [],
|
||||
|
||||
// Part (left side)
|
||||
partLoading: false,
|
||||
@@ -285,13 +289,28 @@ export default {
|
||||
computed: {
|
||||
currentPartId() {
|
||||
return this.currentPart?.partId || "";
|
||||
},
|
||||
selectedLineName() {
|
||||
const found = this.lineList.find(l => l.lineId === this.sharedQueryParams.lineId);
|
||||
return found ? found.lineName : '';
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getPartList();
|
||||
this.getChecklistList();
|
||||
this.loadLineList();
|
||||
},
|
||||
methods: {
|
||||
async loadLineList() {
|
||||
try {
|
||||
const res = await listProductionLine({ pageSize: 999 });
|
||||
if (res.rows) this.lineList = res.rows;
|
||||
if (this.lineList.length > 0) {
|
||||
const suanYa = this.lineList.find(l => l.lineName === '酸轧线');
|
||||
this.sharedQueryParams.productionLine = suanYa ? suanYa.lineId : this.lineList[0].lineId;
|
||||
}
|
||||
this.getPartList();
|
||||
this.getChecklistList();
|
||||
} catch (e) { console.error('加载产线列表失败', e); }
|
||||
},
|
||||
// ========== Shared ==========
|
||||
applySharedParams() {
|
||||
this.partQueryParams.productionLine = this.sharedQueryParams.productionLine;
|
||||
@@ -357,6 +376,7 @@ export default {
|
||||
partId: undefined,
|
||||
inspectPart: undefined,
|
||||
remark: undefined,
|
||||
lineId: undefined,
|
||||
productionLine: undefined,
|
||||
lineSection: undefined
|
||||
};
|
||||
@@ -368,8 +388,8 @@ export default {
|
||||
},
|
||||
handlePartAdd() {
|
||||
this.resetPartForm();
|
||||
if (this.sharedQueryParams.productionLine) {
|
||||
this.partForm.productionLine = this.sharedQueryParams.productionLine;
|
||||
if (this.sharedQueryParams.lineId) {
|
||||
this.partForm.lineId = this.sharedQueryParams.lineId;
|
||||
}
|
||||
if (this.sharedQueryParams.lineSection) {
|
||||
this.partForm.lineSection = this.sharedQueryParams.lineSection;
|
||||
@@ -384,6 +404,10 @@ export default {
|
||||
getEquipmentPart(partId).then(response => {
|
||||
this.partLoading = false;
|
||||
this.partForm = response.data;
|
||||
if (this.partForm.productionLine && this.lineList.length) {
|
||||
const line = this.lineList.find(l => l.lineName === this.partForm.productionLine);
|
||||
if (line) this.$set(this.partForm, 'lineId', line.lineId);
|
||||
}
|
||||
this.partOpen = true;
|
||||
this.partTitle = "修改检验部位";
|
||||
});
|
||||
@@ -392,6 +416,10 @@ export default {
|
||||
this.$refs["partForm"].validate(valid => {
|
||||
if (valid) {
|
||||
this.partButtonLoading = true;
|
||||
if (this.partForm.lineId) {
|
||||
const line = this.lineList.find(l => l.lineId === this.partForm.lineId);
|
||||
if (line) this.partForm.productionLine = line.lineName;
|
||||
}
|
||||
if (this.partForm.partId != null) {
|
||||
updateEquipmentPart(this.partForm).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<!-- <el-form-item label="检验清单ID" prop="checkId">
|
||||
<el-input
|
||||
v-model="queryParams.checkId"
|
||||
placeholder="请输入检验清单ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="产线">
|
||||
<el-select v-model="queryParams.productionLine" placeholder="请选择产线" clearable @change="handleQuery" style="width: 150px;">
|
||||
<el-option v-for="item in lineList" :key="item.lineId" :label="item.lineName" :value="item.lineId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="班次" prop="shift">
|
||||
<el-select v-model="queryParams.shift" placeholder="请选择班次" clearable
|
||||
@change="handleQuery" style="width: 150px;">
|
||||
@@ -198,6 +195,7 @@
|
||||
|
||||
<script>
|
||||
import { listEquipmentInspectionRecord, getEquipmentInspectionRecord, delEquipmentInspectionRecord, addEquipmentInspectionRecord, updateEquipmentInspectionRecord } from "@/api/mes/eqp/equipmentInspectionRecord";
|
||||
import { listProductionLine } from "@/api/wms/productionLine";
|
||||
import ChecklistSelect from "@/components/ChecklistSelect";
|
||||
|
||||
export default {
|
||||
@@ -227,6 +225,7 @@ export default {
|
||||
open: false,
|
||||
// 时间段筛选
|
||||
dateRange: undefined,
|
||||
lineList: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
@@ -238,6 +237,7 @@ export default {
|
||||
runStatus: undefined,
|
||||
inspector: undefined,
|
||||
abnormalDesc: undefined,
|
||||
productionLine: 2,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
@@ -247,9 +247,16 @@ export default {
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.loadLineList();
|
||||
},
|
||||
methods: {
|
||||
async loadLineList() {
|
||||
try {
|
||||
const res = await listProductionLine({ pageSize: 999 });
|
||||
if (res.rows) this.lineList = res.rows;
|
||||
this.getList();
|
||||
} catch (e) { console.error('加载产线列表失败', e); }
|
||||
},
|
||||
/** 查询设备巡检记录列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
|
||||
@@ -13,6 +13,47 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最近排产单 -->
|
||||
<div class="plan-sheet-container">
|
||||
<div v-if="planSheetList.length > 0" class="plan-sheet-section">
|
||||
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ')'" size="small" />
|
||||
<el-tabs v-model="activePlanSheetId" type="card" size="mini">
|
||||
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId" :name="sheet.planSheetId"
|
||||
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
|
||||
</el-tabs>
|
||||
<el-table v-loading="planSheetLoading" :data="activePlanSheetDetails" border stripe size="mini"
|
||||
max-height="300">
|
||||
<el-table-column type="index" label="序号" width="50" />
|
||||
<el-table-column label="订单信息" header-align="center">
|
||||
<el-table-column prop="contractCode" label="合同号" width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="customerName" label="客户" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="salesman" label="业务员" width="100" show-overflow-tooltip />
|
||||
</el-table-column>
|
||||
<el-table-column label="成品信息" header-align="center">
|
||||
<el-table-column prop="productName" label="成品名称" width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="productMaterial" label="材质" width="100" />
|
||||
<el-table-column prop="coatingG" label="镀层g" width="80" />
|
||||
<el-table-column prop="productWidth" label="成品宽度" width="100" />
|
||||
<el-table-column prop="rollingThick" label="轧制厚度" width="100" />
|
||||
<el-table-column prop="markCoatThick" label="标丝厚度" width="100" />
|
||||
<el-table-column prop="tonSteelLengthRange" label="长度区间(m)" width="120" />
|
||||
<el-table-column prop="planQty" label="数量" width="80" />
|
||||
<el-table-column prop="planWeight" label="重量" width="100" />
|
||||
<el-table-column prop="surfaceTreatment" label="表面处理" width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="widthReq" label="切边要求" width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="productPackaging" label="包装要求" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="productEdgeReq" label="宽度要求" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="usageReq" label="用途" width="100" show-overflow-tooltip />
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" width="140" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else-if="planSheetLineName && !planSheetLoading" class="plan-sheet-section">
|
||||
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ')'" size="small" />
|
||||
<el-empty description="今天暂无排产单" :image-size="60" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 流程图区域 -->
|
||||
<div class="flow-container">
|
||||
<!-- 左侧:源卷列表 -->
|
||||
@@ -90,39 +131,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 今日排产单 -->
|
||||
<div v-if="planSheetList.length > 0" class="plan-sheet-section">
|
||||
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ')'" size="small" />
|
||||
<el-tabs v-model="activePlanSheetId" type="card" size="mini">
|
||||
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId"
|
||||
:name="sheet.planSheetId"
|
||||
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
|
||||
</el-tabs>
|
||||
<el-table v-loading="planSheetLoading" :data="activePlanSheetDetails" border stripe size="mini" max-height="300">
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="bizSeqNo" label="序号" width="55" />
|
||||
<el-table-column label="订单信息">
|
||||
<el-table-column prop="orderCode" label="订单号" width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="contractCode" label="合同号" width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="customerName" label="客户" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="salesman" label="业务员" width="80" show-overflow-tooltip />
|
||||
</el-table-column>
|
||||
<el-table-column label="成品信息">
|
||||
<el-table-column prop="productName" label="成品名称" width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="productMaterial" label="材质" width="80" />
|
||||
<el-table-column prop="coatingG" label="镀层g" width="70" />
|
||||
<el-table-column prop="productWidth" label="宽度" width="80" />
|
||||
<el-table-column prop="rollingThick" label="轧厚" width="80" />
|
||||
<el-table-column prop="planQty" label="数量" width="65" />
|
||||
<el-table-column prop="planWeight" label="重量" width="80" />
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" width="100" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else-if="planSheetLineName && !planSheetLoading" class="plan-sheet-section">
|
||||
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ')'" size="small" />
|
||||
<el-empty description="今天暂无排产单" :image-size="60" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:目标卷信息 -->
|
||||
@@ -1031,7 +1039,7 @@ export default {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.merge-coil-container {
|
||||
padding: 20px;
|
||||
padding: 12px;
|
||||
background: #f5f7fa;
|
||||
min-height: calc(100vh - 84px);
|
||||
}
|
||||
@@ -1042,8 +1050,8 @@ export default {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 20px;
|
||||
padding: 10px 16px;
|
||||
margin-bottom: 12px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
@@ -1065,12 +1073,12 @@ export default {
|
||||
/* 流程图容器 */
|
||||
.flow-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
gap: 12px;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
min-height: 600px;
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
.flow-left {
|
||||
@@ -1096,8 +1104,8 @@ export default {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 16px;
|
||||
padding-left: 12px;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
border-left: 4px solid #0066cc;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -1106,10 +1114,10 @@ export default {
|
||||
|
||||
/* 源卷列表 */
|
||||
.source-list {
|
||||
max-height: 500px;
|
||||
max-height: calc(100vh - 280px);
|
||||
overflow-y: auto;
|
||||
padding-right: 10px;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 0;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
@@ -1125,7 +1133,7 @@ export default {
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 8px;
|
||||
transition: all 0.3s;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -1136,7 +1144,7 @@ export default {
|
||||
}
|
||||
|
||||
.source-coil-header {
|
||||
padding: 10px 14px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
@@ -1144,8 +1152,8 @@ export default {
|
||||
}
|
||||
|
||||
.source-number {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
background: #0066cc;
|
||||
color: #fff;
|
||||
@@ -1172,7 +1180,7 @@ export default {
|
||||
}
|
||||
|
||||
.source-coil-body {
|
||||
padding: 10px 14px;
|
||||
padding: 8px 12px;
|
||||
|
||||
&:empty {
|
||||
text-align: center;
|
||||
@@ -1259,7 +1267,7 @@ export default {
|
||||
|
||||
.detail-label {
|
||||
color: #909399;
|
||||
min-width: 80px;
|
||||
min-width: 72px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -1339,29 +1347,29 @@ export default {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.15);
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.target-coil-header {
|
||||
background: #0066cc;
|
||||
color: #fff;
|
||||
padding: 16px 20px;
|
||||
padding: 10px 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.target-coil-body {
|
||||
padding: 20px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* 双列表单布局 */
|
||||
.form-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 12px;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
@@ -1527,7 +1535,26 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/* 排产单区域 */
|
||||
.plan-sheet-container {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.plan-sheet-section {
|
||||
margin-top: 16px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
// 减少表单项间距
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item--small .el-form-item__content,
|
||||
::v-deep .el-form-item--small .el-form-item__label {
|
||||
line-height: 32px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
<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="planId" v-if="showWaybill">
|
||||
<el-select v-model="queryParams.planId" placeholder="请输入发货计划名称搜索" filterable remote clearable
|
||||
:remote-method="remoteSearchWaybill" :loading="waybillLoading" style="width: 220px" @change="handleQuery">
|
||||
<el-option v-for="item in waybillOptions" :key="item.planId" :label="item.planName" :value="item.planId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="入场卷号" prop="enterCoilNo">
|
||||
<el-input v-model="queryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
@@ -10,8 +16,8 @@
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="warehouseId" v-if="useWarehouseIds">
|
||||
<muti-select v-model="warehouseIds" placeholder="请选择逻辑库位"
|
||||
style="width: 100%; display: inline-block;" clearable :options="warehouseOptions">
|
||||
<muti-select v-model="warehouseIds" placeholder="请选择逻辑库位" style="width: 100%; display: inline-block;" clearable
|
||||
:options="warehouseOptions">
|
||||
</muti-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="warehouseId" v-else-if="!hideWarehouseQuery && !leftWarehouseQuery">
|
||||
@@ -68,8 +74,8 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="品质">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable />
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status" placeholder="请选择品质"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="showWaybill" label="发货状态">
|
||||
@@ -97,6 +103,8 @@
|
||||
<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-button type="danger" plain icon="el-icon-close" size="mini" :disabled="multiple" :loading="buttonLoading"
|
||||
@click="handleBatchRemoveFromWaybill">批量移出发货单</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<!-- <el-form-item style="float: right;" v-if="showWaybill" v-loading="loading">
|
||||
@@ -123,6 +131,9 @@
|
||||
<el-button type="info" plain icon="el-icon-printer" size="mini" :disabled="multiple"
|
||||
@click="handleBatchPrintLabel">批量打印标签</el-button>
|
||||
</el-col>
|
||||
<!-- <el-col :span="2" v-if="showWaybill">
|
||||
|
||||
</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>
|
||||
@@ -132,20 +143,20 @@
|
||||
</el-row>
|
||||
|
||||
<div style="display: flex; align-items: flex-start;">
|
||||
<div v-if="leftWarehouseQuery"
|
||||
:style="{
|
||||
<div v-if="leftWarehouseQuery" :style="{
|
||||
width: '220px',
|
||||
height: showAbnormal ? 'calc(100vh - 400px)' : 'calc(100vh - 300px)',
|
||||
backgroundColor: '#ffffff',
|
||||
overflowY: 'auto',
|
||||
overflowX: 'hidden' }">
|
||||
overflowX: 'hidden'
|
||||
}">
|
||||
<warehouse-tree warehouseType="logic" @node-click="handleWarehouseNodeClick" />
|
||||
</div>
|
||||
<div style="flex: 1; width: 100%; overflow: hidden;">
|
||||
<KLPTable v-loading="loading" :data="materialCoilList" @selection-change="handleSelectionChange"
|
||||
:floatLayer="true" :floatLayerConfig="floatLayerConfig" @row-click="handleRowClick"
|
||||
:height="showAbnormal ? 'calc(100vh - 400px)' : 'calc(100vh - 300px)'" border>
|
||||
<!-- <el-table-column type="selection" width="55" align="center" /> -->
|
||||
<el-table-column v-if="showWaybill" type="selection" width="55" align="center" />
|
||||
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
|
||||
<template slot-scope="scope">
|
||||
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
|
||||
@@ -321,7 +332,8 @@
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column prop="action" label="操作" align="center" class-name="small-padding fixed-width" v-if="!moreColumn">
|
||||
<el-table-column prop="action" label="操作" align="center" class-name="small-padding fixed-width"
|
||||
v-if="!moreColumn">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handlePreviewLabel(scope.row)">
|
||||
预览标签
|
||||
@@ -567,7 +579,8 @@
|
||||
<el-form :model="judgeForm" label-width="120px">
|
||||
<el-form-item label="修改质量状态">
|
||||
<el-select v-model="judgeForm.qualityStatus" placeholder="请选择质量状态" style="width: 200px">
|
||||
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :value="item.value" :label="item.label" />
|
||||
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :value="item.value"
|
||||
:label="item.label" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="改判原因">
|
||||
@@ -639,13 +652,15 @@
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" @click="openCoilSelection(scope.row)">选择钢卷</el-button>
|
||||
<el-button size="mini" type="text" style="color: #f56c6c;" @click="deleteTempOrder(scope.row)">删除</el-button>
|
||||
<el-button size="mini" type="text" style="color: #f56c6c;"
|
||||
@click="deleteTempOrder(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 当没有数据时显示提示 -->
|
||||
<div v-if="!tempOrderList || tempOrderList.length === 0" style="text-align: center; padding: 50px; color: #909399;">
|
||||
<div v-if="!tempOrderList || tempOrderList.length === 0"
|
||||
style="text-align: center; padding: 50px; color: #909399;">
|
||||
<i class="el-icon-document" style="font-size: 48px; margin-bottom: 10px;"></i>
|
||||
<div>暂无暂存单据</div>
|
||||
<div style="font-size: 12px; margin-top: 5px;">点击右上角"创建暂存单据"开始使用</div>
|
||||
@@ -681,7 +696,8 @@
|
||||
|
||||
<!-- 下方:钢卷列表 -->
|
||||
<div style="height: 500px;">
|
||||
<el-table v-loading="coilLoading" :data="availableCoils" @selection-change="handleCoilSelection" border height="450">
|
||||
<el-table v-loading="coilLoading" :data="availableCoils" @selection-change="handleCoilSelection" border
|
||||
height="450">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
|
||||
<template slot-scope="scope">
|
||||
@@ -720,14 +736,9 @@
|
||||
</el-table>
|
||||
|
||||
<div style="margin-top: 10px; text-align: center;">
|
||||
<el-pagination
|
||||
@size-change="handleCoilSizeChange"
|
||||
@current-change="handleCoilCurrentChange"
|
||||
:current-page="coilQueryParams.pageNum"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="coilQueryParams.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="coilTotal">
|
||||
<el-pagination @size-change="handleCoilSizeChange" @current-change="handleCoilCurrentChange"
|
||||
:current-page="coilQueryParams.pageNum" :page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="coilQueryParams.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="coilTotal">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
@@ -774,7 +785,8 @@
|
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" style="color: #f56c6c;" @click="removeCoilFromOrder(scope.$index)">移除</el-button>
|
||||
<el-button size="mini" type="text" style="color: #f56c6c;"
|
||||
@click="removeCoilFromOrder(scope.$index)">移除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -797,7 +809,7 @@ import {
|
||||
getCoilStatisticsList,
|
||||
listWithAdjustRecordCoil
|
||||
} from "@/api/wms/coil";
|
||||
import { listBoundCoil } from "@/api/wms/deliveryWaybillDetail";
|
||||
import { listBoundCoil, getBoundCoilStatisticsList } from "@/api/wms/deliveryWaybillDetail";
|
||||
import { addPendingAction } from "@/api/wms/pendingAction";
|
||||
import { listTransferOrderItem } from "@/api/wms/transferOrderItem";
|
||||
import { listCoilQualityRejudge } from "@/api/wms/coilQualityRejudge";
|
||||
@@ -829,6 +841,7 @@ import DragResizeBox from '@/components/DragResizeBox/index.vue';
|
||||
import ProcessFlow from '../components/ProcessFlow.vue';
|
||||
import WarehouseTree from '@/components/KLPService/WarehouseTree/index.vue';
|
||||
import { listDeliveryWaybillDetail, delDeliveryWaybillDetail } from "@/api/wms/deliveryWaybillDetail";
|
||||
import { listDeliveryPlan } from "@/api/wms/deliveryPlan";
|
||||
import { addCoilQualityRejudge } from "@/api/wms/coilQualityRejudge";
|
||||
|
||||
export default {
|
||||
@@ -978,6 +991,8 @@ export default {
|
||||
showProcessFlow: false,
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
waybillLoading: false,
|
||||
waybillOptions: [],
|
||||
// 追溯加载中
|
||||
traceLoading: false,
|
||||
// 选中数组
|
||||
@@ -1019,6 +1034,7 @@ export default {
|
||||
status: '',
|
||||
updateTime: undefined,
|
||||
orderBy: false,
|
||||
planId: undefined,
|
||||
...this.querys,
|
||||
},
|
||||
// 表单参数
|
||||
@@ -1217,6 +1233,9 @@ export default {
|
||||
if (this.useWarehouseIds) {
|
||||
this.warehouseIds = this.warehouseOptions.map(item => item.value).join(',');
|
||||
}
|
||||
if (this.showWaybill) {
|
||||
this.remoteSearchWaybill();
|
||||
}
|
||||
this.getList();
|
||||
// 初始化暂存单据列表
|
||||
this.loadTempOrderList();
|
||||
@@ -1531,6 +1550,50 @@ export default {
|
||||
})
|
||||
// 打开一个弹窗列出查询到的所有单据明细
|
||||
},
|
||||
async handleBatchRemoveFromWaybill() {
|
||||
const selectedRows = this.materialCoilList.filter(item => this.ids.includes(item.coilId));
|
||||
if (selectedRows.length === 0) {
|
||||
this.$message.warning('请先勾选要移除的钢卷');
|
||||
return;
|
||||
}
|
||||
this.$modal.confirm(`确认要将选中的 ${selectedRows.length} 个钢卷从发货单中移除吗?`, {
|
||||
title: '批量移除',
|
||||
type: 'warning',
|
||||
}).then(async () => {
|
||||
this.buttonLoading = true;
|
||||
const detailIds = [];
|
||||
const failCoils = [];
|
||||
for (const row of selectedRows) {
|
||||
try {
|
||||
const res = await listDeliveryWaybillDetail({ coilId: row.coilId });
|
||||
if (res.rows.length === 1) {
|
||||
detailIds.push(res.rows[0].detailId);
|
||||
} else {
|
||||
failCoils.push(row.currentCoilNo);
|
||||
}
|
||||
} catch (e) {
|
||||
failCoils.push(row.currentCoilNo);
|
||||
}
|
||||
}
|
||||
if (detailIds.length === 0) {
|
||||
this.$message.error('未找到任何可移除的发货单明细');
|
||||
this.buttonLoading = false;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await delDeliveryWaybillDetail(detailIds.join(','));
|
||||
if (failCoils.length > 0) {
|
||||
this.$message.warning(`移除完成:成功 ${detailIds.length} 个,失败 ${failCoils.length} 个(${failCoils.join('、')})`);
|
||||
} else {
|
||||
this.$message.success(`成功移除 ${detailIds.length} 个钢卷`);
|
||||
}
|
||||
} catch (e) {
|
||||
this.$message.error('批量移除失败');
|
||||
}
|
||||
this.buttonLoading = false;
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
// 处理重贴标签
|
||||
handleReplaceLabel(row) {
|
||||
updateMaterialCoilSimple({
|
||||
@@ -1756,15 +1819,15 @@ export default {
|
||||
this.loading = false;
|
||||
})
|
||||
// 获取统计数据:已发货的数量和未发货的数量
|
||||
listBoundCoil({ ...query, status: 0 }).then(res => {
|
||||
listBoundCoil({ ...query, status: 0, pageNum: 1, pageSize: 1 }).then(res => {
|
||||
this.unshippedCount = res.total;
|
||||
})
|
||||
// 获取统计数据:已发货的数量和未发货的数量
|
||||
listBoundCoil({ ...query, status: 1 }).then(res => {
|
||||
listBoundCoil({ ...query, status: 1, pageNum: 1, pageSize: 1 }).then(res => {
|
||||
this.shippedCount = res.total;
|
||||
})
|
||||
|
||||
getCoilStatisticsList(query).then(res => {
|
||||
getBoundCoilStatisticsList(query).then(res => {
|
||||
this.statistics = res.data || [];
|
||||
})
|
||||
return;
|
||||
@@ -1892,6 +1955,14 @@ export default {
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
remoteSearchWaybill(query) {
|
||||
this.waybillLoading = true;
|
||||
listDeliveryPlan({ planName: query, pageNum: 1, pageSize: 20, planType: 0 }).then(res => {
|
||||
this.waybillOptions = res.rows || [];
|
||||
}).finally(() => {
|
||||
this.waybillLoading = false;
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
|
||||
@@ -12,6 +12,47 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最近排产单 -->
|
||||
<div class="plan-sheet-container">
|
||||
<div v-if="planSheetList.length > 0" class="plan-sheet-section">
|
||||
<el-descriptions :column="1" border title="最近排产单(酸轧线)" size="small" />
|
||||
<el-tabs v-model="activePlanSheetId" type="card" size="mini">
|
||||
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId" :name="sheet.planSheetId"
|
||||
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
|
||||
</el-tabs>
|
||||
<el-table v-loading="planSheetLoading" :data="activePlanSheetDetails" border stripe size="mini"
|
||||
max-height="300">
|
||||
<el-table-column type="index" label="序号" width="50" />
|
||||
<el-table-column label="订单信息" header-align="center">
|
||||
<el-table-column prop="contractCode" label="合同号" width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="customerName" label="客户" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="salesman" label="业务员" width="100" show-overflow-tooltip />
|
||||
</el-table-column>
|
||||
<el-table-column label="成品信息" header-align="center">
|
||||
<el-table-column prop="productName" label="成品名称" width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="productMaterial" label="材质" width="100" />
|
||||
<el-table-column prop="coatingG" label="镀层g" width="80" />
|
||||
<el-table-column prop="productWidth" label="成品宽度" width="100" />
|
||||
<el-table-column prop="rollingThick" label="轧制厚度" width="100" />
|
||||
<el-table-column prop="markCoatThick" label="标丝厚度" width="100" />
|
||||
<el-table-column prop="tonSteelLengthRange" label="长度区间(m)" width="120" />
|
||||
<el-table-column prop="planQty" label="数量" width="80" />
|
||||
<el-table-column prop="planWeight" label="重量" width="100" />
|
||||
<el-table-column prop="surfaceTreatment" label="表面处理" width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="widthReq" label="切边要求" width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="productPackaging" label="包装要求" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="productEdgeReq" label="宽度要求" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="usageReq" label="用途" width="100" show-overflow-tooltip />
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" width="140" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else-if="!planSheetLoading" class="plan-sheet-section">
|
||||
<el-descriptions :column="1" border title="最近排产单(酸轧线)" size="small" />
|
||||
<el-empty description="今天暂无排产单" :image-size="60" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 流程图区域 -->
|
||||
<div class="flow-container">
|
||||
<!-- 左侧:母卷信息 + 排产信息 -->
|
||||
@@ -84,39 +125,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 今日排产单 -->
|
||||
<div v-if="planSheetList.length > 0" class="plan-sheet-section">
|
||||
<el-descriptions :column="1" border title="最近排产单(酸轧线)" size="small" />
|
||||
<el-tabs v-model="activePlanSheetId" type="card" size="mini">
|
||||
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId"
|
||||
:name="sheet.planSheetId"
|
||||
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
|
||||
</el-tabs>
|
||||
<el-table v-loading="planSheetLoading" :data="activePlanSheetDetails" border stripe size="mini" max-height="300">
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="bizSeqNo" label="序号" width="55" />
|
||||
<el-table-column label="订单信息">
|
||||
<el-table-column prop="orderCode" label="订单号" width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="contractCode" label="合同号" width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="customerName" label="客户" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="salesman" label="业务员" width="80" show-overflow-tooltip />
|
||||
</el-table-column>
|
||||
<el-table-column label="成品信息">
|
||||
<el-table-column prop="productName" label="成品名称" width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="productMaterial" label="材质" width="80" />
|
||||
<el-table-column prop="coatingG" label="镀层g" width="70" />
|
||||
<el-table-column prop="productWidth" label="宽度" width="80" />
|
||||
<el-table-column prop="rollingThick" label="轧厚" width="80" />
|
||||
<el-table-column prop="planQty" label="数量" width="65" />
|
||||
<el-table-column prop="planWeight" label="重量" width="80" />
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" width="100" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else-if="!planSheetLoading" class="plan-sheet-section">
|
||||
<el-descriptions :column="1" border title="最近排产单(酸轧线)" size="small" />
|
||||
<el-empty description="今天暂无排产单" :image-size="60" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:子卷列表 -->
|
||||
@@ -139,7 +147,7 @@
|
||||
class="btn-remove"></el-button>
|
||||
</div>
|
||||
<div class="sub-coil-body">
|
||||
<el-form size="small" label-width="90px">
|
||||
<el-form size="small" label-width="80px">
|
||||
<div class="form-row">
|
||||
<el-form-item label="卷号" required class="form-item-half">
|
||||
<el-input v-model="item.currentCoilNo" placeholder="输入子卷卷号" :disabled="readonly"></el-input>
|
||||
@@ -178,7 +186,8 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="切边要求" prop="trimmingRequirement" class="form-item-half">
|
||||
<el-select v-model="item.trimmingRequirement" placeholder="请选择" style="width: 100%" :disabled="readonly">
|
||||
<el-select v-model="item.trimmingRequirement" placeholder="请选择" style="width: 100%"
|
||||
:disabled="readonly">
|
||||
<el-option label="净边料" value="净边料" />
|
||||
<el-option label="毛边料" value="毛边料" />
|
||||
</el-select>
|
||||
@@ -190,7 +199,8 @@
|
||||
<el-input v-model="item.packingStatus" placeholder="请输入原料材质" :disabled="readonly" />
|
||||
</el-form-item>
|
||||
<el-form-item label="包装要求" prop="packagingRequirement" class="form-item-half">
|
||||
<el-select v-model="item.packagingRequirement" placeholder="请选择" style="width: 100%" :disabled="readonly">
|
||||
<el-select v-model="item.packagingRequirement" placeholder="请选择" style="width: 100%"
|
||||
:disabled="readonly">
|
||||
<el-option label="裸包" value="裸包" />
|
||||
<el-option label="普包" value="普包" />
|
||||
<el-option label="简包" value="简包" />
|
||||
@@ -216,14 +226,14 @@
|
||||
|
||||
<div class="form-row">
|
||||
<el-form-item label="长度(m)" class="form-item-half">
|
||||
<el-input-number :controls="false" v-model="item.length" placeholder="请输入长度"
|
||||
:step="0.01" :disabled="readonly">
|
||||
<el-input-number :controls="false" v-model="item.length" placeholder="请输入长度" :step="0.01"
|
||||
:disabled="readonly">
|
||||
<template slot="append">米</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="实测长度(m)" prop="actualLength" class="form-item-half">
|
||||
<el-input-number :controls="false" v-model="item.actualLength" placeholder="实测长度"
|
||||
:step="0.01" :disabled="readonly">
|
||||
<el-input-number :controls="false" v-model="item.actualLength" placeholder="实测长度" :step="0.01"
|
||||
:disabled="readonly">
|
||||
<template slot="append">m</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
@@ -231,14 +241,14 @@
|
||||
|
||||
<div class="form-row">
|
||||
<el-form-item label="实测厚度(mm)" prop="actualThickness" class="form-item-half">
|
||||
<el-input-number :controls="false" v-model="item.actualThickness" placeholder="实测厚度"
|
||||
:step="0.01" :disabled="readonly">
|
||||
<el-input-number :controls="false" v-model="item.actualThickness" placeholder="实测厚度" :step="0.01"
|
||||
:disabled="readonly">
|
||||
<template slot="append">mm</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="实测宽度(mm)" prop="actualWidth" class="form-item-half">
|
||||
<el-input-number :controls="false" v-model="item.actualWidth" placeholder="实测宽度"
|
||||
:step="0.01" :disabled="readonly">
|
||||
<el-input-number :controls="false" v-model="item.actualWidth" placeholder="实测宽度" :step="0.01"
|
||||
:disabled="readonly">
|
||||
<template slot="append">mm</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
@@ -961,7 +971,7 @@ export default {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.split-coil-container {
|
||||
padding: 20px;
|
||||
padding: 12px;
|
||||
background: #f5f7fa;
|
||||
min-height: calc(100vh - 84px);
|
||||
}
|
||||
@@ -972,8 +982,8 @@ export default {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 20px;
|
||||
padding: 10px 16px;
|
||||
margin-bottom: 12px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
@@ -995,16 +1005,16 @@ export default {
|
||||
/* 流程图容器 */
|
||||
.flow-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
gap: 12px;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
min-height: 600px;
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
.flow-left {
|
||||
flex: 0 0 340px;
|
||||
flex: 0 0 320px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@@ -1017,8 +1027,8 @@ export default {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 16px;
|
||||
padding-left: 12px;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
border-left: 4px solid #0066cc;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -1045,24 +1055,24 @@ export default {
|
||||
.coil-header {
|
||||
background: #0066cc;
|
||||
color: #fff;
|
||||
padding: 16px 20px;
|
||||
padding: 10px 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.coil-title {
|
||||
flex: 1;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.coil-body {
|
||||
padding: 20px;
|
||||
padding: 12px;
|
||||
|
||||
&.two-col {
|
||||
display: grid;
|
||||
@@ -1074,7 +1084,7 @@ export default {
|
||||
.coil-info-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
@@ -1082,8 +1092,8 @@ export default {
|
||||
|
||||
.label {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
min-width: 100px;
|
||||
font-size: 13px;
|
||||
min-width: 90px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -1146,9 +1156,9 @@ export default {
|
||||
|
||||
/* 子卷列表 */
|
||||
.split-list {
|
||||
max-height: 500px;
|
||||
max-height: calc(100vh - 280px);
|
||||
overflow-y: auto;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 0;
|
||||
padding-right: 10px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
@@ -1165,7 +1175,7 @@ export default {
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 10px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
@@ -1176,7 +1186,7 @@ export default {
|
||||
|
||||
.sub-coil-header {
|
||||
background: #f5f7fa;
|
||||
padding: 12px 16px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
@@ -1184,11 +1194,11 @@ export default {
|
||||
}
|
||||
|
||||
.sub-coil-number {
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #0066cc;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background: #ecf5ff;
|
||||
display: flex;
|
||||
@@ -1206,76 +1216,13 @@ export default {
|
||||
}
|
||||
|
||||
.sub-coil-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* 汇总卡片 */
|
||||
.summary-card {
|
||||
background: #ecf5ff;
|
||||
border: 1px solid #d9ecff;
|
||||
border-radius: 8px;
|
||||
padding: 16px 20px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #0066cc;
|
||||
|
||||
&.error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
}
|
||||
|
||||
// 优化按钮文字颜色
|
||||
// 实心primary按钮:白色文字
|
||||
::v-deep .el-button--primary.el-button--small:not(.is-plain) {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
// plain按钮和text按钮:蓝色文字
|
||||
::v-deep .el-button--primary.el-button--small.is-plain,
|
||||
::v-deep .el-button--text {
|
||||
color: #409eff;
|
||||
|
||||
&:hover {
|
||||
color: #66b1ff;
|
||||
}
|
||||
}
|
||||
|
||||
// 修复数字输入框的上下箭头溢出
|
||||
.sub-coil-body {
|
||||
::v-deep input[type="number"] {
|
||||
appearance: textfield;
|
||||
-moz-appearance: textfield;
|
||||
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* 双列表单布局 */
|
||||
.form-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
gap: 10px;
|
||||
margin-bottom: 0;
|
||||
|
||||
&:last-child {
|
||||
@@ -1293,8 +1240,26 @@ export default {
|
||||
}
|
||||
|
||||
/* 排产单区域 */
|
||||
.plan-sheet-container {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.plan-sheet-section {
|
||||
margin-top: 16px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
// 减少表单项间距
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item--small .el-form-item__content,
|
||||
::v-deep .el-form-item--small .el-form-item__label {
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
// 异常信息样式
|
||||
|
||||
@@ -16,30 +16,34 @@
|
||||
<span><i class="el-icon-s-order"></i> {{ currentLineName }}排产计划</span>
|
||||
</div>
|
||||
<el-tabs v-model="activePlanSheetId" type="card" size="mini">
|
||||
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId"
|
||||
:name="sheet.planSheetId"
|
||||
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId" :name="sheet.planSheetId"
|
||||
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
|
||||
</el-tabs>
|
||||
<div style="overflow-x: auto;">
|
||||
<el-table :data="activePlanSheetDetails" size="small" max-height="300" stripe border>
|
||||
<el-table-column label="订单号" prop="orderCode" width="160" />
|
||||
<el-table-column label="合同号" prop="contractCode" width="160" />
|
||||
<el-table-column label="客户" prop="customerName" width="100" />
|
||||
<el-table-column label="业务员" prop="salesman" width="80" />
|
||||
<el-table-column label="成品名称" prop="productName" width="120" />
|
||||
<el-table-column label="成品材质" prop="productMaterial" width="100" />
|
||||
<el-table-column label="成品镀层" prop="coatingG" width="90" />
|
||||
<el-table-column label="成品宽度" prop="productWidth" width="90" />
|
||||
<el-table-column label="轧制厚度" prop="rollingThick" width="90" />
|
||||
<el-table-column label="标签厚度" prop="markCoatThick" width="90" />
|
||||
<el-table-column label="吨钢长度区间" prop="tonSteelLengthRange" width="120" />
|
||||
<el-table-column label="数量" prop="planQty" width="70" />
|
||||
<el-table-column label="重量" prop="planWeight" width="90" />
|
||||
<el-table-column label="表面处理" prop="surfaceTreatment" width="100" />
|
||||
<el-table-column label="切边要求" prop="widthReq" width="90" />
|
||||
<el-table-column label="包装要求" prop="productPackaging" width="90" />
|
||||
<el-table-column label="宽度要求" prop="productEdgeReq" width="90" />
|
||||
<el-table-column label="用途" prop="usageReq" width="100" />
|
||||
<el-table-column type="index" label="序号" width="50" />
|
||||
<el-table-column label="订单信息" header-align="center">
|
||||
<el-table-column prop="contractCode" label="合同号" width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="customerName" label="客户" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="salesman" label="业务员" width="100" show-overflow-tooltip />
|
||||
</el-table-column>
|
||||
<el-table-column label="成品信息" header-align="center">
|
||||
<el-table-column prop="productName" label="成品名称" width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="productMaterial" label="材质" width="100" />
|
||||
<el-table-column prop="coatingG" label="镀层g" width="80" />
|
||||
<el-table-column prop="productWidth" label="成品宽度" width="100" />
|
||||
<el-table-column prop="rollingThick" label="轧制厚度" width="100" />
|
||||
<el-table-column prop="markCoatThick" label="标丝厚度" width="100" />
|
||||
<el-table-column prop="tonSteelLengthRange" label="长度区间(m)" width="120" />
|
||||
<el-table-column prop="planQty" label="数量" width="80" />
|
||||
<el-table-column prop="planWeight" label="重量" width="100" />
|
||||
<el-table-column prop="surfaceTreatment" label="表面处理" width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="widthReq" label="切边要求" width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="productPackaging" label="包装要求" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="productEdgeReq" label="宽度要求" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="usageReq" label="用途" width="100" show-overflow-tooltip />
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" width="140" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
@@ -68,7 +72,8 @@
|
||||
<div v-if="matchedSpec" style="margin-bottom:10px">
|
||||
<el-tag type="success" size="small">
|
||||
<i class="el-icon-s-order" style="margin-right:4px" />
|
||||
已匹配规程:{{ matchedSpec.specCode }}{{ matchedSpec.specName ? ' - ' + matchedSpec.specName : '' }} / {{ matchedSpec.versionCode }}
|
||||
已匹配规程:{{ matchedSpec.specCode }}{{ matchedSpec.specName ? ' - ' + matchedSpec.specName : '' }} / {{
|
||||
matchedSpec.versionCode }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<el-form ref="updateForm" :model="updateForm" :rules="rules" label-width="86px" size="small">
|
||||
|
||||
@@ -56,6 +56,11 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="queryParams.remark" 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>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
@@ -178,7 +183,25 @@
|
||||
<!-- 如果没有绑定订单,这里是使用手机号字段来存储手填的订单编号 -->
|
||||
<el-form-item label="订单编号" prop="principalPhone" v-if="!form.orderId">
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
<el-input v-model="form.principalPhone" placeholder="请输入订单编号" style="flex: 1;" />
|
||||
<el-autocomplete
|
||||
v-model="form.principalPhone"
|
||||
:fetch-suggestions="queryOrderSuggestions"
|
||||
placeholder="请输入订单编号"
|
||||
style="flex: 1;"
|
||||
value-key="orderCode"
|
||||
@select="onOrderAutoSelect"
|
||||
clearable
|
||||
:highlight-first-item="true"
|
||||
popper-class="order-autocomplete-popper"
|
||||
>
|
||||
<template slot-scope="{ item }">
|
||||
<div class="order-suggestion-item">
|
||||
<span class="suggestion-code">{{ item.orderCode }}</span>
|
||||
<span class="suggestion-company">{{ item.companyName }}</span>
|
||||
<span class="suggestion-salesman">{{ item.salesman }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
<el-button type="primary" size="small" @click="bindOrder">绑定订单</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
@@ -344,6 +367,8 @@ export default {
|
||||
// 订单搜索关键词
|
||||
orderQuery: '',
|
||||
orderId: '',
|
||||
// 订单自动补全
|
||||
orderSuggestLoading: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
@@ -645,6 +670,52 @@ export default {
|
||||
this.form.principal = row.salesman;
|
||||
this.orderDialogVisible = false;
|
||||
},
|
||||
/** 订单编号自动补全 */
|
||||
queryOrderSuggestions(queryString, callback) {
|
||||
if (!queryString || queryString.trim() === '') {
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
this.orderSuggestLoading = true;
|
||||
listOrder({ pageNum: 1, pageSize: 10, keyword: queryString }).then(response => {
|
||||
const suggestions = (response.rows || []).map(item => ({
|
||||
...item,
|
||||
value: item.orderCode
|
||||
}));
|
||||
this.orderSuggestLoading = false;
|
||||
callback(suggestions);
|
||||
}).catch(() => {
|
||||
this.orderSuggestLoading = false;
|
||||
callback([]);
|
||||
});
|
||||
},
|
||||
/** 自动补全选择订单 */
|
||||
onOrderAutoSelect(item) {
|
||||
const existing = this.deliveryWaybillList.find(
|
||||
d => d.orderId === item.orderId || d.orderCode === item.orderCode
|
||||
);
|
||||
if (existing) {
|
||||
this.$confirm(
|
||||
`订单"${item.orderCode}"已绑定在发货单"${existing.waybillName}"中,确定继续绑定?`,
|
||||
'提示',
|
||||
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
||||
).then(() => {
|
||||
this.doBindOrder(item);
|
||||
}).catch(() => {
|
||||
this.form.principalPhone = item.orderCode;
|
||||
});
|
||||
} else {
|
||||
this.doBindOrder(item);
|
||||
}
|
||||
},
|
||||
/** 执行订单绑定并填写信息 */
|
||||
doBindOrder(item) {
|
||||
this.form.orderId = item.orderId;
|
||||
this.form.orderCode = item.orderCode;
|
||||
this.form.consigneeUnit = item.companyName;
|
||||
this.form.principal = item.salesman;
|
||||
this.form.principalPhone = item.orderCode;
|
||||
},
|
||||
/** 打印发货单 */
|
||||
handlePrint(row, printType) {
|
||||
this.loading = true;
|
||||
@@ -856,4 +927,58 @@ export default {
|
||||
::v-deep .el-pagination {
|
||||
margin-top: 6px !important;
|
||||
}
|
||||
|
||||
.order-suggestion-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.suggestion-code {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.suggestion-company {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.suggestion-salesman {
|
||||
color: #409eff;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.order-autocomplete-popper {
|
||||
min-width: 380px !important;
|
||||
}
|
||||
|
||||
.order-autocomplete-popper .order-suggestion-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.order-autocomplete-popper .suggestion-code {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.order-autocomplete-popper .suggestion-company {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.order-autocomplete-popper .suggestion-salesman {
|
||||
color: #409eff;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -24,7 +24,12 @@
|
||||
|
||||
<div class="schedule-table-wrapper">
|
||||
<el-table v-loading="loading" :data="attendanceData" border stripe>
|
||||
<el-table-column prop="employeeName" label="员工" width="120" fixed="left" />
|
||||
<el-table-column label="员工" width="150" fixed="left">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.employeeName }}</span>
|
||||
<el-button type="text" size="mini" icon="el-icon-view" @click="handlePersonDetail(scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-for="date in dateList" :key="date" :label="formatDateLabel(date)" width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<div class="attendance-cell" :class="getAttendanceStatusClass(scope.row[date])"
|
||||
@@ -385,6 +390,81 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 个人考勤总览 -->
|
||||
<el-dialog :title="personDialogTitle" :visible.sync="personDialogVisible" width="900px" append-to-body>
|
||||
<div v-if="currentPersonData" v-loading="personLoading">
|
||||
<el-descriptions title="考勤汇总" :column="5" border style="margin-bottom: 20px;">
|
||||
<el-descriptions-item label="姓名">{{ currentPersonData.employeeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="正常">{{ personSummary.normal }}天</el-descriptions-item>
|
||||
<el-descriptions-item label="迟到/早退">{{ personSummary.abnormal }}天</el-descriptions-item>
|
||||
<el-descriptions-item label="半天旷工">{{ personSummary.absentHalf }}天</el-descriptions-item>
|
||||
<el-descriptions-item label="全天旷工">{{ personSummary.absentFull }}天</el-descriptions-item>
|
||||
<el-descriptions-item label="无记录">{{ personSummary.noRecord }}天</el-descriptions-item>
|
||||
<el-descriptions-item label="迟到合计">{{ personSummary.totalLateMinutes }}分钟</el-descriptions-item>
|
||||
<el-descriptions-item label="早退合计">{{ personSummary.totalEarlyMinutes }}分钟</el-descriptions-item>
|
||||
<el-descriptions-item label="总扣款">¥{{ personSummary.totalDeduct }}</el-descriptions-item>
|
||||
<el-descriptions-item label="统计天数">{{ dateList.length }}天</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="left">考勤明细({{ dateList.length }}天)</el-divider>
|
||||
|
||||
<!-- 表格视图:小数据量(≤14天) 或 特大数据量(>62天) -->
|
||||
<el-table v-if="personViewMode === 'table'" :data="personDetailTableData" border stripe size="small" max-height="400">
|
||||
<el-table-column prop="workDate" label="日期" width="120" fixed="left" />
|
||||
<el-table-column prop="shiftName" label="班次" width="120" />
|
||||
<el-table-column prop="overallStatus" label="总体状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span :class="getStatusClass(scope.row.overallStatus)">{{ getStatusText(scope.row.overallStatus) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="p1FirstCheck" label="上班打卡" width="160">
|
||||
<template slot-scope="scope">{{ formatTime(scope.row.p1FirstCheck) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="p1LastCheck" label="下班打卡" width="160">
|
||||
<template slot-scope="scope">{{ formatTime(scope.row.p1LastCheck) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="p1LateMinutes" label="迟到(分)" width="80" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.p1LateMinutes > 0" class="late-info">{{ scope.row.p1LateMinutes }}</span>
|
||||
<span v-else>0</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="p1EarlyMinutes" label="早退(分)" width="80" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.p1EarlyMinutes > 0" class="early-info">{{ scope.row.p1EarlyMinutes }}</span>
|
||||
<span v-else>0</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="p1Deduct" label="扣款" width="80" align="center">
|
||||
<template slot-scope="scope">¥{{ scope.row.p1Deduct || '0.00' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="120" show-overflow-tooltip />
|
||||
</el-table>
|
||||
|
||||
<!-- 日历视图:中等数据量(15~62天) -->
|
||||
<div v-if="personViewMode === 'calendar'" class="calendar-view">
|
||||
<div v-for="month in personCalendarMonths" :key="month.key" class="calendar-month">
|
||||
<h4 class="calendar-month-title">{{ month.label }}</h4>
|
||||
<div class="calendar-grid">
|
||||
<div class="calendar-header" v-for="w in calendarWeekDays" :key="w">{{ w }}</div>
|
||||
<div v-for="(cell, idx) in month.cells" :key="idx"
|
||||
class="calendar-cell" :class="getCalendarCellClass(cell)">
|
||||
<span class="calendar-day">{{ cell.day }}</span>
|
||||
<span v-if="cell.date && cell.status" class="calendar-status">{{ getStatusText(cell.status) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="calendar-legend">
|
||||
<span class="legend-item"><span class="legend-dot normal"></span>正常</span>
|
||||
<span class="legend-item"><span class="legend-dot late"></span>迟到/早退</span>
|
||||
<span class="legend-item"><span class="legend-dot absent-half"></span>半天旷工</span>
|
||||
<span class="legend-item"><span class="legend-dot absent-full"></span>全天旷工</span>
|
||||
<span class="legend-item"><span class="legend-dot no-record"></span>无记录</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="考勤比对" :visible.sync="checkOpen" width="700px" append-to-body>
|
||||
<el-form ref="checkForm" :model="checkForm" :rules="checkRules" label-width="80px">
|
||||
<el-form-item label="开始日期" prop="startDate">
|
||||
@@ -515,7 +595,12 @@ export default {
|
||||
selectedUserIds: [],
|
||||
|
||||
detailRecordsLoading: false,
|
||||
detailRecordsList: []
|
||||
detailRecordsList: [],
|
||||
|
||||
personDialogVisible: false,
|
||||
personDialogTitle: '',
|
||||
currentPersonData: null,
|
||||
personLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -533,7 +618,88 @@ export default {
|
||||
key: String(emp.infoId),
|
||||
label: emp.name + '(' + emp.dept + ')'
|
||||
}))
|
||||
},
|
||||
personSummary() {
|
||||
if (!this.currentPersonData) return { normal: 0, abnormal: 0, absentHalf: 0, absentFull: 0, noRecord: 0, totalLateMinutes: 0, totalEarlyMinutes: 0, totalDeduct: '0.00' };
|
||||
let normal = 0, abnormal = 0, absentHalf = 0, absentFull = 0, noRecord = 0;
|
||||
let totalLate = 0, totalEarly = 0, totalDeduct = 0;
|
||||
this.dateList.forEach(date => {
|
||||
const record = this.currentPersonData[date];
|
||||
if (!record) {
|
||||
noRecord++;
|
||||
return;
|
||||
}
|
||||
const status = record.overallStatus;
|
||||
if (status === 'normal') normal++;
|
||||
else if (status === 'absent_half') absentHalf++;
|
||||
else if (status === 'absent_full') absentFull++;
|
||||
else if (status === 'abnormal' || status === 'late_warn' || status === 'late_one' || status === 'late_two' || status === 'early_warn' || status === 'early_one' || status === 'early_two' || status === 'missed') abnormal++;
|
||||
totalLate += Number(record.p1LateMinutes || 0) + Number(record.p2LateMinutes || 0);
|
||||
totalEarly += Number(record.p1EarlyMinutes || 0) + Number(record.p2EarlyMinutes || 0);
|
||||
totalDeduct += Number(record.p1Deduct || 0) + Number(record.p2Deduct || 0) + Number(record.totalDeduct || 0);
|
||||
});
|
||||
return { normal, abnormal, absentHalf, absentFull, noRecord, totalLateMinutes: totalLate, totalEarlyMinutes: totalEarly, totalDeduct: totalDeduct.toFixed(2) };
|
||||
},
|
||||
personViewMode() {
|
||||
const days = this.dateList.length;
|
||||
if (days <= 14) return 'table';
|
||||
if (days <= 62) return 'calendar';
|
||||
return 'table';
|
||||
},
|
||||
personDetailTableData() {
|
||||
if (!this.currentPersonData) return [];
|
||||
return this.dateList.map(date => {
|
||||
const record = this.currentPersonData[date];
|
||||
if (!record) {
|
||||
return { workDate: date, shiftName: '-', overallStatus: null, p1FirstCheck: null, p1LastCheck: null, p2FirstCheck: null, p2LastCheck: null, p1LateMinutes: 0, p1EarlyMinutes: 0, p1Deduct: 0, p2LateMinutes: 0, p2EarlyMinutes: 0, p2Deduct: 0, totalDeduct: 0, remark: '' };
|
||||
}
|
||||
return {
|
||||
workDate: date,
|
||||
...record,
|
||||
p1LateMinutes: record.p1LateMinutes || 0,
|
||||
p1EarlyMinutes: record.p1EarlyMinutes || 0,
|
||||
};
|
||||
});
|
||||
},
|
||||
calendarWeekDays() {
|
||||
return ['日', '一', '二', '三', '四', '五', '六'];
|
||||
},
|
||||
personCalendarMonths() {
|
||||
if (!this.dateList || this.dateList.length === 0) return [];
|
||||
const months = {};
|
||||
this.dateList.forEach(date => {
|
||||
const d = new Date(date);
|
||||
const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
|
||||
if (!months[key]) {
|
||||
months[key] = { key, label: `${d.getFullYear()}年${d.getMonth() + 1}月`, dates: [] };
|
||||
}
|
||||
months[key].dates.push(date);
|
||||
});
|
||||
return Object.values(months).map(month => {
|
||||
const firstDate = new Date(month.dates[0]);
|
||||
const year = firstDate.getFullYear();
|
||||
const monthNum = firstDate.getMonth();
|
||||
const firstDay = new Date(year, monthNum, 1);
|
||||
const lastDay = new Date(year, monthNum + 1, 0);
|
||||
const startDayOfWeek = firstDay.getDay();
|
||||
const totalDays = lastDay.getDate();
|
||||
const cells = [];
|
||||
for (let i = 0; i < startDayOfWeek; i++) {
|
||||
cells.push({ day: '', date: null });
|
||||
}
|
||||
for (let day = 1; day <= totalDays; day++) {
|
||||
const dateStr = `${year}-${String(monthNum + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||||
const record = this.currentPersonData ? this.currentPersonData[dateStr] : null;
|
||||
cells.push({
|
||||
day,
|
||||
date: dateStr,
|
||||
status: record ? record.overallStatus : null,
|
||||
inRange: month.dates.includes(dateStr),
|
||||
});
|
||||
}
|
||||
return { ...month, cells };
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getAllEmployees().then(() => {
|
||||
@@ -1049,6 +1215,30 @@ export default {
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handlePersonDetail(row) {
|
||||
this.currentPersonData = row
|
||||
this.personDialogTitle = row.employeeName + ' - 考勤总览'
|
||||
this.personDialogVisible = true
|
||||
},
|
||||
getCalendarCellClass(cell) {
|
||||
if (!cell.date) return 'cal-empty'
|
||||
if (!cell.status) return 'cal-no-record'
|
||||
switch (cell.status) {
|
||||
case 'normal': return 'cal-normal'
|
||||
case 'absent_half': return 'cal-absent-half'
|
||||
case 'absent_full': return 'cal-absent-full'
|
||||
case 'abnormal':
|
||||
case 'late_warn':
|
||||
case 'late_one':
|
||||
case 'late_two':
|
||||
case 'early_warn':
|
||||
case 'early_one':
|
||||
case 'early_two':
|
||||
case 'missed':
|
||||
return 'cal-abnormal'
|
||||
default: return 'cal-default'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1229,4 +1419,128 @@ export default {
|
||||
margin-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.early-info {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.calendar-view {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.calendar-month {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.calendar-month-title {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.calendar-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 2px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.calendar-header {
|
||||
text-align: center;
|
||||
padding: 6px 4px;
|
||||
background: #f5f7fa;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.calendar-cell {
|
||||
min-height: 50px;
|
||||
padding: 4px;
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
border-right: 1px solid #ebeef5;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.calendar-day {
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.calendar-status {
|
||||
font-size: 10px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.cal-empty {
|
||||
background: #f9f9f9;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.cal-no-record {
|
||||
background: #fdf6ec;
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.cal-normal {
|
||||
background: #f0f9eb;
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.cal-abnormal {
|
||||
background: #fef0f0;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.cal-absent-half {
|
||||
background: #f4f4f5;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.cal-absent-full {
|
||||
background: #e9e9eb;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.cal-default {
|
||||
background: #f5f7fa;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.calendar-legend {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-top: 12px;
|
||||
flex-wrap: wrap;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.legend-dot {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.legend-dot.normal { background: #f0f9eb; border: 1px solid #67c23a; }
|
||||
.legend-dot.late { background: #fef0f0; border: 1px solid #f56c6c; }
|
||||
.legend-dot.absent-half { background: #f4f4f5; border: 1px solid #909399; }
|
||||
.legend-dot.absent-full { background: #e9e9eb; border: 1px solid #606266; }
|
||||
.legend-dot.no-record { background: #fdf6ec; border: 1px solid #e6a23c; }
|
||||
</style>
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
<el-form-item prop="endTime">
|
||||
<el-button type="primary" @click="getList">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出</el-button>
|
||||
<el-button type="primary" @click="openCustomExport">自定义导出</el-button>
|
||||
<el-button type="primary" @click="settingVisible = true">列设置</el-button>
|
||||
<el-button type="primary" @click="saveReport">保存报表</el-button>
|
||||
</el-form-item>
|
||||
@@ -84,11 +85,45 @@
|
||||
</el-radio-group>
|
||||
<columns-setting :reportType="activeColumnConfig"></columns-setting>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 自定义导出列选择弹窗 -->
|
||||
<el-dialog title="自定义导出 - 选择导出列" :visible.sync="customExportVisible" width="750px">
|
||||
<div class="custom-export-toolbar">
|
||||
<el-input v-model="columnSearch" placeholder="搜索列名" prefix-icon="el-icon-search" clearable size="small" style="width: 220px" />
|
||||
<div class="custom-export-actions">
|
||||
<el-button size="small" @click="selectAllColumns">全选</el-button>
|
||||
<el-button size="small" @click="invertColumns">反选</el-button>
|
||||
<el-button size="small" @click="selectedColumns = []">清空</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-export-body">
|
||||
<el-checkbox-group v-model="selectedColumns">
|
||||
<div v-for="(group, gName) in groupedColumns" :key="gName" class="column-group">
|
||||
<div class="column-group-title">{{ gName }}</div>
|
||||
<div class="column-group-items">
|
||||
<el-checkbox
|
||||
v-for="field in group"
|
||||
:key="field.key"
|
||||
:label="field.key"
|
||||
:style="{ display: columnSearch && !filterMatch(field) ? 'none' : '' }"
|
||||
>{{ field.label }}</el-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<div slot="footer" class="custom-export-footer">
|
||||
<span class="selected-tip">已选 <b>{{ selectedColumns.length }}</b> / {{ flatColumns.length }} 列</span>
|
||||
<el-button @click="customExportVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="doCustomExport" :disabled="selectedColumns.length === 0">
|
||||
导出选中列
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCoilWithIds } from "@/api/wms/coil";
|
||||
import { listCoilWithIds, getExportColumns } from "@/api/wms/coil";
|
||||
import {
|
||||
listPendingAction,
|
||||
} from '@/api/wms/pendingAction';
|
||||
@@ -146,6 +181,20 @@ export default {
|
||||
return {
|
||||
activeColumnConfig: 'coil-report-receive',
|
||||
settingVisible: false,
|
||||
customExportVisible: false,
|
||||
exportColumns: {},
|
||||
selectedColumns: [],
|
||||
columnSearch: '',
|
||||
columnGroups: {
|
||||
'基本信息': ['itemTypeDesc', 'warehouseName', 'actualWarehouseName', 'dataTypeText'],
|
||||
'钢卷号': ['enterCoilNo', 'supplierCoilNo', 'currentCoilNo'],
|
||||
'时间': ['createTime', 'exportTime', 'exportBy'],
|
||||
'物理属性': ['netWeight', 'length', 'specification', 'actualThickness'],
|
||||
'材质属性': ['material', 'manufacturer', 'surfaceTreatmentDesc', 'zincLayer', 'packingStatus', 'temperGrade', 'coatingType'],
|
||||
'用途': ['purpose', 'businessPurpose'],
|
||||
'状态': ['qualityStatus', 'statusDesc', 'isRelatedToOrderText'],
|
||||
'其他': ['itemName', 'itemId', 'packagingRequirement', 'trimmingRequirement', 'transferType', 'saleName', 'remark', 'team'],
|
||||
},
|
||||
list: [],
|
||||
defaultStartTime: startTime,
|
||||
defaultEndTime: endTime,
|
||||
@@ -221,6 +270,21 @@ export default {
|
||||
coilIds() {
|
||||
return this.list.map(item => item.coilId).join(',')
|
||||
},
|
||||
groupedColumns() {
|
||||
const result = {}
|
||||
Object.entries(this.columnGroups).forEach(([groupName, fieldKeys]) => {
|
||||
const items = fieldKeys
|
||||
.filter(key => this.exportColumns[key])
|
||||
.map(key => ({ key, label: this.exportColumns[key] }))
|
||||
if (items.length) {
|
||||
result[groupName] = items
|
||||
}
|
||||
})
|
||||
return result
|
||||
},
|
||||
flatColumns() {
|
||||
return Object.values(this.groupedColumns).flat()
|
||||
},
|
||||
|
||||
},
|
||||
methods: {
|
||||
@@ -282,6 +346,33 @@ export default {
|
||||
coilIds: this.coilIds,
|
||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
// 打开自定义导出弹窗
|
||||
openCustomExport() {
|
||||
getExportColumns().then(res => {
|
||||
this.exportColumns = res.data
|
||||
this.selectedColumns = []
|
||||
this.customExportVisible = true
|
||||
})
|
||||
},
|
||||
// 执行自定义导出
|
||||
doCustomExport() {
|
||||
this.customExportVisible = false
|
||||
this.download('wms/materialCoil/exportCustom', {
|
||||
coilIds: this.coilIds,
|
||||
columns: this.selectedColumns.join(','),
|
||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
filterMatch(field) {
|
||||
const keyword = this.columnSearch.toLowerCase()
|
||||
return !keyword || field.label.toLowerCase().includes(keyword) || field.key.toLowerCase().includes(keyword)
|
||||
},
|
||||
selectAllColumns() {
|
||||
this.selectedColumns = this.flatColumns.map(f => f.key)
|
||||
},
|
||||
invertColumns() {
|
||||
const allKeys = this.flatColumns.map(f => f.key)
|
||||
this.selectedColumns = allKeys.filter(k => !this.selectedColumns.includes(k))
|
||||
},
|
||||
saveReport() {
|
||||
this.loading = true
|
||||
saveReportFile(this.coilIds, {
|
||||
@@ -310,4 +401,53 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.custom-export-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
.custom-export-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.custom-export-body {
|
||||
max-height: 420px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.column-group {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.column-group-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 2px;
|
||||
border-left: 3px solid #409eff;
|
||||
padding-left: 8px;
|
||||
}
|
||||
.column-group-items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 4px 12px;
|
||||
}
|
||||
.column-group-items .el-checkbox {
|
||||
margin-right: 0;
|
||||
}
|
||||
.custom-export-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.selected-tip {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
.selected-tip b {
|
||||
color: #409eff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -654,7 +654,7 @@ export default {
|
||||
|
||||
const [lossRes, outRes] = await Promise.all([
|
||||
listCoilWithIds({ ...this.queryParams, actionIds: lossActionIds.join(',') || '', startTime: '', endTime: '', selectType: 'raw_material' }),
|
||||
listCoilWithIds({ ...this.queryParams, coilIds: outIds.join(',') || '', startTime: '', endTime: '', selectType: 'product' }),
|
||||
listCoilWithIds({ ...this.queryParams, coilIds: outIds.join(',') || '', startTime: '', endTime: '', byCreateTimeStart: this.queryParams.startTime, byCreateTimeEnd: this.queryParams.endTime, selectType: 'product' }),
|
||||
]);
|
||||
|
||||
this.lossList = lossRes.rows.map(item => {
|
||||
@@ -692,7 +692,7 @@ export default {
|
||||
|
||||
const [lossRes, outRes] = await Promise.all([
|
||||
listCoilWithIds({ ...this.queryParams, actionIds: lossActionIds.join(',') || '', startTime: '', endTime: '', selectType: 'raw_material' }),
|
||||
listCoilWithIds({ ...this.queryParams, coilIds: outIds.join(',') || '', startTime: '', endTime: '', selectType: 'product' }),
|
||||
listCoilWithIds({ ...this.queryParams, coilIds: outIds.join(',') || '', startTime: '', endTime: '', byCreateTimeStart: this.queryParams.startTime, byCreateTimeEnd: this.queryParams.endTime, selectType: 'product' }),
|
||||
]);
|
||||
|
||||
if (this.reportType === 'out') {
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
<el-tab-pane label="质保书审批" name="fourth" v-hasPermi="['qc:certificate:approve']">
|
||||
<CertificateBook />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="设备送检记录" name="fifth" v-hasPermi="['mes:eqp:approval']">
|
||||
<EquipmentInspectionApproval readonly :defaultStatus="1" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="其他代办" name="second">
|
||||
<el-empty description="暂无其他代办事项" />
|
||||
</el-tab-pane>
|
||||
@@ -19,6 +22,7 @@
|
||||
import TranferCoilTable from '@/views/wms/coil/views/base/tranfer.vue'
|
||||
import InspectionTask from '@/views/mes/qc/inspection/task.vue'
|
||||
import CertificateBook from '@/views/mes/qc/certificate/book.vue'
|
||||
import EquipmentInspectionApproval from '@/views/mes/eqp/check/approval.vue'
|
||||
|
||||
export default {
|
||||
name: 'TodoIndex',
|
||||
@@ -26,6 +30,7 @@
|
||||
TranferCoilTable,
|
||||
InspectionTask,
|
||||
CertificateBook,
|
||||
EquipmentInspectionApproval,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -134,9 +134,12 @@ public class WmsDeliveryWaybillDetailController extends BaseController {
|
||||
WmsMaterialCoilBo bo,
|
||||
PageQuery pageQuery,
|
||||
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime,
|
||||
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime) {
|
||||
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime,
|
||||
@RequestParam(required = false) Long planId) {
|
||||
List<Long> boundCoilIds;
|
||||
if (startTime != null || endTime != null) {
|
||||
if (planId != null) {
|
||||
boundCoilIds = iWmsDeliveryWaybillDetailService.getBoundCoilIdsByPlanId(planId, startTime, endTime);
|
||||
} else if (startTime != null || endTime != null) {
|
||||
boundCoilIds = iWmsDeliveryWaybillDetailService.getBoundCoilIdsByTimeRange(startTime, endTime);
|
||||
} else {
|
||||
boundCoilIds = iWmsDeliveryWaybillDetailService.getBoundCoilIds();
|
||||
@@ -157,9 +160,12 @@ public class WmsDeliveryWaybillDetailController extends BaseController {
|
||||
public R<java.util.Map<String, java.math.BigDecimal>> getStatistics(
|
||||
WmsMaterialCoilBo bo,
|
||||
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime,
|
||||
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime) {
|
||||
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime,
|
||||
@RequestParam(required = false) Long planId) {
|
||||
List<Long> boundCoilIds;
|
||||
if (startTime != null || endTime != null) {
|
||||
if (planId != null) {
|
||||
boundCoilIds = iWmsDeliveryWaybillDetailService.getBoundCoilIdsByPlanId(planId, startTime, endTime);
|
||||
} else if (startTime != null || endTime != null) {
|
||||
boundCoilIds = iWmsDeliveryWaybillDetailService.getBoundCoilIdsByTimeRange(startTime, endTime);
|
||||
} else {
|
||||
boundCoilIds = iWmsDeliveryWaybillDetailService.getBoundCoilIds();
|
||||
|
||||
@@ -5,6 +5,9 @@ import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -30,6 +33,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.common.utils.StringUtils;
|
||||
import com.klp.domain.bo.WmsMaterialCoilBo;
|
||||
import com.klp.domain.bo.WmsMaterialCoilReportSummaryBo;
|
||||
import com.klp.domain.vo.dashboard.CoilTrimStatisticsVo;
|
||||
@@ -130,6 +134,70 @@ public class WmsMaterialCoilController extends BaseController {
|
||||
List<WmsMaterialCoilExportVo> list = iWmsMaterialCoilService.queryExportList(bo);
|
||||
ExcelUtil.exportExcel(list, "钢卷物料表", WmsMaterialCoilExportVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 个性化导出:前端传入要导出的字段名,仅导出选中列
|
||||
* columns 参数为逗号分隔的 Java 字段名,如 "itemTypeDesc,enterCoilNo,netWeight"
|
||||
* 不传 columns 时等同于 /exportAll 导出全部字段
|
||||
*/
|
||||
@Log(title = "钢卷物料表", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/exportCustom")
|
||||
public void exportCustom(WmsMaterialCoilBo bo,
|
||||
@RequestParam(required = false) String columns,
|
||||
HttpServletResponse response) {
|
||||
List<WmsMaterialCoilAllExportVo> list = iWmsMaterialCoilService.queryExportListAll(bo);
|
||||
if (StringUtils.isNotBlank(columns)) {
|
||||
Set<String> includeFields = new HashSet<>(Arrays.asList(columns.split(",")));
|
||||
ExcelUtil.exportExcel(list, "钢卷物料表", WmsMaterialCoilAllExportVo.class, includeFields, response);
|
||||
} else {
|
||||
ExcelUtil.exportExcel(list, "钢卷物料表", WmsMaterialCoilAllExportVo.class, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可导出的列元数据(供前端列选择器使用)
|
||||
* 返回 { "fieldName": "中文列名" } 的映射,基于完整导出字段
|
||||
*/
|
||||
@GetMapping("/exportColumns")
|
||||
public R<Map<String, String>> getExportColumns() {
|
||||
Map<String, String> columns = new LinkedHashMap<>();
|
||||
columns.put("itemTypeDesc", "类型");
|
||||
columns.put("warehouseName", "逻辑库区");
|
||||
columns.put("actualWarehouseName", "实际库区");
|
||||
columns.put("enterCoilNo", "入场卷号");
|
||||
columns.put("supplierCoilNo", "厂家卷号");
|
||||
columns.put("currentCoilNo", "成品卷号");
|
||||
columns.put("createTime", "日期");
|
||||
columns.put("exportTime", "发货时间");
|
||||
columns.put("exportBy", "发货人");
|
||||
columns.put("netWeight", "重量");
|
||||
columns.put("purpose", "用途");
|
||||
columns.put("trimmingRequirement", "切边要求");
|
||||
columns.put("packagingRequirement", "包装种类");
|
||||
columns.put("qualityStatus", "产品质量");
|
||||
columns.put("packingStatus", "原料材质");
|
||||
columns.put("statusDesc", "库存状态");
|
||||
columns.put("remark", "备注");
|
||||
columns.put("itemName", "名称");
|
||||
columns.put("length", "长度");
|
||||
columns.put("specification", "规格");
|
||||
columns.put("material", "材质");
|
||||
columns.put("manufacturer", "厂家");
|
||||
columns.put("surfaceTreatmentDesc", "表面处理");
|
||||
columns.put("zincLayer", "锌层");
|
||||
columns.put("itemId", "物品ID");
|
||||
columns.put("dataTypeText", "数据类型");
|
||||
columns.put("temperGrade", "调制度");
|
||||
columns.put("coatingType", "镀层种类");
|
||||
columns.put("businessPurpose", "业务用途");
|
||||
columns.put("isRelatedToOrderText", "是否与订单相关");
|
||||
columns.put("saleName", "销售人员");
|
||||
columns.put("actualThickness", "实测厚度");
|
||||
columns.put("transferType", "调拨类型");
|
||||
columns.put("team", "班组");
|
||||
return R.ok(columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出钢卷物料表列表(完整字段版本)
|
||||
* 导出全部字段
|
||||
|
||||
@@ -78,6 +78,7 @@ public class WmsMaterialCoilAllExportVo {
|
||||
private BigDecimal netWeight;
|
||||
|
||||
// 班组
|
||||
@ExcelProperty(value = "班组")
|
||||
private String team;
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,4 +73,9 @@ public interface IWmsDeliveryWaybillDetailService {
|
||||
* 根据负责人(principal)查询已绑定的钢卷ID列表
|
||||
*/
|
||||
List<Long> getBoundCoilIdsByPrincipal(String principal);
|
||||
|
||||
/**
|
||||
* 根据发货计划ID查询已绑定的钢卷ID列表(可结合时间段筛选)
|
||||
*/
|
||||
List<Long> getBoundCoilIdsByPlanId(Long planId, Date startTime, Date endTime);
|
||||
}
|
||||
|
||||
@@ -338,6 +338,33 @@ public class WmsDeliveryWaybillDetailServiceImpl implements IWmsDeliveryWaybillD
|
||||
return list.stream().map(WmsDeliveryWaybillDetail::getCoilId).distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getBoundCoilIdsByPlanId(Long planId, Date startTime, Date endTime) {
|
||||
LambdaQueryWrapper<WmsDeliveryWaybill> waybillWrapper = Wrappers.lambdaQuery();
|
||||
waybillWrapper.eq(WmsDeliveryWaybill::getPlanId, planId);
|
||||
waybillWrapper.eq(WmsDeliveryWaybill::getDelFlag, 0);
|
||||
if (startTime != null) {
|
||||
waybillWrapper.ge(WmsDeliveryWaybill::getDeliveryTime, startTime);
|
||||
}
|
||||
if (endTime != null) {
|
||||
waybillWrapper.le(WmsDeliveryWaybill::getDeliveryTime, endTime);
|
||||
}
|
||||
List<WmsDeliveryWaybill> waybills = wmsDeliveryWaybillMapper.selectList(waybillWrapper);
|
||||
if (waybills == null || waybills.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Long> waybillIds = waybills.stream().map(WmsDeliveryWaybill::getWaybillId).collect(Collectors.toList());
|
||||
|
||||
LambdaQueryWrapper<WmsDeliveryWaybillDetail> detailWrapper = Wrappers.lambdaQuery();
|
||||
detailWrapper.in(WmsDeliveryWaybillDetail::getWaybillId, waybillIds);
|
||||
detailWrapper.isNotNull(WmsDeliveryWaybillDetail::getCoilId);
|
||||
detailWrapper.eq(WmsDeliveryWaybillDetail::getDelFlag, 0);
|
||||
detailWrapper.select(WmsDeliveryWaybillDetail::getCoilId);
|
||||
List<WmsDeliveryWaybillDetail> list = baseMapper.selectList(detailWrapper);
|
||||
return list.stream().map(WmsDeliveryWaybillDetail::getCoilId).distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getBoundCoilIdsByPrincipal(String principal) {
|
||||
if (principal == null || principal.trim().isEmpty()) {
|
||||
|
||||
@@ -630,6 +630,8 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
|
||||
qw.eq(StringUtils.isNotBlank(bo.getBusinessPurpose()), "mc.business_purpose", bo.getBusinessPurpose());
|
||||
// 是否与订单相关(0=否,1=是)
|
||||
qw.eq(bo.getIsRelatedToOrder() != null, "mc.is_related_to_order", bo.getIsRelatedToOrder());
|
||||
// 加上remark的模糊匹配
|
||||
qw.like(StringUtils.isNotBlank(bo.getRemark()), "mc.remark", bo.getRemark());
|
||||
//逻辑删除
|
||||
qw.eq("mc.del_flag", 0);
|
||||
// 统一处理 warehouseId 与 warehouseIds:
|
||||
|
||||
Reference in New Issue
Block a user