Merge remote-tracking branch 'origin/0.8.X' into 0.8.X
This commit is contained in:
@@ -18,8 +18,11 @@ import com.klp.common.core.validate.EditGroup;
|
|||||||
import com.klp.common.enums.BusinessType;
|
import com.klp.common.enums.BusinessType;
|
||||||
import com.klp.common.utils.poi.ExcelUtil;
|
import com.klp.common.utils.poi.ExcelUtil;
|
||||||
import com.klp.flow.domain.vo.SchProdScheduleItemVo;
|
import com.klp.flow.domain.vo.SchProdScheduleItemVo;
|
||||||
|
import com.klp.flow.domain.vo.SchProdScheduleItemMergeValidateVo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
||||||
import com.klp.flow.service.ISchProdScheduleItemService;
|
import com.klp.flow.service.ISchProdScheduleItemService;
|
||||||
import com.klp.common.core.page.TableDataInfo;
|
import com.klp.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
@@ -117,4 +120,22 @@ public class SchProdScheduleItemController extends BaseController {
|
|||||||
public R<Void> merge(@Validated @RequestBody SchProdScheduleItemMergeBo mergeBo) {
|
public R<Void> merge(@Validated @RequestBody SchProdScheduleItemMergeBo mergeBo) {
|
||||||
return toAjax(iSchProdScheduleItemService.mergeByBo(mergeBo));
|
return toAjax(iSchProdScheduleItemService.mergeByBo(mergeBo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收产需单:从 sch_prod_schedule + sch_prod_schedule_detail 全字段复制到 sch_prod_schedule_item
|
||||||
|
*/
|
||||||
|
@Log(title = "排产单主加明细可合并", businessType = BusinessType.INSERT)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PostMapping("/receive")
|
||||||
|
public R<Void> receive(@Validated @RequestBody SchProdScheduleItemReceiveBo receiveBo) {
|
||||||
|
return toAjax(iSchProdScheduleItemService.receiveByBo(receiveBo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并校验:检查待合并记录来源产需单的 header 字段是否一致
|
||||||
|
*/
|
||||||
|
@PostMapping("/mergeValidate")
|
||||||
|
public R<SchProdScheduleItemMergeValidateVo> mergeValidate(@Validated @RequestBody SchProdScheduleItemMergeValidateBo validateBo) {
|
||||||
|
return R.ok(iSchProdScheduleItemService.validateMerge(validateBo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,13 +128,9 @@ public class SchProdScheduleItem extends BaseEntity {
|
|||||||
*/
|
*/
|
||||||
private String returnReason;
|
private String returnReason;
|
||||||
/**
|
/**
|
||||||
* 排产单主表ID
|
* 排产明细关联主表ID(逗号分隔,未合并存单值,合并后存多个)
|
||||||
*/
|
*/
|
||||||
private String scheduleIds;
|
private String scheduleDetailIds;
|
||||||
/**
|
|
||||||
* 来源销售订单明细ID(溯源原始订单规格)
|
|
||||||
*/
|
|
||||||
private String orderDetailIds;
|
|
||||||
/**
|
/**
|
||||||
* 规格 例:1.0X1250
|
* 规格 例:1.0X1250
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -42,6 +42,30 @@ public class TsComplaintAccept extends BaseEntity {
|
|||||||
* 客户诉求
|
* 客户诉求
|
||||||
*/
|
*/
|
||||||
private String customerDemand;
|
private String customerDemand;
|
||||||
|
/**
|
||||||
|
* 关联客户ID
|
||||||
|
*/
|
||||||
|
private Long customerId;
|
||||||
|
/**
|
||||||
|
* 下游使用用户名称
|
||||||
|
*/
|
||||||
|
private String downstreamUserName;
|
||||||
|
/**
|
||||||
|
* 电话
|
||||||
|
*/
|
||||||
|
private String phone;
|
||||||
|
/**
|
||||||
|
* 使用的工程名称
|
||||||
|
*/
|
||||||
|
private String projectName;
|
||||||
|
/**
|
||||||
|
* 工程使用地点
|
||||||
|
*/
|
||||||
|
private String projectLocation;
|
||||||
|
/**
|
||||||
|
* 产品用途
|
||||||
|
*/
|
||||||
|
private String productUsage;
|
||||||
/**
|
/**
|
||||||
* 客户照片凭证等
|
* 客户照片凭证等
|
||||||
*/
|
*/
|
||||||
@@ -64,7 +88,7 @@ public class TsComplaintAccept extends BaseEntity {
|
|||||||
private Date auditTime;
|
private Date auditTime;
|
||||||
/**
|
/**
|
||||||
* 流程阶段:
|
* 流程阶段:
|
||||||
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结
|
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=全部办结
|
||||||
*/
|
*/
|
||||||
private Long flowStatus;
|
private Long flowStatus;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -154,14 +154,9 @@ public class SchProdScheduleItemBo extends BaseEntity {
|
|||||||
private String returnReason;
|
private String returnReason;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排产单主表ID
|
* 排产明细关联主表ID(逗号分隔,未合并存单值,合并后存多个)
|
||||||
*/
|
*/
|
||||||
private String scheduleIds;
|
private String scheduleDetailIds;
|
||||||
|
|
||||||
/**
|
|
||||||
* 来源销售订单明细ID(溯源原始订单规格)
|
|
||||||
*/
|
|
||||||
private String orderDetailIds;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 规格 例:1.0X1250
|
* 规格 例:1.0X1250
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.klp.flow.domain.bo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排产单合并校验请求对象
|
||||||
|
*
|
||||||
|
* @author klp
|
||||||
|
* @date 2026-06-29
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SchProdScheduleItemMergeValidateBo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待合并记录ID列表
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "待合并记录ID不能为空")
|
||||||
|
private List<Long> ids;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.klp.flow.domain.bo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产需单接收请求对象
|
||||||
|
*
|
||||||
|
* @author klp
|
||||||
|
* @date 2026-06-29
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SchProdScheduleItemReceiveBo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排产单主表ID(产需单ID)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "排产单主表ID不能为空")
|
||||||
|
private Long scheduleId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -48,6 +48,36 @@ public class TsComplaintAcceptBo extends BaseEntity {
|
|||||||
*/
|
*/
|
||||||
private String customerDemand;
|
private String customerDemand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联客户ID
|
||||||
|
*/
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下游使用用户名称
|
||||||
|
*/
|
||||||
|
private String downstreamUserName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电话
|
||||||
|
*/
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用的工程名称
|
||||||
|
*/
|
||||||
|
private String projectName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工程使用地点
|
||||||
|
*/
|
||||||
|
private String projectLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品用途
|
||||||
|
*/
|
||||||
|
private String productUsage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户照片凭证等
|
* 客户照片凭证等
|
||||||
*/
|
*/
|
||||||
@@ -75,7 +105,7 @@ public class TsComplaintAcceptBo extends BaseEntity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程阶段:
|
* 流程阶段:
|
||||||
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结
|
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=全部办结
|
||||||
*/
|
*/
|
||||||
private Long flowStatus;
|
private Long flowStatus;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package com.klp.flow.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排产单合并校验视图对象
|
||||||
|
*
|
||||||
|
* @author klp
|
||||||
|
* @date 2026-06-29
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SchProdScheduleItemMergeValidateVo {
|
||||||
|
|
||||||
|
/** 是否所有 header 字段一致 */
|
||||||
|
private Boolean consistent;
|
||||||
|
|
||||||
|
/** 有差异的字段列表 */
|
||||||
|
private List<FieldDiff> diffs;
|
||||||
|
|
||||||
|
/** 被合并记录快照 */
|
||||||
|
private List<ItemInfo> items;
|
||||||
|
|
||||||
|
/** 汇总信息 */
|
||||||
|
private MergedSummary summary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段差异
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class FieldDiff {
|
||||||
|
/** 字段名(Java属性名) */
|
||||||
|
private String fieldName;
|
||||||
|
/** 字段中文标签 */
|
||||||
|
private String fieldLabel;
|
||||||
|
/** scheduleId → 值 */
|
||||||
|
private Map<String, Object> values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 被合并记录快照
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class ItemInfo {
|
||||||
|
/** sch_prod_schedule_item 主键 */
|
||||||
|
private Long itemId;
|
||||||
|
/** 第一个源 schedule_id(从 scheduleIds 解析) */
|
||||||
|
private Long sourceScheduleId;
|
||||||
|
/** 排产单号 */
|
||||||
|
private String scheduleNo;
|
||||||
|
/** 订货单位 */
|
||||||
|
private String customerName;
|
||||||
|
/** 品名 */
|
||||||
|
private String productType;
|
||||||
|
/** 规格 */
|
||||||
|
private String spec;
|
||||||
|
/** 材质 */
|
||||||
|
private String material;
|
||||||
|
/** 排产吨数 */
|
||||||
|
private BigDecimal scheduleWeight;
|
||||||
|
/** 来源排产明细ID串 */
|
||||||
|
private String scheduleDetailIds;
|
||||||
|
/** 业务员 */
|
||||||
|
private String businessUser;
|
||||||
|
/** 联系电话 */
|
||||||
|
private String businessPhone;
|
||||||
|
/** 交货期(天) */
|
||||||
|
private Long deliveryCycle;
|
||||||
|
/** 产品用途 */
|
||||||
|
private String usePurpose;
|
||||||
|
/** 厚度公差 */
|
||||||
|
private String thicknessTolerance;
|
||||||
|
/** 宽度公差 */
|
||||||
|
private String widthTolerance;
|
||||||
|
/** 表面质量 */
|
||||||
|
private String surfaceQuality;
|
||||||
|
/** 表面处理 */
|
||||||
|
private String surfaceTreatment;
|
||||||
|
/** 内径尺寸 */
|
||||||
|
private String innerDiameter;
|
||||||
|
/** 外径要求 */
|
||||||
|
private String outerDiameter;
|
||||||
|
/** 包装要求 */
|
||||||
|
private String packReq;
|
||||||
|
/** 切边要求 */
|
||||||
|
private String cutEdgeReq;
|
||||||
|
/** 单件重量 */
|
||||||
|
private String singleCoilWeight;
|
||||||
|
/** 交货重量偏差 */
|
||||||
|
private String weightDeviation;
|
||||||
|
/** 其他技术要求 */
|
||||||
|
private String otherTechReq;
|
||||||
|
/** 付款情况说明 */
|
||||||
|
private String paymentDesc;
|
||||||
|
/** 关联销售合同号 */
|
||||||
|
private String relContractNo;
|
||||||
|
/** 排产总计划吨数 */
|
||||||
|
private BigDecimal totalPlanWeight;
|
||||||
|
/** 订单日期 */
|
||||||
|
private java.util.Date orderDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并汇总
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class MergedSummary {
|
||||||
|
/** 明细条数 */
|
||||||
|
private int itemCount;
|
||||||
|
/** 合计排产吨数 */
|
||||||
|
private BigDecimal totalScheduleWeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
|
|||||||
import com.klp.common.annotation.ExcelDictFormat;
|
import com.klp.common.annotation.ExcelDictFormat;
|
||||||
import com.klp.common.convert.ExcelDictConvert;
|
import com.klp.common.convert.ExcelDictConvert;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +41,8 @@ public class SchProdScheduleItemVo {
|
|||||||
*/
|
*/
|
||||||
@ExcelProperty(value = "生产日期", converter = ExcelDictConvert.class)
|
@ExcelProperty(value = "生产日期", converter = ExcelDictConvert.class)
|
||||||
@ExcelDictFormat(readConverterExp = "和=合同号组成业务关联键")
|
@ExcelDictFormat(readConverterExp = "和=合同号组成业务关联键")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
private Date prodDate;
|
private Date prodDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,17 +184,10 @@ public class SchProdScheduleItemVo {
|
|||||||
private String returnReason;
|
private String returnReason;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排产单主表ID
|
* 排产明细关联主表ID(逗号分隔)
|
||||||
*/
|
*/
|
||||||
@ExcelProperty(value = "排产单主表ID")
|
@ExcelProperty(value = "排产明细关联主表ID")
|
||||||
private String scheduleIds;
|
private String scheduleDetailIds;
|
||||||
|
|
||||||
/**
|
|
||||||
* 来源销售订单明细ID(溯源原始订单规格)
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "来源销售订单明细ID", converter = ExcelDictConvert.class)
|
|
||||||
@ExcelDictFormat(readConverterExp = "溯=源原始订单规格")
|
|
||||||
private String orderDetailIds;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 规格 例:1.0X1250
|
* 规格 例:1.0X1250
|
||||||
|
|||||||
@@ -52,6 +52,42 @@ public class TsComplaintAcceptVo extends BaseEntity {
|
|||||||
@ExcelProperty(value = "客户诉求")
|
@ExcelProperty(value = "客户诉求")
|
||||||
private String customerDemand;
|
private String customerDemand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联客户ID
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "关联客户ID")
|
||||||
|
private Long customerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下游使用用户名称
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "下游使用用户名称")
|
||||||
|
private String downstreamUserName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电话
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "电话")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用的工程名称
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "使用的工程名称")
|
||||||
|
private String projectName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工程使用地点
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "工程使用地点")
|
||||||
|
private String projectLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品用途
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "产品用途")
|
||||||
|
private String productUsage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户照片凭证等
|
* 客户照片凭证等
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +120,7 @@ public class TsComplaintAcceptVo extends BaseEntity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程阶段:
|
* 流程阶段:
|
||||||
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结
|
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=全部办结
|
||||||
*/
|
*/
|
||||||
@ExcelProperty(value = "流程阶段")
|
@ExcelProperty(value = "流程阶段")
|
||||||
private Long flowStatus;
|
private Long flowStatus;
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ package com.klp.flow.service;
|
|||||||
|
|
||||||
import com.klp.flow.domain.SchProdScheduleItem;
|
import com.klp.flow.domain.SchProdScheduleItem;
|
||||||
import com.klp.flow.domain.vo.SchProdScheduleItemVo;
|
import com.klp.flow.domain.vo.SchProdScheduleItemVo;
|
||||||
|
import com.klp.flow.domain.vo.SchProdScheduleItemMergeValidateVo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
||||||
import com.klp.common.core.page.TableDataInfo;
|
import com.klp.common.core.page.TableDataInfo;
|
||||||
import com.klp.common.core.domain.PageQuery;
|
import com.klp.common.core.domain.PageQuery;
|
||||||
|
|
||||||
@@ -57,4 +60,14 @@ public interface ISchProdScheduleItemService {
|
|||||||
* 合并多条排产单主加明细可合并记录:先删除被合并的记录,再插入合并后的新记录
|
* 合并多条排产单主加明细可合并记录:先删除被合并的记录,再插入合并后的新记录
|
||||||
*/
|
*/
|
||||||
Boolean mergeByBo(SchProdScheduleItemMergeBo mergeBo);
|
Boolean mergeByBo(SchProdScheduleItemMergeBo mergeBo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收产需单:从 sch_prod_schedule + sch_prod_schedule_detail 全字段复制到 sch_prod_schedule_item
|
||||||
|
*/
|
||||||
|
Boolean receiveByBo(SchProdScheduleItemReceiveBo receiveBo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并校验:检查待合并记录来源产需单的 header 字段是否一致
|
||||||
|
*/
|
||||||
|
SchProdScheduleItemMergeValidateVo validateMerge(SchProdScheduleItemMergeValidateBo validateBo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,16 +11,27 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemBo;
|
||||||
import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemReceiveBo;
|
||||||
|
import com.klp.flow.domain.bo.SchProdScheduleItemMergeValidateBo;
|
||||||
import com.klp.flow.domain.vo.SchProdScheduleItemVo;
|
import com.klp.flow.domain.vo.SchProdScheduleItemVo;
|
||||||
|
import com.klp.flow.domain.vo.SchProdScheduleItemMergeValidateVo;
|
||||||
import com.klp.flow.domain.SchProdScheduleItem;
|
import com.klp.flow.domain.SchProdScheduleItem;
|
||||||
|
import com.klp.flow.domain.SchProdSchedule;
|
||||||
|
import com.klp.flow.domain.SchProdScheduleDetail;
|
||||||
import com.klp.flow.mapper.SchProdScheduleItemMapper;
|
import com.klp.flow.mapper.SchProdScheduleItemMapper;
|
||||||
|
import com.klp.flow.mapper.SchProdScheduleMapper;
|
||||||
|
import com.klp.flow.mapper.SchProdScheduleDetailMapper;
|
||||||
import com.klp.flow.service.ISchProdScheduleItemService;
|
import com.klp.flow.service.ISchProdScheduleItemService;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排产单主加明细可合并Service业务层处理
|
* 排产单主加明细可合并Service业务层处理
|
||||||
@@ -33,6 +44,8 @@ import java.util.Collection;
|
|||||||
public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemService {
|
public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemService {
|
||||||
|
|
||||||
private final SchProdScheduleItemMapper baseMapper;
|
private final SchProdScheduleItemMapper baseMapper;
|
||||||
|
private final SchProdScheduleMapper schProdScheduleMapper;
|
||||||
|
private final SchProdScheduleDetailMapper schProdScheduleDetailMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询排产单主加明细可合并
|
* 查询排产单主加明细可合并
|
||||||
@@ -89,8 +102,7 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi
|
|||||||
lqw.eq(StringUtils.isNotBlank(bo.getOtherTechReq()), SchProdScheduleItem::getOtherTechReq, bo.getOtherTechReq());
|
lqw.eq(StringUtils.isNotBlank(bo.getOtherTechReq()), SchProdScheduleItem::getOtherTechReq, bo.getOtherTechReq());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getPaymentDesc()), SchProdScheduleItem::getPaymentDesc, bo.getPaymentDesc());
|
lqw.eq(StringUtils.isNotBlank(bo.getPaymentDesc()), SchProdScheduleItem::getPaymentDesc, bo.getPaymentDesc());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getReturnReason()), SchProdScheduleItem::getReturnReason, bo.getReturnReason());
|
lqw.eq(StringUtils.isNotBlank(bo.getReturnReason()), SchProdScheduleItem::getReturnReason, bo.getReturnReason());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getScheduleIds()), SchProdScheduleItem::getScheduleIds, bo.getScheduleIds());
|
lqw.eq(StringUtils.isNotBlank(bo.getScheduleDetailIds()), SchProdScheduleItem::getScheduleDetailIds, bo.getScheduleDetailIds());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getOrderDetailIds()), SchProdScheduleItem::getOrderDetailIds, bo.getOrderDetailIds());
|
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getSpec()), SchProdScheduleItem::getSpec, bo.getSpec());
|
lqw.eq(StringUtils.isNotBlank(bo.getSpec()), SchProdScheduleItem::getSpec, bo.getSpec());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getMaterial()), SchProdScheduleItem::getMaterial, bo.getMaterial());
|
lqw.eq(StringUtils.isNotBlank(bo.getMaterial()), SchProdScheduleItem::getMaterial, bo.getMaterial());
|
||||||
lqw.eq(bo.getScheduleWeight() != null, SchProdScheduleItem::getScheduleWeight, bo.getScheduleWeight());
|
lqw.eq(bo.getScheduleWeight() != null, SchProdScheduleItem::getScheduleWeight, bo.getScheduleWeight());
|
||||||
@@ -179,4 +191,287 @@ public class SchProdScheduleItemServiceImpl implements ISchProdScheduleItemServi
|
|||||||
}
|
}
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收产需单:从 sch_prod_schedule + sch_prod_schedule_detail 全字段复制到 sch_prod_schedule_item
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Boolean receiveByBo(SchProdScheduleItemReceiveBo receiveBo) {
|
||||||
|
Long scheduleId = receiveBo.getScheduleId();
|
||||||
|
|
||||||
|
// 1. 查询产需单主表
|
||||||
|
SchProdSchedule header = schProdScheduleMapper.selectById(scheduleId);
|
||||||
|
if (header == null) {
|
||||||
|
throw new RuntimeException("产需单不存在,scheduleId=" + scheduleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 查询产需单明细列表
|
||||||
|
List<SchProdScheduleDetail> details = schProdScheduleDetailMapper.selectList(
|
||||||
|
Wrappers.<SchProdScheduleDetail>lambdaQuery()
|
||||||
|
.eq(SchProdScheduleDetail::getScheduleId, scheduleId)
|
||||||
|
);
|
||||||
|
if (details == null || details.isEmpty()) {
|
||||||
|
throw new RuntimeException("产需单无明细数据,scheduleId=" + scheduleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 遍历每条 detail,构建 SchProdScheduleItem 列表
|
||||||
|
List<SchProdScheduleItem> addList = new ArrayList<>(details.size());
|
||||||
|
for (SchProdScheduleDetail detail : details) {
|
||||||
|
SchProdScheduleItem item = new SchProdScheduleItem();
|
||||||
|
|
||||||
|
// 从 header 复制所有字段
|
||||||
|
item.setScheduleNo(header.getScheduleNo());
|
||||||
|
item.setProdDate(header.getProdDate());
|
||||||
|
item.setScheduleStatus(2L); // 已下达
|
||||||
|
item.setTotalPlanWeight(header.getTotalPlanWeight());
|
||||||
|
item.setRelContractNo(header.getRelContractNo());
|
||||||
|
item.setBusinessUser(header.getBusinessUser());
|
||||||
|
item.setBusinessPhone(header.getBusinessPhone());
|
||||||
|
item.setOrderDate(header.getOrderDate());
|
||||||
|
item.setCustomerName(header.getCustomerName());
|
||||||
|
item.setDeliveryCycle(header.getDeliveryCycle());
|
||||||
|
item.setUsePurpose(header.getUsePurpose());
|
||||||
|
item.setProductType(header.getProductType());
|
||||||
|
item.setThicknessTolerance(header.getThicknessTolerance());
|
||||||
|
item.setWidthTolerance(header.getWidthTolerance());
|
||||||
|
item.setSurfaceQuality(header.getSurfaceQuality());
|
||||||
|
item.setSurfaceTreatment(header.getSurfaceTreatment());
|
||||||
|
item.setInnerDiameter(header.getInnerDiameter());
|
||||||
|
item.setOuterDiameter(header.getOuterDiameter());
|
||||||
|
item.setPackReq(header.getPackReq());
|
||||||
|
item.setCutEdgeReq(header.getCutEdgeReq());
|
||||||
|
item.setSingleCoilWeight(header.getSingleCoilWeight());
|
||||||
|
item.setWeightDeviation(header.getWeightDeviation());
|
||||||
|
item.setOtherTechReq(header.getOtherTechReq());
|
||||||
|
item.setPaymentDesc(header.getPaymentDesc());
|
||||||
|
item.setRemark(header.getRemark());
|
||||||
|
// 不复制 returnReason
|
||||||
|
|
||||||
|
// 从 detail 复制
|
||||||
|
item.setSpec(detail.getSpec());
|
||||||
|
item.setMaterial(detail.getMaterial());
|
||||||
|
item.setScheduleWeight(detail.getScheduleWeight());
|
||||||
|
item.setProductItem(detail.getProductType());
|
||||||
|
item.setRowRemark(detail.getRemark());
|
||||||
|
|
||||||
|
// 来源追溯(未合并,各存明细ID)
|
||||||
|
item.setScheduleDetailIds(String.valueOf(detail.getScheduleDetailId()));
|
||||||
|
|
||||||
|
validEntityBeforeSave(item);
|
||||||
|
addList.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 批量插入
|
||||||
|
baseMapper.insertBatch(addList);
|
||||||
|
|
||||||
|
// 5. 更新产需单状态为 2(已下达)
|
||||||
|
header.setScheduleStatus(2L);
|
||||||
|
schProdScheduleMapper.updateById(header);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并校验:检查待合并记录来源产需单的 header 字段是否一致
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SchProdScheduleItemMergeValidateVo validateMerge(SchProdScheduleItemMergeValidateBo validateBo) {
|
||||||
|
List<Long> ids = validateBo.getIds();
|
||||||
|
|
||||||
|
// 1. 查询所有待合并的 sch_prod_schedule_item 记录
|
||||||
|
List<SchProdScheduleItem> items = baseMapper.selectBatchIds(ids);
|
||||||
|
if (items == null || items.size() < 2) {
|
||||||
|
throw new RuntimeException("待合并记录不足,至少需要2条");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 解析每条记录的 scheduleIds(逗号分隔),取第一个作为源 schedule_id
|
||||||
|
// 查询所有源 sch_prod_schedule 记录
|
||||||
|
List<Long> sourceScheduleIds = new ArrayList<>();
|
||||||
|
for (SchProdScheduleItem item : items) {
|
||||||
|
String sids = item.getScheduleDetailIds();
|
||||||
|
if (sids != null && !sids.isEmpty()) {
|
||||||
|
String[] parts = sids.split(",");
|
||||||
|
if (parts.length > 0) {
|
||||||
|
String firstId = parts[0].trim();
|
||||||
|
if (!firstId.isEmpty()) {
|
||||||
|
sourceScheduleIds.add(Long.valueOf(firstId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<Long> distinctSourceIds = sourceScheduleIds.stream().distinct().collect(Collectors.toList());
|
||||||
|
List<SchProdSchedule> sourceHeaders = schProdScheduleMapper.selectBatchIds(distinctSourceIds);
|
||||||
|
Map<Long, SchProdSchedule> headerMap = new LinkedHashMap<>();
|
||||||
|
for (SchProdSchedule h : sourceHeaders) {
|
||||||
|
headerMap.put(h.getScheduleId(), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 定义要比较的字段列表(字段名 → 中文标签)
|
||||||
|
Map<String, String> compareFields = new LinkedHashMap<>();
|
||||||
|
compareFields.put("scheduleNo", "排产单号");
|
||||||
|
compareFields.put("customerName", "订货单位");
|
||||||
|
compareFields.put("businessUser", "业务员");
|
||||||
|
compareFields.put("businessPhone", "联系电话");
|
||||||
|
compareFields.put("deliveryCycle", "交货期(天)");
|
||||||
|
compareFields.put("usePurpose", "产品用途");
|
||||||
|
compareFields.put("productType", "品名");
|
||||||
|
compareFields.put("thicknessTolerance", "厚度公差");
|
||||||
|
compareFields.put("widthTolerance", "宽度公差");
|
||||||
|
compareFields.put("surfaceQuality", "表面质量");
|
||||||
|
compareFields.put("surfaceTreatment", "表面处理");
|
||||||
|
compareFields.put("innerDiameter", "内径尺寸");
|
||||||
|
compareFields.put("outerDiameter", "外径要求");
|
||||||
|
compareFields.put("packReq", "包装要求");
|
||||||
|
compareFields.put("cutEdgeReq", "切边要求");
|
||||||
|
compareFields.put("singleCoilWeight", "单件重量");
|
||||||
|
compareFields.put("weightDeviation", "交货重量偏差");
|
||||||
|
compareFields.put("otherTechReq", "其他技术要求");
|
||||||
|
compareFields.put("paymentDesc", "付款情况说明");
|
||||||
|
compareFields.put("relContractNo", "关联销售合同号");
|
||||||
|
compareFields.put("totalPlanWeight", "排产总计划吨数");
|
||||||
|
compareFields.put("orderDate", "订单日期");
|
||||||
|
|
||||||
|
// 4. 逐一比较字段
|
||||||
|
List<SchProdScheduleItemMergeValidateVo.FieldDiff> diffs = new ArrayList<>();
|
||||||
|
boolean allConsistent = true;
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> entry : compareFields.entrySet()) {
|
||||||
|
String fieldName = entry.getKey();
|
||||||
|
String fieldLabel = entry.getValue();
|
||||||
|
Map<String, Object> values = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (SchProdSchedule header : sourceHeaders) {
|
||||||
|
Long headerId = header.getScheduleId();
|
||||||
|
Object val = getFieldValue(header, fieldName);
|
||||||
|
values.put(String.valueOf(headerId), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断所有值是否一致
|
||||||
|
boolean same = values.values().stream().distinct().count() <= 1;
|
||||||
|
if (!same) {
|
||||||
|
allConsistent = false;
|
||||||
|
SchProdScheduleItemMergeValidateVo.FieldDiff diff = new SchProdScheduleItemMergeValidateVo.FieldDiff();
|
||||||
|
diff.setFieldName(fieldName);
|
||||||
|
diff.setFieldLabel(fieldLabel);
|
||||||
|
diff.setValues(values);
|
||||||
|
diffs.add(diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.1 比对明细级字段(spec, material, productItem)—— 这些字段来自 item 自身,不来自 header
|
||||||
|
Map<String, String> itemCompareFields = new LinkedHashMap<>();
|
||||||
|
itemCompareFields.put("spec", "规格");
|
||||||
|
itemCompareFields.put("material", "材质");
|
||||||
|
itemCompareFields.put("productItem", "品名项");
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> entry : itemCompareFields.entrySet()) {
|
||||||
|
String fieldName = entry.getKey();
|
||||||
|
String fieldLabel = entry.getValue();
|
||||||
|
Map<String, Object> values = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (SchProdScheduleItem item : items) {
|
||||||
|
Object val = getItemFieldValue(item, fieldName);
|
||||||
|
values.put(String.valueOf(item.getScheduleId()), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean same = values.values().stream().distinct().count() <= 1;
|
||||||
|
if (!same) {
|
||||||
|
allConsistent = false;
|
||||||
|
SchProdScheduleItemMergeValidateVo.FieldDiff diff = new SchProdScheduleItemMergeValidateVo.FieldDiff();
|
||||||
|
diff.setFieldName(fieldName);
|
||||||
|
diff.setFieldLabel(fieldLabel);
|
||||||
|
diff.setValues(values);
|
||||||
|
diffs.add(diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 构建 ItemInfo 快照列表
|
||||||
|
List<SchProdScheduleItemMergeValidateVo.ItemInfo> itemInfos = new ArrayList<>();
|
||||||
|
BigDecimal totalWeight = BigDecimal.ZERO;
|
||||||
|
for (SchProdScheduleItem item : items) {
|
||||||
|
SchProdScheduleItemMergeValidateVo.ItemInfo info = new SchProdScheduleItemMergeValidateVo.ItemInfo();
|
||||||
|
info.setItemId(item.getScheduleId());
|
||||||
|
// 解析第一个源 schedule_id
|
||||||
|
String sids = item.getScheduleDetailIds();
|
||||||
|
Long firstSourceId = null;
|
||||||
|
if (sids != null && !sids.isEmpty()) {
|
||||||
|
String[] parts = sids.split(",");
|
||||||
|
if (parts.length > 0) {
|
||||||
|
try {
|
||||||
|
firstSourceId = Long.valueOf(parts[0].trim());
|
||||||
|
} catch (NumberFormatException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.setSourceScheduleId(firstSourceId);
|
||||||
|
info.setScheduleNo(item.getScheduleNo());
|
||||||
|
info.setCustomerName(item.getCustomerName());
|
||||||
|
info.setProductType(item.getProductType());
|
||||||
|
info.setSpec(item.getSpec());
|
||||||
|
info.setMaterial(item.getMaterial());
|
||||||
|
info.setScheduleWeight(item.getScheduleWeight());
|
||||||
|
info.setScheduleDetailIds(item.getScheduleDetailIds());
|
||||||
|
// header 字段
|
||||||
|
info.setBusinessUser(item.getBusinessUser());
|
||||||
|
info.setBusinessPhone(item.getBusinessPhone());
|
||||||
|
info.setDeliveryCycle(item.getDeliveryCycle());
|
||||||
|
info.setUsePurpose(item.getUsePurpose());
|
||||||
|
info.setThicknessTolerance(item.getThicknessTolerance());
|
||||||
|
info.setWidthTolerance(item.getWidthTolerance());
|
||||||
|
info.setSurfaceQuality(item.getSurfaceQuality());
|
||||||
|
info.setSurfaceTreatment(item.getSurfaceTreatment());
|
||||||
|
info.setInnerDiameter(item.getInnerDiameter());
|
||||||
|
info.setOuterDiameter(item.getOuterDiameter());
|
||||||
|
info.setPackReq(item.getPackReq());
|
||||||
|
info.setCutEdgeReq(item.getCutEdgeReq());
|
||||||
|
info.setSingleCoilWeight(item.getSingleCoilWeight());
|
||||||
|
info.setWeightDeviation(item.getWeightDeviation());
|
||||||
|
info.setOtherTechReq(item.getOtherTechReq());
|
||||||
|
info.setPaymentDesc(item.getPaymentDesc());
|
||||||
|
info.setRelContractNo(item.getRelContractNo());
|
||||||
|
info.setTotalPlanWeight(item.getTotalPlanWeight());
|
||||||
|
info.setOrderDate(item.getOrderDate());
|
||||||
|
itemInfos.add(info);
|
||||||
|
totalWeight = totalWeight.add(item.getScheduleWeight() != null ? item.getScheduleWeight() : BigDecimal.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 构建汇总
|
||||||
|
SchProdScheduleItemMergeValidateVo.MergedSummary summary = new SchProdScheduleItemMergeValidateVo.MergedSummary();
|
||||||
|
summary.setItemCount(items.size());
|
||||||
|
summary.setTotalScheduleWeight(totalWeight);
|
||||||
|
|
||||||
|
// 7. 组装返回
|
||||||
|
SchProdScheduleItemMergeValidateVo vo = new SchProdScheduleItemMergeValidateVo();
|
||||||
|
vo.setConsistent(allConsistent);
|
||||||
|
vo.setDiffs(diffs);
|
||||||
|
vo.setItems(itemInfos);
|
||||||
|
vo.setSummary(summary);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反射获取字段值(用于动态字段比较 — SchProdSchedule header)
|
||||||
|
*/
|
||||||
|
private Object getFieldValue(SchProdSchedule header, String fieldName) {
|
||||||
|
try {
|
||||||
|
java.lang.reflect.Field field = SchProdSchedule.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
return field.get(header);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反射获取字段值(用于动态字段比较 — SchProdScheduleItem 明细)
|
||||||
|
*/
|
||||||
|
private Object getItemFieldValue(SchProdScheduleItem item, String fieldName) {
|
||||||
|
try {
|
||||||
|
java.lang.reflect.Field field = SchProdScheduleItem.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
return field.get(item);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ public class SchProdScheduleServiceImpl implements ISchProdScheduleService {
|
|||||||
lqw.eq(StringUtils.isNotBlank(bo.getOtherTechReq()), SchProdSchedule::getOtherTechReq, bo.getOtherTechReq());
|
lqw.eq(StringUtils.isNotBlank(bo.getOtherTechReq()), SchProdSchedule::getOtherTechReq, bo.getOtherTechReq());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getPaymentDesc()), SchProdSchedule::getPaymentDesc, bo.getPaymentDesc());
|
lqw.eq(StringUtils.isNotBlank(bo.getPaymentDesc()), SchProdSchedule::getPaymentDesc, bo.getPaymentDesc());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getReturnReason()), SchProdSchedule::getReturnReason, bo.getReturnReason());
|
lqw.eq(StringUtils.isNotBlank(bo.getReturnReason()), SchProdSchedule::getReturnReason, bo.getReturnReason());
|
||||||
|
// 根据创建时间倒叙排序
|
||||||
|
lqw.orderByDesc(SchProdSchedule::getCreateTime);
|
||||||
return lqw;
|
return lqw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -268,13 +268,27 @@ public class TsComplaintAcceptServiceImpl implements ITsComplaintAcceptService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除投诉受理单主
|
* 批量删除投诉受理单主(级联删除关联的部门任务和执行反馈)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||||
if(isValid){
|
if(isValid){
|
||||||
//TODO 做一些业务上的校验,判断是否需要校验
|
//TODO 做一些业务上的校验,判断是否需要校验
|
||||||
}
|
}
|
||||||
|
if (ids == null || ids.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 级联逻辑删除关联的部门意见任务
|
||||||
|
tsComplaintTaskMapper.delete(
|
||||||
|
Wrappers.<TsComplaintTask>lambdaQuery()
|
||||||
|
.in(TsComplaintTask::getAcceptId, ids)
|
||||||
|
);
|
||||||
|
// 级联逻辑删除关联的执行反馈记录
|
||||||
|
tsPlanExecuteRelMapper.delete(
|
||||||
|
Wrappers.<TsPlanExecuteRel>lambdaQuery()
|
||||||
|
.in(TsPlanExecuteRel::getAcceptId, ids)
|
||||||
|
);
|
||||||
|
// 删除受理单本身
|
||||||
return baseMapper.deleteBatchIds(ids) > 0;
|
return baseMapper.deleteBatchIds(ids) > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,13 @@ public class TsComplaintTaskServiceImpl implements ITsComplaintTaskService {
|
|||||||
public TsComplaintTaskVo queryById(Long taskId){
|
public TsComplaintTaskVo queryById(Long taskId){
|
||||||
TsComplaintTaskVo vo = baseMapper.selectVoById(taskId);
|
TsComplaintTaskVo vo = baseMapper.selectVoById(taskId);
|
||||||
if (vo != null) {
|
if (vo != null) {
|
||||||
|
// 过滤已逻辑删除的售后单关联任务
|
||||||
|
if (vo.getAcceptId() != null) {
|
||||||
|
TsComplaintAcceptVo acceptVo = tsComplaintAcceptMapper.selectVoById(vo.getAcceptId());
|
||||||
|
if (acceptVo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
enrichWithAcceptInfo(Collections.singletonList(vo));
|
enrichWithAcceptInfo(Collections.singletonList(vo));
|
||||||
}
|
}
|
||||||
return vo;
|
return vo;
|
||||||
@@ -115,6 +122,7 @@ public class TsComplaintTaskServiceImpl implements ITsComplaintTaskService {
|
|||||||
lqw.eq(bo.getFillTime() != null, TsComplaintTask::getFillTime, bo.getFillTime());
|
lqw.eq(bo.getFillTime() != null, TsComplaintTask::getFillTime, bo.getFillTime());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getFillFile()), TsComplaintTask::getFillFile, bo.getFillFile());
|
lqw.eq(StringUtils.isNotBlank(bo.getFillFile()), TsComplaintTask::getFillFile, bo.getFillFile());
|
||||||
lqw.eq(bo.getRejectMark() != null, TsComplaintTask::getRejectMark, bo.getRejectMark());
|
lqw.eq(bo.getRejectMark() != null, TsComplaintTask::getRejectMark, bo.getRejectMark());
|
||||||
|
lqw.apply("accept_id IN (SELECT accept_id FROM ts_complaint_accept WHERE del_flag = 0)");
|
||||||
return lqw;
|
return lqw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,12 @@
|
|||||||
<result property="complaintDate" column="complaint_date"/>
|
<result property="complaintDate" column="complaint_date"/>
|
||||||
<result property="complaintContent" column="complaint_content"/>
|
<result property="complaintContent" column="complaint_content"/>
|
||||||
<result property="customerDemand" column="customer_demand"/>
|
<result property="customerDemand" column="customer_demand"/>
|
||||||
|
<result property="customerId" column="customer_id"/>
|
||||||
|
<result property="downstreamUserName" column="downstream_user_name"/>
|
||||||
|
<result property="phone" column="phone"/>
|
||||||
|
<result property="projectName" column="project_name"/>
|
||||||
|
<result property="projectLocation" column="project_location"/>
|
||||||
|
<result property="productUsage" column="product_usage"/>
|
||||||
<result property="file" column="file"/>
|
<result property="file" column="file"/>
|
||||||
<result property="auditStatus" column="audit_status"/>
|
<result property="auditStatus" column="audit_status"/>
|
||||||
<result property="auditOpinion" column="audit_opinion"/>
|
<result property="auditOpinion" column="audit_opinion"/>
|
||||||
|
|||||||
27
klp-ui/src/api/aps/detailCoilRel.js
Normal file
27
klp-ui/src/api/aps/detailCoilRel.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询排产明细-钢卷绑定关系列表
|
||||||
|
export function listDetailCoilRel(query) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/detailCoilRel/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量新增绑定关系
|
||||||
|
export function batchAddDetailCoilRel(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/detailCoilRel/batch',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除绑定关系
|
||||||
|
export function delDetailCoilRel(relIds) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/detailCoilRel/' + relIds,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -70,3 +70,32 @@ export function delScheduleItem(ids) {
|
|||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====== 排产单明细项 接收/合并 ======
|
||||||
|
|
||||||
|
// 接收产需单(后端全字段复制)
|
||||||
|
export function receiveScheduleItem(scheduleId) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodScheduleItem/receive',
|
||||||
|
method: 'post',
|
||||||
|
data: { scheduleId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并验证(检查源排产单字段一致性)
|
||||||
|
export function validateMerge(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodScheduleItem/mergeValidate',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并排产单明细项
|
||||||
|
export function mergeScheduleItem(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodScheduleItem/merge',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<el-input v-model="queryParams.keyword" placeholder="请输入关键字" clearable
|
<el-input v-model="queryParams.keyword" placeholder="请输入关键字" clearable
|
||||||
@keyup.enter.native="handleQuery" style="width: 160px;" />
|
@keyup.enter.native="handleQuery" style="width: 160px;" />
|
||||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">筛选</el-button>
|
<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-sort" size="mini" @click="toggleMoreFilter"
|
<el-button icon="el-icon-sort" size="mini" @click="toggleMoreFilter"
|
||||||
:type="showMoreFilter ? 'primary' : 'default'">
|
:type="showMoreFilter ? 'primary' : 'default'">
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -213,6 +214,7 @@ export default {
|
|||||||
},
|
},
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
resetQuery() {
|
resetQuery() {
|
||||||
|
this.queryParams.keyword = undefined;
|
||||||
this.$refs["queryForm"].resetFields();
|
this.$refs["queryForm"].resetFields();
|
||||||
this.queryParams.signDateStart = undefined;
|
this.queryParams.signDateStart = undefined;
|
||||||
this.queryParams.signDateEnd = undefined;
|
this.queryParams.signDateEnd = undefined;
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ export default {
|
|||||||
Object.assign(item, calculateProductFields(item, 'quantity'));
|
Object.assign(item, calculateProductFields(item, 'quantity'));
|
||||||
});
|
});
|
||||||
this.products = products;
|
this.products = products;
|
||||||
this.remark = data.remark || '净边料/毛边料、简包/裸包、卷重结算';
|
this.remark = data.remark !== undefined ? data.remark : '净边料/毛边料、简包/裸包、卷重结算';
|
||||||
this.productName = data.productName || '';
|
this.productName = data.productName || '';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('解析content失败:', error);
|
console.error('解析content失败:', error);
|
||||||
|
|||||||
@@ -231,7 +231,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { delOrder, listOrderPackaging, updateOrder, getOrder, addOrder } from "@/api/crm/order";
|
import { delOrder, listOrderPackaging, updateOrder, getOrder, addOrder } from "@/api/crm/order";
|
||||||
import { addCustomer } from "@/api/crm/customer";
|
import { addCustomer } from "@/api/crm/customer";
|
||||||
import { getDicts, addData, updateData } from "@/api/system/dict/data";
|
|
||||||
import { listDeliveryWaybill } from "@/api/wms/deliveryWaybill";
|
import { listDeliveryWaybill } from "@/api/wms/deliveryWaybill";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import ContractList from "./components/ContractList.vue";
|
import ContractList from "./components/ContractList.vue";
|
||||||
|
|||||||
334
klp-ui/src/views/wms/coil/components/ScheduleDetailCoilBind.vue
Normal file
334
klp-ui/src/views/wms/coil/components/ScheduleDetailCoilBind.vue
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<el-button icon="el-icon-link" size="mini" @click="open">绑定排产明细</el-button>
|
||||||
|
|
||||||
|
<el-dialog title="排产明细 - 钢卷绑定" :visible.sync="visible" width="1200px" append-to-body :close-on-click-modal="false"
|
||||||
|
v-loading="loading">
|
||||||
|
<!-- 上半部分:今日排产明细 -->
|
||||||
|
<div class="bind-section">
|
||||||
|
<div class="bind-section-header">今日排产明细({{ scheduleItems.length }} 条)</div>
|
||||||
|
<el-table :data="scheduleItems" highlight-current-row @row-click="handleDetailClick" max-height="300"
|
||||||
|
size="small">
|
||||||
|
<el-table-column prop="scheduleNo" label="排产单号" min-width="130" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="prodDate" label="生产日期" width="90" />
|
||||||
|
<el-table-column prop="spec" label="规格" width="90" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="material" label="材质" width="70" />
|
||||||
|
<el-table-column prop="scheduleWeight" label="排产吨数" width="80" />
|
||||||
|
<el-table-column prop="productType" label="品名" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="customerName" label="订货单位" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="已绑钢卷" width="80">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag size="mini" type="info">{{ scope.row._boundCount || 0 }} 卷</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 下半部分:已绑定钢卷 -->
|
||||||
|
<div class="bind-section" v-if="currentDetail" style="margin-top:16px;">
|
||||||
|
<div class="bind-section-header">
|
||||||
|
已绑定钢卷 — {{ currentDetail.spec }} / {{ currentDetail.material }}
|
||||||
|
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openCoilSelect">绑定钢卷</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table :data="boundCoils" size="small" v-loading="boundCoilsLoading">
|
||||||
|
<el-table-column prop="currentCoilNo" label="钢卷号" width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="specification" label="规格" width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="material" label="材质" width="70" />
|
||||||
|
<el-table-column prop="netWeight" label="净重" width="80" />
|
||||||
|
<el-table-column prop="_remark" label="备注" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="70" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" style="color:#ff4d4f;" size="mini" @click="handleUnbind(scope.row)">解绑</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-empty v-if="boundCoils.length === 0 && !boundCoilsLoading" description="暂未绑定钢卷" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-empty v-if="scheduleItems.length === 0 && !loading" description="今日无排产明细" />
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 选卷子弹窗 -->
|
||||||
|
<el-dialog title="选择钢卷" :visible.sync="coilDialogVisible" width="900px" append-to-body
|
||||||
|
:close-on-click-modal="false">
|
||||||
|
<div style="display:flex;gap:8px;margin-bottom:10px;">
|
||||||
|
<el-input v-model="coilQuery.keyword" placeholder="钢卷号 / 入场卷号" size="small" style="width:220px"
|
||||||
|
clearable @keyup.enter.native="searchCoils" />
|
||||||
|
<el-button size="small" type="primary" icon="el-icon-search" @click="searchCoils">搜索</el-button>
|
||||||
|
<span style="margin-left:auto;font-size:12px;color:#909399;line-height:32px;">
|
||||||
|
已选 {{ selectedCoils.length }} 卷
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<el-table :data="coilList" @selection-change="handleCoilSelection" ref="coilSelectTable" size="small"
|
||||||
|
v-loading="coilListLoading" max-height="400">
|
||||||
|
<el-table-column type="selection" width="50" :selectable="checkCoilSelectable" />
|
||||||
|
<el-table-column prop="currentCoilNo" label="钢卷号" width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="enterCoilNo" label="入场卷号" width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="specification" label="规格" width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="material" label="材质"/>
|
||||||
|
<el-table-column prop="netWeight" label="净重" width="80" />
|
||||||
|
<el-table-column prop="warehouseName" label="仓库" width="80" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
<pagination v-show="coilTotal > 0" :total="coilTotal" :page.sync="coilQuery.pageNum"
|
||||||
|
:limit.sync="coilQuery.pageSize" @pagination="searchCoils" style="padding:10px 0 0 0;" />
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button type="primary" @click="confirmBindCoils" :loading="bindLoading"
|
||||||
|
:disabled="selectedCoils.length === 0">确定绑定({{ selectedCoils.length }} 卷)</el-button>
|
||||||
|
<el-button @click="coilDialogVisible = false">取消</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listScheduleItem } from '@/api/aps/schedule'
|
||||||
|
import { listMaterialCoil } from '@/api/wms/coil'
|
||||||
|
import { listDetailCoilRel, batchAddDetailCoilRel, delDetailCoilRel } from '@/api/aps/detailCoilRel'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ScheduleDetailCoilBind',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
loading: false,
|
||||||
|
scheduleItems: [],
|
||||||
|
currentDetail: null,
|
||||||
|
boundCoils: [],
|
||||||
|
boundCoilsLoading: false,
|
||||||
|
allBoundCoilIds: new Set(),
|
||||||
|
|
||||||
|
coilDialogVisible: false,
|
||||||
|
coilListLoading: false,
|
||||||
|
coilList: [],
|
||||||
|
coilTotal: 0,
|
||||||
|
selectedCoils: [],
|
||||||
|
bindLoading: false,
|
||||||
|
coilQuery: {
|
||||||
|
keyword: '',
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
prodDate() {
|
||||||
|
return new Date().toISOString().slice(0, 10)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open() {
|
||||||
|
this.visible = true
|
||||||
|
this.currentDetail = null
|
||||||
|
this.boundCoils = []
|
||||||
|
this.loadScheduleItems()
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadScheduleItems() {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await listScheduleItem({ prodDate: this.prodDate })
|
||||||
|
this.scheduleItems = (res.rows || []).map(item => {
|
||||||
|
item._boundCount = 0
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
// 加载所有已绑定的钢卷ID
|
||||||
|
await this.loadAllBoundCoilIds()
|
||||||
|
} catch (e) {
|
||||||
|
this.scheduleItems = []
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadAllBoundCoilIds() {
|
||||||
|
const ids = this.scheduleItems.map(i => i.id || i.scheduleDetailId).filter(Boolean)
|
||||||
|
if (ids.length === 0) return
|
||||||
|
try {
|
||||||
|
// 尝试批量查询
|
||||||
|
const res = await listDetailCoilRel({ scheduleDetailIds: ids.join(',') })
|
||||||
|
const rows = res.rows || []
|
||||||
|
this.allBoundCoilIds = new Set(rows.map(r => r.coilId))
|
||||||
|
this.applyBoundCounts(rows)
|
||||||
|
} catch (e) {
|
||||||
|
// 批量查询失败则逐个查询
|
||||||
|
try {
|
||||||
|
const allRows = []
|
||||||
|
const tasks = ids.map(id =>
|
||||||
|
listDetailCoilRel({ scheduleDetailId: id }).then(r => {
|
||||||
|
(r.rows || []).forEach(row => allRows.push(row))
|
||||||
|
}).catch(() => {})
|
||||||
|
)
|
||||||
|
await Promise.all(tasks)
|
||||||
|
this.allBoundCoilIds = new Set(allRows.map(r => r.coilId))
|
||||||
|
this.applyBoundCounts(allRows)
|
||||||
|
} catch (e2) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
applyBoundCounts(rows) {
|
||||||
|
const countMap = {}
|
||||||
|
rows.forEach(r => {
|
||||||
|
const key = r.scheduleDetailId
|
||||||
|
countMap[key] = (countMap[key] || 0) + 1
|
||||||
|
})
|
||||||
|
this.scheduleItems.forEach(item => {
|
||||||
|
const key = item.id || item.scheduleDetailId
|
||||||
|
item._boundCount = countMap[key] || 0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleDetailClick(row) {
|
||||||
|
this.currentDetail = row
|
||||||
|
this.boundCoilsLoading = true
|
||||||
|
try {
|
||||||
|
const detailId = row.id || row.scheduleDetailId
|
||||||
|
const res = await listDetailCoilRel({ scheduleDetailId: detailId })
|
||||||
|
const rels = res.rows || []
|
||||||
|
if (rels.length > 0) {
|
||||||
|
const coilIds = rels.map(r => r.coilId).filter(Boolean)
|
||||||
|
const coilRes = await listMaterialCoil({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 200,
|
||||||
|
coilIds: coilIds.join(',')
|
||||||
|
})
|
||||||
|
const coilMap = {}
|
||||||
|
if (coilRes.rows) {
|
||||||
|
coilRes.rows.forEach(c => { coilMap[c.coilId || c.id] = c })
|
||||||
|
}
|
||||||
|
this.boundCoils = rels.map(r => ({
|
||||||
|
...r,
|
||||||
|
...(coilMap[r.coilId] || {}),
|
||||||
|
_remark: r.remark || ''
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
this.boundCoils = []
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.boundCoils = []
|
||||||
|
} finally {
|
||||||
|
this.boundCoilsLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async openCoilSelect() {
|
||||||
|
this.coilDialogVisible = true
|
||||||
|
this.selectedCoils = []
|
||||||
|
this.coilQuery.keyword = ''
|
||||||
|
this.coilQuery.pageNum = 1
|
||||||
|
await this.searchCoils()
|
||||||
|
},
|
||||||
|
|
||||||
|
async searchCoils() {
|
||||||
|
this.coilListLoading = true
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
pageNum: this.coilQuery.pageNum,
|
||||||
|
pageSize: this.coilQuery.pageSize,
|
||||||
|
status: 0,
|
||||||
|
dataType: 1,
|
||||||
|
exclusiveStatus: 0
|
||||||
|
}
|
||||||
|
if (this.coilQuery.keyword) {
|
||||||
|
params.currentCoilNo = this.coilQuery.keyword
|
||||||
|
}
|
||||||
|
const res = await listMaterialCoil(params)
|
||||||
|
// 过滤掉已绑定的钢卷
|
||||||
|
this.coilList = (res.rows || []).filter(c => !this.allBoundCoilIds.has(c.coilId || c.id))
|
||||||
|
this.coilTotal = res.total || 0
|
||||||
|
} catch (e) {
|
||||||
|
this.coilList = []
|
||||||
|
} finally {
|
||||||
|
this.coilListLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkCoilSelectable(row) {
|
||||||
|
return !this.allBoundCoilIds.has(row.coilId || row.id)
|
||||||
|
},
|
||||||
|
|
||||||
|
handleCoilSelection(selection) {
|
||||||
|
this.selectedCoils = selection
|
||||||
|
},
|
||||||
|
|
||||||
|
async confirmBindCoils() {
|
||||||
|
if (this.selectedCoils.length === 0) {
|
||||||
|
this.$message.warning('请至少选择一个钢卷')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.bindLoading = true
|
||||||
|
try {
|
||||||
|
const detailId = this.currentDetail.id || this.currentDetail.scheduleDetailId
|
||||||
|
const data = this.selectedCoils.map(c => ({
|
||||||
|
scheduleDetailId: detailId,
|
||||||
|
coilId: c.coilId || c.id,
|
||||||
|
remark: ''
|
||||||
|
}))
|
||||||
|
await batchAddDetailCoilRel(data)
|
||||||
|
this.$modal.msgSuccess(`成功绑定 ${this.selectedCoils.length} 卷`)
|
||||||
|
this.coilDialogVisible = false
|
||||||
|
// 记录新绑定的钢卷ID
|
||||||
|
this.selectedCoils.forEach(c => {
|
||||||
|
this.allBoundCoilIds.add(c.coilId || c.id)
|
||||||
|
})
|
||||||
|
// 更新当前明细的已绑卷数
|
||||||
|
if (this.currentDetail) {
|
||||||
|
this.currentDetail._boundCount = (this.currentDetail._boundCount || 0) + this.selectedCoils.length
|
||||||
|
}
|
||||||
|
// 刷新已绑定钢卷列表
|
||||||
|
await this.handleDetailClick(this.currentDetail)
|
||||||
|
} catch (e) {
|
||||||
|
this.$modal.msgError('绑定失败')
|
||||||
|
} finally {
|
||||||
|
this.bindLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleUnbind(row) {
|
||||||
|
try {
|
||||||
|
await this.$confirm('确认解绑该钢卷吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
const relId = row.relId || row.id
|
||||||
|
await delDetailCoilRel(relId)
|
||||||
|
this.$modal.msgSuccess('解绑成功')
|
||||||
|
// 从已绑定集合中移除
|
||||||
|
if (row.coilId) {
|
||||||
|
this.allBoundCoilIds.delete(row.coilId)
|
||||||
|
}
|
||||||
|
if (this.currentDetail) {
|
||||||
|
this.currentDetail._boundCount = Math.max(0, (this.currentDetail._boundCount || 0) - 1)
|
||||||
|
}
|
||||||
|
await this.handleDetailClick(this.currentDetail)
|
||||||
|
} catch (e) {
|
||||||
|
if (e !== 'cancel') {
|
||||||
|
this.$modal.msgError('解绑失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.bind-section {
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bind-section-header {
|
||||||
|
background: #f5f7fa;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
<div class="flow-left">
|
<div class="flow-left">
|
||||||
<div class="flow-section-title">
|
<div class="flow-section-title">
|
||||||
<span>源卷列表</span>
|
<span>源卷列表</span>
|
||||||
|
<schedule-detail-coil-bind />
|
||||||
<el-button v-if="!readonly" type="primary" size="small" @click="addSourceCoil">添加源卷</el-button>
|
<el-button v-if="!readonly" type="primary" size="small" @click="addSourceCoil">添加源卷</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -374,6 +375,7 @@ import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
|
|||||||
import TimeInput from "@/components/TimeInput";
|
import TimeInput from "@/components/TimeInput";
|
||||||
import AbnormalForm from './components/AbnormalForm';
|
import AbnormalForm from './components/AbnormalForm';
|
||||||
import PlanSheetViewer from './components/PlanSheetViewer.vue';
|
import PlanSheetViewer from './components/PlanSheetViewer.vue';
|
||||||
|
import ScheduleDetailCoilBind from './components/ScheduleDetailCoilBind'
|
||||||
import { generateCoilNoPrefix } from "@/utils/coil/coilNo";
|
import { generateCoilNoPrefix } from "@/utils/coil/coilNo";
|
||||||
import ContractSelect from "@/components/KLPService/ContractSelect";
|
import ContractSelect from "@/components/KLPService/ContractSelect";
|
||||||
|
|
||||||
@@ -389,6 +391,7 @@ export default {
|
|||||||
AbnormalForm,
|
AbnormalForm,
|
||||||
ContractSelect,
|
ContractSelect,
|
||||||
PlanSheetViewer,
|
PlanSheetViewer,
|
||||||
|
ScheduleDetailCoilBind,
|
||||||
},
|
},
|
||||||
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
|
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
:name="tab.value"></el-tab-pane>
|
:name="tab.value"></el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<h3 class="section-title" v-else>待领物料列表</h3>
|
<h3 class="section-title" v-else>待领物料列表</h3>
|
||||||
|
<schedule-detail-coil-bind />
|
||||||
<el-button size="mini" icon="el-icon-refresh" @click="getMaterialCoil">刷新</el-button>
|
<el-button size="mini" icon="el-icon-refresh" @click="getMaterialCoil">刷新</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -309,6 +310,7 @@ import CoilCard from '@/components/KLPService/Renderer/CoilCard.vue'
|
|||||||
import LabelRender from './LabelRender/index.vue'
|
import LabelRender from './LabelRender/index.vue'
|
||||||
import StepSplit from './stepSplit.vue'
|
import StepSplit from './stepSplit.vue'
|
||||||
import ExceptionManager from '../components/ExceptionManager'
|
import ExceptionManager from '../components/ExceptionManager'
|
||||||
|
import ScheduleDetailCoilBind from '../components/ScheduleDetailCoilBind'
|
||||||
import { getCoilTagPrintType } from '@/views/wms/coil/js/coilPrint'
|
import { getCoilTagPrintType } from '@/views/wms/coil/js/coilPrint'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -334,7 +336,8 @@ export default {
|
|||||||
CoilCard,
|
CoilCard,
|
||||||
LabelRender,
|
LabelRender,
|
||||||
StepSplit,
|
StepSplit,
|
||||||
ExceptionManager
|
ExceptionManager,
|
||||||
|
ScheduleDetailCoilBind
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
<div class="flow-left">
|
<div class="flow-left">
|
||||||
<div class="flow-section-title">
|
<div class="flow-section-title">
|
||||||
<span>母卷信息</span>
|
<span>母卷信息</span>
|
||||||
|
<schedule-detail-coil-bind />
|
||||||
</div>
|
</div>
|
||||||
<div class="coil-card mother-coil">
|
<div class="coil-card mother-coil">
|
||||||
<div class="coil-header">
|
<div class="coil-header">
|
||||||
@@ -377,6 +378,7 @@ import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
|
|||||||
import TimeInput from "@/components/TimeInput";
|
import TimeInput from "@/components/TimeInput";
|
||||||
import AbnormalForm from './components/AbnormalForm';
|
import AbnormalForm from './components/AbnormalForm';
|
||||||
import PlanSheetViewer from './components/PlanSheetViewer.vue';
|
import PlanSheetViewer from './components/PlanSheetViewer.vue';
|
||||||
|
import ScheduleDetailCoilBind from './components/ScheduleDetailCoilBind'
|
||||||
import { generateCoilNoPrefix } from "@/utils/coil/coilNo";
|
import { generateCoilNoPrefix } from "@/utils/coil/coilNo";
|
||||||
import ContractSelect from "@/components/KLPService/ContractSelect";
|
import ContractSelect from "@/components/KLPService/ContractSelect";
|
||||||
|
|
||||||
@@ -391,6 +393,7 @@ export default {
|
|||||||
AbnormalForm,
|
AbnormalForm,
|
||||||
ContractSelect,
|
ContractSelect,
|
||||||
PlanSheetViewer,
|
PlanSheetViewer,
|
||||||
|
ScheduleDetailCoilBind,
|
||||||
},
|
},
|
||||||
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
|
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
<div slot="header" class="card-header">
|
<div slot="header" class="card-header">
|
||||||
<span><i class="el-icon-edit-outline"></i> {{ '更新信息' }}</span>
|
<span><i class="el-icon-edit-outline"></i> {{ '更新信息' }}</span>
|
||||||
<div>
|
<div>
|
||||||
|
<schedule-detail-coil-bind />
|
||||||
<el-button size="small" @click="saveTemp" :loading="loading">暂存内容</el-button>
|
<el-button size="small" @click="saveTemp" :loading="loading">暂存内容</el-button>
|
||||||
<el-button type="primary" size="small" @click="handleSave" :loading="loading">保存更新</el-button>
|
<el-button type="primary" size="small" @click="handleSave" :loading="loading">保存更新</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -405,6 +406,7 @@ import ContractSelect from "@/components/KLPService/ContractSelect";
|
|||||||
import L2MatchPanel from './panels/L2MatchPanel.vue'
|
import L2MatchPanel from './panels/L2MatchPanel.vue'
|
||||||
import DrMatchPanel from './panels/DrMatchPanel.vue';
|
import DrMatchPanel from './panels/DrMatchPanel.vue';
|
||||||
import PlanSheetViewer from './components/PlanSheetViewer.vue';
|
import PlanSheetViewer from './components/PlanSheetViewer.vue';
|
||||||
|
import ScheduleDetailCoilBind from './components/ScheduleDetailCoilBind'
|
||||||
|
|
||||||
|
|
||||||
// actionType -> 产线名称映射
|
// actionType -> 产线名称映射
|
||||||
@@ -431,6 +433,7 @@ export default {
|
|||||||
L2MatchPanel,
|
L2MatchPanel,
|
||||||
DrMatchPanel,
|
DrMatchPanel,
|
||||||
PlanSheetViewer,
|
PlanSheetViewer,
|
||||||
|
ScheduleDetailCoilBind,
|
||||||
},
|
},
|
||||||
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
|
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -418,11 +418,11 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
initDateRange() {
|
initDateRange() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const firstDay = new Date(now.getFullYear(), now.getMonth(), 1)
|
const yesterday = new Date(now)
|
||||||
const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0)
|
yesterday.setDate(yesterday.getDate() - 1)
|
||||||
|
|
||||||
this.defaultStartTime = this.formatDate(firstDay)
|
this.defaultStartTime = this.formatDate(yesterday)
|
||||||
this.defaultEndTime = this.formatDate(lastDay)
|
this.defaultEndTime = this.formatDate(now)
|
||||||
|
|
||||||
this.dateRangeParams = {
|
this.dateRangeParams = {
|
||||||
startDate: this.defaultStartTime,
|
startDate: this.defaultStartTime,
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
<el-table-column label="状态" align="center" prop="state" />
|
<el-table-column label="状态" align="center" prop="state" />
|
||||||
<el-table-column label="创建时间" align="center" prop="createdAt" width="180">
|
<el-table-column label="创建时间" align="center" prop="createdAt" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d}') }}</span>
|
<span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
|||||||
@@ -158,7 +158,7 @@
|
|||||||
<div v-for="order in currentReq.orderList" :key="order.orderId" class="bound-order-card">
|
<div v-for="order in currentReq.orderList" :key="order.orderId" class="bound-order-card">
|
||||||
<div class="bound-order-card-header">
|
<div class="bound-order-card-header">
|
||||||
<span>{{ order.orderCode || ('订单 #' + order.orderId) }}</span>
|
<span>{{ order.orderCode || ('订单 #' + order.orderId) }}</span>
|
||||||
<button v-if="canEdit" class="link-btn" @click="handleUnbindByOrderId(order.orderId)">解绑</button>
|
<button v-if="canEdit" class="link-btn" @click="handleUnbindByOrderId(order)">解绑</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="bound-order-card-body">
|
<div class="bound-order-card-body">
|
||||||
<div style="font-size:12px; color:#7f8c8d; margin-bottom:3px;">
|
<div style="font-size:12px; color:#7f8c8d; margin-bottom:3px;">
|
||||||
@@ -399,6 +399,7 @@ import {
|
|||||||
delRequirement,
|
delRequirement,
|
||||||
addRel,
|
addRel,
|
||||||
delRel,
|
delRel,
|
||||||
|
listRel,
|
||||||
addRequirementDetail,
|
addRequirementDetail,
|
||||||
updateRequirementDetail,
|
updateRequirementDetail,
|
||||||
delRequirementDetail
|
delRequirementDetail
|
||||||
@@ -628,7 +629,8 @@ export default {
|
|||||||
searchBindOrders() {
|
searchBindOrders() {
|
||||||
this.bindSearchLoading = true
|
this.bindSearchLoading = true
|
||||||
listCrmOrder(this.bindQuery).then(res => {
|
listCrmOrder(this.bindQuery).then(res => {
|
||||||
this.candidateOrderList = res.rows || []
|
const boundOrderIds = (this.currentReq?.orderList || []).map(o => o.orderId)
|
||||||
|
this.candidateOrderList = (res.rows || []).filter(o => !boundOrderIds.includes(o.orderId))
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.candidateOrderList = []
|
this.candidateOrderList = []
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -672,65 +674,87 @@ export default {
|
|||||||
}
|
}
|
||||||
this.bindBtnLoading = true
|
this.bindBtnLoading = true
|
||||||
const scheduleId = this.currentReq.scheduleId
|
const scheduleId = this.currentReq.scheduleId
|
||||||
const allPromises = []
|
|
||||||
|
|
||||||
this.selectedBindOrders.forEach(order => {
|
const orderTasks = this.selectedBindOrders.map(order => {
|
||||||
// 1. 创建订单关联
|
return addRel({
|
||||||
allPromises.push(
|
|
||||||
addRel({
|
|
||||||
orderId: order.orderId,
|
orderId: order.orderId,
|
||||||
scheduleId: scheduleId,
|
scheduleId: scheduleId,
|
||||||
relWeight: null,
|
relWeight: null,
|
||||||
remark: ''
|
remark: ''
|
||||||
})
|
}).then(() => {
|
||||||
)
|
if (!order.productContent) return
|
||||||
|
let products = []
|
||||||
// 2. 解析 productContent,每行产品创建一条排产明细
|
let productType = ''
|
||||||
if (order.productContent) {
|
try {
|
||||||
const parsed = parseProductContent(order.productContent)
|
const parsed = parseProductContent(order.productContent)
|
||||||
const products = parsed.products || []
|
products = (parsed.products || []).filter(p => p.spec && p.material)
|
||||||
const productType = parsed.productName || ''
|
productType = parsed.productName || ''
|
||||||
products.forEach(prod => {
|
} catch (e) {
|
||||||
allPromises.push(
|
return
|
||||||
|
}
|
||||||
|
if (products.length === 0) return
|
||||||
|
const detailPromises = products.map(prod =>
|
||||||
addRequirementDetail({
|
addRequirementDetail({
|
||||||
scheduleId: scheduleId,
|
scheduleId: scheduleId,
|
||||||
orderDetailId: order.orderId,
|
orderDetailId: order.orderId,
|
||||||
spec: prod.spec || '',
|
spec: prod.spec,
|
||||||
material: prod.material || '',
|
material: prod.material,
|
||||||
scheduleWeight: prod.quantity || 0,
|
scheduleWeight: prod.quantity || 0,
|
||||||
productType: productType,
|
productType: productType,
|
||||||
remark: prod.remark || ''
|
remark: prod.remark || ''
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
return Promise.all(detailPromises)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Promise.all(allPromises).then(() => {
|
Promise.allSettled(orderTasks).then(results => {
|
||||||
this.$modal.msgSuccess('绑定成功,排产明细已生成')
|
const successCount = results.filter(r => r.status === 'fulfilled').length
|
||||||
|
const failCount = results.filter(r => r.status === 'rejected').length
|
||||||
this.bindDialogVisible = false
|
this.bindDialogVisible = false
|
||||||
this.handleReqClick(this.currentReq)
|
this.handleReqClick(this.currentReq)
|
||||||
}).catch(() => {
|
if (failCount === 0) {
|
||||||
this.$modal.msgError('绑定或创建明细失败')
|
this.$modal.msgSuccess(`成功绑定 ${successCount} 个订单,排产明细已生成`)
|
||||||
|
} else if (successCount === 0) {
|
||||||
|
this.$modal.msgError('绑定失败,请重试')
|
||||||
|
} else {
|
||||||
|
this.$modal.msgWarning(`成功绑定 ${successCount} 个,${failCount} 个失败`)
|
||||||
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.bindBtnLoading = false
|
this.bindBtnLoading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
handleUnbindByOrderId(orderId) {
|
handleUnbindByOrderId(order) {
|
||||||
const order = (this.currentReq.orderList || []).find(o => o.orderId === orderId)
|
this.$confirm('确认解绑该订单吗?解绑将同时删除对应的排产明细。', '提示', {
|
||||||
if (!order) {
|
|
||||||
this.$message.warning('未找到关联记录')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.$confirm('确认解绑该订单吗?', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
delRel(order.relId || orderId).then(() => {
|
const tasks = []
|
||||||
|
// 1. 删除该订单关联的排产明细
|
||||||
|
const detailIds = this.requirementDetailList
|
||||||
|
.filter(d => d.orderDetailId === order.orderId)
|
||||||
|
.map(d => d.scheduleDetailId)
|
||||||
|
detailIds.forEach(id => {
|
||||||
|
tasks.push(delRequirementDetail(id))
|
||||||
|
})
|
||||||
|
// 2. 查询并删除关联表记录
|
||||||
|
tasks.push(
|
||||||
|
listRel({ orderId: order.orderId, scheduleId: this.currentReq.scheduleId }).then(res => {
|
||||||
|
const rows = res.rows || []
|
||||||
|
if (rows.length === 0) {
|
||||||
|
throw new Error('未找到关联记录')
|
||||||
|
}
|
||||||
|
const relId = rows[0].id || rows[0].relId
|
||||||
|
return delRel(relId)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
Promise.all(tasks).then(() => {
|
||||||
this.$modal.msgSuccess('解绑成功')
|
this.$modal.msgSuccess('解绑成功')
|
||||||
this.handleReqClick(this.currentReq)
|
this.handleReqClick(this.currentReq)
|
||||||
|
}).catch(() => {
|
||||||
|
this.$modal.msgError('解绑失败')
|
||||||
})
|
})
|
||||||
}).catch(() => { })
|
}).catch(() => { })
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,22 +17,22 @@
|
|||||||
<el-tab-pane label="待审核" name="pending" />
|
<el-tab-pane label="待审核" name="pending" />
|
||||||
<el-tab-pane label="已排产" name="scheduled" />
|
<el-tab-pane label="已排产" name="scheduled" />
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<div class="aps-sch-summary" v-if="summaryText">
|
<div v-if="summaryText" class="aps-sch-summary">
|
||||||
<span>{{ summaryText }}</span>
|
<span>{{ summaryText }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 待审核 Tab -->
|
<!-- 待审核 Tab -->
|
||||||
<div class="detail-card aps-sch-card" v-show="activeTab === 'pending'">
|
<div v-show="activeTab === 'pending'" class="detail-card aps-sch-card">
|
||||||
<div class="detail-card-header">
|
<div class="detail-card-header">
|
||||||
<span>待审核产需单明细</span>
|
<span>待审核产需单明细</span>
|
||||||
<span v-if="pendingScheduleList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
|
<span v-if="pendingScheduleList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
|
||||||
共 {{ pendingScheduleList.length }} 个产需单
|
共 {{ pendingScheduleList.length }} 个产需单
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card-body" style="padding:0;" v-loading="loading">
|
<div v-loading="loading" class="detail-card-body" style="padding:0;">
|
||||||
<div v-if="pendingScheduleList.length > 0" class="aps-sch-list">
|
<div v-if="pendingScheduleList.length > 0" class="aps-sch-list">
|
||||||
<div class="aps-sch-item" v-for="sch in pendingScheduleList" :key="sch.scheduleId">
|
<div v-for="sch in pendingScheduleList" :key="sch.scheduleId" class="aps-sch-item">
|
||||||
<!-- 产需单头部:排产单号 + 状态标签 + 操作 -->
|
<!-- 产需单头部:排产单号 + 状态标签 + 操作 -->
|
||||||
<div class="aps-sch-item-header">
|
<div class="aps-sch-item-header">
|
||||||
<div class="aps-sch-item-header-left">
|
<div class="aps-sch-item-header-left">
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<!-- 明细列表 -->
|
<!-- 明细列表 -->
|
||||||
<div class="aps-sch-item-details" v-if="(sch.detailList || []).length > 0">
|
<div v-if="(sch.detailList || []).length > 0" class="aps-sch-item-details">
|
||||||
<div class="aps-sch-detail-header">
|
<div class="aps-sch-detail-header">
|
||||||
<span class="aps-sch-detail-col col-spec">规格</span>
|
<span class="aps-sch-detail-col col-spec">规格</span>
|
||||||
<span class="aps-sch-detail-col col-material">材质</span>
|
<span class="aps-sch-detail-col col-material">材质</span>
|
||||||
@@ -140,9 +140,9 @@
|
|||||||
<span class="aps-sch-detail-col col-remark">备注</span>
|
<span class="aps-sch-detail-col col-remark">备注</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="aps-sch-detail-row"
|
|
||||||
v-for="(d, di) in sch.detailList"
|
v-for="(d, di) in sch.detailList"
|
||||||
:key="di"
|
:key="di"
|
||||||
|
class="aps-sch-detail-row"
|
||||||
@click="handleDetailClick(sch, d)"
|
@click="handleDetailClick(sch, d)"
|
||||||
>
|
>
|
||||||
<span class="aps-sch-detail-col col-spec">{{ d.spec }}</span>
|
<span class="aps-sch-detail-col col-spec">{{ d.spec }}</span>
|
||||||
@@ -162,34 +162,84 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 已排产 Tab -->
|
<!-- 已排产 Tab -->
|
||||||
<div class="detail-card aps-sch-card" v-show="activeTab === 'scheduled'">
|
<div v-show="activeTab === 'scheduled'" class="detail-card aps-sch-card">
|
||||||
<div class="detail-card-header">
|
<div class="detail-card-header">
|
||||||
<span>已排产明细</span>
|
<span>已排产明细</span>
|
||||||
|
<div style="display:flex; align-items:center; gap:8px;">
|
||||||
<span v-if="scheduledItemList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
|
<span v-if="scheduledItemList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
|
||||||
共 {{ scheduledItemList.length }} 条
|
共 {{ scheduledItemList.length }} 条
|
||||||
</span>
|
</span>
|
||||||
|
<span v-if="selectedItems.length >= 2" style="margin-left: auto;">
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="warning"
|
||||||
|
icon="el-icon-link"
|
||||||
|
@click.stop="handleMergePrepare"
|
||||||
|
>
|
||||||
|
合并选中项 ({{ selectedItems.length }})
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
<span v-else style="margin-left: auto;">
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="warning"
|
||||||
|
icon="el-icon-link"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
合并选中项
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card-body" style="padding:0;" v-loading="schLoading">
|
</div>
|
||||||
|
<div v-loading="schLoading" class="detail-card-body" style="padding:0;">
|
||||||
<el-table
|
<el-table
|
||||||
v-if="scheduledItemList.length > 0"
|
v-if="scheduledItemList.length > 0"
|
||||||
|
ref="scheduledTable"
|
||||||
:data="scheduledItemList"
|
:data="scheduledItemList"
|
||||||
border
|
border
|
||||||
size="small"
|
size="small"
|
||||||
class="aps-table"
|
class="aps-table"
|
||||||
|
:row-class-name="getItemRowClassName"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<el-table-column label="排产单号" prop="scheduleNo" min-width="140" />
|
<el-table-column type="selection" width="45" align="center" />
|
||||||
<el-table-column label="规格" prop="spec" min-width="120" />
|
<el-table-column label="排产单号" prop="scheduleNo" min-width="140" show-overflow-tooltip />
|
||||||
<el-table-column label="材质" prop="material" width="90" align="center" />
|
<el-table-column label="生产日期" prop="prodDate" width="110" align="center" show-overflow-tooltip />
|
||||||
<el-table-column label="排产吨数" prop="scheduleWeight" width="100" align="right" />
|
<el-table-column label="排产状态" prop="scheduleStatus" width="90" align="center">
|
||||||
<el-table-column label="品名" prop="productType" min-width="100" />
|
|
||||||
<el-table-column label="订货单位" prop="customerName" min-width="140" />
|
|
||||||
<el-table-column label="备注" prop="remark" min-width="100" />
|
|
||||||
<el-table-column label="操作" width="110" align="center" fixed="right">
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span style="white-space:nowrap;">
|
<span class="aps-status-tag" :class="'status-' + (scope.row.scheduleStatus || 1)">{{ statusMap[scope.row.scheduleStatus] || '未知' }}</span>
|
||||||
<el-button type="text" size="small" style="color:#409EFF;" @click="handleEditScheduled(scope.row)">编辑</el-button>
|
</template>
|
||||||
<el-button type="text" size="small" style="color:#ff4d4f;" @click="handleDeleteScheduled(scope.row)">删除</el-button>
|
</el-table-column>
|
||||||
</span>
|
<el-table-column label="规格" prop="spec" min-width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column label="材质" prop="material" width="90" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="排产吨数" prop="scheduleWeight" width="100" align="right" show-overflow-tooltip />
|
||||||
|
<el-table-column label="品名项" prop="productItem" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="品名" prop="productType" min-width="90" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="订货单位" prop="customerName" min-width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column label="业务员" prop="businessUser" width="90" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="联系电话" prop="businessPhone" width="110" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="交货期(天)" prop="deliveryCycle" width="100" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="产品用途" prop="usePurpose" min-width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column label="厚度公差" prop="thicknessTolerance" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="宽度公差" prop="widthTolerance" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="表面质量" prop="surfaceQuality" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="表面处理" prop="surfaceTreatment" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="内径尺寸" prop="innerDiameter" width="90" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="外径要求" prop="outerDiameter" width="90" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="包装要求" prop="packReq" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="切边要求" prop="cutEdgeReq" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="单件重量" prop="singleCoilWeight" width="90" align="center" show-overflow-tooltip />
|
||||||
|
<el-table-column label="交货重量偏差" prop="weightDeviation" min-width="110" show-overflow-tooltip />
|
||||||
|
<el-table-column label="其他技术要求" prop="otherTechReq" min-width="130" show-overflow-tooltip />
|
||||||
|
<el-table-column label="付款情况说明" prop="paymentDesc" min-width="130" show-overflow-tooltip />
|
||||||
|
<el-table-column label="单行排产备注" prop="rowRemark" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="备注" prop="remark" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div style="display:flex; justify-content:center; gap:0;">
|
||||||
|
<el-button type="text" size="small" style="color:#409EFF;padding:0 6px;" @click="handleEditScheduled(scope.row)">编辑</el-button>
|
||||||
|
<el-button type="text" size="small" style="color:#ff4d4f;padding:0 6px;" @click="handleDeleteScheduled(scope.row)">删除</el-button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -237,33 +287,329 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 已排产明细编辑对话框 -->
|
<!-- 已排产明细编辑对话框 -->
|
||||||
<el-dialog :title="editDialogTitle" :visible.sync="editDialogVisible" width="500px" append-to-body
|
<el-dialog
|
||||||
:close-on-click-modal="false">
|
:title="editDialogTitle"
|
||||||
<el-form ref="editForm" :model="editForm" label-width="100px" size="small">
|
:visible.sync="editDialogVisible"
|
||||||
|
width="800px"
|
||||||
|
append-to-body
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form ref="editForm" :model="editForm" label-width="110px" size="small">
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
<el-form-item label="排产单号">
|
<el-form-item label="排产单号">
|
||||||
<span style="color:#2c3e50;">{{ editForm.scheduleNo }}</span>
|
<span style="color:#2c3e50;font-weight:500;">{{ editForm.scheduleNo }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="订货单位">
|
||||||
|
<el-input v-model="editForm.customerName" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
<el-form-item label="规格" prop="spec">
|
<el-form-item label="规格" prop="spec">
|
||||||
<el-input v-model="editForm.spec" />
|
<el-input v-model="editForm.spec" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
<el-form-item label="材质" prop="material">
|
<el-form-item label="材质" prop="material">
|
||||||
<el-input v-model="editForm.material" />
|
<el-input v-model="editForm.material" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="排产吨数" prop="scheduleWeight">
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="排产吨数">
|
||||||
<el-input-number v-model="editForm.scheduleWeight" :min="0" :precision="3" :controls="false" style="width:100%" />
|
<el-input-number v-model="editForm.scheduleWeight" :min="0" :precision="3" :controls="false" style="width:100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="品名" prop="productType">
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="排产总计划吨数">
|
||||||
|
<el-input-number v-model="editForm.totalPlanWeight" :min="0" :precision="3" :controls="false" style="width:100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="品名">
|
||||||
<el-input v-model="editForm.productType" />
|
<el-input v-model="editForm.productType" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="备注" prop="remark">
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="品名项">
|
||||||
|
<el-input v-model="editForm.productItem" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="业务员">
|
||||||
|
<el-input v-model="editForm.businessUser" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话">
|
||||||
|
<el-input v-model="editForm.businessPhone" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<!-- <el-row :gutter="16">-->
|
||||||
|
<!-- <el-col :span="12">-->
|
||||||
|
<!-- <el-form-item label="关联销售合同号">-->
|
||||||
|
<!-- <el-input v-model="editForm.relContractNo" />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- </el-col>-->
|
||||||
|
<!-- <el-col :span="12">-->
|
||||||
|
<!-- <el-form-item label="订单日期">-->
|
||||||
|
<!-- <el-date-picker v-model="editForm.orderDate" type="date" value-format="yyyy-MM-dd" style="width:100%" />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- </el-col>-->
|
||||||
|
<!-- </el-row>-->
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="交货期(天)">
|
||||||
|
<el-input-number v-model="editForm.deliveryCycle" :min="0" :controls="false" style="width:100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="产品用途">
|
||||||
|
<el-input v-model="editForm.usePurpose" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="厚度公差">
|
||||||
|
<el-input v-model="editForm.thicknessTolerance" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="宽度公差">
|
||||||
|
<el-input v-model="editForm.widthTolerance" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="表面质量">
|
||||||
|
<el-input v-model="editForm.surfaceQuality" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="表面处理">
|
||||||
|
<el-input v-model="editForm.surfaceTreatment" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="内径尺寸">
|
||||||
|
<el-input v-model="editForm.innerDiameter" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="外径要求">
|
||||||
|
<el-input v-model="editForm.outerDiameter" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="包装要求">
|
||||||
|
<el-input v-model="editForm.packReq" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="切边要求">
|
||||||
|
<el-input v-model="editForm.cutEdgeReq" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="单件重量">
|
||||||
|
<el-input v-model="editForm.singleCoilWeight" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="交货重量偏差">
|
||||||
|
<el-input v-model="editForm.weightDeviation" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="其他技术要求">
|
||||||
|
<el-input v-model="editForm.otherTechReq" type="textarea" :rows="2" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="付款情况说明">
|
||||||
|
<el-input v-model="editForm.paymentDesc" type="textarea" :rows="2" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="单行排产备注">
|
||||||
|
<el-input v-model="editForm.rowRemark" type="textarea" :rows="2" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="备注">
|
||||||
<el-input v-model="editForm.remark" type="textarea" :rows="2" />
|
<el-input v-model="editForm.remark" type="textarea" :rows="2" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
<el-button :loading="editBtnLoading" type="danger" @click="submitEditForm">确 定</el-button>
|
<el-button :loading="editBtnLoading" type="danger" @click="submitEditForm">确 定</el-button>
|
||||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 合并排产明细对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
title="合并排产明细"
|
||||||
|
:visible.sync="mergeDialogVisible"
|
||||||
|
width="850px"
|
||||||
|
append-to-body
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<div style="margin-bottom:12px;font-size:13px;color:#e67e22;">
|
||||||
|
选中 {{ mergeForm.itemCount }} 条明细,请选择一个作为合并模板,下方字段将自动填充,您可修改后确认合并。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 选择模板 -->
|
||||||
|
<el-table :data="mergeSourceRows" border size="small" style="margin-bottom:12px;" @row-click="pickMergeTemplate">
|
||||||
|
<el-table-column width="50" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-radio v-model="mergeTemplateIndex" :label="scope.$index" @click.native.stop />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="排产单号" prop="scheduleNo" min-width="130" show-overflow-tooltip />
|
||||||
|
<el-table-column label="规格" prop="spec" min-width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="材质" prop="material" width="80" show-overflow-tooltip />
|
||||||
|
<el-table-column label="排产吨数" prop="scheduleWeight" width="90" align="right" />
|
||||||
|
<el-table-column label="品名" prop="productType" min-width="80" show-overflow-tooltip />
|
||||||
|
<el-table-column label="订货单位" prop="customerName" min-width="120" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 合并表单 -->
|
||||||
|
<el-form ref="mergeFormRef" :model="mergeForm" label-width="110px" size="small">
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="排产单号"><el-input v-model="mergeForm.scheduleNo" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="订货单位"><el-input v-model="mergeForm.customerName" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="规格"><el-input v-model="mergeForm.spec" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="材质"><el-input v-model="mergeForm.material" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="排产吨数(累加)">
|
||||||
|
<el-input-number v-model="mergeForm.scheduleWeight" :min="0" :precision="3" :controls="false" style="width:100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="品名"><el-input v-model="mergeForm.productType" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="品名项"><el-input v-model="mergeForm.productItem" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="业务员"><el-input v-model="mergeForm.businessUser" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话"><el-input v-model="mergeForm.businessPhone" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="交货期(天)">
|
||||||
|
<el-input-number v-model="mergeForm.deliveryCycle" :min="0" :controls="false" style="width:100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="产品用途"><el-input v-model="mergeForm.usePurpose" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="厚度公差"><el-input v-model="mergeForm.thicknessTolerance" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="宽度公差"><el-input v-model="mergeForm.widthTolerance" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="表面质量"><el-input v-model="mergeForm.surfaceQuality" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="表面处理"><el-input v-model="mergeForm.surfaceTreatment" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="内径尺寸"><el-input v-model="mergeForm.innerDiameter" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="外径要求"><el-input v-model="mergeForm.outerDiameter" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="包装要求"><el-input v-model="mergeForm.packReq" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="切边要求"><el-input v-model="mergeForm.cutEdgeReq" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="单件重量"><el-input v-model="mergeForm.singleCoilWeight" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="交货重量偏差"><el-input v-model="mergeForm.weightDeviation" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="其他技术要求"><el-input v-model="mergeForm.otherTechReq" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="付款情况说明"><el-input v-model="mergeForm.paymentDesc" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="备注"><el-input v-model="mergeForm.remark" /></el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<div style="margin-top:8px;font-size:12px;color:#909399;">
|
||||||
|
合并后 schedule_detail_ids:{{ mergeForm.scheduleDetailIds }}
|
||||||
|
</div>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button :loading="mergeBtnLoading" type="warning" @click="confirmMerge">确 定 合 并</el-button>
|
||||||
|
<el-button @click="mergeDialogVisible = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -275,9 +621,10 @@ import {
|
|||||||
import {
|
import {
|
||||||
getCrmOrderInfo,
|
getCrmOrderInfo,
|
||||||
listScheduleItem,
|
listScheduleItem,
|
||||||
addScheduleItem,
|
|
||||||
updateScheduleItem,
|
updateScheduleItem,
|
||||||
delScheduleItem
|
delScheduleItem,
|
||||||
|
receiveScheduleItem,
|
||||||
|
mergeScheduleItem
|
||||||
} from '@/api/aps/schedule'
|
} from '@/api/aps/schedule'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -301,6 +648,24 @@ export default {
|
|||||||
|
|
||||||
// 已排产
|
// 已排产
|
||||||
scheduledItemList: [],
|
scheduledItemList: [],
|
||||||
|
selectedItems: [],
|
||||||
|
sourceColorMap: {},
|
||||||
|
|
||||||
|
// 合并对话框
|
||||||
|
mergeDialogVisible: false,
|
||||||
|
mergeBtnLoading: false,
|
||||||
|
mergeTemplateIndex: 0,
|
||||||
|
mergeSourceRows: [],
|
||||||
|
mergeForm: {
|
||||||
|
itemCount: 0, scheduleNo: '', customerName: '', spec: '', material: '',
|
||||||
|
scheduleWeight: 0, productType: '', productItem: '', businessUser: '',
|
||||||
|
businessPhone: '', deliveryCycle: undefined, usePurpose: '',
|
||||||
|
thicknessTolerance: '', widthTolerance: '', surfaceQuality: '',
|
||||||
|
surfaceTreatment: '', innerDiameter: '', outerDiameter: '',
|
||||||
|
packReq: '', cutEdgeReq: '', singleCoilWeight: '',
|
||||||
|
weightDeviation: '', otherTechReq: '', paymentDesc: '',
|
||||||
|
remark: '', scheduleDetailIds: ''
|
||||||
|
},
|
||||||
|
|
||||||
// 驳回
|
// 驳回
|
||||||
rejectDialogVisible: false,
|
rejectDialogVisible: false,
|
||||||
@@ -322,20 +687,47 @@ export default {
|
|||||||
drillOrder: null
|
drillOrder: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
activeTab() {
|
||||||
|
this.selectedItems = []
|
||||||
|
}
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getEmptyEditForm() {
|
getEmptyEditForm() {
|
||||||
return {
|
return {
|
||||||
itemId: undefined,
|
|
||||||
scheduleId: undefined,
|
scheduleId: undefined,
|
||||||
scheduleNo: '',
|
scheduleNo: '',
|
||||||
|
prodDate: '',
|
||||||
|
scheduleStatus: undefined,
|
||||||
|
totalPlanWeight: undefined,
|
||||||
|
relContractNo: '',
|
||||||
|
businessUser: '',
|
||||||
|
businessPhone: '',
|
||||||
|
orderDate: '',
|
||||||
|
customerName: '',
|
||||||
|
deliveryCycle: undefined,
|
||||||
|
usePurpose: '',
|
||||||
|
productType: '',
|
||||||
|
thicknessTolerance: '',
|
||||||
|
widthTolerance: '',
|
||||||
|
surfaceQuality: '',
|
||||||
|
surfaceTreatment: '',
|
||||||
|
innerDiameter: '',
|
||||||
|
outerDiameter: '',
|
||||||
|
packReq: '',
|
||||||
|
cutEdgeReq: '',
|
||||||
|
singleCoilWeight: '',
|
||||||
|
weightDeviation: '',
|
||||||
|
otherTechReq: '',
|
||||||
|
paymentDesc: '',
|
||||||
spec: '',
|
spec: '',
|
||||||
material: '',
|
material: '',
|
||||||
scheduleWeight: 0,
|
scheduleWeight: 0,
|
||||||
productType: '',
|
productItem: '',
|
||||||
customerName: '',
|
rowRemark: '',
|
||||||
remark: ''
|
remark: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -386,40 +778,18 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleAccept(sch) {
|
handleAccept(sch) {
|
||||||
this.$confirm(
|
|
||||||
`确认接收产需单「${sch.scheduleNo}」的全部排产明细吗?`,
|
|
||||||
'提示',
|
|
||||||
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
|
||||||
).then(() => {
|
|
||||||
const details = sch.detailList || []
|
const details = sch.detailList || []
|
||||||
if (details.length === 0) {
|
if (details.length === 0) {
|
||||||
this.$message.warning('该产需单无可排产的明细')
|
this.$message.warning('该产需单无可排产的明细')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
this.$confirm(
|
||||||
const promises = details.map(detail =>
|
`确认接收产需单「${sch.scheduleNo}」的全部排产明细吗?共 ${details.length} 条明细`,
|
||||||
addScheduleItem({
|
'提示',
|
||||||
scheduleId: sch.scheduleId,
|
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
||||||
scheduleNo: sch.scheduleNo,
|
).then(() => {
|
||||||
spec: detail.spec || '',
|
|
||||||
material: detail.material || '',
|
|
||||||
scheduleWeight: detail.scheduleWeight || 0,
|
|
||||||
productType: sch.productType || detail.productType || '',
|
|
||||||
customerName: sch.customerName || '',
|
|
||||||
remark: detail.remark || ''
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
// 更新产需单状态为 2(已接收)
|
|
||||||
promises.push(
|
|
||||||
updateRequirement({
|
|
||||||
scheduleId: sch.scheduleId,
|
|
||||||
scheduleStatus: 2
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
this.$message.info('正在处理接收...')
|
this.$message.info('正在处理接收...')
|
||||||
Promise.all(promises).then(() => {
|
receiveScheduleItem(sch.scheduleId).then(() => {
|
||||||
this.$modal.msgSuccess('接收成功,排产明细已写入')
|
this.$modal.msgSuccess('接收成功,排产明细已写入')
|
||||||
this.queryPending()
|
this.queryPending()
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
@@ -463,12 +833,24 @@ export default {
|
|||||||
queryScheduled() {
|
queryScheduled() {
|
||||||
this.schLoading = true
|
this.schLoading = true
|
||||||
this.scheduledItemList = []
|
this.scheduledItemList = []
|
||||||
|
this.sourceColorMap = {}
|
||||||
|
this.selectedItems = []
|
||||||
|
|
||||||
listScheduleItem({ prodDate: this.queryDate, pageNum: 1, pageSize: 999 }).then(res => {
|
listScheduleItem({ prodDate: this.queryDate, pageNum: 1, pageSize: 999 }).then(res => {
|
||||||
this.scheduledItemList = res.rows || []
|
this.scheduledItemList = (res.rows || []).sort((a, b) => (a.scheduleNo || '').localeCompare(b.scheduleNo || ''))
|
||||||
const totalWeight = this.scheduledItemList.reduce((sum, d) => sum + (parseFloat(d.scheduleWeight) || 0), 0)
|
try {
|
||||||
|
this.sourceColorMap = this.buildGroupColorMap(this.scheduledItemList)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('buildGroupColorMap error:', e)
|
||||||
|
this.sourceColorMap = {}
|
||||||
|
}
|
||||||
|
const totalWeight = this.scheduledItemList.reduce((sum, d) => {
|
||||||
|
const w = parseFloat(d.scheduleWeight)
|
||||||
|
return sum + (isNaN(w) ? 0 : w)
|
||||||
|
}, 0)
|
||||||
this.summaryText = `共 ${this.scheduledItemList.length} 条明细,排产总吨数 ${totalWeight.toFixed(3)} 吨`
|
this.summaryText = `共 ${this.scheduledItemList.length} 条明细,排产总吨数 ${totalWeight.toFixed(3)} 吨`
|
||||||
}).catch(() => {
|
}).catch((e) => {
|
||||||
|
console.error('queryScheduled error:', e)
|
||||||
this.scheduledItemList = []
|
this.scheduledItemList = []
|
||||||
this.summaryText = ''
|
this.summaryText = ''
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -504,7 +886,7 @@ export default {
|
|||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
delScheduleItem(row.itemId || row.scheduleItemId).then(() => {
|
delScheduleItem(row.scheduleId).then(() => {
|
||||||
this.$modal.msgSuccess('删除成功')
|
this.$modal.msgSuccess('删除成功')
|
||||||
this.queryScheduled()
|
this.queryScheduled()
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
@@ -513,6 +895,97 @@ export default {
|
|||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ====== 合并 ======
|
||||||
|
handleSelectionChange(rows) {
|
||||||
|
this.selectedItems = rows
|
||||||
|
},
|
||||||
|
|
||||||
|
getItemRowClassName({ row }) {
|
||||||
|
const key = row.scheduleNo
|
||||||
|
if (!key) return ''
|
||||||
|
const colorIndex = this.sourceColorMap[key]
|
||||||
|
return colorIndex !== undefined ? `merge-source-${colorIndex}` : ''
|
||||||
|
},
|
||||||
|
|
||||||
|
buildGroupColorMap(list) {
|
||||||
|
const map = {}
|
||||||
|
let colorIdx = 0
|
||||||
|
list.forEach(item => {
|
||||||
|
const key = item.scheduleNo
|
||||||
|
if (!key) return
|
||||||
|
if (!(key in map)) {
|
||||||
|
map[key] = colorIdx % 5
|
||||||
|
colorIdx++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return map
|
||||||
|
},
|
||||||
|
|
||||||
|
handleMergePrepare() {
|
||||||
|
if (this.selectedItems.length < 2) {
|
||||||
|
this.$message.warning('请至少选择2条排产明细进行合并')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.mergeSourceRows = [...this.selectedItems]
|
||||||
|
this.mergeTemplateIndex = 0
|
||||||
|
this.pickMergeTemplate(this.mergeSourceRows[0])
|
||||||
|
this.mergeDialogVisible = true
|
||||||
|
},
|
||||||
|
|
||||||
|
pickMergeTemplate(row) {
|
||||||
|
const idx = this.mergeSourceRows.indexOf(row)
|
||||||
|
if (idx >= 0) this.mergeTemplateIndex = idx
|
||||||
|
this.mergeForm = {
|
||||||
|
itemCount: this.mergeSourceRows.length,
|
||||||
|
scheduleNo: row.scheduleNo || '',
|
||||||
|
customerName: row.customerName || '',
|
||||||
|
spec: row.spec || '',
|
||||||
|
material: row.material || '',
|
||||||
|
scheduleWeight: this.mergeSourceRows.reduce((sum, r) => sum + (parseFloat(r.scheduleWeight) || 0), 0),
|
||||||
|
productType: row.productType || '',
|
||||||
|
productItem: row.productItem || '',
|
||||||
|
businessUser: row.businessUser || '',
|
||||||
|
businessPhone: row.businessPhone || '',
|
||||||
|
deliveryCycle: row.deliveryCycle,
|
||||||
|
usePurpose: row.usePurpose || '',
|
||||||
|
thicknessTolerance: row.thicknessTolerance || '',
|
||||||
|
widthTolerance: row.widthTolerance || '',
|
||||||
|
surfaceQuality: row.surfaceQuality || '',
|
||||||
|
surfaceTreatment: row.surfaceTreatment || '',
|
||||||
|
innerDiameter: row.innerDiameter || '',
|
||||||
|
outerDiameter: row.outerDiameter || '',
|
||||||
|
packReq: row.packReq || '',
|
||||||
|
cutEdgeReq: row.cutEdgeReq || '',
|
||||||
|
singleCoilWeight: row.singleCoilWeight || '',
|
||||||
|
weightDeviation: row.weightDeviation || '',
|
||||||
|
otherTechReq: row.otherTechReq || '',
|
||||||
|
paymentDesc: row.paymentDesc || '',
|
||||||
|
remark: row.remark || '',
|
||||||
|
scheduleDetailIds: this.mergeSourceRows.map(r => r.scheduleDetailIds || '').filter(Boolean).join(',')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmMerge() {
|
||||||
|
this.mergeBtnLoading = true
|
||||||
|
const ids = this.mergeSourceRows.map(r => r.scheduleId)
|
||||||
|
const mergedBo = {
|
||||||
|
...this.mergeForm,
|
||||||
|
prodDate: this.queryDate,
|
||||||
|
scheduleStatus: 2
|
||||||
|
}
|
||||||
|
delete mergedBo.itemCount
|
||||||
|
mergeScheduleItem({ ids, mergedBo }).then(() => {
|
||||||
|
this.$modal.msgSuccess(`合并成功:${ids.length} 条明细合并为 1 条`)
|
||||||
|
this.mergeDialogVisible = false
|
||||||
|
this.selectedItems = []
|
||||||
|
this.queryScheduled()
|
||||||
|
}).catch(() => {
|
||||||
|
this.$modal.msgError('合并失败')
|
||||||
|
}).finally(() => {
|
||||||
|
this.mergeBtnLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
// ====== 下钻 & 辅助方法 ======
|
// ====== 下钻 & 辅助方法 ======
|
||||||
scheduleTotalWeight(sch) {
|
scheduleTotalWeight(sch) {
|
||||||
const details = sch.detailList || []
|
const details = sch.detailList || []
|
||||||
@@ -594,6 +1067,7 @@ export default {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -830,4 +1304,21 @@ export default {
|
|||||||
color: $aps-text-muted;
|
color: $aps-text-muted;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====== 合并候选行颜色高亮(同一源排产单 → 同色) ======
|
||||||
|
::v-deep .el-table__body tr.merge-source-0 > td {
|
||||||
|
background-color: #f0f5ff !important;
|
||||||
|
}
|
||||||
|
::v-deep .el-table__body tr.merge-source-1 > td {
|
||||||
|
background-color: #f6ffed !important;
|
||||||
|
}
|
||||||
|
::v-deep .el-table__body tr.merge-source-2 > td {
|
||||||
|
background-color: #fff7e6 !important;
|
||||||
|
}
|
||||||
|
::v-deep .el-table__body tr.merge-source-3 > td {
|
||||||
|
background-color: #f9f0ff !important;
|
||||||
|
}
|
||||||
|
::v-deep .el-table__body tr.merge-source-4 > td {
|
||||||
|
background-color: #fff0f6 !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,13 +1,63 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="enabled" class="section-container">
|
<div v-if="enabled" class="section-container">
|
||||||
<div class="detail-section">
|
<div class="detail-section">
|
||||||
<div class="detail-section-label">Complaint Content · 投诉情况</div>
|
<div class="detail-section-label">Complaint Content · 投诉情况与客户诉求</div>
|
||||||
<div class="detail-section-text">{{ data.complaintContent || '-' }}</div>
|
<div class="detail-section-text">{{ data.complaintContent || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-section" v-if="customerInfo">
|
||||||
|
<div class="detail-section-label">Customer · 关联客户</div>
|
||||||
|
<div class="customer-info-card">
|
||||||
|
<div class="customer-row">
|
||||||
|
<span class="customer-row-label">公司名称</span>
|
||||||
|
<span class="customer-row-value">{{ customerInfo.companyName || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="customer-row">
|
||||||
|
<span class="customer-row-label">联系人</span>
|
||||||
|
<span class="customer-row-value">{{ customerInfo.contactPerson || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="customer-row">
|
||||||
|
<span class="customer-row-label">联系方式</span>
|
||||||
|
<span class="customer-row-value">{{ customerInfo.contactWay || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="customer-row">
|
||||||
|
<span class="customer-row-label">客户地址</span>
|
||||||
|
<span class="customer-row-value">{{ customerInfo.address || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="customer-row">
|
||||||
|
<span class="customer-row-label">客户等级</span>
|
||||||
|
<span class="customer-row-value">{{ customerInfo.customerLevel || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="detail-section" v-else>
|
||||||
|
<div class="detail-section-label">Customer · 关联客户</div>
|
||||||
|
<div class="detail-section-text">-</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="detail-section">
|
<div class="detail-section">
|
||||||
<div class="detail-section-label">Customer Demand · 客户诉求</div>
|
<div class="detail-section-label">Downstream User · 下游使用用户</div>
|
||||||
<div class="detail-section-text">{{ data.customerDemand || '-' }}</div>
|
<div class="detail-section-text">{{ data.downstreamUserName || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-section">
|
||||||
|
<div class="detail-section-label">Phone · 电话</div>
|
||||||
|
<div class="detail-section-text">{{ data.phone || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-section">
|
||||||
|
<div class="detail-section-label">Project Name · 工程名称</div>
|
||||||
|
<div class="detail-section-text">{{ data.projectName || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-section">
|
||||||
|
<div class="detail-section-label">Project Location · 使用地点</div>
|
||||||
|
<div class="detail-section-text">{{ data.projectLocation || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-section">
|
||||||
|
<div class="detail-section-label">Product Usage · 产品用途</div>
|
||||||
|
<div class="detail-section-text">{{ data.productUsage || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="detail-section" v-if="data.file">
|
<div class="detail-section" v-if="data.file">
|
||||||
@@ -19,6 +69,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import FileList from "@/components/FileList/index.vue";
|
import FileList from "@/components/FileList/index.vue";
|
||||||
|
import { getCustomer } from "@/api/crm/customer";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'BasicInfoSection',
|
name: 'BasicInfoSection',
|
||||||
@@ -32,6 +83,27 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
customerInfo: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'data.customerId': {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
if (val) {
|
||||||
|
getCustomer(val).then(response => {
|
||||||
|
this.customerInfo = response.data || null;
|
||||||
|
}).catch(() => {
|
||||||
|
this.customerInfo = null;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.customerInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -59,4 +131,38 @@ export default {
|
|||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
border-bottom: 1px solid #eeeae4;
|
border-bottom: 1px solid #eeeae4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== 客户信息卡片 ===== */
|
||||||
|
.customer-info-card {
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: #faf8f5;
|
||||||
|
border: 1px solid #e8e4de;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
padding: 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-row + .customer-row {
|
||||||
|
border-top: 1px solid #f0ece6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-row-label {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 70px;
|
||||||
|
font-family: 'Georgia', 'Times New Roman', serif;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #8c8c8c;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-row-value {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -11,15 +11,18 @@
|
|||||||
<el-table-column label="厂家卷号" align="center" prop="coilInfo.supplierCoilNo" width="140" show-overflow-tooltip />
|
<el-table-column label="厂家卷号" align="center" prop="coilInfo.supplierCoilNo" width="140" show-overflow-tooltip />
|
||||||
<el-table-column label="物料名称" align="center" prop="coilInfo.itemName" width="100" />
|
<el-table-column label="物料名称" align="center" prop="coilInfo.itemName" width="100" />
|
||||||
<el-table-column label="规格" align="center" prop="coilInfo.specification" width="100" />
|
<el-table-column label="规格" align="center" prop="coilInfo.specification" width="100" />
|
||||||
|
<el-table-column label="制造时间" align="center" prop="coilInfo.createTime" width="90" />
|
||||||
|
<el-table-column label="发货时间" align="center" prop="coilInfo.exportTime" width="90" />
|
||||||
|
<el-table-column label="发货人" align="center" prop="coilInfo.exportBy" width="90" />
|
||||||
<el-table-column label="材质" align="center" prop="coilInfo.material" width="100" />
|
<el-table-column label="材质" align="center" prop="coilInfo.material" width="100" />
|
||||||
<el-table-column label="厂家" align="center" prop="coilInfo.manufacturer" width="90" />
|
<el-table-column label="厂家" align="center" prop="coilInfo.manufacturer" width="60" />
|
||||||
<el-table-column label="净重(t)" align="center" prop="coilInfo.netWeight" width="80" />
|
<el-table-column label="净重(t)" align="center" prop="coilInfo.netWeight" width="80" />
|
||||||
<el-table-column label="质量状态" align="center" prop="coilInfo.qualityStatus" width="90">
|
<el-table-column label="品质" align="center" prop="coilInfo.qualityStatus" width="60">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<dict-tag v-if="scope.row.coilInfo.qualityStatus" :options="dict.type.coil_quality_status" :value="scope.row.coilInfo.qualityStatus"></dict-tag>
|
<dict-tag v-if="scope.row.coilInfo.qualityStatus" :options="dict.type.coil_quality_status" :value="scope.row.coilInfo.qualityStatus"></dict-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="备注" align="center" prop="coilInfo.remark" width="140" show-overflow-tooltip />
|
<el-table-column label="备注" align="center" prop="coilInfo.remark" show-overflow-tooltip />
|
||||||
<el-table-column v-if="editable" label="操作" align="center" width="70" fixed="right">
|
<el-table-column v-if="editable" label="操作" align="center" width="70" fixed="right">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="$emit('remove', scope.row)"></el-button>
|
<el-button size="mini" type="text" icon="el-icon-delete" @click="$emit('remove', scope.row)"></el-button>
|
||||||
|
|||||||
@@ -17,8 +17,13 @@
|
|||||||
<el-tag v-else-if="item.taskStatus === 1" type="success" size="mini">已完成</el-tag>
|
<el-tag v-else-if="item.taskStatus === 1" type="success" size="mini">已完成</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="opinion-card-body">
|
<div class="opinion-card-body">
|
||||||
|
<template v-if="isJsonOpinion(item.deptOpinion)">
|
||||||
|
<DeptOpinionPreview :deptId="item.deptId" :jsonData="item.deptOpinion" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
<div v-if="item.deptOpinion" class="opinion-content" v-html="item.deptOpinion"></div>
|
<div v-if="item.deptOpinion" class="opinion-content" v-html="item.deptOpinion"></div>
|
||||||
<div v-else class="opinion-empty">— No opinion yet · 暂无意见 —</div>
|
<div v-else class="opinion-empty">— No opinion yet · 暂无意见 —</div>
|
||||||
|
</template>
|
||||||
<div v-if="item.fillFile" class="opinion-file">
|
<div v-if="item.fillFile" class="opinion-file">
|
||||||
<FileList :ossIds="item.fillFile" />
|
<FileList :ossIds="item.fillFile" />
|
||||||
</div>
|
</div>
|
||||||
@@ -35,10 +40,11 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import FileList from "@/components/FileList/index.vue";
|
import FileList from "@/components/FileList/index.vue";
|
||||||
|
import DeptOpinionPreview from "./DeptOpinionPreview.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DepartmentOpinionSection',
|
name: 'DepartmentOpinionSection',
|
||||||
components: { FileList },
|
components: { FileList, DeptOpinionPreview },
|
||||||
props: {
|
props: {
|
||||||
enabled: {
|
enabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -50,6 +56,15 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
isJsonOpinion(str) {
|
||||||
|
if (!str) return false;
|
||||||
|
try {
|
||||||
|
const obj = JSON.parse(str);
|
||||||
|
return obj && typeof obj === 'object' && !Array.isArray(obj);
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
getDeptName(deptId) {
|
getDeptName(deptId) {
|
||||||
const map = { 1: '生产部', 2: '质量部', 3: '销售部' };
|
const map = { 1: '生产部', 2: '质量部', 3: '销售部' };
|
||||||
return map[deptId] || '部门' + deptId;
|
return map[deptId] || '部门' + deptId;
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dept-form-container">
|
||||||
|
<!-- 生产部 deptId=1 -->
|
||||||
|
<template v-if="deptId === 1">
|
||||||
|
<el-form-item label="内部调查情况" prop="internalInvestigation">
|
||||||
|
<el-input v-model="formData.internalInvestigation" type="textarea" :rows="3" placeholder="请描述内部调查情况" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="确认人" prop="internalConfirmer">
|
||||||
|
<el-input v-model="formData.internalConfirmer" placeholder="请输入确认人" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="日期" prop="internalConfirmDate">
|
||||||
|
<el-date-picker v-model="formData.internalConfirmDate" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" style="width:100%" @change="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-form-item label="外部调查情况" prop="externalInvestigation">
|
||||||
|
<el-input v-model="formData.externalInvestigation" type="textarea" :rows="3" placeholder="请描述外部调查情况" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="确认人" prop="externalConfirmer">
|
||||||
|
<el-input v-model="formData.externalConfirmer" placeholder="请输入确认人" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="日期" prop="externalConfirmDate">
|
||||||
|
<el-date-picker v-model="formData.externalConfirmDate" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" style="width:100%" @change="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-form-item label="责任单位" prop="responsibleUnit">
|
||||||
|
<el-input v-model="formData.responsibleUnit" placeholder="请输入责任单位" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="接收人" prop="receiver">
|
||||||
|
<el-input v-model="formData.receiver" placeholder="请输入接收人" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="接受日期" prop="acceptDate">
|
||||||
|
<el-date-picker v-model="formData.acceptDate" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" style="width:100%" @change="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 质量部 deptId=2 -->
|
||||||
|
<template v-else-if="deptId === 2">
|
||||||
|
<el-form-item label="产生原因" prop="cause">
|
||||||
|
<el-input v-model="formData.cause" type="textarea" :rows="3" placeholder="请描述产生原因" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="流出原因" prop="escapeReason">
|
||||||
|
<el-input v-model="formData.escapeReason" type="textarea" :rows="3" placeholder="请描述流出原因" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="纠正措施" prop="correctiveAction">
|
||||||
|
<el-input v-model="formData.correctiveAction" type="textarea" :rows="3" placeholder="请输入纠正措施" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="预计整改完成日期" prop="rectifyDate">
|
||||||
|
<el-date-picker v-model="formData.rectifyDate" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" style="width:100%" @change="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="主管意见" prop="supervisorOpinion">
|
||||||
|
<el-input v-model="formData.supervisorOpinion" type="textarea" :rows="2" placeholder="请输入主管意见" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 销售部 deptId=3 -->
|
||||||
|
<template v-else>
|
||||||
|
<el-form-item label="处理意见" prop="handlingOpinion">
|
||||||
|
<el-input v-model="formData.handlingOpinion" type="textarea" :rows="4" placeholder="请输入处理意见" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="领导意见" prop="leaderOpinion">
|
||||||
|
<el-input v-model="formData.leaderOpinion" type="textarea" :rows="3" placeholder="请输入领导意见" @input="emitJson" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'DeptOpinionForm',
|
||||||
|
props: {
|
||||||
|
deptId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
jsonData: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formData: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
jsonData: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
this.parseJson(val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deptId() {
|
||||||
|
this.parseJson(this.jsonData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
parseJson(val) {
|
||||||
|
const defaults = this.getDefaults();
|
||||||
|
if (val) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(val);
|
||||||
|
this.formData = { ...defaults, ...parsed };
|
||||||
|
} catch (e) {
|
||||||
|
this.formData = { ...defaults };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.formData = { ...defaults };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDefaults() {
|
||||||
|
if (this.deptId === 1) {
|
||||||
|
return { internalInvestigation: '', internalConfirmer: '', internalConfirmDate: '', externalInvestigation: '', externalConfirmer: '', externalConfirmDate: '', responsibleUnit: '', receiver: '', acceptDate: '' };
|
||||||
|
} else if (this.deptId === 2) {
|
||||||
|
return { cause: '', escapeReason: '', correctiveAction: '', rectifyDate: '', supervisorOpinion: '' };
|
||||||
|
} else {
|
||||||
|
return { handlingOpinion: '', leaderOpinion: '' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emitJson() {
|
||||||
|
this.$emit('input', JSON.stringify(this.formData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dept-form-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dept-preview-container">
|
||||||
|
<template v-if="parsedData">
|
||||||
|
<!-- 生产部 deptId=1 -->
|
||||||
|
<template v-if="deptId === 1">
|
||||||
|
<div class="preview-row" v-if="parsedData.internalInvestigation">
|
||||||
|
<span class="preview-label">内部调查情况</span>
|
||||||
|
<span class="preview-value">{{ parsedData.internalInvestigation }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.internalConfirmer || parsedData.internalConfirmDate">
|
||||||
|
<span class="preview-label">内部确认</span>
|
||||||
|
<span class="preview-value">{{ parsedData.internalConfirmer || '-' }} / {{ parsedData.internalConfirmDate || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.externalInvestigation">
|
||||||
|
<span class="preview-label">外部调查情况</span>
|
||||||
|
<span class="preview-value">{{ parsedData.externalInvestigation }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.externalConfirmer || parsedData.externalConfirmDate">
|
||||||
|
<span class="preview-label">外部确认</span>
|
||||||
|
<span class="preview-value">{{ parsedData.externalConfirmer || '-' }} / {{ parsedData.externalConfirmDate || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.responsibleUnit">
|
||||||
|
<span class="preview-label">责任单位</span>
|
||||||
|
<span class="preview-value">{{ parsedData.responsibleUnit }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.receiver || parsedData.acceptDate">
|
||||||
|
<span class="preview-label">接收</span>
|
||||||
|
<span class="preview-value">{{ parsedData.receiver || '-' }} / {{ parsedData.acceptDate || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 质量部 deptId=2 -->
|
||||||
|
<template v-else-if="deptId === 2">
|
||||||
|
<div class="preview-row" v-if="parsedData.cause">
|
||||||
|
<span class="preview-label">产生原因</span>
|
||||||
|
<span class="preview-value">{{ parsedData.cause }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.escapeReason">
|
||||||
|
<span class="preview-label">流出原因</span>
|
||||||
|
<span class="preview-value">{{ parsedData.escapeReason }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.correctiveAction">
|
||||||
|
<span class="preview-label">纠正措施</span>
|
||||||
|
<span class="preview-value">{{ parsedData.correctiveAction }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.rectifyDate">
|
||||||
|
<span class="preview-label">预计整改日期</span>
|
||||||
|
<span class="preview-value">{{ parsedData.rectifyDate }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.supervisorOpinion">
|
||||||
|
<span class="preview-label">主管意见</span>
|
||||||
|
<span class="preview-value">{{ parsedData.supervisorOpinion }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 销售部 deptId=3 -->
|
||||||
|
<template v-else>
|
||||||
|
<div class="preview-row" v-if="parsedData.handlingOpinion">
|
||||||
|
<span class="preview-label">处理意见</span>
|
||||||
|
<span class="preview-value">{{ parsedData.handlingOpinion }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-row" v-if="parsedData.leaderOpinion">
|
||||||
|
<span class="preview-label">领导意见</span>
|
||||||
|
<span class="preview-value">{{ parsedData.leaderOpinion }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<div v-else class="preview-empty">— No data · 暂无数据 —</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'DeptOpinionPreview',
|
||||||
|
props: {
|
||||||
|
deptId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
jsonData: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
parsedData() {
|
||||||
|
if (!this.jsonData) return null;
|
||||||
|
try {
|
||||||
|
return JSON.parse(this.jsonData);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dept-preview-container {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #3a3a3a;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 4px 0;
|
||||||
|
border-bottom: 1px solid #f0ece6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-label {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 100px;
|
||||||
|
font-family: 'Georgia', 'Times New Roman', serif;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #8c8c8c;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-value {
|
||||||
|
flex: 1;
|
||||||
|
color: #1a1a1a;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-empty {
|
||||||
|
color: #bab5ae;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
font-family: 'Georgia', 'Times New Roman', serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,621 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="导出质量异议资料" :visible.sync="visible" width="90%" top="3vh" append-to-body destroy-on-close
|
||||||
|
:close-on-click-modal="false" @close="handleClose">
|
||||||
|
<div v-loading="loading" class="export-preview">
|
||||||
|
<div ref="pdfContent" class="pdf-content">
|
||||||
|
<!-- ========== 附件一:质量异议反馈单 ========== -->
|
||||||
|
<div class="attachment-section">
|
||||||
|
<h2 class="doc-title">质量异议反馈单</h2>
|
||||||
|
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:120px">异议反馈单位</td>
|
||||||
|
<td colspan="5">{{ customer.companyName || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">联系人</td>
|
||||||
|
<td style="width:180px">{{ customer.contactPerson || '' }}</td>
|
||||||
|
<td class="label" style="width:100px">联系电话</td>
|
||||||
|
<td colspan="3">{{ customer.contactWay || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="form-table" style="margin-top:-1px">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:60px;vertical-align:middle" :rowspan="8">情况概述<br>(用户提供)</td>
|
||||||
|
<td class="label" style="width:120px">产品名称</td>
|
||||||
|
<td style="width:180px">{{ firstCoil.itemName || '' }}</td>
|
||||||
|
<td class="label" style="width:110px">异议合同号</td>
|
||||||
|
<td>{{ firstContract.contractCode || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">合同交货量</td>
|
||||||
|
<td>{{ firstContract.orderAmount || '' }}</td>
|
||||||
|
<td class="label">牌号/钢种</td>
|
||||||
|
<td>{{ firstCoil.material || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">规格</td>
|
||||||
|
<td>{{ firstCoil.specification || '' }}</td>
|
||||||
|
<td class="label">异议量</td>
|
||||||
|
<td>{{ coilWeightSummary }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">采购日期</td>
|
||||||
|
<td>{{ detail.complaintDate | formatDate }}</td>
|
||||||
|
<td class="label">使用日期</td>
|
||||||
|
<td>{{ firstCoil.exportTime | formatDate }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">产品卷号</td>
|
||||||
|
<td colspan="3">{{ coilNoSummary }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">产品生产日期</td>
|
||||||
|
<td colspan="3">{{ firstCoil.createTime | formatDate }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">下游使用用户名称</td>
|
||||||
|
<td>{{ detail.downstreamUserName || '' }}</td>
|
||||||
|
<td class="label">电话</td>
|
||||||
|
<td>{{ detail.phone || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">使用的工程名称</td>
|
||||||
|
<td>{{ detail.projectName || '' }}</td>
|
||||||
|
<td class="label">工程使用地点</td>
|
||||||
|
<td>{{ detail.projectLocation || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="vertical-align:middle">产品用途</td>
|
||||||
|
<td colspan="3">{{ detail.productUsage || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="complaint-desc">
|
||||||
|
<div class="desc-label">产品异议描述:(缺陷描述、缺陷程度、缺陷部位、缺陷数量、发生缺陷的生产/使用工序、特殊说明等等)</div>
|
||||||
|
<div class="desc-content">{{ detail.complaintContent || '' }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stamp-area">
|
||||||
|
<div>单位盖章:</div>
|
||||||
|
<div style="margin-top:20px">日期:</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="company-section">
|
||||||
|
<div class="company-header">科伦普公司填写</div>
|
||||||
|
<table class="form-table" style="margin-top:0">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:120px">异议提交人</td>
|
||||||
|
<td>{{ currentUser }}</td>
|
||||||
|
<td class="label" style="width:80px">日期</td>
|
||||||
|
<td>{{ today }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========== 附件二:质量投诉立案、确认及处置单 ========== -->
|
||||||
|
<div class="page-break"></div>
|
||||||
|
<div class="attachment-section">
|
||||||
|
<h2 class="doc-title">附件 2</h2>
|
||||||
|
<h3 class="sub-title">质量投诉立案、确认及处置单</h3>
|
||||||
|
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:120px">收到日期</td>
|
||||||
|
<td style="width:180px">{{ detail.complaintDate | formatDate }}</td>
|
||||||
|
<td class="label" style="width:100px">投诉单编号</td>
|
||||||
|
<td>{{ detail.complaintNo || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">异议反馈单位</td>
|
||||||
|
<td>{{ customer.companyName || '' }}</td>
|
||||||
|
<td class="label">反馈人姓名</td>
|
||||||
|
<td>{{ customer.contactPerson || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">信息接收人</td>
|
||||||
|
<td>{{ detail.auditOpinion || '' }}</td>
|
||||||
|
<td class="label">联系方式</td>
|
||||||
|
<td>{{ customer.contactWay || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">订货用户及使用<br>用户名称及地址</td>
|
||||||
|
<td colspan="3">{{ customer.companyName || '' }} {{ customer.address || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">产品名称</td>
|
||||||
|
<td>{{ firstCoil.itemName || '' }}</td>
|
||||||
|
<td class="label">合同号</td>
|
||||||
|
<td>{{ firstContract.contractCode || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">合同交货量</td>
|
||||||
|
<td>{{ firstContract.orderAmount || '' }}</td>
|
||||||
|
<td class="label">未出库量</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">规格(mm)</td>
|
||||||
|
<td>{{ firstCoil.specification || '' }}</td>
|
||||||
|
<td class="label">产品钢种/牌号</td>
|
||||||
|
<td>{{ firstCoil.material || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">异议量</td>
|
||||||
|
<td>{{ coilWeightSummary }}</td>
|
||||||
|
<td class="label">产品用途</td>
|
||||||
|
<td>{{ detail.productUsage || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="complaint-desc">
|
||||||
|
<div class="desc-label">问题描述:(产品卷号、产品生产日期、缺陷名称、缺陷描述、缺陷程度、缺陷数量、发生问题的生产工序等以及附加缺陷照片)</div>
|
||||||
|
<div class="desc-content">客户反馈:{{ detail.complaintContent || '' }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:100px;vertical-align:middle" :rowspan="2">问题内/<br>外部调<br>查、核<br>实、确认</td>
|
||||||
|
<td class="label" style="width:60px">内部</td>
|
||||||
|
<td>
|
||||||
|
<div>{{ prodOpinion.internalInvestigation || '' }}</div>
|
||||||
|
<div style="text-align:right;margin-top:8px">
|
||||||
|
确认人:{{ prodOpinion.internalConfirmer || '' }} 日期:{{ prodOpinion.internalConfirmDate || '' }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">外部</td>
|
||||||
|
<td>
|
||||||
|
<div>{{ prodOpinion.externalInvestigation || '' }}</div>
|
||||||
|
<div style="text-align:right;margin-top:8px">
|
||||||
|
确认人:{{ prodOpinion.externalConfirmer || '' }} 日期:{{ prodOpinion.externalConfirmDate || '' }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="form-table" style="margin-top:-1px">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:100px">责任单位</td>
|
||||||
|
<td style="width:200px">{{ prodOpinion.responsibleUnit || '' }}</td>
|
||||||
|
<td class="label" style="width:100px">接收人/日期</td>
|
||||||
|
<td>{{ prodOpinion.receiver || '' }} {{ prodOpinion.acceptDate || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="form-table" style="margin-top:-1px">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:100px;vertical-align:middle" :rowspan="2">原因分析</td>
|
||||||
|
<td class="label" style="width:70px">产生原因</td>
|
||||||
|
<td>{{ qualityOpinion.cause || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">流出原因</td>
|
||||||
|
<td>{{ qualityOpinion.escapeReason || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="form-table" style="margin-top:-1px">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:100px">纠正/预防措施</td>
|
||||||
|
<td>{{ qualityOpinion.correctiveAction || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="form-table" style="margin-top:-1px">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:100px">整改计划完成时间</td>
|
||||||
|
<td style="width:200px">{{ qualityOpinion.rectifyDate || '' }}</td>
|
||||||
|
<td class="label" style="width:100px">责任人签字/日期</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="form-table" style="margin-top:-1px">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:120px">品质部主管审核</td>
|
||||||
|
<td>{{ qualityOpinion.supervisorOpinion || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="form-table" style="margin-top:-1px">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:70px;vertical-align:middle">意见</td>
|
||||||
|
<td>
|
||||||
|
<div style="text-align:right">签字:{{ qualityOpinion.internalConfirmer || '' }} 日期:{{ qualityOpinion.internalConfirmDate || '' }}</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="vertical-align:middle">商务<br>处置</td>
|
||||||
|
<td>
|
||||||
|
<table class="inner-table">
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="width:100px">销售人员处<br>意见</td>
|
||||||
|
<td>{{ salesOpinion.handlingOpinion || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">销售部领导<br>审核意见</td>
|
||||||
|
<td>{{ salesOpinion.leaderOpinion || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label" style="vertical-align:middle">公司领导审批意<br>见</td>
|
||||||
|
<td>
|
||||||
|
<div style="min-height:40px">{{ detail.planContent || '' }}</div>
|
||||||
|
<div style="text-align:right;margin-top:8px">签字: 日期:</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========== 附件三:缺陷图片 ========== -->
|
||||||
|
<div class="page-break"></div>
|
||||||
|
<div class="attachment-section">
|
||||||
|
<h2 class="doc-title">附缺陷照片:</h2>
|
||||||
|
<div v-if="defectImages.length > 0" class="defect-grid">
|
||||||
|
<div v-for="(img, idx) in defectImages" :key="idx" class="defect-item">
|
||||||
|
<img :src="img" class="defect-img" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="empty-tip">暂无缺陷照片</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" :loading="exporting" @click="exportPdf">
|
||||||
|
<i class="el-icon-download"></i> 导出PDF
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getComplaintAccept } from "@/api/flow/complaintAccept";
|
||||||
|
import { listComplaintTask } from "@/api/flow/complaintTask";
|
||||||
|
import { listAcceptCoilRel } from "@/api/flow/acceptCoilRel";
|
||||||
|
import { getCustomer } from "@/api/crm/customer";
|
||||||
|
import { listByIds } from "@/api/system/oss";
|
||||||
|
import html2canvas from 'html2canvas';
|
||||||
|
import jsPDF from 'jspdf';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ExportPdfDialog',
|
||||||
|
filters: {
|
||||||
|
formatDate(val) {
|
||||||
|
if (!val) return '';
|
||||||
|
const d = new Date(val);
|
||||||
|
if (isNaN(d.getTime())) return val;
|
||||||
|
const y = d.getFullYear();
|
||||||
|
const m = String(d.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(d.getDate()).padStart(2, '0');
|
||||||
|
return `${y}.${m}.${day}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
loading: false,
|
||||||
|
exporting: false,
|
||||||
|
acceptId: null,
|
||||||
|
detail: {},
|
||||||
|
customer: {},
|
||||||
|
coilList: [],
|
||||||
|
taskList: [],
|
||||||
|
defectImages: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
currentUser() {
|
||||||
|
return this.$store.state.user.name || '';
|
||||||
|
},
|
||||||
|
today() {
|
||||||
|
const d = new Date();
|
||||||
|
const y = d.getFullYear();
|
||||||
|
const m = String(d.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(d.getDate()).padStart(2, '0');
|
||||||
|
return `${y}.${m}.${day}`;
|
||||||
|
},
|
||||||
|
firstCoil() {
|
||||||
|
if (this.coilList.length === 0) return {};
|
||||||
|
const rel = this.coilList[0];
|
||||||
|
return rel.coilInfo || {};
|
||||||
|
},
|
||||||
|
firstContract() {
|
||||||
|
if (this.coilList.length === 0) return {};
|
||||||
|
const rel = this.coilList[0];
|
||||||
|
const orders = (rel.coilInfo && rel.coilInfo.orderList) || [];
|
||||||
|
return orders[0] || {};
|
||||||
|
},
|
||||||
|
coilNoSummary() {
|
||||||
|
return this.coilList
|
||||||
|
.map(rel => (rel.coilInfo && rel.coilInfo.currentCoilNo) || '')
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('、');
|
||||||
|
},
|
||||||
|
coilWeightSummary() {
|
||||||
|
const weights = this.coilList
|
||||||
|
.map(rel => parseFloat((rel.coilInfo && rel.coilInfo.netWeight) || 0))
|
||||||
|
.filter(w => w > 0);
|
||||||
|
if (weights.length === 0) return '';
|
||||||
|
const total = weights.reduce((a, b) => a + b, 0);
|
||||||
|
return total.toFixed(3) + 't';
|
||||||
|
},
|
||||||
|
prodOpinion() {
|
||||||
|
return this.parseDeptOpinion(1);
|
||||||
|
},
|
||||||
|
qualityOpinion() {
|
||||||
|
return this.parseDeptOpinion(2);
|
||||||
|
},
|
||||||
|
salesOpinion() {
|
||||||
|
return this.parseDeptOpinion(3);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(acceptId) {
|
||||||
|
this.acceptId = acceptId;
|
||||||
|
this.visible = true;
|
||||||
|
this.loadData();
|
||||||
|
},
|
||||||
|
async loadData() {
|
||||||
|
this.loading = true;
|
||||||
|
try {
|
||||||
|
const [detailRes, taskRes, coilRes] = await Promise.all([
|
||||||
|
getComplaintAccept(this.acceptId),
|
||||||
|
listComplaintTask({ acceptId: this.acceptId, pageNum: 1, pageSize: 999 }),
|
||||||
|
listAcceptCoilRel({ acceptId: this.acceptId, pageNum: 1, pageSize: 999 })
|
||||||
|
]);
|
||||||
|
this.detail = detailRes.data || {};
|
||||||
|
this.taskList = (taskRes.rows || []).filter(t => t.rejectMark !== 1);
|
||||||
|
this.coilList = coilRes.rows || [];
|
||||||
|
|
||||||
|
if (this.detail.customerId) {
|
||||||
|
try {
|
||||||
|
const custRes = await getCustomer(this.detail.customerId);
|
||||||
|
this.customer = custRes.data || {};
|
||||||
|
} catch (e) {
|
||||||
|
this.customer = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.detail.file) {
|
||||||
|
try {
|
||||||
|
const fileRes = await listByIds(this.detail.file);
|
||||||
|
const files = fileRes.data || [];
|
||||||
|
this.defectImages = files.map(f => f.url).filter(Boolean);
|
||||||
|
} catch (e) {
|
||||||
|
this.defectImages = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载导出数据失败:', e);
|
||||||
|
this.$modal.msgError('加载数据失败');
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parseDeptOpinion(deptId) {
|
||||||
|
const task = this.taskList.find(t => t.deptId === deptId);
|
||||||
|
if (!task || !task.deptOpinion) return {};
|
||||||
|
try {
|
||||||
|
const obj = JSON.parse(task.deptOpinion);
|
||||||
|
return obj && typeof obj === 'object' ? obj : {};
|
||||||
|
} catch (e) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleClose() {
|
||||||
|
this.detail = {};
|
||||||
|
this.customer = {};
|
||||||
|
this.coilList = [];
|
||||||
|
this.taskList = [];
|
||||||
|
this.defectImages = [];
|
||||||
|
},
|
||||||
|
async exportPdf() {
|
||||||
|
const element = this.$refs.pdfContent;
|
||||||
|
if (!element) return;
|
||||||
|
this.exporting = true;
|
||||||
|
try {
|
||||||
|
const canvas = await html2canvas(element, {
|
||||||
|
scale: 2,
|
||||||
|
useCORS: true,
|
||||||
|
logging: false,
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
windowWidth: 794
|
||||||
|
});
|
||||||
|
const imgData = canvas.toDataURL('image/png');
|
||||||
|
const pdf = new jsPDF('p', 'mm', 'a4');
|
||||||
|
const pdfWidth = pdf.internal.pageSize.getWidth();
|
||||||
|
const pageHeight = pdf.internal.pageSize.getHeight();
|
||||||
|
const imgWidth = pdfWidth;
|
||||||
|
const imgHeight = (canvas.height * imgWidth) / canvas.width;
|
||||||
|
|
||||||
|
if (imgHeight <= pageHeight) {
|
||||||
|
pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight);
|
||||||
|
} else {
|
||||||
|
let posY = 0;
|
||||||
|
const ratio = pdfWidth / canvas.width;
|
||||||
|
const pageCanvasHeight = pageHeight / ratio;
|
||||||
|
while (posY < canvas.height) {
|
||||||
|
if (posY > 0) pdf.addPage();
|
||||||
|
const pieceCanvas = document.createElement('canvas');
|
||||||
|
pieceCanvas.width = canvas.width;
|
||||||
|
pieceCanvas.height = Math.min(pageCanvasHeight, canvas.height - posY);
|
||||||
|
const ctx = pieceCanvas.getContext('2d');
|
||||||
|
ctx.drawImage(canvas, 0, posY, canvas.width, pieceCanvas.height, 0, 0, canvas.width, pieceCanvas.height);
|
||||||
|
const pieceData = pieceCanvas.toDataURL('image/png');
|
||||||
|
pdf.addImage(pieceData, 'PNG', 0, 0, imgWidth, pieceCanvas.height * ratio);
|
||||||
|
posY += pageCanvasHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pdf.save(`${this.detail.complaintNo || '售后单'}_质量异议全套资料.pdf`);
|
||||||
|
this.$modal.msgSuccess('PDF导出成功');
|
||||||
|
this.visible = false;
|
||||||
|
} catch (err) {
|
||||||
|
console.error('PDF导出失败:', err);
|
||||||
|
this.$modal.msgError('PDF导出失败');
|
||||||
|
} finally {
|
||||||
|
this.exporting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.export-preview {
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-content {
|
||||||
|
width: 794px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 40px 50px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachment-section {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-break {
|
||||||
|
page-break-after: always;
|
||||||
|
break-after: page;
|
||||||
|
height: 1px;
|
||||||
|
margin: 20px 0;
|
||||||
|
border-top: 1px dashed #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
font-family: 'SimSun', 'Noto Serif SC', serif;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
font-family: 'SimSun', 'Noto Serif SC', serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: 1px solid #000;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-table td {
|
||||||
|
border: 1px solid #000;
|
||||||
|
padding: 6px 8px;
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-table .label {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-table td {
|
||||||
|
border: 1px solid #000;
|
||||||
|
padding: 6px 8px;
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.complaint-desc {
|
||||||
|
border: 1px solid #000;
|
||||||
|
border-top: none;
|
||||||
|
padding: 10px 12px;
|
||||||
|
min-height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-content {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.8;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stamp-area {
|
||||||
|
border: 1px solid #000;
|
||||||
|
border-top: none;
|
||||||
|
padding: 16px 12px;
|
||||||
|
min-height: 60px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-section {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-header {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defect-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defect-item {
|
||||||
|
flex: 0 0 calc(50% - 6px);
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defect-img {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
object-fit: contain;
|
||||||
|
max-height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-tip {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
padding: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,8 +8,6 @@
|
|||||||
<el-step title="待审核" icon="el-icon-document" />
|
<el-step title="待审核" icon="el-icon-document" />
|
||||||
<el-step title="意见填写" icon="el-icon-edit-outline" />
|
<el-step title="意见填写" icon="el-icon-edit-outline" />
|
||||||
<el-step title="汇总方案" icon="el-icon-s-data" />
|
<el-step title="汇总方案" icon="el-icon-s-data" />
|
||||||
<el-step title="执行反馈" icon="el-icon-s-promotion" />
|
|
||||||
<el-step title="执行完成" icon="el-icon-success" />
|
|
||||||
<el-step title="全部办结" icon="el-icon-circle-check" />
|
<el-step title="全部办结" icon="el-icon-circle-check" />
|
||||||
</el-steps>
|
</el-steps>
|
||||||
<div class="current-status">
|
<div class="current-status">
|
||||||
@@ -34,15 +32,13 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
/**
|
/**
|
||||||
* el-steps 的 active 属性是从 0 开始索引的。
|
* el-steps active 从 0 开始。
|
||||||
* 当 status=1 时 active=0(待审核高亮),
|
* 1=待审核→0, 2=意见填写→1, 3=汇总方案→2, 4=全部办结→3
|
||||||
* status=2 时 active=1(已完成待审核+意见填写中高亮),依此类推。
|
|
||||||
* status=5(执行完成)和 status=6(全部办结)共享第5步作为已完成状态。
|
|
||||||
*/
|
*/
|
||||||
activeStep() {
|
activeStep() {
|
||||||
if (this.flowStatus == null) return -1;
|
if (this.flowStatus == null) return -1;
|
||||||
const v = Number(this.flowStatus);
|
const v = Number(this.flowStatus);
|
||||||
if (v >= 6) return 5; // 全部办结 -> 第5步已完成
|
if (v >= 4) return 3;
|
||||||
return v - 1;
|
return v - 1;
|
||||||
},
|
},
|
||||||
flowStatusText() {
|
flowStatusText() {
|
||||||
@@ -50,9 +46,7 @@ export default {
|
|||||||
1: '待审核',
|
1: '待审核',
|
||||||
2: '意见填写中',
|
2: '意见填写中',
|
||||||
3: '待汇总方案',
|
3: '待汇总方案',
|
||||||
4: '执行反馈中',
|
4: '全部办结'
|
||||||
5: '执行完成',
|
|
||||||
6: '全部办结'
|
|
||||||
};
|
};
|
||||||
return map[this.flowStatus] || '未知';
|
return map[this.flowStatus] || '未知';
|
||||||
},
|
},
|
||||||
@@ -61,9 +55,7 @@ export default {
|
|||||||
1: 'info',
|
1: 'info',
|
||||||
2: 'warning',
|
2: 'warning',
|
||||||
3: '',
|
3: '',
|
||||||
4: 'warning',
|
4: 'success'
|
||||||
5: 'success',
|
|
||||||
6: 'success'
|
|
||||||
};
|
};
|
||||||
return map[this.flowStatus] || '';
|
return map[this.flowStatus] || '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
<span v-if="meta.complaintDate" title="投诉日期"><i class="el-icon-date"></i> 投诉日期:{{ parseTime(meta.complaintDate, '{y}-{m}-{d}') }}</span>
|
<span v-if="meta.complaintDate" title="投诉日期"><i class="el-icon-date"></i> 投诉日期:{{ parseTime(meta.complaintDate, '{y}-{m}-{d}') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<slot name="flow-overview"></slot>
|
||||||
|
|
||||||
<slot name="basic-info"></slot>
|
<slot name="basic-info"></slot>
|
||||||
<slot name="contract-info"></slot>
|
<slot name="contract-info"></slot>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,9 +60,7 @@ export default {
|
|||||||
1: '待审核',
|
1: '待审核',
|
||||||
2: '意见填写中',
|
2: '意见填写中',
|
||||||
3: '待汇总方案',
|
3: '待汇总方案',
|
||||||
4: '执行反馈中',
|
4: '全部办结'
|
||||||
5: '执行完成',
|
|
||||||
6: '全部办结'
|
|
||||||
};
|
};
|
||||||
return map[this.flowStatus] || '未知';
|
return map[this.flowStatus] || '未知';
|
||||||
},
|
},
|
||||||
@@ -69,9 +69,7 @@ export default {
|
|||||||
1: 'info',
|
1: 'info',
|
||||||
2: 'warning',
|
2: 'warning',
|
||||||
3: '',
|
3: '',
|
||||||
4: 'warning',
|
4: 'success'
|
||||||
5: 'success',
|
|
||||||
6: 'success'
|
|
||||||
};
|
};
|
||||||
return map[this.flowStatus] || '';
|
return map[this.flowStatus] || '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,7 @@
|
|||||||
<el-option label="待审核" :value="1" />
|
<el-option label="待审核" :value="1" />
|
||||||
<el-option label="意见填写中" :value="2" />
|
<el-option label="意见填写中" :value="2" />
|
||||||
<el-option label="待汇总方案" :value="3" />
|
<el-option label="待汇总方案" :value="3" />
|
||||||
<el-option label="执行反馈中" :value="4" />
|
<el-option label="全部办结" :value="4" />
|
||||||
<el-option label="执行完成" :value="5" />
|
|
||||||
<el-option label="全部办结" :value="6" />
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -40,11 +38,11 @@
|
|||||||
<el-tag v-if="item.flowStatus === 1" type="info" size="mini">待审核</el-tag>
|
<el-tag v-if="item.flowStatus === 1" type="info" size="mini">待审核</el-tag>
|
||||||
<el-tag v-else-if="item.flowStatus === 2" type="warning" size="mini">意见填写中</el-tag>
|
<el-tag v-else-if="item.flowStatus === 2" type="warning" size="mini">意见填写中</el-tag>
|
||||||
<el-tag v-else-if="item.flowStatus === 3" size="mini">待汇总方案</el-tag>
|
<el-tag v-else-if="item.flowStatus === 3" size="mini">待汇总方案</el-tag>
|
||||||
<el-tag v-else-if="item.flowStatus === 4" type="warning" size="mini">执行反馈中</el-tag>
|
<el-tag v-else-if="item.flowStatus === 4" type="success" size="mini">全部办结</el-tag>
|
||||||
<el-tag v-else-if="item.flowStatus === 5" type="success" size="mini">执行完成</el-tag>
|
|
||||||
<el-tag v-else-if="item.flowStatus === 6" type="success" size="mini">全部办结</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="item-actions">
|
<div class="item-actions">
|
||||||
|
<el-button v-if="item.flowStatus === 4" size="mini" type="text" icon="el-icon-download"
|
||||||
|
@click.stop="handleExportPdf(item)" title="导出PDF"></el-button>
|
||||||
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(item)"></el-button>
|
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(item)"></el-button>
|
||||||
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(item)"></el-button>
|
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(item)"></el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,7 +74,7 @@
|
|||||||
:disabled="pdfLoading" title="导出PDF">导出PDF</el-button> -->
|
:disabled="pdfLoading" title="导出PDF">导出PDF</el-button> -->
|
||||||
<el-button v-if="currentRow.flowStatus === 1" size="mini" type="primary" plain
|
<el-button v-if="currentRow.flowStatus === 1" size="mini" type="primary" plain
|
||||||
icon="el-icon-s-promotion" @click="handleOpinionDispatch">意见下发</el-button>
|
icon="el-icon-s-promotion" @click="handleOpinionDispatch">意见下发</el-button>
|
||||||
<el-button v-if="currentRow.flowStatus === 3" size="mini" type="warning" plain
|
<el-button v-if="false" size="mini" type="warning" plain
|
||||||
icon="el-icon-s-promotion" @click="handleFeedbackDispatch">执行下发</el-button>
|
icon="el-icon-s-promotion" @click="handleFeedbackDispatch">执行下发</el-button>
|
||||||
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail"
|
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail"
|
||||||
title="刷新详情">刷新</el-button>
|
title="刷新详情">刷新</el-button>
|
||||||
@@ -85,6 +83,10 @@
|
|||||||
@click="handleDelete(currentRow)">删除</el-button>
|
@click="handleDelete(currentRow)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #flow-overview>
|
||||||
|
<FlowOverviewSection :flowStatus="currentRow.flowStatus" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #basic-info>
|
<template #basic-info>
|
||||||
<BasicInfoSection :data="currentRow" />
|
<BasicInfoSection :data="currentRow" />
|
||||||
</template>
|
</template>
|
||||||
@@ -92,8 +94,6 @@
|
|||||||
|
|
||||||
<el-divider />
|
<el-divider />
|
||||||
|
|
||||||
<FlowOverviewSection :flowStatus="currentRow.flowStatus" />
|
|
||||||
|
|
||||||
<CoilInfoSection :coilList="coilList" :loading="coilLoading" :editable="currentRow.flowStatus === 1"
|
<CoilInfoSection :coilList="coilList" :loading="coilLoading" :editable="currentRow.flowStatus === 1"
|
||||||
@refresh="loadCoilList(currentRow.acceptId)"
|
@refresh="loadCoilList(currentRow.acceptId)"
|
||||||
@remove="handleRemoveCoil">
|
@remove="handleRemoveCoil">
|
||||||
@@ -114,8 +114,11 @@
|
|||||||
<div class="section-gap" />
|
<div class="section-gap" />
|
||||||
<HandlingSchemeSection :content="currentRow.planContent" :editable="currentRow.flowStatus === 3" @save="handleSavePlan" />
|
<HandlingSchemeSection :content="currentRow.planContent" :editable="currentRow.flowStatus === 3" @save="handleSavePlan" />
|
||||||
|
|
||||||
|
<div class="section-gap" />
|
||||||
|
<template v-if="false">
|
||||||
<div class="section-gap" />
|
<div class="section-gap" />
|
||||||
<ExecutionFeedbackSection :executeList="executeList" @refresh="refreshExecuteList" />
|
<ExecutionFeedbackSection :executeList="executeList" @refresh="refreshExecuteList" />
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -131,10 +134,25 @@
|
|||||||
placeholder="请选择投诉日期" style="width:100%" />
|
placeholder="请选择投诉日期" style="width:100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="投诉情况" prop="complaintContent">
|
<el-form-item label="投诉情况" prop="complaintContent">
|
||||||
<el-input v-model="form.complaintContent" type="textarea" :rows="4" placeholder="请输入投诉情况描述" />
|
<el-input v-model="form.complaintContent" type="textarea" :rows="4" placeholder="请输入投诉情况(含客户诉求)" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="客户诉求" prop="customerDemand">
|
<el-form-item label="关联客户" prop="customerId">
|
||||||
<el-input v-model="form.customerDemand" type="textarea" :rows="3" placeholder="请输入客户诉求" />
|
<CustomerSelect v-model="form.customerId" :style="{width:'100%'}" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="下游使用用户" prop="downstreamUserName">
|
||||||
|
<el-input v-model="form.downstreamUserName" placeholder="请输入下游使用用户名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="电话" prop="phone">
|
||||||
|
<el-input v-model="form.phone" placeholder="请输入电话" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="工程名称" prop="projectName">
|
||||||
|
<el-input v-model="form.projectName" placeholder="请输入使用的工程名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="使用地点" prop="projectLocation">
|
||||||
|
<el-input v-model="form.projectLocation" placeholder="请输入工程使用地点" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="产品用途" prop="productUsage">
|
||||||
|
<el-input v-model="form.productUsage" placeholder="请输入产品用途" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="关联钢卷">
|
<el-form-item label="关联钢卷">
|
||||||
<CoilSelector :multiple="true" :filters="{ status: 1 }" placeholder="选择钢卷" @confirm="handleCoilConfirm">
|
<CoilSelector :multiple="true" :filters="{ status: 1 }" placeholder="选择钢卷" @confirm="handleCoilConfirm">
|
||||||
@@ -170,6 +188,8 @@
|
|||||||
<el-button :loading="dispatchLoading" type="primary" @click="confirmFeedbackDispatch">确 定</el-button>
|
<el-button :loading="dispatchLoading" type="primary" @click="confirmFeedbackDispatch">确 定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<ExportPdfDialog ref="exportPdfDialog" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -183,6 +203,7 @@ import jsPDF from 'jspdf';
|
|||||||
import CoilSelector from "@/components/CoilSelector/index.vue";
|
import CoilSelector from "@/components/CoilSelector/index.vue";
|
||||||
import CurrentCoilNo from "@/components/KLPService/Renderer/CurrentCoilNo.vue";
|
import CurrentCoilNo from "@/components/KLPService/Renderer/CurrentCoilNo.vue";
|
||||||
import DragResizePanel from "@/components/DragResizePanel/index.vue";
|
import DragResizePanel from "@/components/DragResizePanel/index.vue";
|
||||||
|
import CustomerSelect from "@/components/KLPService/CustomerSelect/index.vue";
|
||||||
import HeaderControlSection from "./components/HeaderControlSection.vue";
|
import HeaderControlSection from "./components/HeaderControlSection.vue";
|
||||||
import BasicInfoSection from "./components/BasicInfoSection.vue";
|
import BasicInfoSection from "./components/BasicInfoSection.vue";
|
||||||
import ContractInfoSection from "./components/ContractInfoSection.vue";
|
import ContractInfoSection from "./components/ContractInfoSection.vue";
|
||||||
@@ -191,13 +212,15 @@ import DepartmentOpinionSection from "./components/DepartmentOpinionSection.vue"
|
|||||||
import HandlingSchemeSection from "./components/HandlingSchemeSection.vue";
|
import HandlingSchemeSection from "./components/HandlingSchemeSection.vue";
|
||||||
import ExecutionFeedbackSection from "./components/ExecutionFeedbackSection.vue";
|
import ExecutionFeedbackSection from "./components/ExecutionFeedbackSection.vue";
|
||||||
import FlowOverviewSection from "./components/FlowOverviewSection.vue";
|
import FlowOverviewSection from "./components/FlowOverviewSection.vue";
|
||||||
|
import ExportPdfDialog from "./components/ExportPdfDialog.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "AftermarketObjection",
|
name: "AftermarketObjection",
|
||||||
components: {
|
components: {
|
||||||
CoilSelector, CurrentCoilNo, DragResizePanel,
|
CoilSelector, CurrentCoilNo, DragResizePanel, CustomerSelect,
|
||||||
HeaderControlSection, BasicInfoSection, ContractInfoSection,
|
HeaderControlSection, BasicInfoSection, ContractInfoSection,
|
||||||
CoilInfoSection, DepartmentOpinionSection, HandlingSchemeSection, ExecutionFeedbackSection, FlowOverviewSection
|
CoilInfoSection, DepartmentOpinionSection, HandlingSchemeSection, ExecutionFeedbackSection, FlowOverviewSection,
|
||||||
|
ExportPdfDialog
|
||||||
},
|
},
|
||||||
dicts: ['coil_quality_status'],
|
dicts: ['coil_quality_status'],
|
||||||
data() {
|
data() {
|
||||||
@@ -235,8 +258,7 @@ export default {
|
|||||||
rules: {
|
rules: {
|
||||||
complaintNo: [{ required: true, message: "请输入售后编号", trigger: "blur" }],
|
complaintNo: [{ required: true, message: "请输入售后编号", trigger: "blur" }],
|
||||||
complaintDate: [{ required: true, message: "请选择投诉日期", trigger: "blur" }],
|
complaintDate: [{ required: true, message: "请选择投诉日期", trigger: "blur" }],
|
||||||
complaintContent: [{ required: true, message: "请输入投诉情况", trigger: "blur" }],
|
complaintContent: [{ required: true, message: "请输入投诉情况", trigger: "blur" }]
|
||||||
customerDemand: [{ required: true, message: "请输入客户诉求", trigger: "blur" }]
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -329,7 +351,12 @@ export default {
|
|||||||
complaintNo: undefined,
|
complaintNo: undefined,
|
||||||
complaintDate: undefined,
|
complaintDate: undefined,
|
||||||
complaintContent: undefined,
|
complaintContent: undefined,
|
||||||
customerDemand: undefined,
|
customerId: undefined,
|
||||||
|
downstreamUserName: undefined,
|
||||||
|
phone: undefined,
|
||||||
|
projectName: undefined,
|
||||||
|
projectLocation: undefined,
|
||||||
|
productUsage: undefined,
|
||||||
file: undefined,
|
file: undefined,
|
||||||
auditStatus: undefined,
|
auditStatus: undefined,
|
||||||
auditOpinion: undefined,
|
auditOpinion: undefined,
|
||||||
@@ -523,6 +550,9 @@ export default {
|
|||||||
this.$modal.msgSuccess("移除成功");
|
this.$modal.msgSuccess("移除成功");
|
||||||
this.loadCoilList(this.currentRow.acceptId);
|
this.loadCoilList(this.currentRow.acceptId);
|
||||||
}).catch(() => { });
|
}).catch(() => { });
|
||||||
|
},
|
||||||
|
handleExportPdf(row) {
|
||||||
|
this.$refs.exportPdfDialog.open(row.acceptId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -73,6 +73,10 @@
|
|||||||
<BasicInfoSection :data="acceptDetail" />
|
<BasicInfoSection :data="acceptDetail" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #flow-overview>
|
||||||
|
<FlowOverviewSection :flowStatus="acceptDetail.flowStatus" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #contract-info>
|
<template #contract-info>
|
||||||
<ContractInfoSection :coilList="dialogCoilList" />
|
<ContractInfoSection :coilList="dialogCoilList" />
|
||||||
</template>
|
</template>
|
||||||
@@ -80,20 +84,27 @@
|
|||||||
|
|
||||||
<el-divider />
|
<el-divider />
|
||||||
|
|
||||||
<FlowOverviewSection :flowStatus="acceptDetail.flowStatus" />
|
|
||||||
|
|
||||||
<CoilInfoSection :coilList="dialogCoilList" :loading="coilLoading" :editable="false" />
|
<CoilInfoSection :coilList="dialogCoilList" :loading="coilLoading" :editable="false" />
|
||||||
|
|
||||||
|
<div v-if="currentTask.taskStatus === 1 && opinionForm.deptOpinion" class="section-gap" />
|
||||||
|
<div v-if="currentTask.taskStatus === 1 && opinionForm.deptOpinion" class="opinion-preview-wrapper">
|
||||||
|
<div class="section-title">
|
||||||
|
<span>已提交意见 <span class="en-sub">· Submitted Opinion</span></span>
|
||||||
|
</div>
|
||||||
|
<DeptOpinionPreview :deptId="currentTask.deptId" :jsonData="opinionForm.deptOpinion" />
|
||||||
|
<div v-if="opinionForm.fillFile" class="opinion-file" style="margin-top:8px;">
|
||||||
|
<FileList :ossIds="opinionForm.fillFile" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="isEditable" class="section-gap" />
|
<div v-if="isEditable" class="section-gap" />
|
||||||
<div v-if="isEditable" class="opinion-form-wrapper">
|
<div v-if="isEditable" class="opinion-form-wrapper">
|
||||||
<div class="opinion-form-section">
|
<div class="opinion-form-section">
|
||||||
<div class="section-title">
|
<div class="section-title">
|
||||||
<span>填写处理意见 <span class="en-sub">· Fill in Opinion</span></span>
|
<span>{{ currentTask.taskStatus === 1 ? '修改处理意见' : '填写处理意见' }} <span class="en-sub">· {{ currentTask.taskStatus === 1 ? 'Edit Opinion' : 'Fill in Opinion' }}</span></span>
|
||||||
</div>
|
</div>
|
||||||
<el-form ref="opinionForm" :model="opinionForm" label-width="100px">
|
<el-form ref="opinionForm" :model="opinionForm" label-width="100px">
|
||||||
<el-form-item label="处理意见" prop="deptOpinion">
|
<DeptOpinionForm :deptId="currentTask.deptId" :jsonData="opinionForm.deptOpinion" @input="val => opinionForm.deptOpinion = val" />
|
||||||
<editor v-model="opinionForm.deptOpinion" :min-height="200" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="意见文件">
|
<el-form-item label="意见文件">
|
||||||
<file-upload v-model="opinionForm.fillFile" />
|
<file-upload v-model="opinionForm.fillFile" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -121,10 +132,13 @@ import BasicInfoSection from "./components/BasicInfoSection.vue";
|
|||||||
import CoilInfoSection from "./components/CoilInfoSection.vue";
|
import CoilInfoSection from "./components/CoilInfoSection.vue";
|
||||||
import ContractInfoSection from "./components/ContractInfoSection.vue";
|
import ContractInfoSection from "./components/ContractInfoSection.vue";
|
||||||
import FlowOverviewSection from "./components/FlowOverviewSection.vue";
|
import FlowOverviewSection from "./components/FlowOverviewSection.vue";
|
||||||
|
import DeptOpinionForm from "./components/DeptOpinionForm.vue";
|
||||||
|
import DeptOpinionPreview from "./components/DeptOpinionPreview.vue";
|
||||||
|
import FileList from "@/components/FileList/index.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "AftermarketOpinion",
|
name: "AftermarketOpinion",
|
||||||
components: { DragResizePanel, HeaderControlSection, BasicInfoSection, CoilInfoSection, ContractInfoSection, FlowOverviewSection },
|
components: { DragResizePanel, HeaderControlSection, BasicInfoSection, CoilInfoSection, ContractInfoSection, FlowOverviewSection, DeptOpinionForm, DeptOpinionPreview, FileList },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -212,7 +226,7 @@ export default {
|
|||||||
},
|
},
|
||||||
canEdit(row) {
|
canEdit(row) {
|
||||||
const status = (row.acceptInfo || {}).flowStatus;
|
const status = (row.acceptInfo || {}).flowStatus;
|
||||||
return (status === 2 || status === 3) && row.taskStatus === 0;
|
return status === 2;
|
||||||
},
|
},
|
||||||
confirmCancel() {
|
confirmCancel() {
|
||||||
this.$modal.confirm('确认取消?已填写的内容将不会保存。').then(() => {
|
this.$modal.confirm('确认取消?已填写的内容将不会保存。').then(() => {
|
||||||
@@ -235,7 +249,14 @@ export default {
|
|||||||
}).catch(() => { }).finally(() => { this.rejectLoading = false; });
|
}).catch(() => { }).finally(() => { this.rejectLoading = false; });
|
||||||
},
|
},
|
||||||
submitOpinion() {
|
submitOpinion() {
|
||||||
if (!this.opinionForm.deptOpinion) {
|
try {
|
||||||
|
const data = JSON.parse(this.opinionForm.deptOpinion || '{}');
|
||||||
|
const hasContent = Object.values(data).some(v => v);
|
||||||
|
if (!hasContent) {
|
||||||
|
this.$modal.msgWarning("请至少填写一项处理意见");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
this.$modal.msgWarning("请填写处理意见");
|
this.$modal.msgWarning("请填写处理意见");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -457,6 +478,10 @@ export default {
|
|||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opinion-preview-wrapper {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.opinion-form-section {
|
.opinion-form-section {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
464
klp-ui/src/views/wms/post/objection/summary.vue
Normal file
464
klp-ui/src/views/wms/post/objection/summary.vue
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container objection-container">
|
||||||
|
<DragResizePanel :initialSize="280" :minSize="280" :maxSize="600">
|
||||||
|
<template #panelA>
|
||||||
|
<div class="left-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<div class="header-title">
|
||||||
|
<i class="el-icon-s-data"></i>
|
||||||
|
<span>意见汇总</span>
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-refresh" @click="getList" style="margin-left:4px;"
|
||||||
|
title="刷新列表"></el-button>
|
||||||
|
</div>
|
||||||
|
<el-select v-model="queryParams.flowStatus" placeholder="全部阶段" clearable size="mini" @change="handleQuery"
|
||||||
|
class="header-filter">
|
||||||
|
<el-option label="待汇总方案" :value="3" />
|
||||||
|
<el-option label="全部办结" :value="4" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-row">
|
||||||
|
<el-input v-model="queryParams.complaintNo" placeholder="搜索售后编号..." clearable prefix-icon="el-icon-search"
|
||||||
|
size="small" @keyup.enter.native="handleQuery" @clear="handleQuery" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-loading="loading" class="list-body">
|
||||||
|
<div v-for="item in dataList" :key="item.acceptId" class="list-item"
|
||||||
|
:class="{ active: currentRow && currentRow.acceptId === item.acceptId }" @click="handleRowClick(item)">
|
||||||
|
<div class="item-main">
|
||||||
|
<span class="item-title">{{ item.complaintNo }}</span>
|
||||||
|
<span class="item-sub">{{ parseTime(item.complaintDate, '{y}-{m}-{d}') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="item-meta">
|
||||||
|
<el-tag v-if="item.flowStatus === 3" size="mini">待汇总方案</el-tag>
|
||||||
|
<el-tag v-else-if="item.flowStatus === 4" type="success" size="mini">全部办结</el-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="dataList.length === 0 && !loading" class="list-empty">
|
||||||
|
<i class="el-icon-folder-opened"></i>
|
||||||
|
<span>暂无待汇总的售后单</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="list-footer">
|
||||||
|
<pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
|
||||||
|
@pagination="getList" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #panelB>
|
||||||
|
<div class="right-panel">
|
||||||
|
<div v-if="!currentRow" class="empty-tip">
|
||||||
|
<i class="el-icon-info"></i>
|
||||||
|
<span>请在左侧列表中选择一条售后单查看详情</span>
|
||||||
|
</div>
|
||||||
|
<div v-else v-loading="detailLoading" class="detail-content">
|
||||||
|
<HeaderControlSection :complaintNo="currentRow.complaintNo" :flowStatus="currentRow.flowStatus"
|
||||||
|
:meta="currentRow">
|
||||||
|
<template #actions>
|
||||||
|
<el-button v-if="currentRow.flowStatus === 3" size="mini" type="success" plain
|
||||||
|
icon="el-icon-circle-check" :loading="completeLoading" @click="handleComplete">办 结</el-button>
|
||||||
|
<el-button v-if="currentRow.flowStatus === 4" size="mini" type="primary" plain
|
||||||
|
icon="el-icon-download" @click="handleExportPdf">导出</el-button>
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail"
|
||||||
|
title="刷新详情">刷新</el-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #basic-info>
|
||||||
|
<BasicInfoSection :data="currentRow" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #flow-overview>
|
||||||
|
<FlowOverviewSection :flowStatus="currentRow.flowStatus" />
|
||||||
|
</template>
|
||||||
|
</HeaderControlSection>
|
||||||
|
|
||||||
|
<el-divider />
|
||||||
|
|
||||||
|
<CoilInfoSection :coilList="coilList" :loading="coilLoading" :editable="false"
|
||||||
|
@refresh="loadCoilList(currentRow.acceptId)" />
|
||||||
|
|
||||||
|
<div class="section-gap" />
|
||||||
|
<ContractInfoSection :coilList="coilList" />
|
||||||
|
|
||||||
|
<div class="section-gap" />
|
||||||
|
<DepartmentOpinionSection :taskList="taskList" @refresh="refreshTaskList" />
|
||||||
|
|
||||||
|
<div class="section-gap" />
|
||||||
|
<HandlingSchemeSection :content="currentRow.planContent" :editable="currentRow.flowStatus === 3" @save="handleSavePlan" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</DragResizePanel>
|
||||||
|
|
||||||
|
<ExportPdfDialog ref="exportPdfDialog" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listComplaintAccept, getComplaintAccept, updateComplaintAccept } from "@/api/flow/complaintAccept";
|
||||||
|
import { listComplaintTask } from "@/api/flow/complaintTask";
|
||||||
|
import { listAcceptCoilRel } from "@/api/flow/acceptCoilRel";
|
||||||
|
import DragResizePanel from "@/components/DragResizePanel/index.vue";
|
||||||
|
import HeaderControlSection from "./components/HeaderControlSection.vue";
|
||||||
|
import BasicInfoSection from "./components/BasicInfoSection.vue";
|
||||||
|
import ContractInfoSection from "./components/ContractInfoSection.vue";
|
||||||
|
import CoilInfoSection from "./components/CoilInfoSection.vue";
|
||||||
|
import DepartmentOpinionSection from "./components/DepartmentOpinionSection.vue";
|
||||||
|
import HandlingSchemeSection from "./components/HandlingSchemeSection.vue";
|
||||||
|
import FlowOverviewSection from "./components/FlowOverviewSection.vue";
|
||||||
|
import ExportPdfDialog from "./components/ExportPdfDialog.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "AftermarketSummary",
|
||||||
|
components: {
|
||||||
|
DragResizePanel,
|
||||||
|
HeaderControlSection, BasicInfoSection, ContractInfoSection,
|
||||||
|
CoilInfoSection, DepartmentOpinionSection, HandlingSchemeSection, FlowOverviewSection,
|
||||||
|
ExportPdfDialog
|
||||||
|
},
|
||||||
|
dicts: ['coil_quality_status'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
detailLoading: false,
|
||||||
|
coilLoading: false,
|
||||||
|
completeLoading: false,
|
||||||
|
total: 0,
|
||||||
|
dataList: [],
|
||||||
|
currentRow: null,
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
complaintNo: undefined,
|
||||||
|
flowStatus: 3
|
||||||
|
},
|
||||||
|
coilList: [],
|
||||||
|
taskList: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getList() {
|
||||||
|
this.loading = true;
|
||||||
|
listComplaintAccept(this.queryParams).then(response => {
|
||||||
|
this.dataList = response.rows;
|
||||||
|
this.total = response.total;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleQuery() {
|
||||||
|
this.queryParams.pageNum = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
handleRowClick(row) {
|
||||||
|
this.currentRow = row;
|
||||||
|
this.loadDetail(row.acceptId);
|
||||||
|
},
|
||||||
|
loadDetail(acceptId) {
|
||||||
|
this.detailLoading = true;
|
||||||
|
getComplaintAccept(acceptId).then(response => {
|
||||||
|
this.currentRow = response.data;
|
||||||
|
this.loadRelData(acceptId);
|
||||||
|
}).finally(() => { this.detailLoading = false; });
|
||||||
|
},
|
||||||
|
loadRelData(acceptId) {
|
||||||
|
this.loadCoilList(acceptId);
|
||||||
|
listComplaintTask({ acceptId, pageNum: 1, pageSize: 999 }).then(r => {
|
||||||
|
this.taskList = r.rows || [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadCoilList(acceptId) {
|
||||||
|
this.coilLoading = true;
|
||||||
|
listAcceptCoilRel({ acceptId, pageNum: 1, pageSize: 999 }).then(r => {
|
||||||
|
this.coilList = r.rows || [];
|
||||||
|
}).finally(() => { this.coilLoading = false; });
|
||||||
|
},
|
||||||
|
handleRefreshDetail() {
|
||||||
|
if (this.currentRow && this.currentRow.acceptId) {
|
||||||
|
this.loadDetail(this.currentRow.acceptId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSavePlan(planContent) {
|
||||||
|
updateComplaintAccept({ acceptId: this.currentRow.acceptId, planContent }).then(() => {
|
||||||
|
this.$modal.msgSuccess("处理方案保存成功");
|
||||||
|
this.loadDetail(this.currentRow.acceptId);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
refreshTaskList() {
|
||||||
|
if (this.currentRow && this.currentRow.acceptId) {
|
||||||
|
listComplaintTask({ acceptId: this.currentRow.acceptId, pageNum: 1, pageSize: 999 }).then(r => {
|
||||||
|
this.taskList = r.rows || [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleComplete() {
|
||||||
|
this.$modal.confirm('确认将此售后单办结?办结后部门将无法再修改意见。').then(() => {
|
||||||
|
this.completeLoading = true;
|
||||||
|
return updateComplaintAccept({ acceptId: this.currentRow.acceptId, flowStatus: 4 });
|
||||||
|
}).then(() => {
|
||||||
|
this.$modal.msgSuccess("已办结");
|
||||||
|
this.completeLoading = false;
|
||||||
|
this.loadDetail(this.currentRow.acceptId);
|
||||||
|
this.getList();
|
||||||
|
}).catch(() => { this.completeLoading = false; });
|
||||||
|
},
|
||||||
|
handleExportPdf() {
|
||||||
|
this.$refs.exportPdfDialog.open(this.currentRow.acceptId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.objection-container {
|
||||||
|
height: calc(100vh - 84px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-panel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-right: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 14px 8px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-title i {
|
||||||
|
color: #409eff;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-filter {
|
||||||
|
width: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 0 14px 10px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-body {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 12px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item:hover {
|
||||||
|
background: #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item.active {
|
||||||
|
background: #d9ecff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item.active .item-title {
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-sub {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-meta {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-empty {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 60px 0;
|
||||||
|
color: #c0c4cc;
|
||||||
|
font-size: 13px;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-empty i {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-footer {
|
||||||
|
border-top: 1px solid #e4e7ed;
|
||||||
|
padding: 2px 8px 0;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== 右侧面板 ========== */
|
||||||
|
.right-panel {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #faf8f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .detail-content {
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 28px 32px 36px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0,0,0,0.06), 0 2px 12px rgba(0,0,0,0.04);
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-tip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin: 22px 0 12px 0;
|
||||||
|
padding: 0 0 10px 0;
|
||||||
|
border-bottom: 1px solid #d4d0c8;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-gap {
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plan-content {
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #faf8f5;
|
||||||
|
border: 1px solid #e8e4de;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.8;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-data {
|
||||||
|
color: #8c8c8c;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 8px 0;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 正式表格覆写 */
|
||||||
|
.right-panel .el-table {
|
||||||
|
border: 1px solid #e8e4de !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-table thead th {
|
||||||
|
background-color: #2c3e50 !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
font-size: 11px !important;
|
||||||
|
letter-spacing: 0.5px !important;
|
||||||
|
border-bottom: none !important;
|
||||||
|
font-family: 'Georgia', 'Times New Roman', serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-table thead th .cell {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-table__body tr:hover > td {
|
||||||
|
background-color: #f7f5f0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-table--border td {
|
||||||
|
border-right: 1px solid #f0ece6 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-table--border th {
|
||||||
|
border-right: 1px solid #3a5166 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-table td {
|
||||||
|
padding: 6px 4px !important;
|
||||||
|
color: #3a3a3a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-divider--horizontal {
|
||||||
|
margin: 8px 0 4px;
|
||||||
|
background-color: #e0dcd6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-tag {
|
||||||
|
border-radius: 2px;
|
||||||
|
font-family: 'Georgia', 'Times New Roman', serif;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-tag--mini {
|
||||||
|
padding: 0 6px;
|
||||||
|
line-height: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel .el-tag--small {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -72,12 +72,14 @@
|
|||||||
<template #basic-info>
|
<template #basic-info>
|
||||||
<BasicInfoSection :data="acceptDetail" />
|
<BasicInfoSection :data="acceptDetail" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #flow-overview>
|
||||||
|
<FlowOverviewSection :flowStatus="acceptDetail.flowStatus" />
|
||||||
|
</template>
|
||||||
</HeaderControlSection>
|
</HeaderControlSection>
|
||||||
|
|
||||||
<el-divider />
|
<el-divider />
|
||||||
|
|
||||||
<FlowOverviewSection :flowStatus="acceptDetail.flowStatus" />
|
|
||||||
|
|
||||||
<CoilInfoSection :coilList="dialogCoilList" :loading="coilLoading" :editable="false" />
|
<CoilInfoSection :coilList="dialogCoilList" :loading="coilLoading" :editable="false" />
|
||||||
|
|
||||||
<ContractInfoSection :coilList="dialogCoilList" />
|
<ContractInfoSection :coilList="dialogCoilList" />
|
||||||
|
|||||||
Reference in New Issue
Block a user