package cn.iocoder.yudao.module.mes.api.qc;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
|
import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO;
|
import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportItemRespDTO;
|
import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportRespDTO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult.MesQcIndicatorResultDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult.MesQcIndicatorResultDetailDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesQcIndicatorItemTypeEnum;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesQcResultValueTypeEnum;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
|
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
|
import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
|
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
|
import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService;
|
import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService;
|
import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcLineService;
|
import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcLineService;
|
import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcLineService;
|
import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcLineService;
|
import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcService;
|
import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
|
import cn.iocoder.yudao.module.srm.api.supplier.dto.SrmSupplierRespDTO;
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.Comparator;
|
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Set;
|
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
|
/**
|
* MES 质检单数据 API 实现类
|
* <p>
|
* 四类质检单的行表结构完全一致(仅父键名不同:iqc_id / ipqc_id / oqc_id / rqc_id),
|
* 所以「取行」只写四个薄适配方法,映射逻辑一份共用。
|
*/
|
@Service
|
@Validated
|
public class MesQcReportApiImpl implements MesQcReportApi {
|
|
/**
|
* 组名合并格里「这一格让位给上面那一行」的标记值。
|
* <p>
|
* 报告侧把它原样写成 HTML 的 {@code hidden} 属性,所以值本身是什么不重要,
|
* 重要的是它非空 —— 空串在两侧渲染器里都表示「不输出这个属性」,也就是这一格照常可见。
|
*/
|
private static final String GROUP_CELL_HIDDEN = "hidden";
|
|
@Resource
|
private MesQcIqcService iqcService;
|
@Resource
|
private MesQcIpqcService ipqcService;
|
@Resource
|
private MesQcOqcService oqcService;
|
@Resource
|
private MesQcRqcService rqcService;
|
|
@Resource
|
private MesQcIqcLineService iqcLineService;
|
@Resource
|
private MesQcIpqcLineService ipqcLineService;
|
@Resource
|
private MesQcOqcLineService oqcLineService;
|
@Resource
|
private MesQcRqcLineService rqcLineService;
|
|
@Resource
|
private MesQcIndicatorResultService indicatorResultService;
|
@Resource
|
private MesQcIndicatorService indicatorService;
|
|
@Resource
|
private MesMdItemService itemService;
|
@Resource
|
private MesMdUnitMeasureService unitMeasureService;
|
@Resource
|
private MesProWorkOrderService workOrderService;
|
@Resource
|
private AdminUserApi adminUserApi;
|
@Resource
|
private SrmSupplierApi srmSupplierApi;
|
@Resource
|
private CrmCustomerApi customerApi;
|
|
@Override
|
public MesQcReportRespDTO getQcReportData(Integer qcType, Long qcId) {
|
if (qcType == null || qcId == null) {
|
return null;
|
}
|
MesQcReportRespDTO resp;
|
List<LineRow> lines;
|
Long inspectorUserId;
|
if (Objects.equals(qcType, MesQcTypeEnum.IQC.getType())) {
|
MesQcIqcDO order = iqcService.getIqc(qcId);
|
if (order == null) {
|
return null;
|
}
|
resp = common(qcType, order.getId(), order.getCode(), order.getName(), order.getTemplateId(),
|
order.getSourceDocType(), order.getSourceDocCode(), order.getItemId(), order.getCheckQuantity(),
|
order.getQualifiedQuantity(), order.getUnqualifiedQuantity(), order.getCheckResult(),
|
order.getInspectDate(), order.getStatus(), order.getRemark());
|
resp.setVendorBatch(defaultStr(order.getVendorBatch()));
|
resp.setVendorName(supplierName(order.getVendorId()));
|
lines = loadIqcLines(qcId);
|
inspectorUserId = order.getInspectorUserId();
|
} else if (Objects.equals(qcType, MesQcTypeEnum.IPQC.getType())) {
|
MesQcIpqcDO order = ipqcService.getIpqc(qcId);
|
if (order == null) {
|
return null;
|
}
|
resp = common(qcType, order.getId(), order.getCode(), order.getName(), order.getTemplateId(),
|
order.getSourceDocType(), order.getSourceDocCode(), order.getItemId(), order.getCheckQuantity(),
|
order.getQualifiedQuantity(), order.getUnqualifiedQuantity(), order.getCheckResult(),
|
order.getInspectDate(), order.getStatus(), order.getRemark());
|
resp.setWorkOrderCode(workOrderCode(order.getWorkOrderId()));
|
lines = loadIpqcLines(qcId);
|
inspectorUserId = order.getInspectorUserId();
|
} else if (Objects.equals(qcType, MesQcTypeEnum.OQC.getType())) {
|
MesQcOqcDO order = oqcService.getOqc(qcId);
|
if (order == null) {
|
return null;
|
}
|
resp = common(qcType, order.getId(), order.getCode(), order.getName(), order.getTemplateId(),
|
order.getSourceDocType(), order.getSourceDocCode(), order.getItemId(), order.getCheckQuantity(),
|
order.getQualifiedQuantity(), order.getUnqualifiedQuantity(), order.getCheckResult(),
|
order.getInspectDate(), order.getStatus(), order.getRemark());
|
resp.setBatchCode(defaultStr(order.getBatchCode()));
|
resp.setClientName(clientName(order.getClientId()));
|
lines = loadOqcLines(qcId);
|
inspectorUserId = order.getInspectorUserId();
|
} else if (Objects.equals(qcType, MesQcTypeEnum.RQC.getType())) {
|
MesQcRqcDO order = rqcService.getRqc(qcId);
|
if (order == null) {
|
return null;
|
}
|
resp = common(qcType, order.getId(), order.getCode(), order.getName(), order.getTemplateId(),
|
order.getSourceDocType(), order.getSourceDocCode(), order.getItemId(), order.getCheckQuantity(),
|
order.getQualifiedQuantity(), order.getUnqualifiedQuantity(), order.getCheckResult(),
|
order.getInspectDate(), order.getStatus(), order.getRemark());
|
resp.setBatchCode(defaultStr(order.getBatchCode()));
|
lines = loadRqcLines(qcId);
|
inspectorUserId = order.getInspectorUserId();
|
} else {
|
throw new IllegalArgumentException("暂不支持 qcType=" + qcType);
|
}
|
|
// 物料与单位:单位优先取行上的(检验时实际用的单位),缺失才回退物料的默认单位
|
MesMdItemDO item = resp.getItemId() == null ? null
|
: itemService.getItemMap(Collections.singletonList(resp.getItemId())).get(resp.getItemId());
|
if (item != null) {
|
resp.setItemCode(defaultStr(item.getCode()));
|
resp.setItemName(defaultStr(item.getName()));
|
resp.setItemSpecification(defaultStr(item.getSpecification()));
|
}
|
Map<Long, MesMdUnitMeasureDO> unitMap = unitMapOf(lines, item);
|
if (item != null) {
|
MesMdUnitMeasureDO itemUnit = unitMap.get(item.getUnitMeasureId());
|
resp.setUnitName(itemUnit == null ? "" : defaultStr(itemUnit.getName()));
|
}
|
resp.setInspectorName(userName(inspectorUserId));
|
BuiltItems built = buildItems(resp.getQcId(), qcType, lines, unitMap, item);
|
resp.setItems(built.items());
|
resp.setChildlessGroupNames(built.childlessGroupNames());
|
resp.setSynthesizedGroupNames(built.synthesizedGroupNames());
|
resp.setMissingIndicatorCount(built.missingIndicatorCount());
|
return resp;
|
}
|
|
/** 四类单据共有的单头字段 */
|
private MesQcReportRespDTO common(Integer qcType, Long qcId, String code, String name, Long templateId,
|
Integer sourceDocType, String sourceDocCode, Long itemId, BigDecimal checkQuantity,
|
BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity,
|
Integer checkResult, LocalDateTime inspectDate, Integer status, String remark) {
|
return new MesQcReportRespDTO()
|
.setQcType(qcType)
|
.setQcTypeName(qcTypeName(qcType))
|
.setQcId(qcId)
|
.setQcCode(defaultStr(code))
|
.setQcName(defaultStr(name))
|
.setTemplateId(templateId)
|
.setSourceDocType(sourceDocType)
|
.setSourceDocCode(defaultStr(sourceDocCode))
|
.setItemId(itemId)
|
.setCheckQuantity(checkQuantity)
|
.setQualifiedQuantity(qualifiedQuantity)
|
.setUnqualifiedQuantity(unqualifiedQuantity)
|
.setCheckResult(checkResult)
|
.setCheckResultText(checkResultName(checkResult))
|
.setInspectDate(inspectDate)
|
.setStatus(status)
|
.setStatusName(statusName(status))
|
.setFinished(Objects.equals(status, MesQcStatusEnum.FINISHED.getStatus()))
|
.setRemark(defaultStr(remark));
|
}
|
|
/**
|
* 检验项 = 「样品 × 指标」一行,按分组结构排好序。
|
* <p>
|
* 归属只看指标的 {@code parent_id}:被本单里别的行用 parent_id 指认的分组项就是组头,
|
* 它自己那一行连同所有子项行合成一组,组名在报告里纵向合并。三处刻意不这么做:
|
* 不用 {@code result_type IS NULL} 判分组(方向是反的,丢掉的恰好是带公式的组名、
|
* 留下的恰好是过程参数),不靠行序(行表里组头与它的子项并不相邻),也不把组头丢掉
|
* (组名与公式是分组检验项最不该丢的两样东西)。
|
*/
|
private BuiltItems buildItems(Long qcId, Integer qcType, List<LineRow> lines,
|
Map<Long, MesMdUnitMeasureDO> unitMap, MesMdItemDO item) {
|
if (CollUtil.isEmpty(lines)) {
|
return new BuiltItems(Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), 0);
|
}
|
Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(
|
convertSet(lines, LineRow::indicatorId));
|
// 样品 → 该样品的实测值明细
|
Map<Long, List<MesQcIndicatorResultDetailDO>> detailMap = Collections.emptyMap();
|
List<MesQcIndicatorResultDO> samples = indicatorResultService.getIndicatorResultListByQcIdAndType(qcId, qcType);
|
if (CollUtil.isNotEmpty(samples)) {
|
List<MesQcIndicatorResultDetailDO> details = indicatorResultService.getIndicatorResultDetailListByResultIds(
|
new ArrayList<>(convertSet(samples, MesQcIndicatorResultDO::getId)));
|
detailMap = new LinkedHashMap<>();
|
for (MesQcIndicatorResultDetailDO detail : details) {
|
detailMap.computeIfAbsent(detail.getResultId(), k -> new ArrayList<>()).add(detail);
|
}
|
}
|
|
// ① 行 → 指标;指标被删掉的行还原不出任何东西,只计数
|
List<LineRow> liveLines = new ArrayList<>(lines.size());
|
List<MesQcIndicatorDO> liveIndicators = new ArrayList<>(lines.size());
|
int missingIndicatorCount = 0;
|
for (LineRow line : lines) {
|
MesQcIndicatorDO indicator = indicatorMap.get(line.indicatorId());
|
if (indicator == null) {
|
missingIndicatorCount++;
|
continue;
|
}
|
liveLines.add(line);
|
liveIndicators.add(indicator);
|
}
|
|
// ② 组头指标可能压根没排进本单(模板只选了子项),补取出来,否则整组的组名与公式会丢
|
Map<Long, MesQcIndicatorDO> allIndicators = new LinkedHashMap<>(indicatorMap);
|
Set<Long> extraIds = new LinkedHashSet<>();
|
for (MesQcIndicatorDO indicator : liveIndicators) {
|
Long parentId = indicator.getParentId();
|
if (parentId != null && parentId != 0 && !allIndicators.containsKey(parentId)) {
|
extraIds.add(parentId);
|
}
|
}
|
if (CollUtil.isNotEmpty(extraIds)) {
|
allIndicators.putAll(indicatorService.getIndicatorMap(extraIds));
|
}
|
|
// ③ 每一行归到「组头自己的行」或「某个组的子项行」
|
Map<Long, List<Integer>> ownLinesOf = new LinkedHashMap<>();
|
Map<Long, List<Integer>> childLinesOf = new LinkedHashMap<>();
|
for (int i = 0; i < liveLines.size(); i++) {
|
Long headId = groupHeadId(liveIndicators.get(i), allIndicators);
|
if (headId == null) {
|
ownLinesOf.computeIfAbsent(liveLines.get(i).indicatorId(), k -> new ArrayList<>()).add(i);
|
} else {
|
childLinesOf.computeIfAbsent(headId, k -> new ArrayList<>()).add(i);
|
}
|
}
|
|
// ④ 顶层条目 = 组 + 独立项;组头那一行从独立项里摘出来当作组的锚点行
|
List<String> childlessGroupNames = new ArrayList<>();
|
List<String> synthesizedGroupNames = new ArrayList<>();
|
List<Entry> entries = new ArrayList<>();
|
for (Map.Entry<Long, List<Integer>> each : childLinesOf.entrySet()) {
|
Long headId = each.getKey();
|
MesQcIndicatorDO head = allIndicators.get(headId);
|
List<Integer> children = sortByIndicatorOrder(each.getValue(), liveIndicators);
|
List<Integer> own = ownLinesOf.remove(headId);
|
if (CollUtil.isEmpty(own)) {
|
synthesizedGroupNames.add(defaultStr(head.getName()));
|
}
|
entries.add(new Entry(head, own == null ? Collections.emptyList() : own, children,
|
children.get(0)));
|
}
|
for (Map.Entry<Long, List<Integer>> each : ownLinesOf.entrySet()) {
|
MesQcIndicatorDO indicator = allIndicators.get(each.getKey());
|
if (MesQcIndicatorItemTypeEnum.isGroup(indicator.getItemType())) {
|
// 指标主数据里是分组项,本单却没有属于它的子项:照常出成独立检验项,只是组不起来
|
childlessGroupNames.add(defaultStr(indicator.getName()));
|
}
|
entries.add(new Entry(indicator, each.getValue(), Collections.emptyList(), each.getValue().get(0)));
|
}
|
// 排序号缺失的排最后;同值保持行序(List.sort 稳定,比较键里再带上首行下标兜底)
|
entries.sort(Comparator.comparingInt((Entry entry) -> sortKey(entry.indicator()))
|
.thenComparingInt(Entry::firstLine));
|
|
// ⑤ 逐条目产出行,并把分组信息下发到每一行
|
List<MesQcReportItemRespDTO> items = new ArrayList<>();
|
int index = 0;
|
for (Entry entry : entries) {
|
List<MesQcReportItemRespDTO> groupRows = new ArrayList<>();
|
for (Integer lineIndex : entry.ownLines()) {
|
groupRows.addAll(expandRows(liveIndicators.get(lineIndex), liveLines.get(lineIndex),
|
samples, detailMap, unitMap, item));
|
}
|
boolean grouped = CollUtil.isNotEmpty(entry.childLines());
|
if (grouped && groupRows.isEmpty()) {
|
// 组头没有自己的行:补一行,否则组名与公式无处可放
|
groupRows.add(toItem(entry.indicator(), emptyLine(entry.indicator()), "", "", "", unitMap, item));
|
}
|
int anchorCount = groupRows.size();
|
List<MesQcReportItemRespDTO> entryRows = new ArrayList<>(groupRows);
|
for (Integer lineIndex : entry.childLines()) {
|
for (MesQcReportItemRespDTO row : expandRows(liveIndicators.get(lineIndex), liveLines.get(lineIndex),
|
samples, detailMap, unitMap, item)) {
|
row.setGroupChildName(defaultStr(liveIndicators.get(lineIndex).getName()));
|
entryRows.add(row);
|
}
|
}
|
int span = grouped ? entryRows.size() : 1;
|
for (int i = 0; i < entryRows.size(); i++) {
|
MesQcReportItemRespDTO row = entryRows.get(i);
|
row.setIndex(++index);
|
// 组名的合并格只挂在组的第一行,组内其余行整格隐藏、让位给它
|
row.setGroupSpan(i == 0 ? span : 1);
|
row.setGroupHidden(i == 0 ? "" : GROUP_CELL_HIDDEN);
|
row.setRequirement(i < anchorCount
|
? anchorRequirement(entry.indicator(), row)
|
: defaultStr(row.getStandardValue()));
|
items.add(row);
|
}
|
}
|
return new BuiltItems(items, childlessGroupNames, synthesizedGroupNames, missingIndicatorCount);
|
}
|
|
/** 装配结果:检验项本身,以及没能成组、被补了行而必须让调用方知道的那些 */
|
private record BuiltItems(List<MesQcReportItemRespDTO> items, List<String> childlessGroupNames,
|
List<String> synthesizedGroupNames, int missingIndicatorCount) {
|
}
|
|
/**
|
* 一个顶层条目:一个分组(组头指标 + 它的子项行),或一个独立检验项。
|
*
|
* @param indicator 组头的指标 / 独立项的指标
|
* @param ownLines 组头自己那些行(独立项时就是它全部的行)在行表里的下标
|
* @param childLines 组内子项行的下标,独立项恒为空
|
* @param firstLine 条目第一行在行表里的下标,排序号相同时靠它保持行序
|
*/
|
private record Entry(MesQcIndicatorDO indicator, List<Integer> ownLines, List<Integer> childLines,
|
int firstLine) {
|
}
|
|
/**
|
* 这一行的组头指标编号:{@code parent_id} 指向一个「分组项」才算数。
|
* <p>
|
* 指向录入项属于指标主数据配置有问题,不能拿它去合并单元格;
|
* 指向的指标已被删除同样不成组。
|
*/
|
private static Long groupHeadId(MesQcIndicatorDO indicator, Map<Long, MesQcIndicatorDO> allIndicators) {
|
Long parentId = indicator.getParentId();
|
if (parentId == null || parentId == 0) {
|
return null;
|
}
|
MesQcIndicatorDO head = allIndicators.get(parentId);
|
return head != null && MesQcIndicatorItemTypeEnum.isGroup(head.getItemType()) ? parentId : null;
|
}
|
|
/** 组头的「检测要求」放公式(分组项只有公式、没有规格),没配公式就照常放标准要求 */
|
private static String anchorRequirement(MesQcIndicatorDO head, MesQcReportItemRespDTO row) {
|
String formula = defaultStr(head.getFormulaText());
|
return formula.isEmpty() ? defaultStr(row.getStandardValue()) : formula;
|
}
|
|
/** 组头没排进本单时补出来的那一行:只有指标本身,没有单据行 */
|
private static LineRow emptyLine(MesQcIndicatorDO head) {
|
return new LineRow(head.getId(), head.getTool(), null, null, null, null, null, null);
|
}
|
|
/**
|
* 一个检验项摊平成若干行:多样品、一个指标被录了多次实测值都会摊平。
|
* 一行都没有(尚未录入实测值)时仍出一行,避免报告漏项。
|
*/
|
private List<MesQcReportItemRespDTO> expandRows(MesQcIndicatorDO indicator, LineRow line,
|
List<MesQcIndicatorResultDO> samples,
|
Map<Long, List<MesQcIndicatorResultDetailDO>> detailMap,
|
Map<Long, MesMdUnitMeasureDO> unitMap, MesMdItemDO item) {
|
List<MesQcReportItemRespDTO> rows = new ArrayList<>();
|
for (MesQcIndicatorResultDO sample : samples) {
|
for (MesQcIndicatorResultDetailDO detail : detailMap.getOrDefault(sample.getId(),
|
Collections.emptyList())) {
|
if (Objects.equals(detail.getIndicatorId(), line.indicatorId())) {
|
rows.add(toItem(indicator, line, sample.getCode(), detail.getValue(), detail.getRemark(),
|
unitMap, item));
|
}
|
}
|
}
|
if (rows.isEmpty()) {
|
rows.add(toItem(indicator, line, "", "", "", unitMap, item));
|
}
|
return rows;
|
}
|
|
/** 排序键:指标没设排序号的一律排最后 */
|
private static int sortKey(MesQcIndicatorDO indicator) {
|
Integer sortOrder = indicator.getSortOrder();
|
return sortOrder == null ? Integer.MAX_VALUE : sortOrder;
|
}
|
|
/** 按各行的指标排序号排,同值保持行序 */
|
private static List<Integer> sortByIndicatorOrder(List<Integer> lineIndexes,
|
List<MesQcIndicatorDO> indicators) {
|
List<Integer> sorted = new ArrayList<>(lineIndexes);
|
sorted.sort(Comparator.comparingInt((Integer i) -> sortKey(indicators.get(i)))
|
.thenComparingInt(Integer::intValue));
|
return sorted;
|
}
|
|
private MesQcReportItemRespDTO toItem(MesQcIndicatorDO indicator, LineRow line, String sampleCode, String value,
|
String detailRemark, Map<Long, MesMdUnitMeasureDO> unitMap,
|
MesMdItemDO item) {
|
MesMdUnitMeasureDO unit = unitMap.get(line.unitMeasureId());
|
if (unit == null && item != null) {
|
unit = unitMap.get(item.getUnitMeasureId());
|
}
|
return new MesQcReportItemRespDTO()
|
.setIndicatorId(indicator.getId())
|
.setIndicatorCode(defaultStr(indicator.getCode()))
|
.setIndicatorName(defaultStr(indicator.getName()))
|
.setCheckMethod(defaultStr(line.checkMethod()))
|
.setTool(defaultStr(line.tool()))
|
.setStandardValue(plain(line.standardValue()))
|
.setActualValue(defaultStr(value))
|
.setUnit(unit == null ? "" : defaultStr(unit.getName()))
|
.setUpperLimit(line.maxThreshold())
|
.setLowerLimit(line.minThreshold())
|
.setValueType(indicator.getResultType())
|
.setValueTypeName(valueTypeName(indicator.getResultType()))
|
.setSampleNo(defaultStr(sampleCode))
|
// 默认「不是子项、不参与合并」;真子项由装配那一步改写
|
.setGroupChildName("")
|
.setGroupSpan(1)
|
.setGroupHidden("")
|
.setRemark(mergeRemark(line.remark(), detailRemark));
|
}
|
|
// ==================== 取行(四类同构) ====================
|
|
private List<LineRow> loadIqcLines(Long qcId) {
|
List<MesQcIqcLineDO> lines = iqcLineService.getIqcLineListByIqcId(qcId);
|
if (CollUtil.isEmpty(lines)) {
|
return Collections.emptyList();
|
}
|
List<LineRow> rows = new ArrayList<>(lines.size());
|
for (MesQcIqcLineDO l : lines) {
|
rows.add(new LineRow(l.getIndicatorId(), l.getTool(), l.getCheckMethod(), l.getStandardValue(),
|
l.getUnitMeasureId(), l.getMaxThreshold(), l.getMinThreshold(), l.getRemark()));
|
}
|
return rows;
|
}
|
|
private List<LineRow> loadIpqcLines(Long qcId) {
|
List<MesQcIpqcLineDO> lines = ipqcLineService.getIpqcLineListByIpqcId(qcId);
|
if (CollUtil.isEmpty(lines)) {
|
return Collections.emptyList();
|
}
|
List<LineRow> rows = new ArrayList<>(lines.size());
|
for (MesQcIpqcLineDO l : lines) {
|
rows.add(new LineRow(l.getIndicatorId(), l.getTool(), l.getCheckMethod(), l.getStandardValue(),
|
l.getUnitMeasureId(), l.getMaxThreshold(), l.getMinThreshold(), l.getRemark()));
|
}
|
return rows;
|
}
|
|
private List<LineRow> loadOqcLines(Long qcId) {
|
List<MesQcOqcLineDO> lines = oqcLineService.getOqcLineListByOqcId(qcId);
|
if (CollUtil.isEmpty(lines)) {
|
return Collections.emptyList();
|
}
|
List<LineRow> rows = new ArrayList<>(lines.size());
|
for (MesQcOqcLineDO l : lines) {
|
rows.add(new LineRow(l.getIndicatorId(), l.getTool(), l.getCheckMethod(), l.getStandardValue(),
|
l.getUnitMeasureId(), l.getMaxThreshold(), l.getMinThreshold(), l.getRemark()));
|
}
|
return rows;
|
}
|
|
private List<LineRow> loadRqcLines(Long qcId) {
|
List<MesQcRqcLineDO> lines = rqcLineService.getRqcLineListByRqcId(qcId);
|
if (CollUtil.isEmpty(lines)) {
|
return Collections.emptyList();
|
}
|
List<LineRow> rows = new ArrayList<>(lines.size());
|
for (MesQcRqcLineDO l : lines) {
|
rows.add(new LineRow(l.getIndicatorId(), l.getTool(), l.getCheckMethod(), l.getStandardValue(),
|
l.getUnitMeasureId(), l.getMaxThreshold(), l.getMinThreshold(), l.getRemark()));
|
}
|
return rows;
|
}
|
|
// ==================== 关联名称 ====================
|
|
private Map<Long, MesMdUnitMeasureDO> unitMapOf(List<LineRow> lines, MesMdItemDO item) {
|
List<Long> unitIds = new ArrayList<>();
|
for (LineRow line : lines) {
|
if (line.unitMeasureId() != null) {
|
unitIds.add(line.unitMeasureId());
|
}
|
}
|
if (item != null && item.getUnitMeasureId() != null) {
|
unitIds.add(item.getUnitMeasureId());
|
}
|
return unitIds.isEmpty() ? Collections.emptyMap() : unitMeasureService.getUnitMeasureMap(unitIds);
|
}
|
|
private String supplierName(Long vendorId) {
|
if (vendorId == null) {
|
return "";
|
}
|
List<SrmSupplierRespDTO> suppliers = srmSupplierApi.getSupplierList(Collections.singleton(vendorId))
|
.getCheckedData();
|
return CollUtil.isEmpty(suppliers) ? "" : defaultStr(suppliers.get(0).getName());
|
}
|
|
private String clientName(Long clientId) {
|
if (clientId == null) {
|
return "";
|
}
|
CrmCustomerRespDTO client = customerApi.getCustomerMap(Collections.singleton(clientId)).get(clientId);
|
return client == null ? "" : defaultStr(client.getName());
|
}
|
|
private String workOrderCode(Long workOrderId) {
|
if (workOrderId == null) {
|
return "";
|
}
|
MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(workOrderId);
|
return workOrder == null ? "" : defaultStr(workOrder.getCode());
|
}
|
|
private String userName(Long userId) {
|
if (userId == null) {
|
return "";
|
}
|
AdminUserRespDTO user = adminUserApi.getUserMap(Collections.singleton(userId)).get(userId);
|
return user == null ? "" : defaultStr(user.getNickname());
|
}
|
|
// ==================== 小工具 ====================
|
|
/** 去掉无意义的小数尾零,避免报告里出现 5.0000 这种由数据库精度带出来的尾巴 */
|
private static String plain(BigDecimal value) {
|
return value == null ? "" : value.stripTrailingZeros().toPlainString();
|
}
|
|
private static String mergeRemark(String lineRemark, String detailRemark) {
|
if (StrUtil.isBlank(lineRemark)) {
|
return defaultStr(detailRemark);
|
}
|
return StrUtil.isBlank(detailRemark) ? lineRemark : lineRemark + ";" + detailRemark;
|
}
|
|
private static String defaultStr(String value) {
|
return value == null ? "" : value;
|
}
|
|
private static String qcTypeName(Integer qcType) {
|
for (MesQcTypeEnum e : MesQcTypeEnum.values()) {
|
if (Objects.equals(e.getType(), qcType)) {
|
return e.getName();
|
}
|
}
|
return "";
|
}
|
|
private static String statusName(Integer status) {
|
for (MesQcStatusEnum e : MesQcStatusEnum.values()) {
|
if (Objects.equals(e.getStatus(), status)) {
|
return e.getName();
|
}
|
}
|
return "";
|
}
|
|
private static String checkResultName(Integer checkResult) {
|
for (MesQcCheckResultEnum e : MesQcCheckResultEnum.values()) {
|
if (Objects.equals(e.getType(), checkResult)) {
|
return e.getName();
|
}
|
}
|
return "";
|
}
|
|
private static String valueTypeName(Integer resultType) {
|
for (MesQcResultValueTypeEnum e : MesQcResultValueTypeEnum.values()) {
|
if (Objects.equals(e.getType(), resultType)) {
|
return e.getName();
|
}
|
}
|
return "";
|
}
|
|
/** 四类行表字段完全一致,抽成统一形态后共用映射 */
|
private record LineRow(Long indicatorId, String tool, String checkMethod, BigDecimal standardValue,
|
Long unitMeasureId, BigDecimal maxThreshold, BigDecimal minThreshold, String remark) {
|
}
|
|
}
|