refactor: drop klp_pocketfactory/cgldb/double_rack and related code
- Remove klp-pocket module entirely (acid/galvanize1/common) - Remove klp-da OEE files (depended on pocket) - Remove klp-wms Dr* files (double-rack) - Strip double-rack code from WmsCoilPendingActionServiceImpl - Remove acid/galvanize1/double-rack datasources from prod/dev yml - Remove sql-server-api, da.oee, oee.acid config
This commit is contained in:
@@ -19,12 +19,6 @@
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-framework</artifactId>
|
||||
</dependency>
|
||||
<!-- OEE 聚合依赖 pocket 原子能力(酸轧/镀锌一线) -->
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-pocket</artifactId>
|
||||
<version>0.8.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
||||
@@ -1,884 +0,0 @@
|
||||
package com.klp.da.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.da.service.OeeWordAiAnalysisService;
|
||||
import com.klp.da.service.OeeReportJobService;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeDailySummaryVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeIdealCycleVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeLoss7Vo;
|
||||
import com.klp.pocket.acid.domain.vo.Klptcm1ProStoppageVo;
|
||||
import com.klp.pocket.acid.service.IAcidOeeService;
|
||||
import com.klp.pocket.galvanize1.service.IGalvanizeOeeService;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFRun;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFTable;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* OEE 报表对外接口(聚合层)
|
||||
*
|
||||
* 当前阶段:主要暴露酸轧线相关接口,通过 `klp-pocket` 的 {@link IAcidOeeService} 取数。
|
||||
* - 当月 summary / loss7 优先走 Redis 预计算缓存;
|
||||
* - 任意日期范围通过异步任务接口实现。
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/oee/line")
|
||||
public class OeeReportController extends BaseController {
|
||||
|
||||
private final IAcidOeeService acidOeeService;
|
||||
private final IGalvanizeOeeService galvanizeOeeService;
|
||||
private final StringRedisTemplate stringRedisTemplate;
|
||||
private final OeeReportJobService oeeReportJobService;
|
||||
private final OeeWordAiAnalysisService oeeWordAiAnalysisService;
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
|
||||
private static final String JOB_META_KEY_PATTERN = "oee:report:job:meta:%s";
|
||||
private static final String JOB_RESULT_KEY_PATTERN = "oee:report:job:result:%s";
|
||||
|
||||
/**
|
||||
* 酸轧线 OEE 日汇总(含趋势)
|
||||
*
|
||||
* 路由:GET /oee/line/acid/summary
|
||||
* 说明:
|
||||
* - 支持 startDate/endDate 参数(yyyy-MM-dd);
|
||||
* - 若不传则默认查询当前月份(1号~今天);
|
||||
* - 仅实时计算,不走缓存。
|
||||
*/
|
||||
@GetMapping("/acid/summary")
|
||||
public R<List<AcidOeeDailySummaryVo>> getAcidSummary(
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate,
|
||||
@RequestParam(required = false, defaultValue = "acid") String lineType
|
||||
) {
|
||||
String[] range = resolveDateRange(startDate, endDate);
|
||||
List<AcidOeeDailySummaryVo> dailyList = isGalvanize(lineType)
|
||||
? galvanizeOeeService.getDailySummary(range[0], range[1])
|
||||
: acidOeeService.getDailySummary(range[0], range[1]);
|
||||
return R.ok(dailyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 酸轧线 7 大损失汇总
|
||||
*
|
||||
* 路由:GET /oee/line/acid/loss7
|
||||
* 说明:
|
||||
* - 不接受 start/end 参数,固定返回“当前月份(1号~今天)”的当月预计算结果;
|
||||
* - {@code topN} 用于限制返回的损失类别条数(按损失时间降序截取)。
|
||||
*/
|
||||
@GetMapping("/acid/loss7")
|
||||
public R<List<AcidOeeLoss7Vo>> getAcidLoss7(
|
||||
@RequestParam(required = false, defaultValue = "50") Integer topN,
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate,
|
||||
@RequestParam(required = false, defaultValue = "acid") String lineType
|
||||
) {
|
||||
String[] range = resolveDateRange(startDate, endDate);
|
||||
List<AcidOeeLoss7Vo> lossList = isGalvanize(lineType)
|
||||
? galvanizeOeeService.getLoss7Summary(range[0], range[1])
|
||||
: acidOeeService.getLoss7Summary(range[0], range[1]);
|
||||
|
||||
if (topN != null && topN > 0 && lossList.size() > topN) {
|
||||
lossList = new ArrayList<>(lossList.subList(0, topN));
|
||||
}
|
||||
|
||||
return R.ok(lossList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 酸轧线停机/损失事件明细(分页)
|
||||
*
|
||||
* 路由:GET /oee/line/acid/events
|
||||
* 说明:
|
||||
* - 若未传入开始/结束时间,则默认查询当月。
|
||||
* - 当前实现为在内存中进行简单过滤与分页,后续可按需下沉到 pocket 或 Mapper。
|
||||
*/
|
||||
@GetMapping("/acid/events")
|
||||
public TableDataInfo<Klptcm1ProStoppageVo> getAcidEvents(
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime,
|
||||
@RequestParam(required = false) String stopType,
|
||||
@RequestParam(required = false) String keyword,
|
||||
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(required = false, defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(required = false, defaultValue = "acid") String lineType
|
||||
) {
|
||||
// 事件明细底层按「日期」查询,这里从时间字符串中截取日期部分
|
||||
String startDate = extractDateOrDefault(startTime, true);
|
||||
String endDate = extractDateOrDefault(endTime, false);
|
||||
|
||||
List<Klptcm1ProStoppageVo> events = isGalvanize(lineType)
|
||||
? galvanizeOeeService.getStoppageEvents(startDate, endDate)
|
||||
: acidOeeService.getStoppageEvents(startDate, endDate);
|
||||
|
||||
// 业务筛选:stopType、关键字(目前对 stopType / remark 做 contains 匹配)
|
||||
List<Klptcm1ProStoppageVo> filtered = events.stream()
|
||||
.filter(e -> {
|
||||
if (StringUtils.isNotBlank(stopType) &&
|
||||
!StringUtils.equals(stopType, e.getStopType())) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isBlank(keyword)) {
|
||||
return true;
|
||||
}
|
||||
String remark = e.getRemark();
|
||||
String type = e.getStopType();
|
||||
return (StringUtils.isNotBlank(remark) && remark.contains(keyword))
|
||||
|| (StringUtils.isNotBlank(type) && type.contains(keyword));
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
long total = filtered.size();
|
||||
int page = (pageNum == null || pageNum < 1) ? 1 : pageNum;
|
||||
int size = (pageSize == null || pageSize < 1) ? 10 : pageSize;
|
||||
int fromIndex = (page - 1) * size;
|
||||
int toIndex = Math.min(fromIndex + size, filtered.size());
|
||||
|
||||
List<Klptcm1ProStoppageVo> pageList;
|
||||
if (fromIndex >= filtered.size()) {
|
||||
pageList = new ArrayList<>();
|
||||
} else {
|
||||
pageList = filtered.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
TableDataInfo<Klptcm1ProStoppageVo> rsp = TableDataInfo.build();
|
||||
rsp.setRows(pageList);
|
||||
rsp.setTotal(total);
|
||||
return rsp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 酸轧线理论节拍(统计口径:历史优良日中位数)
|
||||
*
|
||||
* 路由:GET /oee/line/acid/idealCycle
|
||||
*/
|
||||
@GetMapping("/acid/idealCycle")
|
||||
public R<AcidOeeIdealCycleVo> getAcidIdealCycle(
|
||||
@RequestParam String startDate,
|
||||
@RequestParam String endDate,
|
||||
@RequestParam(required = false, defaultValue = "acid") String lineType
|
||||
) {
|
||||
AcidOeeIdealCycleVo data = isGalvanize(lineType)
|
||||
? galvanizeOeeService.getIdealCycle(startDate, endDate)
|
||||
: acidOeeService.getIdealCycle(startDate, endDate);
|
||||
return R.ok(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出酸轧线 OEE 报表 Word(docx)
|
||||
*
|
||||
* 路由:GET /oee/line/acid/exportWord?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd
|
||||
* 说明:
|
||||
* - 文档结构尽量贴近前端页面(表格为主,图表不嵌入);
|
||||
* - 将右侧“公式与口径说明”置于文档最上方。
|
||||
*/
|
||||
@GetMapping("/acid/exportWord")
|
||||
public void exportAcidWord(
|
||||
@RequestParam String startDate,
|
||||
@RequestParam String endDate,
|
||||
HttpServletResponse response
|
||||
) throws IOException {
|
||||
String[] range = resolveDateRange(startDate, endDate);
|
||||
String start = range[0];
|
||||
String end = range[1];
|
||||
|
||||
// 取数:按选择范围实时拉取(避免 summary/loss7 的“当月固定”逻辑)
|
||||
List<AcidOeeDailySummaryVo> summary = acidOeeService.getDailySummary(start, end);
|
||||
List<AcidOeeLoss7Vo> loss7 = acidOeeService.getLoss7Summary(start, end);
|
||||
List<Klptcm1ProStoppageVo> events = acidOeeService.getStoppageEvents(start, end);
|
||||
AcidOeeIdealCycleVo idealCycle = acidOeeService.getIdealCycle(start, end);
|
||||
|
||||
XWPFDocument doc = new XWPFDocument();
|
||||
|
||||
// 标题
|
||||
addTitle(doc, String.format("酸轧线OEE报表(%s ~ %s)", start, end));
|
||||
|
||||
// 口径说明(置顶)
|
||||
addSectionTitle(doc, "公式与口径说明");
|
||||
addParagraph(doc, "OEE 总公式:OEE = A × P × Q", true);
|
||||
addBullet(doc, "A(时间稼动率) = (负荷时间 − 停机时间) / 负荷时间");
|
||||
addBullet(doc, "P(性能稼动率,吨维度) = (理论节拍 × 产量吨) / 实际运转时间");
|
||||
addBullet(doc, "Q(良品率) = 良品吨 / 总产量吨");
|
||||
addParagraph(doc, "关键字段定义:", true);
|
||||
addBullet(doc, "负荷时间:计划生产时间扣除计划停机后的时间");
|
||||
addBullet(doc, "停机时间:所有停机/中断(按 stop_type 汇总)的总时长");
|
||||
addBullet(doc, "实际运转时间:负荷时间 − 停机时间");
|
||||
addBullet(doc, "理论节拍:按“优良日统计口径”得到的稳定节拍(分钟/吨)");
|
||||
addBullet(doc, "良品/次品:按 WMS quality_status 判断,C+/C/C-/D+/D/D- 为次品");
|
||||
|
||||
if (idealCycle != null) {
|
||||
addParagraph(doc, "当前理论节拍(统计口径):", true);
|
||||
XWPFTable t = doc.createTable(5, 2);
|
||||
setTableHeaderRow(t.getRow(0), "指标", "值");
|
||||
setTableRow(t.getRow(1), "理论节拍 (min/吨)", fmtNum(getIdealCycleTime(idealCycle), 2));
|
||||
setTableRow(t.getRow(2), "生产节拍中位数 (min/吨)", fmtNum(getMedianCycleTime(idealCycle), 2));
|
||||
setTableRow(t.getRow(3), "样本天数", String.valueOf(getSampleDays(idealCycle)));
|
||||
setTableRow(t.getRow(4), "吨数下限 (吨)", fmtNum(getMinWeightTon(idealCycle), 2));
|
||||
}
|
||||
|
||||
// 一、KPI 总览
|
||||
addSectionTitle(doc, "一、KPI 总览(酸轧线 SY)");
|
||||
addParagraph(doc, "展示所选期间酸轧线整体 OEE 及 A/P/Q 等关键指标,用于快速判断本期综合表现好坏。", false);
|
||||
AcidKpiAgg kpi = calcKpi(summary);
|
||||
XWPFTable kpiTable = doc.createTable(2, 11);
|
||||
setTableRow(kpiTable.getRow(0),
|
||||
"OEE (%)",
|
||||
"时间稼动率 A (%)",
|
||||
"性能稼动率 P_ton (%)",
|
||||
"良品率 Q (%)",
|
||||
"负荷时间 (min)",
|
||||
"停机时间 (min)",
|
||||
"运转时间 (min)",
|
||||
"总产量 (吨)",
|
||||
"总产量 (卷)",
|
||||
"良品量 (吨)",
|
||||
"次品量 (吨)"
|
||||
);
|
||||
setTableRow(kpiTable.getRow(1),
|
||||
fmtPercent1(kpi.oee),
|
||||
fmtPercent1(kpi.availability),
|
||||
fmtPercent1(kpi.performanceTon),
|
||||
fmtPercent1(kpi.quality),
|
||||
fmtInt(kpi.loadingTimeMin),
|
||||
fmtInt(kpi.downtimeMin),
|
||||
fmtInt(kpi.runTimeMin),
|
||||
fmtNum(kpi.totalOutputTon, 2),
|
||||
fmtInt(kpi.totalOutputCoil),
|
||||
fmtNum(kpi.goodOutputTon, 2),
|
||||
fmtNum(kpi.defectOutputTon, 2)
|
||||
);
|
||||
addAiAnalysisIfEnabled(doc, "KPI 总览", buildMarkdownTable(
|
||||
new String[]{"OEE(%)", "A(%)", "P_ton(%)", "Q(%)", "负荷(min)", "停机(min)", "运转(min)", "总产(吨)", "总产(卷)", "良品(吨)", "次品(吨)"},
|
||||
new String[][]{{
|
||||
fmtPercent1(kpi.oee),
|
||||
fmtPercent1(kpi.availability),
|
||||
fmtPercent1(kpi.performanceTon),
|
||||
fmtPercent1(kpi.quality),
|
||||
fmtInt(kpi.loadingTimeMin),
|
||||
fmtInt(kpi.downtimeMin),
|
||||
fmtInt(kpi.runTimeMin),
|
||||
fmtNum(kpi.totalOutputTon, 2),
|
||||
fmtInt(kpi.totalOutputCoil),
|
||||
fmtNum(kpi.goodOutputTon, 2),
|
||||
fmtNum(kpi.defectOutputTon, 2)
|
||||
}}), "区间:" + start + " ~ " + end);
|
||||
|
||||
// 二、日明细
|
||||
addSectionTitle(doc, "二、日明细(用于趋势分析)");
|
||||
addParagraph(doc, "按天拆分 A/P/Q 及产量等指标,用于观察趋势、波动点以及与重大事件的对应关系。", false);
|
||||
XWPFTable dailyTable = doc.createTable(Math.max(1, summary.size()) + 1, 11);
|
||||
setTableRow(dailyTable.getRow(0),
|
||||
"日期",
|
||||
"OEE (%)",
|
||||
"A (%)",
|
||||
"P_ton (%)",
|
||||
"Q (%)",
|
||||
"负荷 (min)",
|
||||
"停机 (min)",
|
||||
"运转 (min)",
|
||||
"总产量 (吨)",
|
||||
"总产量 (卷)",
|
||||
"良品 (吨)"
|
||||
);
|
||||
for (int i = 0; i < summary.size(); i++) {
|
||||
AcidOeeDailySummaryVo row = summary.get(i);
|
||||
setTableRow(dailyTable.getRow(i + 1),
|
||||
safeStr(row.getStatDate()),
|
||||
fmtPercent1(row.getOee()),
|
||||
fmtPercent1(row.getAvailability()),
|
||||
fmtPercent1(row.getPerformanceTon()),
|
||||
fmtPercent1(row.getQuality()),
|
||||
fmtInt(row.getLoadingTimeMin()),
|
||||
fmtInt(row.getDowntimeMin()),
|
||||
fmtInt(row.getRunTimeMin()),
|
||||
fmtNum(row.getTotalOutputTon(), 2),
|
||||
fmtInt(row.getTotalOutputCoil()),
|
||||
fmtNum(row.getGoodOutputTon(), 2)
|
||||
);
|
||||
}
|
||||
addAiAnalysisIfEnabled(doc, "日明细", buildDailySummaryMarkdown(summary, 31), "区间:" + start + " ~ " + end);
|
||||
|
||||
// 三、理论节拍(说明 + 表)
|
||||
addSectionTitle(doc, "三、理论节拍(统计口径)");
|
||||
addParagraph(doc, "基于历史“优良日”统计得到的理论节拍(中位数),用于作为性能稼动率计算的稳定标尺。", false);
|
||||
if (idealCycle == null) {
|
||||
addParagraph(doc, "(本区间未获取到理论节拍数据)", false);
|
||||
}
|
||||
|
||||
// 四、7 大损失
|
||||
addSectionTitle(doc, "四、7 大损失汇总(按 stop_type 分类)");
|
||||
addParagraph(doc, "将所有停机事件按 stop_type 归类,统计时间占比和次数,用于确定“先从哪几类损失下手改善”。", false);
|
||||
XWPFTable loss7Table = doc.createTable(Math.max(1, loss7.size()) + 1, 5);
|
||||
setTableRow(loss7Table.getRow(0),
|
||||
"损失类别",
|
||||
"损失时间 (min)",
|
||||
"占比 (%)",
|
||||
"次数",
|
||||
"平均时长 (min)"
|
||||
);
|
||||
for (int i = 0; i < loss7.size(); i++) {
|
||||
AcidOeeLoss7Vo row = loss7.get(i);
|
||||
setTableRow(loss7Table.getRow(i + 1),
|
||||
safeStr(row.getLossCategoryName()),
|
||||
fmtNum(row.getLossTimeMin(), 2),
|
||||
fmtPercent1(row.getLossTimeRate()),
|
||||
fmtInt(row.getCount()),
|
||||
fmtNum(row.getAvgDurationMin(), 2)
|
||||
);
|
||||
}
|
||||
addAiAnalysisIfEnabled(doc, "7 大损失汇总", buildLoss7Markdown(loss7, 30), "区间:" + start + " ~ " + end);
|
||||
|
||||
// 五、停机/损失事件明细
|
||||
addSectionTitle(doc, "五、停机/损失事件明细");
|
||||
addParagraph(doc, "罗列每一条停机/损失事件,包含时间段、区域、机组和备注,方便对照现场记录进行原因分析。", false);
|
||||
int eventRows = Math.max(1, events.size()) + 1;
|
||||
XWPFTable eventTable = doc.createTable(eventRows, 9);
|
||||
setTableRow(eventTable.getRow(0),
|
||||
"开始时间",
|
||||
"结束时间",
|
||||
"时长 (s)",
|
||||
"时长 (min)",
|
||||
"停机类型 (stop_type)",
|
||||
"区域",
|
||||
"机组",
|
||||
"班次",
|
||||
"备注"
|
||||
);
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
Klptcm1ProStoppageVo e = events.get(i);
|
||||
long durationSec = safeLong(e.getDuration());
|
||||
double durationMin = durationSec / 60d;
|
||||
setTableRow(eventTable.getRow(i + 1),
|
||||
safeStr(e.getStartDate()),
|
||||
safeStr(e.getEndDate()),
|
||||
String.valueOf(durationSec),
|
||||
fmtNum(durationMin, 3),
|
||||
safeStr(e.getStopType()),
|
||||
safeStr(e.getArea()),
|
||||
safeStr(e.getUnit()),
|
||||
safeStr(e.getShift()),
|
||||
safeStr(e.getRemark())
|
||||
);
|
||||
}
|
||||
addAiAnalysisIfEnabled(doc, "停机/损失事件明细", buildEventsMarkdown(events, 40), "区间:" + start + " ~ " + end);
|
||||
|
||||
String filename = String.format("酸轧线OEE报表_%s_%s.docx", start, end);
|
||||
String encoded = URLEncoder.encode(filename, StandardCharsets.UTF_8.name());
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename*=UTF-8''" + encoded);
|
||||
response.setHeader(HttpHeaders.CACHE_CONTROL, "no-store, no-cache");
|
||||
|
||||
try (ServletOutputStream os = response.getOutputStream()) {
|
||||
doc.write(os);
|
||||
os.flush();
|
||||
} finally {
|
||||
doc.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 若未显式传入日期范围,则默认当前月 [1号, 今天]。
|
||||
*/
|
||||
private boolean isGalvanize(String lineType) {
|
||||
return "galvanize1".equalsIgnoreCase(lineType) || "galvanize".equalsIgnoreCase(lineType) || "dx".equalsIgnoreCase(lineType);
|
||||
}
|
||||
|
||||
private String[] resolveDateRange(String startDate, String endDate) {
|
||||
if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
|
||||
return new String[]{startDate, endDate};
|
||||
}
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate firstDay = today.withDayOfMonth(1);
|
||||
return new String[]{firstDay.format(DATE_FORMATTER), today.format(DATE_FORMATTER)};
|
||||
}
|
||||
|
||||
/**
|
||||
* 从完整时间字符串中截取 yyyy-MM-dd;若为空则回退到当月默认范围。
|
||||
*/
|
||||
private String extractDateOrDefault(String dateTime, boolean isStart) {
|
||||
if (StringUtils.isNotBlank(dateTime)) {
|
||||
// 期望格式 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss,统一截前 10 位
|
||||
if (dateTime.length() >= 10) {
|
||||
return dateTime.substring(0, 10);
|
||||
}
|
||||
}
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate firstDay = today.withDayOfMonth(1);
|
||||
return isStart ? firstDay.format(DATE_FORMATTER) : today.format(DATE_FORMATTER);
|
||||
}
|
||||
|
||||
// ======================== Word 生成辅助方法 ========================
|
||||
|
||||
private void addTitle(XWPFDocument doc, String text) {
|
||||
XWPFParagraph p = doc.createParagraph();
|
||||
p.setAlignment(ParagraphAlignment.CENTER);
|
||||
XWPFRun r = p.createRun();
|
||||
r.setBold(true);
|
||||
r.setFontSize(16);
|
||||
r.setText(text);
|
||||
}
|
||||
|
||||
private void addSectionTitle(XWPFDocument doc, String text) {
|
||||
XWPFParagraph p = doc.createParagraph();
|
||||
p.setSpacingBefore(200);
|
||||
XWPFRun r = p.createRun();
|
||||
r.setBold(true);
|
||||
r.setFontSize(12);
|
||||
r.setText(text);
|
||||
}
|
||||
|
||||
private void addParagraph(XWPFDocument doc, String text, boolean bold) {
|
||||
XWPFParagraph p = doc.createParagraph();
|
||||
XWPFRun r = p.createRun();
|
||||
r.setBold(bold);
|
||||
r.setFontSize(11);
|
||||
r.setText(text);
|
||||
}
|
||||
|
||||
private void addBullet(XWPFDocument doc, String text) {
|
||||
XWPFParagraph p = doc.createParagraph();
|
||||
XWPFRun r = p.createRun();
|
||||
r.setFontSize(11);
|
||||
r.setText("• " + text);
|
||||
}
|
||||
|
||||
private void addAiAnalysisIfEnabled(XWPFDocument doc, String tableTitle, String tableMarkdown, String extraContext) {
|
||||
String analysis = null;
|
||||
try {
|
||||
analysis = oeeWordAiAnalysisService.analyzeTable(tableTitle, tableMarkdown, extraContext);
|
||||
} catch (Exception e) {
|
||||
// 不影响导出
|
||||
}
|
||||
if (StringUtils.isNotBlank(analysis)) {
|
||||
addParagraph(doc, "AI 分析:", true);
|
||||
// 多行按段落输出
|
||||
String[] lines = analysis.split("\\r?\\n");
|
||||
for (String line : lines) {
|
||||
if (StringUtils.isNotBlank(line)) {
|
||||
addBullet(doc, line.trim().replaceFirst("^[\\-•\\*\\d\\.\\s]+", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String buildMarkdownTable(String[] headers, String[][] rows) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("|");
|
||||
for (String h : headers) sb.append(escapePipe(h)).append("|");
|
||||
sb.append("\n|");
|
||||
for (int i = 0; i < headers.length; i++) sb.append("---|");
|
||||
sb.append("\n");
|
||||
for (String[] r : rows) {
|
||||
sb.append("|");
|
||||
for (String c : r) sb.append(escapePipe(c)).append("|");
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String escapePipe(String s) {
|
||||
if (s == null) return "";
|
||||
return s.replace("|", "\\|");
|
||||
}
|
||||
|
||||
private String buildDailySummaryMarkdown(List<AcidOeeDailySummaryVo> list, int maxRows) {
|
||||
List<AcidOeeDailySummaryVo> src = list == null ? new ArrayList<>() : list;
|
||||
int n = Math.min(src.size(), Math.max(1, maxRows));
|
||||
String[] headers = new String[]{"日期", "OEE(%)", "A(%)", "P_ton(%)", "Q(%)", "负荷(min)", "停机(min)", "运转(min)", "总产(吨)", "良品(吨)"};
|
||||
String[][] rows = new String[n][headers.length];
|
||||
for (int i = 0; i < n; i++) {
|
||||
AcidOeeDailySummaryVo r = src.get(i);
|
||||
rows[i] = new String[]{
|
||||
safeStr(r.getStatDate()),
|
||||
fmtPercent1(r.getOee()),
|
||||
fmtPercent1(r.getAvailability()),
|
||||
fmtPercent1(r.getPerformanceTon()),
|
||||
fmtPercent1(r.getQuality()),
|
||||
fmtInt(r.getLoadingTimeMin()),
|
||||
fmtInt(r.getDowntimeMin()),
|
||||
fmtInt(r.getRunTimeMin()),
|
||||
fmtNum(r.getTotalOutputTon(), 2),
|
||||
fmtNum(r.getGoodOutputTon(), 2)
|
||||
};
|
||||
}
|
||||
String md = buildMarkdownTable(headers, rows);
|
||||
if (src.size() > n) {
|
||||
md += "\n(仅展示前 " + n + " 行,已截断)\n";
|
||||
}
|
||||
return md;
|
||||
}
|
||||
|
||||
private String buildLoss7Markdown(List<AcidOeeLoss7Vo> list, int maxRows) {
|
||||
List<AcidOeeLoss7Vo> src = list == null ? new ArrayList<>() : list;
|
||||
int n = Math.min(src.size(), Math.max(1, maxRows));
|
||||
String[] headers = new String[]{"损失类别", "损失时间(min)", "占比(%)", "次数", "平均时长(min)"};
|
||||
String[][] rows = new String[n][headers.length];
|
||||
for (int i = 0; i < n; i++) {
|
||||
AcidOeeLoss7Vo r = src.get(i);
|
||||
rows[i] = new String[]{
|
||||
safeStr(r.getLossCategoryName()),
|
||||
fmtNum(r.getLossTimeMin(), 2),
|
||||
fmtPercent1(r.getLossTimeRate()),
|
||||
fmtInt(r.getCount()),
|
||||
fmtNum(r.getAvgDurationMin(), 2)
|
||||
};
|
||||
}
|
||||
String md = buildMarkdownTable(headers, rows);
|
||||
if (src.size() > n) {
|
||||
md += "\n(仅展示前 " + n + " 行,已截断)\n";
|
||||
}
|
||||
return md;
|
||||
}
|
||||
|
||||
private String buildEventsMarkdown(List<Klptcm1ProStoppageVo> list, int maxRows) {
|
||||
List<Klptcm1ProStoppageVo> src = list == null ? new ArrayList<>() : list;
|
||||
int n = Math.min(src.size(), Math.max(1, maxRows));
|
||||
String[] headers = new String[]{"开始", "结束", "时长(s)", "时长(min)", "停机类型", "区域", "机组", "备注"};
|
||||
String[][] rows = new String[n][headers.length];
|
||||
for (int i = 0; i < n; i++) {
|
||||
Klptcm1ProStoppageVo e = src.get(i);
|
||||
long durationSec = safeLong(e.getDuration());
|
||||
rows[i] = new String[]{
|
||||
safeStr(e.getStartDate()),
|
||||
safeStr(e.getEndDate()),
|
||||
String.valueOf(durationSec),
|
||||
fmtNum(durationSec / 60d, 3),
|
||||
safeStr(e.getStopType()),
|
||||
safeStr(e.getArea()),
|
||||
safeStr(e.getUnit()),
|
||||
safeStr(e.getRemark())
|
||||
};
|
||||
}
|
||||
String md = buildMarkdownTable(headers, rows);
|
||||
md += "\n总事件数:" + src.size() + "\n";
|
||||
if (src.size() > n) {
|
||||
md += "(仅展示前 " + n + " 行,已截断)\n";
|
||||
}
|
||||
return md;
|
||||
}
|
||||
|
||||
private void setTableHeaderRow(XWPFTableRow row, String c1, String c2) {
|
||||
setCellText(row.getCell(0), c1, true);
|
||||
setCellText(row.getCell(1), c2, true);
|
||||
}
|
||||
|
||||
private void setTableRow(XWPFTableRow row, String... cols) {
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
XWPFTableCell cell = row.getCell(i);
|
||||
if (cell == null) {
|
||||
cell = row.createCell();
|
||||
}
|
||||
setCellText(cell, cols[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCellText(XWPFTableCell cell, String text, boolean bold) {
|
||||
cell.removeParagraph(0);
|
||||
XWPFParagraph p = cell.addParagraph();
|
||||
XWPFRun r = p.createRun();
|
||||
r.setBold(bold);
|
||||
r.setFontSize(10);
|
||||
r.setText(text == null ? "" : text);
|
||||
}
|
||||
|
||||
private String safeStr(Object o) {
|
||||
return o == null ? "" : String.valueOf(o);
|
||||
}
|
||||
|
||||
private long safeLong(Object o) {
|
||||
if (o == null) return 0L;
|
||||
try {
|
||||
return Long.parseLong(String.valueOf(o));
|
||||
} catch (Exception ex) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
private String fmtPercent1(Object value) {
|
||||
Double v = toDouble(value);
|
||||
if (v == null) return "-";
|
||||
return String.format(Locale.ROOT, "%.1f", v);
|
||||
}
|
||||
|
||||
private String fmtNum(Object value, int scale) {
|
||||
Double v = toDouble(value);
|
||||
if (v == null) return "-";
|
||||
return String.format(Locale.ROOT, "%." + scale + "f", v);
|
||||
}
|
||||
|
||||
private String fmtInt(Object value) {
|
||||
Double v = toDouble(value);
|
||||
if (v == null) return "0";
|
||||
return String.valueOf((long) Math.round(v));
|
||||
}
|
||||
|
||||
private Double toDouble(Object value) {
|
||||
if (value == null) return null;
|
||||
if (value instanceof Number) return ((Number) value).doubleValue();
|
||||
String s = String.valueOf(value);
|
||||
if (StringUtils.isBlank(s)) return null;
|
||||
try {
|
||||
return Double.parseDouble(s);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class AcidKpiAgg {
|
||||
private double oee;
|
||||
private double availability;
|
||||
private double performanceTon;
|
||||
private double quality;
|
||||
private double loadingTimeMin;
|
||||
private double downtimeMin;
|
||||
private double runTimeMin;
|
||||
private double totalOutputTon;
|
||||
private double totalOutputCoil;
|
||||
private double goodOutputTon;
|
||||
private double defectOutputTon;
|
||||
}
|
||||
|
||||
private AcidKpiAgg calcKpi(List<AcidOeeDailySummaryVo> list) {
|
||||
AcidKpiAgg k = new AcidKpiAgg();
|
||||
if (list == null || list.isEmpty()) {
|
||||
return k;
|
||||
}
|
||||
int n = list.size();
|
||||
double sumOee = 0, sumA = 0, sumP = 0, sumQ = 0;
|
||||
double sumLoading = 0, sumDown = 0, sumRun = 0;
|
||||
double sumTotalTon = 0, sumGoodTon = 0, sumDefectTon = 0, sumCoil = 0;
|
||||
for (AcidOeeDailySummaryVo r : list) {
|
||||
sumLoading += safeNum(r.getLoadingTimeMin());
|
||||
sumDown += safeNum(r.getDowntimeMin());
|
||||
sumRun += safeNum(r.getRunTimeMin());
|
||||
sumTotalTon += safeNum(r.getTotalOutputTon());
|
||||
sumGoodTon += safeNum(r.getGoodOutputTon());
|
||||
sumDefectTon += safeNum(r.getDefectOutputTon());
|
||||
sumCoil += safeNum(r.getTotalOutputCoil());
|
||||
sumOee += safeNum(r.getOee());
|
||||
sumA += safeNum(r.getAvailability());
|
||||
sumP += safeNum(r.getPerformanceTon());
|
||||
sumQ += safeNum(r.getQuality());
|
||||
}
|
||||
double defectAgg = Math.max(0, sumTotalTon - sumGoodTon);
|
||||
k.setOee(sumOee / n);
|
||||
k.setAvailability(sumA / n);
|
||||
k.setPerformanceTon(sumP / n);
|
||||
k.setQuality(sumQ / n);
|
||||
k.setLoadingTimeMin(sumLoading);
|
||||
k.setDowntimeMin(sumDown);
|
||||
k.setRunTimeMin(sumRun);
|
||||
k.setTotalOutputTon(sumTotalTon);
|
||||
k.setTotalOutputCoil(sumCoil);
|
||||
k.setGoodOutputTon(sumGoodTon);
|
||||
k.setDefectOutputTon(defectAgg > 0 ? defectAgg : sumDefectTon);
|
||||
return k;
|
||||
}
|
||||
|
||||
private double safeNum(Object v) {
|
||||
Double d = toDouble(v);
|
||||
return d == null ? 0d : d;
|
||||
}
|
||||
|
||||
// idealCycle 字段做容错(避免 VO 字段名差异导致编译失败)
|
||||
private Object getIdealCycleTime(AcidOeeIdealCycleVo vo) {
|
||||
try {
|
||||
return vo.getClass().getMethod("getIdealCycleTimeMinPerTon").invoke(vo);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Object getMedianCycleTime(AcidOeeIdealCycleVo vo) {
|
||||
try {
|
||||
return vo.getClass().getMethod("getMedianCycleTimeMinPerTon").invoke(vo);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private int getSampleDays(AcidOeeIdealCycleVo vo) {
|
||||
try {
|
||||
Object v = vo.getClass().getMethod("getSampleDays").invoke(vo);
|
||||
Double d = toDouble(v);
|
||||
return d == null ? 0 : d.intValue();
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private Object getMinWeightTon(AcidOeeIdealCycleVo vo) {
|
||||
try {
|
||||
return vo.getClass().getMethod("getMinWeightTon").invoke(vo);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 任意日期范围异步任务(酸轧线) ========================
|
||||
|
||||
/**
|
||||
* 提交酸轧线 OEE 报表异步任务(任意日期范围)。
|
||||
*
|
||||
* 路由:POST /oee/line/acid/report-jobs
|
||||
*/
|
||||
@PostMapping("/acid/report-jobs")
|
||||
public R<OeeReportJobMeta> submitAcidReportJob(@RequestBody OeeReportJobSubmitBo body) {
|
||||
if (body == null || StringUtils.isBlank(body.getStartDate()) || StringUtils.isBlank(body.getEndDate())) {
|
||||
return R.fail("startDate/endDate 不能为空");
|
||||
}
|
||||
|
||||
String jobId = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
OeeReportJobMeta meta = new OeeReportJobMeta();
|
||||
meta.setJobId(jobId);
|
||||
meta.setStatus("PENDING");
|
||||
meta.setSubmittedAt(now.format(DATE_TIME_FORMATTER));
|
||||
meta.setStartDate(body.getStartDate());
|
||||
meta.setEndDate(body.getEndDate());
|
||||
|
||||
// 先写入 PENDING 状态
|
||||
String metaKey = String.format(JOB_META_KEY_PATTERN, jobId);
|
||||
stringRedisTemplate.opsForValue().set(metaKey, JSON.toJSONString(meta), 1, TimeUnit.DAYS);
|
||||
|
||||
boolean includeSummary = body.getIncludeSummary() == null || Boolean.TRUE.equals(body.getIncludeSummary());
|
||||
boolean includeLoss7 = body.getIncludeLoss7() == null || Boolean.TRUE.equals(body.getIncludeLoss7());
|
||||
String resultKey = String.format(JOB_RESULT_KEY_PATTERN, jobId);
|
||||
|
||||
// 异步执行实际计算
|
||||
oeeReportJobService.executeAcidReportJob(
|
||||
jobId,
|
||||
metaKey,
|
||||
resultKey,
|
||||
body.getStartDate(),
|
||||
body.getEndDate(),
|
||||
includeSummary,
|
||||
includeLoss7
|
||||
);
|
||||
|
||||
return R.ok(meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询酸轧线 OEE 报表任务状态。
|
||||
*
|
||||
* 路由:GET /oee/line/acid/report-jobs/{jobId}
|
||||
*/
|
||||
@GetMapping("/acid/report-jobs/{jobId}")
|
||||
public R<OeeReportJobMeta> getAcidReportJob(@PathVariable String jobId) {
|
||||
String metaKey = String.format(JOB_META_KEY_PATTERN, jobId);
|
||||
String json = stringRedisTemplate.opsForValue().get(metaKey);
|
||||
if (StringUtils.isBlank(json)) {
|
||||
return R.fail("任务不存在或已过期");
|
||||
}
|
||||
OeeReportJobMeta meta = JSON.parseObject(json, OeeReportJobMeta.class);
|
||||
return R.ok(meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取酸轧线 OEE 报表任务结果。
|
||||
*
|
||||
* 路由:GET /oee/line/acid/report-jobs/{jobId}/result
|
||||
*/
|
||||
@GetMapping("/acid/report-jobs/{jobId}/result")
|
||||
public R<OeeReportJobResult> getAcidReportJobResult(@PathVariable String jobId) {
|
||||
String metaKey = String.format(JOB_META_KEY_PATTERN, jobId);
|
||||
String metaJson = stringRedisTemplate.opsForValue().get(metaKey);
|
||||
if (StringUtils.isBlank(metaJson)) {
|
||||
return R.fail("任务不存在或已过期");
|
||||
}
|
||||
OeeReportJobMeta meta = JSON.parseObject(metaJson, OeeReportJobMeta.class);
|
||||
if (!"COMPLETED".equals(meta.getStatus())) {
|
||||
return R.fail("结果未就绪,当前状态:" + meta.getStatus());
|
||||
}
|
||||
|
||||
String resultKey = String.format(JOB_RESULT_KEY_PATTERN, jobId);
|
||||
String resultJson = stringRedisTemplate.opsForValue().get(resultKey);
|
||||
if (StringUtils.isBlank(resultJson)) {
|
||||
return R.fail("任务结果不存在或已过期");
|
||||
}
|
||||
|
||||
OeeReportJobResult result = JSON.parseObject(resultJson, OeeReportJobResult.class);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
// ======================== 内部 DTO ========================
|
||||
|
||||
@Data
|
||||
private static class OeeReportJobSubmitBo {
|
||||
/** 开始日期(yyyy-MM-dd) */
|
||||
private String startDate;
|
||||
/** 结束日期(yyyy-MM-dd) */
|
||||
private String endDate;
|
||||
/** 是否计算 summary(默认 true) */
|
||||
private Boolean includeSummary;
|
||||
/** 是否计算 loss7(默认 true) */
|
||||
private Boolean includeLoss7;
|
||||
/**
|
||||
* 口径开关等扩展选项(JSON 文本或键值对),当前实现暂不解析,仅作为预留字段。
|
||||
*/
|
||||
private String options;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class OeeReportJobMeta {
|
||||
private String jobId;
|
||||
/** PENDING / RUNNING / COMPLETED / FAILED / EXPIRED */
|
||||
private String status;
|
||||
private String submittedAt;
|
||||
private String startedAt;
|
||||
private String completedAt;
|
||||
private String startDate;
|
||||
private String endDate;
|
||||
private String errorMessage;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class OeeReportJobResult {
|
||||
/** 日汇总结果(用于 KPI + 趋势) */
|
||||
private List<AcidOeeDailySummaryVo> summary;
|
||||
/** 7 大损失结果 */
|
||||
private List<AcidOeeLoss7Vo> loss7;
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.klp.da.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* OEE 查询条件 Bo
|
||||
*
|
||||
* 主要用于两条产线(酸轧线、镀锌一线)的聚合查询。
|
||||
* 具体字段与 docs/oee-report-design.md 中“接口设计”保持一致。
|
||||
*/
|
||||
@Data
|
||||
public class OeeQueryBo {
|
||||
|
||||
/**
|
||||
* 开始日期(yyyy-MM-dd)
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate startDate;
|
||||
|
||||
/**
|
||||
* 结束日期(yyyy-MM-dd)
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate endDate;
|
||||
|
||||
/**
|
||||
* 产线 ID 列表,例如 ["SY", "DX1"]
|
||||
*/
|
||||
private List<String> lineIds;
|
||||
|
||||
/**
|
||||
* 事件查询:开始时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 事件查询:结束时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 7 大损失类别编码(可选)
|
||||
*/
|
||||
private String lossCategoryCode;
|
||||
|
||||
/**
|
||||
* 关键字(事件明细筛选,匹配原因/备注等)
|
||||
*/
|
||||
private String keyword;
|
||||
|
||||
/**
|
||||
* TopN 设置(7 大损失 TOP 原因等,可选)
|
||||
*/
|
||||
private Integer topN;
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.klp.da.service;
|
||||
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.da.domain.bo.OeeQueryBo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeDailySummaryVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeLoss7Vo;
|
||||
import com.klp.pocket.acid.domain.vo.Klptcm1ProStoppageVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* OEE 聚合 Service 接口(酸轧线)
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-01-31
|
||||
*/
|
||||
public interface IDaAcidOeeService {
|
||||
|
||||
/**
|
||||
* 获取 OEE 日汇总(当月走缓存,历史查询走实时)
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 日汇总列表
|
||||
*/
|
||||
List<AcidOeeDailySummaryVo> getDailySummary(OeeQueryBo bo);
|
||||
|
||||
/**
|
||||
* 获取 7 大损失汇总(当月走缓存,历史查询走实时)
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 7 大损失列表
|
||||
*/
|
||||
List<AcidOeeLoss7Vo> getLoss7Summary(OeeQueryBo bo);
|
||||
|
||||
/**
|
||||
* 获取停机事件明细(实时分页查询)
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 分页后的停机事件列表
|
||||
*/
|
||||
TableDataInfo<Klptcm1ProStoppageVo> getStoppageEvents(OeeQueryBo bo);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
package com.klp.da.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeDailySummaryVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeLoss7Vo;
|
||||
import com.klp.pocket.acid.service.IAcidOeeService;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* OEE 报表异步任务执行 Service(酸轧线)。
|
||||
*
|
||||
* 负责在后台线程中执行任意日期范围的 summary/loss7 计算,
|
||||
* 并将任务状态与结果写入 Redis。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class OeeReportJobService {
|
||||
|
||||
private final IAcidOeeService acidOeeService;
|
||||
private final StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
|
||||
/**
|
||||
* 异步执行酸轧线报表任务。
|
||||
*
|
||||
* @param jobId 任务 ID
|
||||
* @param metaKey 任务元信息 Redis key
|
||||
* @param resultKey 任务结果 Redis key
|
||||
* @param startDate 开始日期(yyyy-MM-dd)
|
||||
* @param endDate 结束日期(yyyy-MM-dd)
|
||||
* @param includeSummary 是否计算 summary
|
||||
* @param includeLoss7 是否计算 loss7
|
||||
*/
|
||||
@Async
|
||||
public void executeAcidReportJob(
|
||||
String jobId,
|
||||
String metaKey,
|
||||
String resultKey,
|
||||
String startDate,
|
||||
String endDate,
|
||||
boolean includeSummary,
|
||||
boolean includeLoss7
|
||||
) {
|
||||
try {
|
||||
// 更新状态为 RUNNING
|
||||
OeeReportJobMeta meta = readMeta(metaKey);
|
||||
if (meta == null) {
|
||||
meta = new OeeReportJobMeta();
|
||||
meta.setJobId(jobId);
|
||||
meta.setStartDate(startDate);
|
||||
meta.setEndDate(endDate);
|
||||
}
|
||||
meta.setStatus("RUNNING");
|
||||
meta.setStartedAt(LocalDateTime.now().format(DATE_TIME_FORMATTER));
|
||||
writeMeta(metaKey, meta);
|
||||
|
||||
// 实际计算
|
||||
OeeReportJobResult result = new OeeReportJobResult();
|
||||
if (includeSummary) {
|
||||
List<AcidOeeDailySummaryVo> summary =
|
||||
acidOeeService.getDailySummary(startDate, endDate);
|
||||
result.setSummary(summary);
|
||||
}
|
||||
if (includeLoss7) {
|
||||
List<AcidOeeLoss7Vo> loss7 =
|
||||
acidOeeService.getLoss7Summary(startDate, endDate);
|
||||
result.setLoss7(loss7);
|
||||
}
|
||||
|
||||
stringRedisTemplate.opsForValue()
|
||||
.set(resultKey, JSON.toJSONString(result), 1, TimeUnit.DAYS);
|
||||
|
||||
// 标记为 COMPLETED
|
||||
meta.setStatus("COMPLETED");
|
||||
meta.setCompletedAt(LocalDateTime.now().format(DATE_TIME_FORMATTER));
|
||||
writeMeta(metaKey, meta);
|
||||
} catch (Exception e) {
|
||||
log.error("[OeeReportJobService] executeAcidReportJob error, jobId={}", jobId, e);
|
||||
OeeReportJobMeta meta = readMeta(metaKey);
|
||||
if (meta == null) {
|
||||
meta = new OeeReportJobMeta();
|
||||
meta.setJobId(jobId);
|
||||
meta.setStartDate(startDate);
|
||||
meta.setEndDate(endDate);
|
||||
}
|
||||
meta.setStatus("FAILED");
|
||||
meta.setCompletedAt(LocalDateTime.now().format(DATE_TIME_FORMATTER));
|
||||
meta.setErrorMessage(e.getMessage());
|
||||
writeMeta(metaKey, meta);
|
||||
}
|
||||
}
|
||||
|
||||
private OeeReportJobMeta readMeta(String metaKey) {
|
||||
String json = stringRedisTemplate.opsForValue().get(metaKey);
|
||||
if (json == null || json.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return JSON.parseObject(json, OeeReportJobMeta.class);
|
||||
}
|
||||
|
||||
private void writeMeta(String metaKey, OeeReportJobMeta meta) {
|
||||
stringRedisTemplate.opsForValue()
|
||||
.set(metaKey, JSON.toJSONString(meta), 1, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class OeeReportJobMeta {
|
||||
private String jobId;
|
||||
private String status;
|
||||
private String submittedAt;
|
||||
private String startedAt;
|
||||
private String completedAt;
|
||||
private String startDate;
|
||||
private String endDate;
|
||||
private String errorMessage;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class OeeReportJobResult {
|
||||
private List<AcidOeeDailySummaryVo> summary;
|
||||
private List<AcidOeeLoss7Vo> loss7;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
package com.klp.da.service;
|
||||
|
||||
import com.klp.common.config.DeepseekConfig;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* OEE Word 导出:表格内容大模型分析(可选)
|
||||
*
|
||||
* 默认关闭,通过配置开启:
|
||||
* oee:
|
||||
* word:
|
||||
* ai:
|
||||
* enabled: true
|
||||
*
|
||||
* 大模型连接配置复用 sales.script.ai(DeepSeek):
|
||||
* sales:
|
||||
* script:
|
||||
* ai:
|
||||
* api-key/base-url/model-name/max-retries/temperature
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class OeeWordAiAnalysisService {
|
||||
|
||||
@Value("${oee.word.ai.enabled:false}")
|
||||
private boolean enabled;
|
||||
|
||||
@Qualifier("salesScriptRestTemplate")
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private final DeepseekConfig deepseekConfig;
|
||||
|
||||
public String analyzeTable(String tableTitle, String tableMarkdown, String extraContext) {
|
||||
if (!enabled) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isBlank(tableMarkdown)) {
|
||||
return null;
|
||||
}
|
||||
if (deepseekConfig == null || StringUtils.isBlank(deepseekConfig.getApiKey())
|
||||
|| StringUtils.isBlank(deepseekConfig.getBaseUrl())
|
||||
|| StringUtils.isBlank(deepseekConfig.getModelName())) {
|
||||
log.warn("OEE Word AI 已开启但 sales.script.ai 配置不完整,跳过分析");
|
||||
return null;
|
||||
}
|
||||
|
||||
String prompt = buildPrompt(tableTitle, tableMarkdown, extraContext);
|
||||
return callAi(prompt);
|
||||
}
|
||||
|
||||
private String buildPrompt(String tableTitle, String tableMarkdown, String extraContext) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("你是一名制造业OEE报表分析专家。请基于下面表格数据,给出简洁的分析结论。\n");
|
||||
sb.append("输出要求:\n");
|
||||
sb.append("1) 用中文输出;\n");
|
||||
sb.append("2) 只输出 3~6 条要点(每条不超过 30 字),不要写长段落;\n");
|
||||
sb.append("3) 可以指出异常/波动/占比最高项/可能原因与建议方向;\n");
|
||||
sb.append("4) 不要复述表格标题,不要输出Markdown表格。\n\n");
|
||||
sb.append("【表格】").append(tableTitle).append("\n");
|
||||
if (StringUtils.isNotBlank(extraContext)) {
|
||||
sb.append("【上下文】").append(extraContext).append("\n");
|
||||
}
|
||||
sb.append("【数据】\n");
|
||||
sb.append(tableMarkdown);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String callAi(String prompt) {
|
||||
Map<String, Object> requestBody = new HashMap<>();
|
||||
requestBody.put("model", deepseekConfig.getModelName());
|
||||
|
||||
Map<String, String> systemMessage = new HashMap<>();
|
||||
systemMessage.put("role", "system");
|
||||
systemMessage.put("content", "你是一个严谨的数据分析助手");
|
||||
|
||||
Map<String, String> userMessage = new HashMap<>();
|
||||
userMessage.put("role", "user");
|
||||
userMessage.put("content", prompt);
|
||||
|
||||
requestBody.put("messages", Arrays.asList(systemMessage, userMessage));
|
||||
requestBody.put("temperature", deepseekConfig.getTemperature() == null ? 0.2 : deepseekConfig.getTemperature());
|
||||
requestBody.put("max_tokens", 800);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setBearerAuth(deepseekConfig.getApiKey());
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
|
||||
|
||||
int retries = deepseekConfig.getMaxRetries() == null ? 1 : Math.max(1, deepseekConfig.getMaxRetries());
|
||||
for (int i = 0; i < retries; i++) {
|
||||
try {
|
||||
ResponseEntity<Map> response = restTemplate.postForEntity(
|
||||
deepseekConfig.getBaseUrl() + "/chat/completions", entity, Map.class);
|
||||
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||
Map<String, Object> body = response.getBody();
|
||||
List<Map<String, Object>> choices = (List<Map<String, Object>>) body.get("choices");
|
||||
if (choices != null && !choices.isEmpty()) {
|
||||
Map<String, Object> choice = choices.get(0);
|
||||
Map<String, Object> message = (Map<String, Object>) choice.get("message");
|
||||
String content = message == null ? null : (String) message.get("content");
|
||||
if (StringUtils.isNotBlank(content)) {
|
||||
return content.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("OEE Word AI 调用失败,重试 {}/{}:{}", i + 1, retries, e.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.klp.da.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.utils.DateUtils;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.da.domain.bo.OeeQueryBo;
|
||||
import com.klp.da.service.IDaAcidOeeService;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeDailySummaryVo;
|
||||
import com.klp.pocket.acid.domain.vo.AcidOeeLoss7Vo;
|
||||
import com.klp.pocket.acid.domain.vo.Klptcm1ProStoppageVo;
|
||||
import com.klp.pocket.acid.service.IAcidOeeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class DaAcidOeeServiceImpl implements IDaAcidOeeService {
|
||||
|
||||
private static final String SUMMARY_KEY_PATTERN = "oee:report:month:summary:%s:SY";
|
||||
private static final DateTimeFormatter YEAR_MONTH_FMT = DateTimeFormatter.ofPattern("yyyyMM");
|
||||
|
||||
private final IAcidOeeService acidOeeService;
|
||||
private final StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Override
|
||||
public List<AcidOeeDailySummaryVo> getDailySummary(OeeQueryBo bo) {
|
||||
// 检查是否查询当月,如果是,则尝试从 Redis 缓存获取
|
||||
if (isCurrentMonthQuery(bo.getStartDate(), bo.getEndDate())) {
|
||||
String yyyyMM = LocalDate.now().format(YEAR_MONTH_FMT);
|
||||
String summaryKey = String.format(SUMMARY_KEY_PATTERN, yyyyMM);
|
||||
try {
|
||||
String summaryJson = stringRedisTemplate.opsForValue().get(summaryKey);
|
||||
if (StringUtils.isNotBlank(summaryJson)) {
|
||||
log.info("[DaAcidOeeService] Hit cache for acid summary, key={}", summaryKey);
|
||||
return JSON.parseObject(summaryJson, new TypeReference<List<AcidOeeDailySummaryVo>>() {});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[DaAcidOeeService] Failed to get acid summary from redis cache, key={}", summaryKey, e);
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存未命中或查询历史数据,则实时调用 pocket service
|
||||
log.info("[DaAcidOeeService] Cache miss for acid summary, calling pocket service...");
|
||||
return acidOeeService.getDailySummary(
|
||||
DateUtils.parseDateToStr("yyyy-MM-dd", DateUtils.toDate(bo.getStartDate())),
|
||||
DateUtils.parseDateToStr("yyyy-MM-dd", DateUtils.toDate(bo.getEndDate()))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AcidOeeLoss7Vo> getLoss7Summary(OeeQueryBo bo) {
|
||||
// 7大损失目前没有预计算,直接实时调用
|
||||
return acidOeeService.getLoss7Summary(
|
||||
DateUtils.parseDateToStr("yyyy-MM-dd", DateUtils.toDate(bo.getStartDate())),
|
||||
DateUtils.parseDateToStr("yyyy-MM-dd", DateUtils.toDate(bo.getEndDate()))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<Klptcm1ProStoppageVo> getStoppageEvents(OeeQueryBo bo) {
|
||||
// 实时分页查询
|
||||
List<Klptcm1ProStoppageVo> list = acidOeeService.getStoppageEvents(
|
||||
DateUtils.parseDateToStr("yyyy-MM-dd", DateUtils.toDate(bo.getStartDate())),
|
||||
DateUtils.parseDateToStr("yyyy-MM-dd", DateUtils.toDate(bo.getEndDate()))
|
||||
);
|
||||
return TableDataInfo.build(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断查询范围是否为当月
|
||||
*/
|
||||
private boolean isCurrentMonthQuery(LocalDate startDate, LocalDate endDate) {
|
||||
if (startDate == null || endDate == null) {
|
||||
return false;
|
||||
}
|
||||
LocalDate now = LocalDate.now();
|
||||
LocalDate firstDayOfMonth = now.withDayOfMonth(1);
|
||||
return !startDate.isBefore(firstDayOfMonth) && !endDate.isAfter(now);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsAutoScheduleMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsAutoScheduleMapper">
|
||||
|
||||
<select id="selectPlanByIdForUpdate"
|
||||
parameterType="long"
|
||||
resultType="com.klp.aps.domain.row.ApsSchedulePlanRow">
|
||||
resultType="com.fad.aps.domain.row.ApsSchedulePlanRow">
|
||||
SELECT
|
||||
plan_id AS planId,
|
||||
plan_code AS planCode,
|
||||
@@ -23,7 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<select id="selectOrderDetailsByOrderId"
|
||||
parameterType="long"
|
||||
resultType="com.klp.aps.domain.row.ApsOrderDetailRow">
|
||||
resultType="com.fad.aps.domain.row.ApsOrderDetailRow">
|
||||
SELECT
|
||||
detail_id AS detailId,
|
||||
product_id AS productId,
|
||||
@@ -36,7 +36,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<select id="selectPlanDetailsByPlanId"
|
||||
parameterType="long"
|
||||
resultType="com.klp.aps.domain.row.ApsPlanDetailRow">
|
||||
resultType="com.fad.aps.domain.row.ApsPlanDetailRow">
|
||||
SELECT
|
||||
detail_id AS detailId,
|
||||
task_id AS taskId,
|
||||
@@ -50,7 +50,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<select id="selectLineCandidatesByProductAndLine"
|
||||
resultType="com.klp.aps.domain.row.ApsLineCapabilityRow">
|
||||
resultType="com.fad.aps.domain.row.ApsLineCapabilityRow">
|
||||
SELECT
|
||||
line_id AS lineId,
|
||||
capacity_per_hour AS capacityPerHour,
|
||||
@@ -63,14 +63,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
ORDER BY CASE WHEN product_id = #{productId} THEN 0 ELSE 1 END, priority ASC, capability_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectLineMetaById" resultType="com.klp.aps.domain.row.ApsLineMetaRow">
|
||||
<select id="selectLineMetaById" resultType="com.fad.aps.domain.row.ApsLineMetaRow">
|
||||
SELECT line_id AS lineId, line_name AS lineName
|
||||
FROM wms_production_line
|
||||
WHERE line_id = #{lineId}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectProductMetaById" resultType="com.klp.aps.domain.row.ApsProductMetaRow">
|
||||
<select id="selectProductMetaById" resultType="com.fad.aps.domain.row.ApsProductMetaRow">
|
||||
SELECT product_id AS productId, product_name AS productName, specification AS specification, material AS material
|
||||
FROM wms_product
|
||||
WHERE product_id = #{productId}
|
||||
@@ -78,7 +78,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<select id="selectAvailableShifts"
|
||||
resultType="com.klp.aps.domain.row.ApsShiftSlotRow">
|
||||
resultType="com.fad.aps.domain.row.ApsShiftSlotRow">
|
||||
SELECT
|
||||
cs.calendar_date AS calendarDate,
|
||||
cs.line_id AS lineId,
|
||||
@@ -146,7 +146,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<insert id="insertOperation"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleOperationEntity"
|
||||
parameterType="com.fad.aps.domain.entity.ApsScheduleOperationEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="operationId"
|
||||
keyColumn="operation_id">
|
||||
@@ -193,7 +193,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</insert>
|
||||
|
||||
<insert id="insertChangeLog"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleChangeLogEntity"
|
||||
parameterType="com.fad.aps.domain.entity.ApsScheduleChangeLogEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="logId"
|
||||
keyColumn="log_id">
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsCalendarMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsCalendarMapper">
|
||||
|
||||
<resultMap type="com.klp.aps.domain.entity.ApsCalendarEntity" id="ApsCalendarResult">
|
||||
<resultMap type="com.fad.aps.domain.entity.ApsCalendarEntity" id="ApsCalendarResult">
|
||||
<result property="calendarId" column="calendar_id"/>
|
||||
<result property="calendarDate" column="calendar_date"/>
|
||||
<result property="calendarType" column="calendar_type"/>
|
||||
@@ -22,7 +22,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
FROM wms_calendar
|
||||
</sql>
|
||||
|
||||
<select id="selectCalendarList" parameterType="com.klp.aps.domain.entity.ApsCalendarEntity" resultMap="ApsCalendarResult">
|
||||
<select id="selectCalendarList" parameterType="com.fad.aps.domain.entity.ApsCalendarEntity" resultMap="ApsCalendarResult">
|
||||
<include refid="selectCalendarVo"/>
|
||||
<where>
|
||||
<if test="calendarDate != null">
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsCalendarShiftMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsCalendarShiftMapper">
|
||||
|
||||
<select id="selectByDateLineAndShift" resultType="com.klp.aps.domain.entity.ApsCalendarShiftEntity">
|
||||
<select id="selectByDateLineAndShift" resultType="com.fad.aps.domain.entity.ApsCalendarShiftEntity">
|
||||
SELECT *
|
||||
FROM wms_calendar_shift
|
||||
WHERE calendar_date = #{calendarDate}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsGanttMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsGanttMapper">
|
||||
|
||||
<select id="selectGanttItems"
|
||||
parameterType="com.klp.aps.domain.dto.ApsGanttQueryReq"
|
||||
resultType="com.klp.aps.domain.vo.ApsGanttItemVo">
|
||||
parameterType="com.fad.aps.domain.dto.ApsGanttQueryReq"
|
||||
resultType="com.fad.aps.domain.vo.ApsGanttItemVo">
|
||||
SELECT
|
||||
o.operation_id AS operationId,
|
||||
o.plan_id AS planId,
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsLineCapabilityMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsLineCapabilityMapper">
|
||||
|
||||
<select id="selectByLineProductAndProcess" resultType="com.klp.aps.domain.entity.ApsLineCapabilityEntity">
|
||||
<select id="selectByLineProductAndProcess" resultType="com.fad.aps.domain.entity.ApsLineCapabilityEntity">
|
||||
SELECT *
|
||||
FROM wms_line_capability
|
||||
WHERE line_id = #{lineId}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsLockMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsLockMapper">
|
||||
|
||||
<insert id="insertLock"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleLockEntity"
|
||||
parameterType="com.fad.aps.domain.entity.ApsScheduleLockEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="lockId"
|
||||
keyColumn="lock_id">
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsOperationMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsOperationMapper">
|
||||
|
||||
<resultMap id="ApsScheduleOperationMap"
|
||||
type="com.klp.aps.domain.entity.ApsScheduleOperationEntity">
|
||||
type="com.fad.aps.domain.entity.ApsScheduleOperationEntity">
|
||||
<id property="operationId" column="operation_id"/>
|
||||
<result property="planId" column="plan_id"/>
|
||||
<result property="detailId" column="detail_id"/>
|
||||
@@ -54,7 +54,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<update id="updateSlot"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleOperationEntity">
|
||||
parameterType="com.fad.aps.domain.entity.ApsScheduleOperationEntity">
|
||||
UPDATE wms_schedule_operation
|
||||
SET line_id = #{lineId},
|
||||
start_time = #{startTime},
|
||||
@@ -65,7 +65,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</update>
|
||||
|
||||
<insert id="insertChangeLog"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleChangeLogEntity"
|
||||
parameterType="com.fad.aps.domain.entity.ApsScheduleChangeLogEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="logId"
|
||||
keyColumn="log_id">
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsPlanMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsPlanMapper">
|
||||
|
||||
<select id="selectOrderDetailsByOrderId"
|
||||
parameterType="long"
|
||||
resultType="com.klp.aps.domain.row.ApsOrderDetailRow">
|
||||
resultType="com.fad.aps.domain.row.ApsOrderDetailRow">
|
||||
SELECT
|
||||
detail_id AS detailId,
|
||||
product_id AS productId,
|
||||
@@ -17,7 +17,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
ORDER BY detail_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectCrmOrderById" resultType="com.klp.aps.domain.row.ApsCrmOrderRow">
|
||||
<select id="selectCrmOrderById" resultType="com.fad.aps.domain.row.ApsCrmOrderRow">
|
||||
SELECT
|
||||
order_id AS orderId,
|
||||
order_code AS orderCode,
|
||||
@@ -31,7 +31,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectCrmOrderItemsByOrderId" resultType="com.klp.aps.domain.row.ApsCrmOrderItemRow">
|
||||
<select id="selectCrmOrderItemsByOrderId" resultType="com.fad.aps.domain.row.ApsCrmOrderItemRow">
|
||||
SELECT
|
||||
item_id AS itemId,
|
||||
order_id AS orderId,
|
||||
@@ -45,7 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
ORDER BY item_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectWmsOrderByCode" resultType="com.klp.aps.domain.row.ApsWmsOrderRow">
|
||||
<select id="selectWmsOrderByCode" resultType="com.fad.aps.domain.row.ApsWmsOrderRow">
|
||||
SELECT order_id AS orderId, order_code AS orderCode
|
||||
FROM wms_order
|
||||
WHERE order_code = #{orderCode}
|
||||
@@ -53,7 +53,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insertWmsOrder" parameterType="com.klp.aps.domain.dto.ApsWmsOrderCreateReq">
|
||||
<insert id="insertWmsOrder" parameterType="com.fad.aps.domain.dto.ApsWmsOrderCreateReq">
|
||||
INSERT INTO wms_order
|
||||
(
|
||||
order_code,
|
||||
@@ -84,7 +84,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertWmsOrderDetail" parameterType="com.klp.aps.domain.dto.ApsWmsOrderDetailCreateReq">
|
||||
<insert id="insertWmsOrderDetail" parameterType="com.fad.aps.domain.dto.ApsWmsOrderDetailCreateReq">
|
||||
INSERT INTO wms_order_detail
|
||||
(
|
||||
order_id,
|
||||
@@ -124,7 +124,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<insert id="insertSchedulePlan"
|
||||
parameterType="com.klp.aps.domain.entity.ApsSchedulePlanEntity"
|
||||
parameterType="com.fad.aps.domain.entity.ApsSchedulePlanEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="planId"
|
||||
keyColumn="plan_id">
|
||||
@@ -159,7 +159,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</insert>
|
||||
|
||||
<insert id="insertSchedulePlanDetail"
|
||||
parameterType="com.klp.aps.domain.entity.ApsSchedulePlanDetailEntity"
|
||||
parameterType="com.fad.aps.domain.entity.ApsSchedulePlanDetailEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="detailId"
|
||||
keyColumn="detail_id">
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsScheduleSheetMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsScheduleSheetMapper">
|
||||
|
||||
<select id="selectSheetRows"
|
||||
parameterType="com.klp.aps.domain.dto.ApsScheduleSheetQueryReq"
|
||||
resultType="com.klp.aps.domain.vo.ApsScheduleSheetRowVo">
|
||||
parameterType="com.fad.aps.domain.dto.ApsScheduleSheetQueryReq"
|
||||
resultType="com.fad.aps.domain.vo.ApsScheduleSheetRowVo">
|
||||
SELECT
|
||||
o.operation_id AS operationId,
|
||||
o.line_id AS lineId,
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsShiftTemplateMapper">
|
||||
<mapper namespace="com.fad.aps.mapper.ApsShiftTemplateMapper">
|
||||
|
||||
<select id="selectByShiftCode" resultType="com.klp.aps.domain.entity.ApsShiftTemplateEntity">
|
||||
<select id="selectByShiftCode" resultType="com.fad.aps.domain.entity.ApsShiftTemplateEntity">
|
||||
SELECT *
|
||||
FROM wms_shift_template
|
||||
WHERE shift_code = #{shiftCode}
|
||||
|
||||
Reference in New Issue
Block a user