diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java index 9405a62a..7171e29d 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java @@ -57,6 +57,7 @@ import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; import org.jeecg.modules.xslmes.service.IMesXslWeightRecordService; import org.jeecg.modules.xslmes.service.MesXslStompNotifyService; import org.jeecg.modules.xslmes.vo.MesXslRawMaterialCardBriefVO; +import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; @@ -1021,6 +1022,30 @@ public class MesXslDesktopAnonController { //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检实验标准查询----------- //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检记录保存----------- + @Operation(summary = "胶料快检记录-免密分页列表") + @GetMapping("/xslmes/mesXslRubberQuickTestRecord/anon/list") + public Result> rubberQuickTestRecordAnonList( + MesXslRubberQuickTestRecord model, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "20") Integer pageSize, + HttpServletRequest req) { + QueryWrapper qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap()); + qw.orderByDesc("create_time"); + IPage page = rubberQuickTestRecordService.page(new Page<>(pageNo, pageSize), qw); + return Result.OK(page); + } + + @Operation(summary = "胶料快检记录-免密通过id查询(含明细)") + @GetMapping("/xslmes/mesXslRubberQuickTestRecord/anon/queryById") + public Result rubberQuickTestRecordAnonQueryById(@RequestParam(name = "id") String id) { + MesXslRubberQuickTestRecord entity = rubberQuickTestRecordService.getById(id); + if (entity == null) { + return Result.error("未找到对应数据"); + } + fillRubberQuickTestRecordDetails(entity); + return Result.OK(entity); + } + @Operation(summary = "胶料快检记录-免密添加") @PostMapping("/xslmes/mesXslRubberQuickTestRecord/anon/add") public Result rubberQuickTestRecordAnonAdd(@RequestBody MesXslRubberQuickTestRecord record) { @@ -1030,16 +1055,23 @@ public class MesXslDesktopAnonController { if (oConvertUtils.isEmpty(record.getRubberMaterialName())) { return Result.error("胶料名称不能为空"); } - List lineList = record.getLineList(); - if (lineList == null || lineList.isEmpty()) { - return Result.error("请维护检验明细"); + if (CollectionUtils.isEmpty(record.getStdLineList())) { + return Result.error("请维护数据标准明细"); } + if (CollectionUtils.isEmpty(record.getRawLineList())) { + return Result.error("请维护试验结果明细"); + } + //update-begin---author:jiangxh ---date:20260617 for:【快检记录】桌面端同步须含曲线图数据----------- + if (CollectionUtils.isEmpty(record.getChartPointList())) { + return Result.error("请维护曲线图数据"); + } + //update-end---author:jiangxh ---date:20260617 for:【快检记录】桌面端同步须含曲线图数据----------- try { if (oConvertUtils.isEmpty(record.getRecordNo())) { record.setRecordNo(rubberQuickTestRecordService.generateDesktopRecordNo(record)); } - rubberQuickTestRecordService.fillQuickTestTypeForRecord(record); - rubberQuickTestRecordService.saveMain(record, lineList); + rubberQuickTestRecordService.fillStdAndTypeForRecord(record); + rubberQuickTestRecordService.saveMain(record, record.getLineList()); stompNotify.publishRubberQuickTestRecordChanged("add", record.getId()); return Result.OK(record.getRecordNo()); } catch (Exception e) { @@ -1047,6 +1079,17 @@ public class MesXslDesktopAnonController { return Result.error(e.getMessage()); } } + + private void fillRubberQuickTestRecordDetails(MesXslRubberQuickTestRecord entity) { + if (entity == null || oConvertUtils.isEmpty(entity.getId())) { + return; + } + String id = entity.getId(); + entity.setStdLineList(rubberQuickTestRecordService.selectStdLinesByRecordId(id)); + entity.setRawLineList(rubberQuickTestRecordService.selectRawLinesByRecordId(id)); + entity.setChartPointList(rubberQuickTestRecordService.selectChartPointsByRecordId(id)); + entity.setLineList(rubberQuickTestRecordService.selectLinesByRecordId(id)); + } //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】桌面端胶料快检记录保存----------- //update-begin---author:jiangxh ---date:20260618 for:【快检实验标准】桌面端回填实验方法关联实验类型----------- diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestRecordController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestRecordController.java index f523cd00..fd1449bb 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestRecordController.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestRecordController.java @@ -23,8 +23,10 @@ import org.jeecg.modules.mes.material.service.IMesMaterialService; import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.service.ISysUserService; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordChartPoint; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordStdLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService; @@ -32,6 +34,7 @@ import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestRecordBatchFromMaterialV import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestRecordPage; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; @@ -117,16 +120,9 @@ public class MesXslRubberQuickTestRecordController @RequiresPermissions("mes:mes_material:rubberQuickTestInspect") @PostMapping(value = "/batchFromMaterial") public Result> batchFromMaterial(@RequestBody MesXslRubberQuickTestRecordBatchFromMaterialVO vo) { - try { - //update-begin---author:jiangxh ---date:20260616 for:【MES】胶料快检记录批量生成默认带出当前登录检验人----------- - fillInspectorIfEmpty(vo); - //update-end---author:jiangxh ---date:20260616 for:【MES】胶料快检记录批量生成默认带出当前登录检验人----------- - List ids = mesXslRubberQuickTestRecordService.batchFromMaterial(vo); - return Result.OK("成功生成 " + ids.size() + " 条快检记录", ids); - } catch (Exception e) { - log.error(e.getMessage(), e); - return Result.error(e.getMessage()); - } + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】取消胶料列表批量生成,改由桌面端同步----------- + return Result.error("该功能已停用,请通过桌面端新增并同步胶料快检记录"); + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】取消胶料列表批量生成,改由桌面端同步----------- } @AutoLog(value = "MES胶料快检记录-删除") @@ -154,6 +150,12 @@ public class MesXslRubberQuickTestRecordController if (entity == null) { return Result.error("未找到对应数据"); } + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】查询含数据标准/试验结果/曲线图明细----------- + entity.setStdLineList(mesXslRubberQuickTestRecordService.selectStdLinesByRecordId(id)); + entity.setRawLineList(mesXslRubberQuickTestRecordService.selectRawLinesByRecordId(id)); + entity.setChartPointList(mesXslRubberQuickTestRecordService.selectChartPointsByRecordId(id)); + entity.setLineList(mesXslRubberQuickTestRecordService.selectLinesByRecordId(id)); + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】查询含数据标准/试验结果/曲线图明细----------- return Result.OK(entity); } @@ -173,6 +175,22 @@ public class MesXslRubberQuickTestRecordController } //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】查询原始数据明细----------- + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】查询数据标准明细与曲线图----------- + @Operation(summary = "MES胶料快检记录-查询数据标准明细") + @GetMapping(value = "/queryStdLineListByRecordId") + public Result> queryStdLineListByRecordId( + @RequestParam(name = "id", required = true) String id) { + return Result.OK(mesXslRubberQuickTestRecordService.selectStdLinesByRecordId(id)); + } + + @Operation(summary = "MES胶料快检记录-查询曲线图数据点") + @GetMapping(value = "/queryChartPointListByRecordId") + public Result> queryChartPointListByRecordId( + @RequestParam(name = "id", required = true) String id) { + return Result.OK(mesXslRubberQuickTestRecordService.selectChartPointsByRecordId(id)); + } + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】查询数据标准明细与曲线图----------- + @RequiresPermissions("mes:mes_xsl_rubber_quick_test_record:exportXls") @RequestMapping(value = "/exportXls") public ModelAndView exportXls(HttpServletRequest request, MesXslRubberQuickTestRecord model) { @@ -189,14 +207,22 @@ public class MesXslRubberQuickTestRecordController if (main == null) { return "参数不能为空"; } - if (oConvertUtils.isEmpty(main.getRubberMaterialId())) { - return "请选择胶料"; + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】Web保存校验支持桌面端三类明细----------- + if (oConvertUtils.isNotEmpty(main.getRubberMaterialId())) { + MesMaterial material = mesMaterialService.getById(main.getRubberMaterialId()); + if (material == null) { + return "所选胶料不存在"; + } + main.setRubberMaterialName(material.getMaterialName()); + } else if (oConvertUtils.isEmpty(main.getRubberMaterialName())) { + return "胶料名称不能为空"; } - MesMaterial material = mesMaterialService.getById(main.getRubberMaterialId()); - if (material == null) { - return "所选胶料不存在"; + + if (!CollectionUtils.isEmpty(main.getStdLineList()) && !CollectionUtils.isEmpty(main.getRawLineList())) { + resolveInspector(main); + return null; } - main.setRubberMaterialName(material.getMaterialName()); + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】Web保存校验支持桌面端三类明细----------- if (oConvertUtils.isNotEmpty(main.getQuickTestTypeId())) { MesXslRubberQuickTestType type = mesXslRubberQuickTestTypeService.getById(main.getQuickTestTypeId()); diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecord.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecord.java index 694a3325..db1fe703 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecord.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecord.java @@ -32,8 +32,8 @@ public class MesXslRubberQuickTestRecord implements Serializable { @TableId(type = IdType.ASSIGN_ID) private String id; - @Excel(name = "单号", width = 16) - @Schema(description = "单号(JL+yyyyMMdd+4位流水)") + @Excel(name = "快检记录号", width = 16) + @Schema(description = "快检记录号(yyyyMMdd+4位流水+胶料名称)") private String recordNo; @Schema(description = "胶料ID mes_material.id") @@ -46,14 +46,25 @@ public class MesXslRubberQuickTestRecord implements Serializable { @Schema(description = "引用的实验标准ID") private String stdId; - @Schema(description = "生产机台ID") + @Excel(name = "实验标准", width = 20) + @Schema(description = "实验标准名称冗余") + private String stdName; + + @Schema(description = "实验方法ID") + private String testMethodId; + + @Excel(name = "实验方法", width = 20) + @Schema(description = "实验方法名称冗余") + private String testMethodName; + + @Schema(description = "炼机台ID") private String prodEquipmentLedgerId; - @Excel(name = "生产机台", width = 16) - @Schema(description = "生产机台名称冗余") + @Excel(name = "炼机台", width = 16) + @Schema(description = "炼机台名称冗余") private String prodEquipmentName; - @Excel(name = "生产日期", width = 12, format = "yyyy-MM-dd") + @Excel(name = "密炼日期", width = 12, format = "yyyy-MM-dd") @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd") private Date productionDate; @@ -69,7 +80,7 @@ public class MesXslRubberQuickTestRecord implements Serializable { @Dict(dicCode = "xslmes_rubber_quick_test_work_team") private String workTeam; - @Excel(name = "检验次数", width = 10) + @Excel(name = "试验次数", width = 10) private Integer inspectTimes; @Excel(name = "检验时间", width = 18, format = "yyyy-MM-dd HH:mm:ss") @@ -86,17 +97,17 @@ public class MesXslRubberQuickTestRecord implements Serializable { @Excel(name = "检验人", width = 12) private String inspectorRealname; - @Schema(description = "检验类型ID") + @Schema(description = "实验类型ID") private String quickTestTypeId; - @Excel(name = "检验类型", width = 16) + @Excel(name = "实验类型", width = 16) private String quickTestTypeName; @Excel(name = "检验结果", width = 10, dicCode = "xslmes_rubber_quick_test_record_result") @Dict(dicCode = "xslmes_rubber_quick_test_record_result") private String inspectResult; - @Excel(name = "生产计划号", width = 16) + @Excel(name = "密炼计划", width = 16) private String productionPlanNo; @Schema(description = "检验机台ID") @@ -134,4 +145,14 @@ public class MesXslRubberQuickTestRecord implements Serializable { @TableField(exist = false) @Schema(description = "原始数据明细(试验结果全部检测值)") private List rawLineList; + + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】数据标准明细与曲线图----------- + @TableField(exist = false) + @Schema(description = "数据标准明细(实验标准快照)") + private List stdLineList; + + @TableField(exist = false) + @Schema(description = "曲线图数据点") + private List chartPointList; + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】数据标准明细与曲线图----------- } diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordChartPoint.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordChartPoint.java new file mode 100644 index 00000000..306d3d2a --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordChartPoint.java @@ -0,0 +1,59 @@ +package org.jeecg.modules.xslmes.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.springframework.format.annotation.DateTimeFormat; + +/** + * MES 胶料快检记录曲线图数据点 + */ +@Data +@TableName("mes_xsl_rubber_quick_test_record_chart_point") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "MES胶料快检记录曲线图数据点") +public class MesXslRubberQuickTestRecordChartPoint implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "主表ID mes_xsl_rubber_quick_test_record.id") + private String recordId; + + @Excel(name = "时间(min)", width = 12, type = 10) + private BigDecimal timeMin; + + @Excel(name = "上模温度", width = 12, type = 10) + private BigDecimal upperTemp; + + @Excel(name = "下模温度", width = 12, type = 10) + private BigDecimal lowerTemp; + + @Excel(name = "S'(dNm)", width = 12, type = 10) + private BigDecimal torqueS; + + private Integer sortNo; + private String createBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + private String updateBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordStdLine.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordStdLine.java new file mode 100644 index 00000000..2f00f450 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslRubberQuickTestRecordStdLine.java @@ -0,0 +1,68 @@ +package org.jeecg.modules.xslmes.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.springframework.format.annotation.DateTimeFormat; + +/** + * MES 胶料快检记录数据标准明细(实验标准快照) + */ +@Data +@TableName("mes_xsl_rubber_quick_test_record_std_line") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(description = "MES胶料快检记录数据标准明细") +public class MesXslRubberQuickTestRecordStdLine implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private String id; + + @Schema(description = "主表ID mes_xsl_rubber_quick_test_record.id") + private String recordId; + + @Schema(description = "数据点ID") + private String dataPointId; + + @Excel(name = "数据点", width = 18) + private String pointName; + + @Excel(name = "下限值", width = 12, type = 10) + private BigDecimal lowerLimit; + + @Excel(name = "上限值", width = 12, type = 10) + private BigDecimal upperLimit; + + @Excel(name = "下限预警", width = 12, type = 10) + private BigDecimal lowerWarn; + + @Excel(name = "上限预警", width = 12, type = 10) + private BigDecimal upperWarn; + + @Excel(name = "目标值", width = 12, type = 10) + private BigDecimal targetValue; + + private Integer sortNo; + private String createBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + private String updateBy; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordChartPointMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordChartPointMapper.java new file mode 100644 index 00000000..6703258a --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordChartPointMapper.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordChartPoint; + +public interface MesXslRubberQuickTestRecordChartPointMapper extends BaseMapper {} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordStdLineMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordStdLineMapper.java new file mode 100644 index 00000000..7293b267 --- /dev/null +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslRubberQuickTestRecordStdLineMapper.java @@ -0,0 +1,7 @@ +package org.jeecg.modules.xslmes.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordStdLine; + +public interface MesXslRubberQuickTestRecordStdLineMapper extends BaseMapper { +} diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslRubberQuickTestRecordService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslRubberQuickTestRecordService.java index 4801b300..5fcc7983 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslRubberQuickTestRecordService.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslRubberQuickTestRecordService.java @@ -5,8 +5,10 @@ import java.io.Serializable; import java.util.Collection; import java.util.List; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordChartPoint; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordStdLine; import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestRecordBatchFromMaterialVO; public interface IMesXslRubberQuickTestRecordService extends IService { @@ -23,6 +25,15 @@ public interface IMesXslRubberQuickTestRecordService extends IService selectRawLinesByRecordId(String recordId); + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】数据标准明细与曲线图查询----------- + List selectStdLinesByRecordId(String recordId); + + List selectChartPointsByRecordId(String recordId); + + /** 桌面端保存前:按实验标准回填标准名、方法名、实验类型 */ + void fillStdAndTypeForRecord(MesXslRubberQuickTestRecord record); + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】数据标准明细与曲线图查询----------- + String generateRecordNo(MesXslRubberQuickTestRecord context); //update-begin---author:jiangxh ---date:20260618 for:【快检记录】桌面端快检记录号生成----------- diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestRecordServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestRecordServiceImpl.java index a40639f3..3526e0d1 100644 --- a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestRecordServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestRecordServiceImpl.java @@ -19,14 +19,18 @@ import org.jeecg.modules.mes.material.service.IMesMaterialService; import org.jeecg.modules.xslmes.common.XslMesBizConstants; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestMethod; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordChartPoint; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine; +import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordStdLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType; +import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordChartPointMapper; import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordLineMapper; import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordMapper; import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordRawLineMapper; +import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordStdLineMapper; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; @@ -50,6 +54,12 @@ public class MesXslRubberQuickTestRecordServiceImpl @Autowired private MesXslRubberQuickTestRecordRawLineMapper mesXslRubberQuickTestRecordRawLineMapper; + @Autowired + private MesXslRubberQuickTestRecordStdLineMapper mesXslRubberQuickTestRecordStdLineMapper; + + @Autowired + private MesXslRubberQuickTestRecordChartPointMapper mesXslRubberQuickTestRecordChartPointMapper; + @Autowired private IMesXslRubberQuickTestStdService mesXslRubberQuickTestStdService; @@ -73,6 +83,10 @@ public class MesXslRubberQuickTestRecordServiceImpl //update-begin---author:jiangxh ---date:2026-06-17 for:【快检记录】保存试验结果原始数据明细----------- insertRawLines(main.getId(), main.getRawLineList()); //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】保存试验结果原始数据明细----------- + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】保存数据标准明细与曲线图----------- + insertStdLines(main.getId(), main.getStdLineList()); + insertChartPoints(main.getId(), main.getChartPointList()); + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】保存数据标准明细与曲线图----------- } @Override @@ -95,6 +109,16 @@ public class MesXslRubberQuickTestRecordServiceImpl .eq(MesXslRubberQuickTestRecordRawLine::getRecordId, main.getId())); insertRawLines(main.getId(), main.getRawLineList()); //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】更新时同步原始数据明细----------- + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】更新时同步数据标准与曲线图----------- + mesXslRubberQuickTestRecordStdLineMapper.delete( + new LambdaQueryWrapper() + .eq(MesXslRubberQuickTestRecordStdLine::getRecordId, main.getId())); + insertStdLines(main.getId(), main.getStdLineList()); + mesXslRubberQuickTestRecordChartPointMapper.delete( + new LambdaQueryWrapper() + .eq(MesXslRubberQuickTestRecordChartPoint::getRecordId, main.getId())); + insertChartPoints(main.getId(), main.getChartPointList()); + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】更新时同步数据标准与曲线图----------- } private void insertLines(String recordId, List lineList) { @@ -128,6 +152,40 @@ public class MesXslRubberQuickTestRecordServiceImpl } //update-end---author:jiangxh ---date:2026-06-17 for:【快检记录】原始数据明细入库----------- + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】数据标准明细与曲线图入库----------- + private void insertStdLines(String recordId, List stdLineList) { + if (CollectionUtils.isEmpty(stdLineList)) { + return; + } + int sort = 0; + for (MesXslRubberQuickTestRecordStdLine line : stdLineList) { + if (line == null) { + continue; + } + line.setId(null); + line.setRecordId(recordId); + line.setSortNo(sort++); + mesXslRubberQuickTestRecordStdLineMapper.insert(line); + } + } + + private void insertChartPoints(String recordId, List chartPointList) { + if (CollectionUtils.isEmpty(chartPointList)) { + return; + } + int sort = 0; + for (MesXslRubberQuickTestRecordChartPoint point : chartPointList) { + if (point == null) { + continue; + } + point.setId(null); + point.setRecordId(recordId); + point.setSortNo(sort++); + mesXslRubberQuickTestRecordChartPointMapper.insert(point); + } + } + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】数据标准明细与曲线图入库----------- + @Override @Transactional(rollbackFor = Exception.class) public void delMain(String id) { @@ -135,6 +193,10 @@ public class MesXslRubberQuickTestRecordServiceImpl new LambdaQueryWrapper().eq(MesXslRubberQuickTestRecordLine::getRecordId, id)); mesXslRubberQuickTestRecordRawLineMapper.delete( new LambdaQueryWrapper().eq(MesXslRubberQuickTestRecordRawLine::getRecordId, id)); + mesXslRubberQuickTestRecordStdLineMapper.delete( + new LambdaQueryWrapper().eq(MesXslRubberQuickTestRecordStdLine::getRecordId, id)); + mesXslRubberQuickTestRecordChartPointMapper.delete( + new LambdaQueryWrapper().eq(MesXslRubberQuickTestRecordChartPoint::getRecordId, id)); this.removeById(id); } @@ -162,6 +224,22 @@ public class MesXslRubberQuickTestRecordServiceImpl .orderByAsc(MesXslRubberQuickTestRecordRawLine::getSortNo)); } + @Override + public List selectStdLinesByRecordId(String recordId) { + return mesXslRubberQuickTestRecordStdLineMapper.selectList( + new LambdaQueryWrapper() + .eq(MesXslRubberQuickTestRecordStdLine::getRecordId, recordId) + .orderByAsc(MesXslRubberQuickTestRecordStdLine::getSortNo)); + } + + @Override + public List selectChartPointsByRecordId(String recordId) { + return mesXslRubberQuickTestRecordChartPointMapper.selectList( + new LambdaQueryWrapper() + .eq(MesXslRubberQuickTestRecordChartPoint::getRecordId, recordId) + .orderByAsc(MesXslRubberQuickTestRecordChartPoint::getSortNo)); + } + //update-begin---author:jiangxh ---date:20260528 for:【MES】胶料快检记录单号JL+日期+4位流水自动生成----------- @Override public String generateRecordNo(MesXslRubberQuickTestRecord context) { @@ -256,69 +334,52 @@ public class MesXslRubberQuickTestRecordServiceImpl @Override public void fillQuickTestTypeForRecord(MesXslRubberQuickTestRecord record) { - if (record == null || oConvertUtils.isNotEmpty(record.getQuickTestTypeId())) { + fillStdAndTypeForRecord(record); + } + + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】回填实验标准/方法/类型----------- + @Override + public void fillStdAndTypeForRecord(MesXslRubberQuickTestRecord record) { + if (record == null) { return; } - String testMethodId = null; + String testMethodId = record.getTestMethodId(); if (oConvertUtils.isNotEmpty(record.getStdId())) { MesXslRubberQuickTestStd std = mesXslRubberQuickTestStdService.getById(record.getStdId()); if (std != null) { - testMethodId = std.getTestMethodId(); + if (oConvertUtils.isEmpty(record.getStdName())) { + record.setStdName(std.getStdName()); + } + if (oConvertUtils.isEmpty(testMethodId)) { + testMethodId = std.getTestMethodId(); + record.setTestMethodId(testMethodId); + } } } - if (oConvertUtils.isEmpty(testMethodId)) { - return; + if (oConvertUtils.isNotEmpty(testMethodId) && oConvertUtils.isEmpty(record.getTestMethodName())) { + MesXslRubberQuickTestMethod method = mesXslRubberQuickTestMethodService.getById(testMethodId); + if (method != null) { + record.setTestMethodName(method.getMethodName()); + if (oConvertUtils.isEmpty(record.getQuickTestTypeId()) + && oConvertUtils.isNotEmpty(method.getQuickTestTypeId())) { + fillQuickTestType(record, method.getQuickTestTypeId()); + } + } } - MesXslRubberQuickTestMethod method = mesXslRubberQuickTestMethodService.getById(testMethodId); - if (method != null && oConvertUtils.isNotEmpty(method.getQuickTestTypeId())) { - fillQuickTestType(record, method.getQuickTestTypeId()); + if (oConvertUtils.isNotEmpty(record.getQuickTestTypeId()) && oConvertUtils.isEmpty(record.getQuickTestTypeName())) { + fillQuickTestType(record, record.getQuickTestTypeId()); } } + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】回填实验标准/方法/类型----------- //update-end---author:jiangxh ---date:20260618 for:【快检记录】桌面端快检记录号 yyyyMMdd+流水+胶料号----------- //update-begin---author:jiangxh ---date:20260525 for:【MES】胶料信息多选按实验标准批量生成快检记录----------- @Override @Transactional(rollbackFor = Exception.class) public List batchFromMaterial(MesXslRubberQuickTestRecordBatchFromMaterialVO vo) { - if (vo == null || CollectionUtils.isEmpty(vo.getMaterialIds())) { - throw new JeecgBootException("请至少选择一条胶料信息"); - } - List createdIds = new ArrayList<>(); - for (String materialId : vo.getMaterialIds()) { - if (oConvertUtils.isEmpty(materialId)) { - continue; - } - String mid = materialId.trim(); - MesMaterial material = mesMaterialService.getById(mid); - if (material == null) { - throw new JeecgBootException("胶料不存在:" + mid); - } - MesXslRubberQuickTestStd std = findApprovedStdForMaterial(mid); - if (std == null) { - throw new JeecgBootException( - "胶料【" + material.getMaterialName() + "】未找到已启用且已批准的实验标准,请先在胶料快检实验标准中维护"); - } - List stdLines = mesXslRubberQuickTestStdService.selectLinesByStdId(std.getId()); - if (CollectionUtils.isEmpty(stdLines)) { - throw new JeecgBootException("胶料【" + material.getMaterialName() + "】关联的实验标准无明细数据"); - } - MesXslRubberQuickTestRecord main = buildMainFromMaterial(material, std, vo); - List recordLines = new ArrayList<>(); - for (MesXslRubberQuickTestStdLine stdLine : stdLines) { - MesXslRubberQuickTestRecordLine rl = new MesXslRubberQuickTestRecordLine(); - rl.setDataPointId(stdLine.getDataPointId()); - rl.setInspectItem(stdLine.getPointName()); - rl.setLowerLimit(stdLine.getLowerLimit()); - rl.setUpperLimit(stdLine.getUpperLimit()); - recordLines.add(rl); - } - saveMain(main, recordLines); - createdIds.add(main.getId()); - } - if (createdIds.isEmpty()) { - throw new JeecgBootException("未生成任何快检记录"); - } - return createdIds; + //update-begin---author:jiangxh ---date:2026-06-22 for:【快检记录】取消胶料列表批量生成,改由桌面端同步----------- + throw new JeecgBootException("胶料快检记录已改为由桌面端同步创建,请使用桌面端「胶料快检记录」功能"); + //update-end---author:jiangxh ---date:2026-06-22 for:【快检记录】取消胶料列表批量生成,改由桌面端同步----------- } private MesXslRubberQuickTestStd findApprovedStdForMaterial(String materialId) { diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_158__mes_xsl_rubber_quick_test_record_std_chart.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_158__mes_xsl_rubber_quick_test_record_std_chart.sql new file mode 100644 index 00000000..47d7f2f9 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_158__mes_xsl_rubber_quick_test_record_std_chart.sql @@ -0,0 +1,42 @@ +-- MES 胶料快检记录:主表扩展实验标准/方法字段;新增数据标准明细与曲线图明细 +SET NAMES utf8mb4; + +ALTER TABLE `mes_xsl_rubber_quick_test_record` + ADD COLUMN `std_name` varchar(200) DEFAULT NULL COMMENT '实验标准名称冗余' AFTER `std_id`, + ADD COLUMN `test_method_id` varchar(32) DEFAULT NULL COMMENT '实验方法ID' AFTER `std_name`, + ADD COLUMN `test_method_name` varchar(200) DEFAULT NULL COMMENT '实验方法名称冗余' AFTER `test_method_id`; + +CREATE TABLE IF NOT EXISTS `mes_xsl_rubber_quick_test_record_std_line` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `record_id` varchar(32) NOT NULL COMMENT '主表 mes_xsl_rubber_quick_test_record.id', + `data_point_id` varchar(32) DEFAULT NULL COMMENT '数据点ID', + `point_name` varchar(128) DEFAULT NULL COMMENT '数据点名称', + `lower_limit` decimal(18,6) DEFAULT NULL COMMENT '下限值', + `lower_warn` decimal(18,6) DEFAULT NULL COMMENT '下警告值', + `target_value` decimal(18,6) DEFAULT NULL COMMENT '目标值', + `upper_warn` decimal(18,6) DEFAULT NULL COMMENT '上警告值', + `upper_limit` decimal(18,6) DEFAULT NULL COMMENT '上限值', + `sort_no` int DEFAULT NULL COMMENT '排序号', + `create_by` varchar(32) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(32) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_rubber_quick_test_record_std_record_id` (`record_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES胶料快检记录数据标准明细'; + +CREATE TABLE IF NOT EXISTS `mes_xsl_rubber_quick_test_record_chart_point` ( + `id` varchar(32) NOT NULL COMMENT '主键', + `record_id` varchar(32) NOT NULL COMMENT '主表 mes_xsl_rubber_quick_test_record.id', + `time_min` decimal(10,4) DEFAULT NULL COMMENT '时间(min)', + `upper_temp` decimal(18,6) DEFAULT NULL COMMENT '上模温度', + `lower_temp` decimal(18,6) DEFAULT NULL COMMENT '下模温度', + `torque_s` decimal(18,6) DEFAULT NULL COMMENT 'S''(dNm)', + `sort_no` int DEFAULT NULL COMMENT '排序号', + `create_by` varchar(32) DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(32) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_rubber_quick_test_record_chart_record_id` (`record_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES胶料快检记录曲线图数据点'; diff --git a/jeecgboot-vue3/src/views/mes/material/MesMaterialList.vue b/jeecgboot-vue3/src/views/mes/material/MesMaterialList.vue index ae8e0fa1..b6c74ff3 100644 --- a/jeecgboot-vue3/src/views/mes/material/MesMaterialList.vue +++ b/jeecgboot-vue3/src/views/mes/material/MesMaterialList.vue @@ -5,15 +5,6 @@ 新增 导出 导入 - - 检验 - + + diff --git a/yy-admin-master/YY.Admin.Core/Core/Events/RubberQuickTestRecordChangedEvent.cs b/yy-admin-master/YY.Admin.Core/Core/Events/RubberQuickTestRecordChangedEvent.cs new file mode 100644 index 00000000..ab74d184 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Core/Events/RubberQuickTestRecordChangedEvent.cs @@ -0,0 +1,11 @@ +using Prism.Events; + +namespace YY.Admin.Core.Events; + +public class RubberQuickTestRecordChangedPayload +{ + public string Action { get; set; } = string.Empty; + public string? RecordId { get; set; } +} + +public class RubberQuickTestRecordChangedEvent : PubSubEvent { } diff --git a/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestRecordService.cs b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestRecordService.cs new file mode 100644 index 00000000..ca20c70d --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Core/Services/IRubberQuickTestRecordService.cs @@ -0,0 +1,31 @@ +using YY.Admin.Core.Entity; + +namespace YY.Admin.Core.Services; + +public interface IRubberQuickTestRecordService +{ + Task PageAsync( + int pageNo, + int pageSize, + string? filterRecordNo = null, + string? filterRubberMaterialName = null, + string? filterPlanNo = null, + CancellationToken ct = default); + + Task GetByIdAsync(string id, CancellationToken ct = default); + + RubberQuickTestRecordLocalItem? GetByLocalId(string localId); + + Task SaveAsync(MesXslRubberQuickTestRecord entity, CancellationToken ct = default); + + /// 删除本地同步失败的快检记录(已同步或待同步不可删) + bool DeleteFailedLocal(string localId); + + string GenerateRecordNo(string rubberMaterialName); +} + +public record RubberQuickTestRecordPageResult( + List Records, + long Total, + int PageNo, + int PageSize); diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecord.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecord.cs index 0e39eced..aeb9b6b9 100644 --- a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecord.cs +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecord.cs @@ -7,6 +7,9 @@ public class MesXslRubberQuickTestRecord public string? RubberMaterialId { get; set; } public string? RubberMaterialName { get; set; } public string? StdId { get; set; } + public string? StdName { get; set; } + public string? TestMethodId { get; set; } + public string? TestMethodName { get; set; } public string? ProdEquipmentLedgerId { get; set; } public string? ProdEquipmentName { get; set; } public DateTime? ProductionDate { get; set; } @@ -17,8 +20,18 @@ public class MesXslRubberQuickTestRecord public string? InspectorUserId { get; set; } public string? InspectorUsername { get; set; } public string? InspectorRealname { get; set; } + public string? QuickTestTypeId { get; set; } + public string? QuickTestTypeName { get; set; } public string? InspectResult { get; set; } public string? ProductionPlanNo { get; set; } - public List? LineList { get; set; } + public DateTime? CreateTime { get; set; } + public List? StdLineList { get; set; } public List? RawLineList { get; set; } + public List? ChartPointList { get; set; } + + /// 列表展示:班次文本 + public string? WorkShiftText { get; set; } + + /// 列表展示:是否合格 + public string? InspectResultText { get; set; } } diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordChartPoint.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordChartPoint.cs new file mode 100644 index 00000000..537d380b --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordChartPoint.cs @@ -0,0 +1,13 @@ +namespace YY.Admin.Core.Entity; + +/// 胶料快检记录曲线图数据点 +public class MesXslRubberQuickTestRecordChartPoint +{ + public string? Id { get; set; } + public string? RecordId { get; set; } + public decimal? TimeMin { get; set; } + public decimal? UpperTemp { get; set; } + public decimal? LowerTemp { get; set; } + public decimal? TorqueS { get; set; } + public int? SortNo { get; set; } +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordStdLine.cs b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordStdLine.cs new file mode 100644 index 00000000..ac889f85 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/MesXslRubberQuickTestRecordStdLine.cs @@ -0,0 +1,16 @@ +namespace YY.Admin.Core.Entity; + +/// 胶料快检记录数据标准明细(实验标准快照) +public class MesXslRubberQuickTestRecordStdLine +{ + public string? Id { get; set; } + public string? RecordId { get; set; } + public string? DataPointId { get; set; } + public string? PointName { get; set; } + public decimal? LowerLimit { get; set; } + public decimal? UpperLimit { get; set; } + public decimal? LowerWarn { get; set; } + public decimal? UpperWarn { get; set; } + public decimal? TargetValue { get; set; } + public int? SortNo { get; set; } +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordListRow.cs b/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordListRow.cs new file mode 100644 index 00000000..324decf4 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordListRow.cs @@ -0,0 +1,32 @@ +namespace YY.Admin.Core.Entity; + +/// 胶料快检记录列表行 +public class RubberQuickTestRecordListRow +{ + public string? LocalId { get; set; } + public string? MesId { get; set; } + public string? RecordNo { get; set; } + public DateTime? ProductionDate { get; set; } + public string? ProdEquipmentName { get; set; } + public string? WorkShiftDisplay { get; set; } + public string? ProductionPlanNo { get; set; } + public string? RubberMaterialName { get; set; } + public string? StdName { get; set; } + public string? TestMethodName { get; set; } + public string? QuickTestTypeName { get; set; } + public string? TrainNo { get; set; } + public int? InspectTimes { get; set; } + public string? InspectorRealname { get; set; } + public DateTime? InspectDate { get; set; } + public string? InspectResultDisplay { get; set; } + public string SyncStatus { get; set; } = "Pending"; + public string SyncStatusDisplay => SyncStatus switch + { + "Synced" => "已同步", + "Failed" => "失败", + _ => "待同步" + }; + + /// 仅本地同步失败记录可删除 + public bool CanDelete => SyncStatus == "Failed" && !string.IsNullOrWhiteSpace(LocalId); +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordLocalItem.cs b/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordLocalItem.cs new file mode 100644 index 00000000..ec8bffbd --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordLocalItem.cs @@ -0,0 +1,13 @@ +namespace YY.Admin.Core.Entity; + +/// 桌面端本地胶料快检记录包装(含同步状态) +public class RubberQuickTestRecordLocalItem +{ + public string LocalId { get; set; } = Guid.NewGuid().ToString("N"); + public string? MesId { get; set; } + /// Pending / Synced / Failed + public string SyncStatus { get; set; } = "Pending"; + public string? SyncError { get; set; } + public DateTime LocalCreateTime { get; set; } = DateTime.Now; + public MesXslRubberQuickTestRecord Record { get; set; } = new(); +} diff --git a/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordSaveResult.cs b/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordSaveResult.cs new file mode 100644 index 00000000..d4ab8ff0 --- /dev/null +++ b/yy-admin-master/YY.Admin.Core/Entity/RubberQuickTestRecordSaveResult.cs @@ -0,0 +1,8 @@ +namespace YY.Admin.Core.Entity; + +public class RubberQuickTestRecordSaveResult +{ + public MesXslRubberQuickTestRecord Record { get; set; } = new(); + public string LocalId { get; set; } = string.Empty; + public string SyncStatus { get; set; } = "Pending"; +} diff --git a/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs b/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs index 95fd7f1c..c19295a9 100644 --- a/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs +++ b/yy-admin-master/YY.Admin.Core/SeedData/SysMenuSeedData.cs @@ -51,7 +51,7 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData // 胶料快检实验标准(桌面端只读) new SysMenu{ Id=1300150011301, Pid=1300150000101, Title="胶料快检实验标准", Path="/xslmes/mesXslRubberQuickTestStd", Name="mesXslRubberQuickTestStd", Component="RubberQuickTestStdListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=112 }, // 胶料快检记录(紧接实验标准之后) - new SysMenu{ Id=1300150011201, Pid=1300150000101, Title="胶料快检记录", Path="/xslmes/rubberQuickTestOperation", Name="rubberQuickTestOperation", Component="RubberQuickTestOperationView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=113 }, + new SysMenu{ Id=1300150011201, Pid=1300150000101, Title="胶料快检记录", Path="/xslmes/rubberQuickTestRecord", Name="rubberQuickTestRecord", Component="RubberQuickTestRecordListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=113 }, // 密炼计划 new SysMenu{ Id=1300150011401, Pid=1300150000101, Title="密炼计划", Path="/xslmes/mesXslMixingProductionPlan", Name="mesXslMixingProductionPlan", Component="MixingProductionPlanListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=114 }, diff --git a/yy-admin-master/YY.Admin.Core/SqlSugar/SqlSugarSetup.cs b/yy-admin-master/YY.Admin.Core/SqlSugar/SqlSugarSetup.cs index 14ea2257..b7e37389 100644 --- a/yy-admin-master/YY.Admin.Core/SqlSugar/SqlSugarSetup.cs +++ b/yy-admin-master/YY.Admin.Core/SqlSugar/SqlSugarSetup.cs @@ -518,6 +518,9 @@ namespace YY.Admin.Core.SqlSugar dbProvider.Updateable() .SetColumns(m => m.Title == "胶料快检记录") + .SetColumns(m => m.Path == "/xslmes/rubberQuickTestRecord") + .SetColumns(m => m.Name == "rubberQuickTestRecord") + .SetColumns(m => m.Component == "RubberQuickTestRecordListView") .SetColumns(m => m.OrderNo == 113) .Where(m => m.Id == quickTestRecordMenuId) .ExecuteCommand(); diff --git a/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestRecordService.cs b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestRecordService.cs new file mode 100644 index 00000000..61c365c5 --- /dev/null +++ b/yy-admin-master/YY.Admin.Services/Service/RubberQuickTest/RubberQuickTestRecordService.cs @@ -0,0 +1,502 @@ +using Microsoft.Extensions.Configuration; +using Prism.Events; +using System.IO; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Web; +using YY.Admin.Core; +using YY.Admin.Core.Entity; +using YY.Admin.Core.Events; +using YY.Admin.Core.Services; + +namespace YY.Admin.Services.Service.RubberQuickTest; + +public class RubberQuickTestRecordService : IRubberQuickTestRecordService, ISingletonDependency +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly IConfiguration _configuration; + private readonly INetworkMonitor _networkMonitor; + private readonly IEventAggregator _eventAggregator; + private readonly ILoggerService _logger; + private readonly SemaphoreSlim _syncLock = new(1, 1); + private readonly object _cacheLock = new(); + private readonly string _cacheFilePath; + private List _localItems = new(); + + private static readonly JsonSerializerOptions _jsonOpts = new() + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Converters = { new NullableDateTimeJsonConverter() } + }; + + public RubberQuickTestRecordService( + IHttpClientFactory httpClientFactory, + IConfiguration configuration, + INetworkMonitor networkMonitor, + IEventAggregator eventAggregator, + ILoggerService logger) + { + _httpClientFactory = httpClientFactory; + _configuration = configuration; + _networkMonitor = networkMonitor; + _eventAggregator = eventAggregator; + _logger = logger; + + var appDataDir = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "YY.Admin", "sync-cache"); + Directory.CreateDirectory(appDataDir); + _cacheFilePath = Path.Combine(appDataDir, "rubber-quick-test-record-items.json"); + + LoadCacheFromDisk(); + _logger.Information($"[快检记录同步] 初始化完成,本地记录={_localItems.Count}"); + + _networkMonitor.StatusChanged += OnNetworkStatusChanged; + if (_networkMonitor.IsOnline) + _ = Task.Run(() => PushPendingAsync(CancellationToken.None)); + } + + private string BaseUrl => (_configuration.GetValue("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/'); + private int DefaultTenantId => (int?)_configuration.GetValue("JeecgIntegration:DefaultTenantId") ?? 1002; + + private HttpClient CreateClient() => _httpClientFactory.CreateClient("JeecgApi"); + + public async Task PageAsync( + int pageNo, int pageSize, + string? filterRecordNo = null, + string? filterRubberMaterialName = null, + string? filterPlanNo = null, + CancellationToken ct = default) + { + var rows = await BuildAllRowsAsync(ct).ConfigureAwait(false); + var filtered = ApplyFilters(rows, filterRecordNo, filterRubberMaterialName, filterPlanNo); + var total = filtered.Count; + var records = filtered + .OrderByDescending(r => r.InspectDate ?? DateTime.MinValue) + .Skip(Math.Max(0, (pageNo - 1) * pageSize)) + .Take(pageSize) + .ToList(); + return new RubberQuickTestRecordPageResult(records, total, pageNo, pageSize); + } + + public async Task GetByIdAsync(string id, CancellationToken ct = default) + { + RubberQuickTestRecordLocalItem? local = null; + lock (_cacheLock) + { + local = _localItems.FirstOrDefault(x => + string.Equals(x.LocalId, id, StringComparison.OrdinalIgnoreCase) + || string.Equals(x.MesId, id, StringComparison.OrdinalIgnoreCase) + || string.Equals(x.Record.RecordNo, id, StringComparison.OrdinalIgnoreCase)); + } + + if (local != null) + return CloneRecord(local.Record); + + if (_networkMonitor.IsOnline) + { + try + { + var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestRecord/anon/queryById?id={Uri.EscapeDataString(id)}&tenantId={DefaultTenantId}"; + using var client = CreateClient(); + var resp = await client.GetAsync(url, ct).ConfigureAwait(false); + if (resp.IsSuccessStatusCode) + { + var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false); + using var doc = JsonDocument.Parse(json); + if (doc.RootElement.TryGetProperty("result", out var resultEl)) + return resultEl.Deserialize(_jsonOpts); + } + } + catch (Exception ex) + { + _logger.Warning($"[快检记录详情] 远端查询异常 id={id}: {ex.Message}"); + } + } + + return null; + } + + public RubberQuickTestRecordLocalItem? GetByLocalId(string localId) + { + lock (_cacheLock) + { + var item = _localItems.FirstOrDefault(x => string.Equals(x.LocalId, localId, StringComparison.OrdinalIgnoreCase)); + return item == null ? null : CloneLocalItem(item); + } + } + + public async Task SaveAsync(MesXslRubberQuickTestRecord entity, CancellationToken ct = default) + { + var record = CloneRecord(entity); + record.CreateTime ??= DateTime.Now; + record.InspectTime ??= record.CreateTime; + + var item = new RubberQuickTestRecordLocalItem + { + LocalId = Guid.NewGuid().ToString("N"), + LocalCreateTime = DateTime.Now, + SyncStatus = "Pending", + Record = record + }; + + if (_networkMonitor.IsOnline) + { + try + { + var recordNo = await RemoteAddAsync(record, ct).ConfigureAwait(false); + if (!string.IsNullOrWhiteSpace(recordNo)) + { + item.Record.RecordNo = recordNo; + item.SyncStatus = "Synced"; + } + } + catch (Exception ex) + { + item.SyncStatus = "Failed"; + item.SyncError = ex.Message; + _logger.Warning($"[快检记录新增] 远端失败,保留本地:{ex.Message}"); + } + } + + lock (_cacheLock) + { + _localItems.Add(CloneLocalItem(item)); + SaveCacheToDiskUnsafe(); + } + + _eventAggregator.GetEvent() + .Publish(new RubberQuickTestRecordChangedPayload { Action = "add", RecordId = item.LocalId }); + + return new RubberQuickTestRecordSaveResult + { + LocalId = item.LocalId, + SyncStatus = item.SyncStatus, + Record = CloneRecord(item.Record) + }; + } + + public bool DeleteFailedLocal(string localId) + { + if (string.IsNullOrWhiteSpace(localId)) return false; + + bool removed; + lock (_cacheLock) + { + var item = _localItems.FirstOrDefault(x => + string.Equals(x.LocalId, localId.Trim(), StringComparison.OrdinalIgnoreCase)); + if (item == null || !string.Equals(item.SyncStatus, "Failed", StringComparison.OrdinalIgnoreCase)) + return false; + + removed = _localItems.Remove(item); + if (removed) + SaveCacheToDiskUnsafe(); + } + + if (!removed) return false; + + _eventAggregator.GetEvent() + .Publish(new RubberQuickTestRecordChangedPayload { Action = "delete", RecordId = localId }); + _logger.Information($"[快检记录删除] 已删除同步失败本地记录 localId={localId}"); + return true; + } + + public string GenerateRecordNo(string rubberMaterialName) + { + var dateStr = DateTime.Now.ToString("yyyyMMdd"); + var material = rubberMaterialName.Trim(); + int maxSeq = 0; + lock (_cacheLock) + { + foreach (var item in _localItems) + { + var no = item.Record.RecordNo; + if (string.IsNullOrWhiteSpace(no) || !no.StartsWith(dateStr, StringComparison.Ordinal) || !no.EndsWith(material, StringComparison.Ordinal)) + continue; + var seqPart = no.Substring(dateStr.Length, Math.Min(4, no.Length - dateStr.Length - material.Length)); + if (int.TryParse(seqPart, out var seq)) + maxSeq = Math.Max(maxSeq, seq); + } + } + return dateStr + (maxSeq + 1).ToString("D4") + material; + } + + private async Task> BuildAllRowsAsync(CancellationToken ct) + { + var rows = new List(); + var seenRecordNos = new HashSet(StringComparer.OrdinalIgnoreCase); + + lock (_cacheLock) + { + foreach (var item in _localItems) + { + rows.Add(ToListRow(item)); + if (!string.IsNullOrWhiteSpace(item.Record.RecordNo)) + seenRecordNos.Add(item.Record.RecordNo); + } + } + + if (_networkMonitor.IsOnline) + { + try + { + foreach (var remote in await FetchRemoteListAsync(ct).ConfigureAwait(false)) + { + if (!string.IsNullOrWhiteSpace(remote.RecordNo) && seenRecordNos.Contains(remote.RecordNo)) + continue; + rows.Add(ToListRow(remote, "Synced", remote.Id)); + } + } + catch (Exception ex) + { + _logger.Warning($"[快检记录列表] 远端拉取失败:{ex.Message}"); + } + } + + return rows; + } + + private static RubberQuickTestRecordListRow ToListRow(RubberQuickTestRecordLocalItem item) => + ToListRow(item.Record, item.SyncStatus, item.MesId, item.LocalId); + + private static RubberQuickTestRecordListRow ToListRow( + MesXslRubberQuickTestRecord r, + string syncStatus, + string? mesId = null, + string? localId = null) => new() + { + LocalId = localId, + MesId = mesId ?? r.Id, + RecordNo = r.RecordNo, + ProductionDate = r.ProductionDate, + ProdEquipmentName = r.ProdEquipmentName, + WorkShiftDisplay = r.WorkShiftText ?? r.WorkShift, + ProductionPlanNo = r.ProductionPlanNo, + RubberMaterialName = r.RubberMaterialName, + StdName = r.StdName, + TestMethodName = r.TestMethodName, + QuickTestTypeName = r.QuickTestTypeName, + TrainNo = r.TrainNo, + InspectTimes = r.InspectTimes, + InspectorRealname = r.InspectorRealname, + InspectDate = r.CreateTime ?? r.InspectTime, + InspectResultDisplay = r.InspectResultText ?? (r.InspectResult == "1" ? "合格" : r.InspectResult == "0" ? "不合格" : ""), + SyncStatus = syncStatus + }; + + private async Task RemoteAddAsync(MesXslRubberQuickTestRecord entity, CancellationToken ct) + { + var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestRecord/anon/add?tenantId={DefaultTenantId}"; + var payload = CloneRecord(entity); + payload.Id = null; + + using var client = CreateClient(); + var body = JsonSerializer.Serialize(payload, _jsonOpts); + using var content = new StringContent(body, Encoding.UTF8, "application/json"); + var resp = await client.PostAsync(url, content, ct).ConfigureAwait(false); + var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false); + using var doc = JsonDocument.Parse(json); + if (!doc.RootElement.TryGetProperty("success", out var successEl) || !successEl.GetBoolean()) + { + var msg = doc.RootElement.TryGetProperty("message", out var msgEl) ? msgEl.GetString() : "保存失败"; + throw new InvalidOperationException(msg ?? "保存失败"); + } + + if (doc.RootElement.TryGetProperty("result", out var resultEl) && resultEl.ValueKind == JsonValueKind.String) + return resultEl.GetString(); + return entity.RecordNo; + } + + private async Task> FetchRemoteListAsync(CancellationToken ct) + { + var query = HttpUtility.ParseQueryString(string.Empty); + query["pageNo"] = "1"; + query["pageSize"] = "10000"; + query["tenantId"] = DefaultTenantId.ToString(); + var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestRecord/anon/list?{query}"; + using var client = CreateClient(); + var resp = await client.GetAsync(url, ct).ConfigureAwait(false); + resp.EnsureSuccessStatusCode(); + var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false); + using var doc = JsonDocument.Parse(json); + var result = doc.RootElement.GetProperty("result"); + return result.GetProperty("records").Deserialize>(_jsonOpts) ?? new(); + } + + private void OnNetworkStatusChanged(bool isOnline) + { + if (!isOnline) return; + _ = Task.Run(() => PushPendingAsync(CancellationToken.None)); + } + + private async Task PushPendingAsync(CancellationToken ct) + { + if (!await _syncLock.WaitAsync(0, ct).ConfigureAwait(false)) return; + try + { + List pending; + lock (_cacheLock) + { + pending = _localItems.Where(x => x.SyncStatus != "Synced").Select(CloneLocalItem).ToList(); + } + + foreach (var item in pending) + { + if (!_networkMonitor.IsOnline) break; + try + { + var recordNo = await RemoteAddAsync(item.Record, ct).ConfigureAwait(false); + lock (_cacheLock) + { + var target = _localItems.FirstOrDefault(x => x.LocalId == item.LocalId); + if (target == null) continue; + if (!string.IsNullOrWhiteSpace(recordNo)) + target.Record.RecordNo = recordNo; + target.SyncStatus = "Synced"; + target.SyncError = null; + SaveCacheToDiskUnsafe(); + } + } + catch (Exception ex) + { + lock (_cacheLock) + { + var target = _localItems.FirstOrDefault(x => x.LocalId == item.LocalId); + if (target != null) + { + target.SyncStatus = "Failed"; + target.SyncError = ex.Message; + SaveCacheToDiskUnsafe(); + } + } + } + } + } + finally + { + _syncLock.Release(); + } + } + + private static List ApplyFilters( + List source, + string? filterRecordNo, + string? filterRubberMaterialName, + string? filterPlanNo) + { + IEnumerable q = source; + if (!string.IsNullOrWhiteSpace(filterRecordNo)) + q = q.Where(r => (r.RecordNo ?? "").Contains(filterRecordNo.Trim(), StringComparison.OrdinalIgnoreCase)); + if (!string.IsNullOrWhiteSpace(filterRubberMaterialName)) + q = q.Where(r => (r.RubberMaterialName ?? "").Contains(filterRubberMaterialName.Trim(), StringComparison.OrdinalIgnoreCase)); + if (!string.IsNullOrWhiteSpace(filterPlanNo)) + q = q.Where(r => (r.ProductionPlanNo ?? "").Contains(filterPlanNo.Trim(), StringComparison.OrdinalIgnoreCase)); + return q.ToList(); + } + + private void LoadCacheFromDisk() + { + try + { + if (!File.Exists(_cacheFilePath)) return; + var data = JsonSerializer.Deserialize>(File.ReadAllText(_cacheFilePath), _jsonOpts); + _localItems = data ?? new(); + } + catch { _localItems = new(); } + } + + private void SaveCacheToDiskUnsafe() => + File.WriteAllText(_cacheFilePath, JsonSerializer.Serialize(_localItems, _jsonOpts)); + + private static RubberQuickTestRecordLocalItem CloneLocalItem(RubberQuickTestRecordLocalItem src) => new() + { + LocalId = src.LocalId, + MesId = src.MesId, + SyncStatus = src.SyncStatus, + SyncError = src.SyncError, + LocalCreateTime = src.LocalCreateTime, + Record = CloneRecord(src.Record) + }; + + private static MesXslRubberQuickTestRecord CloneRecord(MesXslRubberQuickTestRecord src) => new() + { + Id = src.Id, + RecordNo = src.RecordNo, + RubberMaterialId = src.RubberMaterialId, + RubberMaterialName = src.RubberMaterialName, + StdId = src.StdId, + StdName = src.StdName, + TestMethodId = src.TestMethodId, + TestMethodName = src.TestMethodName, + ProdEquipmentLedgerId = src.ProdEquipmentLedgerId, + ProdEquipmentName = src.ProdEquipmentName, + ProductionDate = src.ProductionDate, + TrainNo = src.TrainNo, + WorkShift = src.WorkShift, + InspectTimes = src.InspectTimes, + InspectTime = src.InspectTime, + InspectorUserId = src.InspectorUserId, + InspectorUsername = src.InspectorUsername, + InspectorRealname = src.InspectorRealname, + QuickTestTypeId = src.QuickTestTypeId, + QuickTestTypeName = src.QuickTestTypeName, + InspectResult = src.InspectResult, + ProductionPlanNo = src.ProductionPlanNo, + CreateTime = src.CreateTime, + StdLineList = src.StdLineList?.Select(l => new MesXslRubberQuickTestRecordStdLine + { + Id = l.Id, RecordId = l.RecordId, DataPointId = l.DataPointId, PointName = l.PointName, + LowerLimit = l.LowerLimit, UpperLimit = l.UpperLimit, LowerWarn = l.LowerWarn, + UpperWarn = l.UpperWarn, TargetValue = l.TargetValue, SortNo = l.SortNo + }).ToList(), + RawLineList = src.RawLineList?.Select(l => new MesXslRubberQuickTestRecordRawLine + { + Id = l.Id, RecordId = l.RecordId, RowNo = l.RowNo, DataPointId = l.DataPointId, + InspectItem = l.InspectItem, LowerLimit = l.LowerLimit, UpperLimit = l.UpperLimit, + InspectValue = l.InspectValue, RowInspectResult = l.RowInspectResult, SortNo = l.SortNo + }).ToList(), + ChartPointList = src.ChartPointList?.Select(p => new MesXslRubberQuickTestRecordChartPoint + { + Id = p.Id, RecordId = p.RecordId, TimeMin = p.TimeMin, UpperTemp = p.UpperTemp, + LowerTemp = p.LowerTemp, TorqueS = p.TorqueS, SortNo = p.SortNo + }).ToList(), + WorkShiftText = src.WorkShiftText, + InspectResultText = src.InspectResultText + }; + + private sealed class NullableDateTimeJsonConverter : JsonConverter + { + private static readonly string[] SupportedFormats = + [ + "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.fff", + "yyyy-MM-ddTHH:mm:ss", "yyyy-MM-ddTHH:mm:ss.fff", + "yyyy-MM-ddTHH:mm:ssZ", "yyyy-MM-ddTHH:mm:ss.fffZ", + "yyyy-MM-dd" + ]; + + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) return null; + if (reader.TokenType == JsonTokenType.String) + { + var raw = reader.GetString(); + if (string.IsNullOrWhiteSpace(raw)) return null; + if (DateTime.TryParseExact(raw, SupportedFormats, + System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.AssumeLocal, out var exact)) return exact; + if (DateTime.TryParse(raw, out var fallback)) return fallback; + } + throw new JsonException($"无法转换为 DateTime?,token={reader.TokenType}"); + } + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + { + if (value == null) writer.WriteNullValue(); + else writer.WriteStringValue(value.Value.ToString("yyyy-MM-dd HH:mm:ss")); + } + } +} diff --git a/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs b/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs index 08597703..b96bc61a 100644 --- a/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs +++ b/yy-admin-master/YY.Admin/Module/NavigationExtensions.cs @@ -99,6 +99,7 @@ namespace YY.Admin // 密炼物料皮重策略 containerRegistry.RegisterForNavigation(); // 胶料快检记录操作台 + containerRegistry.RegisterForNavigation(); containerRegistry.RegisterForNavigation(); // 胶料快检实验标准(只读) containerRegistry.RegisterForNavigation(); diff --git a/yy-admin-master/YY.Admin/Module/SyncModule.cs b/yy-admin-master/YY.Admin/Module/SyncModule.cs index 646aa9ec..67473158 100644 --- a/yy-admin-master/YY.Admin/Module/SyncModule.cs +++ b/yy-admin-master/YY.Admin/Module/SyncModule.cs @@ -89,7 +89,8 @@ public class SyncModule : IModule containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); - // 胶料快检记录操作台 + // 胶料快检记录:本地存储 + MES 同步 + containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); // 胶料快检实验标准(MES 只读同步) diff --git a/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs index bdd42ea5..96c56d63 100644 --- a/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/Control/MenuTreeViewModel.cs @@ -153,6 +153,9 @@ namespace YY.Admin.ViewModels.Control ["mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView", // 已实现页面:胶料快检记录操作台 + ["RubberQuickTestRecordListView"] = "RubberQuickTestRecordListView", + ["/xslmes/rubberQuickTestRecord"] = "RubberQuickTestRecordListView", + ["rubberQuickTestRecord"] = "RubberQuickTestRecordListView", ["RubberQuickTestOperationView"] = "RubberQuickTestOperationView", ["/xslmes/rubberQuickTestOperation"] = "RubberQuickTestOperationView", ["rubberQuickTestOperation"] = "RubberQuickTestOperationView", diff --git a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs index 049795ac..e0856f2f 100644 --- a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs +++ b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestOperationViewModel.cs @@ -10,9 +10,12 @@ using Prism.Events; using Prism.Mvvm; +using Prism.Navigation; + using SkiaSharp; using System.Collections.ObjectModel; +using System.Threading; using YY.Admin.Core; @@ -165,11 +168,11 @@ public class QuickTestInspectRowViewModel : BindableBase /// 胶料快检记录操作台 ViewModel(密炼计划、实验标准均读本地缓存) -public class RubberQuickTestOperationViewModel : BaseViewModel +public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware { - private readonly IRubberQuickTestOperationService _operationService; + private readonly IRubberQuickTestRecordService _recordService; private readonly IMixingProductionPlanService _planService; @@ -177,6 +180,12 @@ public class RubberQuickTestOperationViewModel : BaseViewModel private readonly Random _rnd = new(); + private bool _saveInProgress; + + private string? _loadedDetailLocalId; + private string? _loadedDetailMesId; + private int _navigationApplyVersion; + private List _allPlans = new(); private List _allStds = new(); @@ -200,7 +209,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel public RubberQuickTestOperationViewModel( - IRubberQuickTestOperationService operationService, + IRubberQuickTestRecordService recordService, IMixingProductionPlanService planService, @@ -212,7 +221,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel { - _operationService = operationService; + _recordService = recordService; _planService = planService; @@ -228,7 +237,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel RemoveInspectRowCommand = new DelegateCommand(() => RemoveInspectRow(SelectedInspectRow), () => SelectedInspectRow != null); - SaveCommand = new DelegateCommand(async () => await SaveAsync(), () => InspectRows.Count > 0); + SaveCommand = new DelegateCommand(async () => await SaveAsync(), () => CanSave); RefreshPlansCommand = new DelegateCommand(async () => await LoadLocalDataAsync(showSuccess: true)); @@ -259,13 +268,104 @@ public class RubberQuickTestOperationViewModel : BaseViewModel _stdChangedToken = _eventAggregator.GetEvent() .Subscribe(async _ => await ReloadLocalDataQuietAsync(), ThreadOption.UIThread); - - - _ = LoadLocalDataAsync(showSuccess: false); - RecalculateOverallInspectResult(); } + private bool _isReadOnly; + public bool IsReadOnly + { + get => _isReadOnly; + private set + { + if (!SetProperty(ref _isReadOnly, value)) return; + RaisePropertyChanged(nameof(IsEditable)); + RaisePropertyChanged(nameof(ShowSaveButton)); + NotifySaveStateChanged(); + InspectColumnsChanged?.Invoke(); + } + } + + public bool IsEditable => !IsReadOnly; + public bool ShowSaveButton => !IsReadOnly; + public bool CanSave => InspectRows.Count > 0 && !_saveInProgress && !IsReadOnly; + + private void NotifySaveStateChanged() + { + RaisePropertyChanged(nameof(CanSave)); + SaveCommand.RaiseCanExecuteChanged(); + } + + protected override void OnIsLoadingChanged() + { + base.OnIsLoadingChanged(); + NotifySaveStateChanged(); + } + + public void OnNavigatedTo(NavigationContext navigationContext) + { + _ = ApplyNavigationAsync(navigationContext.Parameters); + } + + private async Task ApplyNavigationAsync(INavigationParameters parameters) + { + var version = Interlocked.Increment(ref _navigationApplyVersion); + + if (parameters.TryGetValue("readOnly", out var readOnly) && readOnly) + { + if (parameters.TryGetValue("localId", out var localId) && !string.IsNullOrWhiteSpace(localId)) + { + _loadedDetailLocalId = localId; + _loadedDetailMesId = null; + await LoadFromLocalItemAsync(localId); + return; + } + + if (parameters.TryGetValue("mesId", out var mesId) && !string.IsNullOrWhiteSpace(mesId)) + { + _loadedDetailMesId = mesId; + _loadedDetailLocalId = null; + await LoadFromMesIdAsync(mesId); + return; + } + } + + if (version != _navigationApplyVersion) return; + + _loadedDetailLocalId = null; + _loadedDetailMesId = null; + IsReadOnly = false; + ResetFormForNewEntry(); + await LoadLocalDataAsync(showSuccess: false); + } + + public bool IsNavigationTarget(NavigationContext navigationContext) + { + var parameters = navigationContext.Parameters; + if (parameters.TryGetValue("readOnly", out var readOnly) && readOnly) + { + if (parameters.TryGetValue("localId", out var localId) && !string.IsNullOrWhiteSpace(localId)) + return IsReadOnly && string.Equals(_loadedDetailLocalId, localId, StringComparison.OrdinalIgnoreCase); + + if (parameters.TryGetValue("mesId", out var mesId) && !string.IsNullOrWhiteSpace(mesId)) + return IsReadOnly && string.Equals(_loadedDetailMesId, mesId, StringComparison.OrdinalIgnoreCase); + + return false; + } + + return !IsReadOnly && _loadedDetailLocalId == null && _loadedDetailMesId == null; + } + + private void ResetFormForNewEntry() + { + RecordNo = null; + TrainNo = null; + InspectTimesText = "1"; + ClearPlanAndStdSelection(); + RecalculateOverallInspectResult(); + NotifySaveStateChanged(); + } + public void OnNavigatedFrom(NavigationContext navigationContext) { } + private static string ResolveInspectorDisplay() @@ -648,8 +748,8 @@ public class RubberQuickTestOperationViewModel : BaseViewModel private async Task ReloadLocalDataQuietAsync() - { + if (IsReadOnly) return; try @@ -1070,7 +1170,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel InspectRows.Add(row); - SaveCommand.RaiseCanExecuteChanged(); + NotifySaveStateChanged(); RecalculateOverallInspectResult(); @@ -1090,7 +1190,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel RenumberInspectRows(); - SaveCommand.RaiseCanExecuteChanged(); + NotifySaveStateChanged(); RecalculateOverallInspectResult(); @@ -1099,145 +1199,90 @@ public class RubberQuickTestOperationViewModel : BaseViewModel private async Task SaveAsync() - { + if (_saveInProgress) return; - if (string.IsNullOrWhiteSpace(TrainNo)) - - { - - Growl.Warning("请填写车次"); - - return; - - } - - if (SelectedPlan == null) - - { - - Growl.Warning("请选择密炼计划"); - - return; - - } - - if (string.IsNullOrWhiteSpace(RubberMaterialName)) - - { - - Growl.Warning("请先选择密炼计划以带出胶料名称"); - - return; - - } - - if (SelectedStd == null || _currentStd == null) - - { - - Growl.Warning("请选择实验标准"); - - return; - - } - - - - if (InspectRows.Any(r => r.InspectResultText == "待填写" || string.IsNullOrWhiteSpace(r.InspectResultText))) - - { - - Growl.Warning("请手填全部检验行的检测值后再保存"); - - return; - - } - - - - if (!TryParseInspectTimes(out var inspectTimes, out var inspectTimesError)) - - { - - Growl.Warning(inspectTimesError); - - return; - - } - - - - var lineList = BuildAveragedLineList(); - - if (lineList.Count == 0) - - { - - Growl.Warning("无法根据试验结果计算明细数据"); - - return; - - } - - - - var rawLineList = BuildRawLineList(); - - if (rawLineList.Count == 0) - - { - - Growl.Warning("无法生成试验结果原始数据"); - - return; - - } - - - - var user = AppSession.CurrentUser; - - IsLoading = true; + _saveInProgress = true; + NotifySaveStateChanged(); try - { + if (string.IsNullOrWhiteSpace(TrainNo)) + { + Growl.Warning("请填写车次"); + return; + } - var record = BuildSaveRecord(lineList, rawLineList, inspectTimes, user); + if (SelectedPlan == null) + { + Growl.Warning("请选择密炼计划"); + return; + } - var recordNo = await _operationService.SaveRecordAsync(record); + if (string.IsNullOrWhiteSpace(RubberMaterialName)) + { + Growl.Warning("请先选择密炼计划以带出胶料名称"); + return; + } - RecordNo = recordNo; + if (SelectedStd == null || _currentStd == null) + { + Growl.Warning("请选择实验标准"); + return; + } - Growl.Success(string.IsNullOrWhiteSpace(recordNo) + if (InspectRows.Any(r => r.InspectResultText == "待填写" || string.IsNullOrWhiteSpace(r.InspectResultText))) + { + Growl.Warning("请手填全部检验行的检测值后再保存"); + return; + } - ? "胶料快检记录已保存到 MES" + if (!TryParseInspectTimes(out var inspectTimes, out var inspectTimesError)) + { + Growl.Warning(inspectTimesError); + return; + } - : $"胶料快检记录已保存,单号:{recordNo}"); + var rawLineList = BuildRawLineList(); + if (rawLineList.Count == 0) + { + Growl.Warning("无法生成试验结果原始数据"); + return; + } + + var stdLineList = BuildStdLineList(); + if (stdLineList.Count == 0) + { + Growl.Warning("无法生成数据标准明细"); + return; + } + + var chartPointList = BuildChartPointList(); + var user = AppSession.CurrentUser; + + IsLoading = true; + var record = BuildSaveRecord(stdLineList, rawLineList, chartPointList, inspectTimes, user); + var saved = await _recordService.SaveAsync(record); + RecordNo = saved.Record.RecordNo; + + var syncHint = saved.SyncStatus == "Synced" ? "并已同步到 MES" : "(MES 同步待重试)"; + Growl.Success(string.IsNullOrWhiteSpace(RecordNo) + ? $"胶料快检记录已保存到本地{syncHint}" + : $"胶料快检记录已保存,快检记录号:{RecordNo}{syncHint}"); InspectRows.Clear(); - - SaveCommand.RaiseCanExecuteChanged(); - + NotifySaveStateChanged(); } - catch (Exception ex) - { - Growl.Error($"保存失败:{ex.Message}"); - } - finally - { - IsLoading = false; - + _saveInProgress = false; + NotifySaveStateChanged(); } - } @@ -1432,10 +1477,12 @@ public class RubberQuickTestOperationViewModel : BaseViewModel private MesXslRubberQuickTestRecord BuildSaveRecord( - List lineList, + List stdLineList, List rawLineList, + List chartPointList, + int inspectTimes, SysUser? user) @@ -1446,13 +1493,19 @@ public class RubberQuickTestOperationViewModel : BaseViewModel { - LineList = lineList, + StdLineList = stdLineList, RawLineList = rawLineList, + ChartPointList = chartPointList, + InspectTime = DateTime.Now, - InspectResult = OverallInspectResultCode + CreateTime = DateTime.Now, + + InspectResult = OverallInspectResultCode, + + RecordNo = _recordService.GenerateRecordNo(RubberMaterialName ?? string.Empty) }; @@ -1470,6 +1523,26 @@ public class RubberQuickTestOperationViewModel : BaseViewModel record.StdId = _currentStd.Id; + if (!string.IsNullOrWhiteSpace(_currentStd?.StdName)) + + record.StdName = _currentStd.StdName; + + if (!string.IsNullOrWhiteSpace(_currentStd?.TestMethodId)) + + record.TestMethodId = _currentStd.TestMethodId; + + if (!string.IsNullOrWhiteSpace(TestMethodName)) + + record.TestMethodName = TestMethodName; + + if (!string.IsNullOrWhiteSpace(_currentStd?.QuickTestTypeId)) + + record.QuickTestTypeId = _currentStd.QuickTestTypeId; + + if (!string.IsNullOrWhiteSpace(_currentStd?.QuickTestTypeName)) + + record.QuickTestTypeName = _currentStd.QuickTestTypeName; + if (!string.IsNullOrWhiteSpace(_selectedPlan?.MachineId)) @@ -1502,9 +1575,9 @@ public class RubberQuickTestOperationViewModel : BaseViewModel - if (!string.IsNullOrWhiteSpace(_selectedPlan?.PlanMaterialNo)) + if (!string.IsNullOrWhiteSpace(_selectedPlan?.PlanNo)) - record.ProductionPlanNo = _selectedPlan.PlanMaterialNo; + record.ProductionPlanNo = _selectedPlan.PlanNo; @@ -1528,6 +1601,169 @@ public class RubberQuickTestOperationViewModel : BaseViewModel } + private List BuildStdLineList() + { + var lines = new List(); + int sort = 0; + foreach (var col in DataPointColumns) + { + lines.Add(new MesXslRubberQuickTestRecordStdLine + { + DataPointId = col.DataPointId, + PointName = col.PointName, + LowerLimit = col.LowerLimit, + LowerWarn = col.LowerWarn, + TargetValue = col.TargetValue, + UpperWarn = col.UpperWarn, + UpperLimit = col.UpperLimit, + SortNo = sort++ + }); + } + return lines; + } + + private List BuildChartPointList() + { + var points = new List(); + int sort = 0; + for (int i = 0; i < ChartPointCount && i < UpperTempValues.Count; i++) + { + points.Add(new MesXslRubberQuickTestRecordChartPoint + { + TimeMin = (decimal)(UpperTempValues[i].X ?? ChartTimeMinutes[i]), + UpperTemp = UpperTempValues[i].Y.HasValue ? (decimal)UpperTempValues[i].Y!.Value : null, + LowerTemp = i < LowerTempValues.Count && LowerTempValues[i].Y.HasValue ? (decimal)LowerTempValues[i].Y!.Value : null, + TorqueS = i < TorqueValues.Count && TorqueValues[i].Y.HasValue ? (decimal)TorqueValues[i].Y!.Value : null, + SortNo = sort++ + }); + } + return points; + } + + private async Task LoadFromLocalItemAsync(string localId) + { + var item = _recordService.GetByLocalId(localId); + if (item == null) + { + Growl.Warning("未找到快检记录"); + return; + } + + await ApplyRecordDetailAsync(item.Record); + } + + private async Task LoadFromMesIdAsync(string mesId) + { + var record = await _recordService.GetByIdAsync(mesId); + if (record == null) + { + Growl.Warning("未找到快检记录"); + return; + } + + await ApplyRecordDetailAsync(record); + } + + private async Task ApplyRecordDetailAsync(MesXslRubberQuickTestRecord r) + { + IsReadOnly = true; + RecordNo = r.RecordNo; + MixingDate = r.ProductionDate ?? DateTime.Today; + SelectedMachine = r.ProdEquipmentName; + TrainNo = r.TrainNo; + InspectTimesText = r.InspectTimes?.ToString() ?? "1"; + InspectorDisplay = r.InspectorRealname ?? ResolveInspectorDisplay(); + OverallInspectResultCode = r.InspectResult ?? "0"; + OverallInspectResultDisplay = string.Equals(r.InspectResult, "1", StringComparison.Ordinal) ? "合格" : "不合格"; + TestMethodName = r.TestMethodName; + + MachineOptions.Clear(); + if (!string.IsNullOrWhiteSpace(r.ProdEquipmentName)) + MachineOptions.Add(r.ProdEquipmentName); + + ShiftOptions.Clear(); + var shift = new WorkShiftOption(r.WorkShift ?? "", r.WorkShift ?? ""); + ShiftOptions.Add(shift); + SelectedShift = shift; + + PlanOptions.Clear(); + var plan = new MesXslMixingProductionPlan + { + PlanNo = r.ProductionPlanNo, + MaterialName = r.RubberMaterialName, + MachineName = r.ProdEquipmentName + }; + PlanOptions.Add(plan); + _selectedPlan = plan; + RaisePropertyChanged(nameof(SelectedPlan)); + RaisePropertyChanged(nameof(MachineName)); + RaisePropertyChanged(nameof(RubberMaterialName)); + + StdOptions.Clear(); + var std = new MesXslRubberQuickTestStd { Id = r.StdId, StdName = r.StdName, TestMethodName = r.TestMethodName }; + StdOptions.Add(std); + _selectedStd = std; + RaisePropertyChanged(nameof(SelectedStd)); + + DataPointColumns.Clear(); + InspectRows.Clear(); + foreach (var sl in (r.StdLineList ?? new List()).OrderBy(x => x.SortNo ?? 0)) + { + DataPointColumns.Add(new MesXslRubberQuickTestStdLine + { + DataPointId = sl.DataPointId, + PointName = sl.PointName, + LowerLimit = sl.LowerLimit, + LowerWarn = sl.LowerWarn, + TargetValue = sl.TargetValue, + UpperWarn = sl.UpperWarn, + UpperLimit = sl.UpperLimit, + SortNo = sl.SortNo + }); + } + InspectColumnsChanged?.Invoke(); + + var grouped = (r.RawLineList ?? new List()) + .GroupBy(x => x.RowNo ?? string.Empty) + .OrderBy(g => g.Key, StringComparer.Ordinal); + foreach (var g in grouped) + { + var row = new QuickTestInspectRowViewModel { RowNo = g.Key }; + for (int i = 0; i < DataPointColumns.Count; i++) + { + var col = DataPointColumns[i]; + var raw = g.FirstOrDefault(x => x.DataPointId == col.DataPointId || x.InspectItem == col.PointName); + var cell = new QuickTestInspectCellViewModel + { + DataPointId = col.DataPointId, + PointName = col.PointName ?? string.Empty, + LowerLimit = col.LowerLimit, + UpperLimit = col.UpperLimit, + Value = raw?.InspectValue + }; + row.Cells.Add(cell); + } + row.RecalculateResult(); + InspectRows.Add(row); + } + + UpperTempValues.Clear(); + LowerTempValues.Clear(); + TorqueValues.Clear(); + foreach (var pt in (r.ChartPointList ?? new List()).OrderBy(x => x.SortNo ?? 0)) + { + var time = (double)(pt.TimeMin ?? 0); + if (pt.UpperTemp != null) UpperTempValues.Add(new ObservablePoint(time, (double)pt.UpperTemp.Value)); + if (pt.LowerTemp != null) LowerTempValues.Add(new ObservablePoint(time, (double)pt.LowerTemp.Value)); + if (pt.TorqueS != null) TorqueValues.Add(new ObservablePoint(time, (double)pt.TorqueS.Value)); + } + if (UpperTempValues.Count > 0) UpperMoldTemp = UpperTempValues[^1].Y ?? 0; + if (LowerTempValues.Count > 0) LowerMoldTemp = LowerTempValues[^1].Y ?? 0; + if (TorqueValues.Count > 0) TorqueS = TorqueValues[^1].Y ?? 0; + + await Task.CompletedTask; + } + private static Axis[] BuildTimeAxis() => new[] diff --git a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestRecordDetailDialogViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestRecordDetailDialogViewModel.cs new file mode 100644 index 00000000..e7dd0d08 --- /dev/null +++ b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestRecordDetailDialogViewModel.cs @@ -0,0 +1,104 @@ +using LiveChartsCore; +using LiveChartsCore.Defaults; +using LiveChartsCore.SkiaSharpView; +using Prism.Mvvm; +using System.Collections.ObjectModel; +using YY.Admin.Core.Entity; + +namespace YY.Admin.ViewModels.RubberQuickTest; + +public class RubberQuickTestRecordDetailDialogViewModel : BindableBase +{ + private MesXslRubberQuickTestRecord? _record; + public MesXslRubberQuickTestRecord? Record + { + get => _record; + private set => SetProperty(ref _record, value); + } + + private string? _inspectResultDisplay; + public string? InspectResultDisplay + { + get => _inspectResultDisplay; + private set => SetProperty(ref _inspectResultDisplay, value); + } + + public ObservableCollection StdLines { get; } = new(); + public ObservableCollection RawLines { get; } = new(); + + public ObservableCollection TemperatureSeries { get; } + public ObservableCollection TorqueSeries { get; } + public ObservableCollection UpperTempValues { get; } = new(); + public ObservableCollection LowerTempValues { get; } = new(); + public ObservableCollection TorqueValues { get; } = new(); + + public Axis[] TemperatureXAxes { get; } = BuildTimeAxis(); + public Axis[] TemperatureYAxes { get; } = BuildTempYAxis(); + public Axis[] TorqueXAxes { get; } = BuildTimeAxis(); + public Axis[] TorqueYAxes { get; } = BuildTorqueYAxis(); + + public RubberQuickTestRecordDetailDialogViewModel() + { + TemperatureSeries = new ObservableCollection + { + new LineSeries { Name = "上模温度", Values = UpperTempValues, GeometrySize = 4, LineSmoothness = 0.3 }, + new LineSeries { Name = "下模温度", Values = LowerTempValues, GeometrySize = 4, LineSmoothness = 0.3 } + }; + TorqueSeries = new ObservableCollection + { + new LineSeries { Name = "S'(dNm)", Values = TorqueValues, GeometrySize = 4, LineSmoothness = 0.3 } + }; + } + + public void Initialize(MesXslRubberQuickTestRecord record) + { + Record = record; + InspectResultDisplay = record.InspectResult switch + { + "1" => "合格", + "0" => "不合格", + _ => record.InspectResultText ?? record.InspectResult ?? "" + }; + StdLines.Clear(); + foreach (var line in record.StdLineList ?? []) + StdLines.Add(line); + + RawLines.Clear(); + foreach (var line in record.RawLineList ?? []) + RawLines.Add(line); + + UpperTempValues.Clear(); + LowerTempValues.Clear(); + TorqueValues.Clear(); + foreach (var p in (record.ChartPointList ?? []).OrderBy(x => x.SortNo ?? 0)) + { + var time = (double)(p.TimeMin ?? 0); + UpperTempValues.Add(new ObservablePoint(time, (double)(p.UpperTemp ?? 0))); + LowerTempValues.Add(new ObservablePoint(time, (double)(p.LowerTemp ?? 0))); + TorqueValues.Add(new ObservablePoint(time, (double)(p.TorqueS ?? 0))); + } + } + + private static Axis[] BuildTimeAxis() => new[] + { + new Axis { Name = "时间(min)", MinLimit = 0, MaxLimit = 2, Labeler = v => v.ToString("0.0#") } + }; + + private static Axis[] BuildTempYAxis() => new[] + { + new Axis { Name = "温度(℃)", MinLimit = 189, MaxLimit = 201 } + }; + + private static readonly double[] TorqueYTicks = { 0.0, 3.0, 5.9, 8.9, 11.8, 14.8 }; + + private static Axis[] BuildTorqueYAxis() => new[] + { + new Axis + { + Name = "S'(dNm)", + MinLimit = 0, + MaxLimit = 14.8, + CustomSeparators = TorqueYTicks + } + }; +} diff --git a/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestRecordListViewModel.cs b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestRecordListViewModel.cs new file mode 100644 index 00000000..f0b8dcc7 --- /dev/null +++ b/yy-admin-master/YY.Admin/ViewModels/RubberQuickTest/RubberQuickTestRecordListViewModel.cs @@ -0,0 +1,227 @@ +using HandyControl.Controls; +using Prism.Events; +using Prism.Navigation; +using System.Collections.ObjectModel; +using System.Diagnostics; +using YY.Admin.Core; +using YY.Admin.Core.Entity; +using YY.Admin.Core.Events; +using YY.Admin.Core.Helper; +using YY.Admin.Core.Services; +using YY.Admin.Event; +using YY.Admin.Module; +using YY.Admin.Services.Service; + +namespace YY.Admin.ViewModels.RubberQuickTest; + +public class RubberQuickTestRecordListViewModel : BaseViewModel +{ + private readonly IRubberQuickTestRecordService _recordService; + private readonly IJeecgDictSyncService _dictSyncService; + private SubscriptionToken? _changedToken; + + private ObservableCollection _records = new(); + public ObservableCollection Records + { + get => _records; + set => SetProperty(ref _records, value); + } + + private long _total; + public long Total { get => _total; set => SetProperty(ref _total, value); } + + private int _pageNo = 1; + public int PageNo { get => _pageNo; set => SetProperty(ref _pageNo, value); } + + private int _pageSize = 20; + public int PageSize { get => _pageSize; set => SetProperty(ref _pageSize, value); } + + private string? _filterRecordNo; + public string? FilterRecordNo { get => _filterRecordNo; set => SetProperty(ref _filterRecordNo, value); } + + private string? _filterRubberMaterialName; + public string? FilterRubberMaterialName { get => _filterRubberMaterialName; set => SetProperty(ref _filterRubberMaterialName, value); } + + private string? _filterPlanNo; + public string? FilterPlanNo { get => _filterPlanNo; set => SetProperty(ref _filterPlanNo, value); } + + public DelegateCommand SearchCommand { get; } + public DelegateCommand ResetCommand { get; } + public DelegateCommand AddCommand { get; } + public DelegateCommand ViewDetailCommand { get; } + public DelegateCommand DeleteCommand { get; } + public DelegateCommand PrevPageCommand { get; } + public DelegateCommand NextPageCommand { get; } + + public RubberQuickTestRecordListViewModel( + IRubberQuickTestRecordService recordService, + IJeecgDictSyncService dictSyncService, + IContainerExtension container, + IRegionManager regionManager) : base(container, regionManager) + { + _recordService = recordService; + _dictSyncService = dictSyncService; + + SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); }); + ResetCommand = new DelegateCommand(async () => + { + FilterRecordNo = null; + FilterRubberMaterialName = null; + FilterPlanNo = null; + PageNo = 1; + await LoadAsync(); + }); + AddCommand = new DelegateCommand(OpenAddPage); + ViewDetailCommand = new DelegateCommand(async r => await ShowDetailAsync(r)); + DeleteCommand = new DelegateCommand( + async r => await DeleteAsync(r), + r => r != null && r.CanDelete); + PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } }); + NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } }); + + _changedToken = _eventAggregator.GetEvent() + .Subscribe(async _ => await LoadAsync(), ThreadOption.UIThread); + + _ = InitializeAsync(); + } + + private async Task InitializeAsync() + { + try + { + await UIHelper.WaitForRenderAsync(); + await LoadAsync(); + } + catch (Exception ex) + { + Debug.WriteLine($"快检记录列表初始化失败: {ex.Message}"); + } + } + + public async Task LoadAsync() + { + try + { + IsLoading = true; + var result = await _recordService.PageAsync( + PageNo, PageSize, FilterRecordNo, FilterRubberMaterialName, FilterPlanNo); + + var shiftMap = (await _dictSyncService.GetDictOptionsAsync("xslmes_rubber_quick_test_work_shift", includeAll: false)) + .ToDictionary(x => x.Value, x => x.Key); + foreach (var r in result.Records) + { + if (!string.IsNullOrWhiteSpace(r.WorkShiftDisplay) && shiftMap.TryGetValue(r.WorkShiftDisplay, out var txt)) + r.WorkShiftDisplay = txt; + } + + Records = new ObservableCollection(result.Records); + Total = result.Total; + } + catch (Exception ex) + { + Growl.Error($"加载快检记录失败:{ex.Message}"); + } + finally + { + IsLoading = false; + } + } + + private void OpenAddPage() + { + _eventAggregator.GetEvent().Publish(new TabSource + { + Name = "新增胶料快检记录", + Icon = "\ue7de", + ViewName = "RubberQuickTestOperationView" + }); + } + + private async Task DeleteAsync(RubberQuickTestRecordListRow? row) + { + if (row == null || !row.CanDelete || string.IsNullOrWhiteSpace(row.LocalId)) + return; + + var label = row.RecordNo ?? row.LocalId; + var confirm = System.Windows.MessageBox.Show( + $"确定删除同步失败的快检记录「{label}」?\n此操作仅删除本地记录,不可恢复。", + "确认删除", + System.Windows.MessageBoxButton.YesNo, + System.Windows.MessageBoxImage.Warning); + if (confirm != System.Windows.MessageBoxResult.Yes) + return; + + try + { + if (_recordService.DeleteFailedLocal(row.LocalId)) + { + Growl.Success("删除成功"); + await LoadAsync(); + } + else + { + Growl.Warning("仅同步失败的本地记录可删除"); + } + } + catch (Exception ex) + { + Growl.Error($"删除失败:{ex.Message}"); + } + } + + private async Task ShowDetailAsync(RubberQuickTestRecordListRow? row) + { + if (row == null) return; + try + { + if (!string.IsNullOrWhiteSpace(row.LocalId)) + { + if (_recordService.GetByLocalId(row.LocalId) == null) + { + Growl.Warning("未找到快检记录详情"); + return; + } + } + else if (!string.IsNullOrWhiteSpace(row.MesId)) + { + var remote = await _recordService.GetByIdAsync(row.MesId); + if (remote == null) + { + Growl.Warning("未找到快检记录详情"); + return; + } + } + else + { + Growl.Warning("无法定位快检记录"); + return; + } + + var parameters = new NavigationParameters { { "readOnly", true } }; + if (!string.IsNullOrWhiteSpace(row.LocalId)) + parameters.Add("localId", row.LocalId); + else + parameters.Add("mesId", row.MesId!); + + var title = row.RecordNo ?? row.LocalId ?? row.MesId ?? "详情"; + _eventAggregator.GetEvent().Publish(new TabSource + { + Name = $"快检记录 {title}", + Icon = "\ue7de", + ViewName = "RubberQuickTestOperationView", + NavigationParameter = parameters + }); + } + catch (Exception ex) + { + Growl.Error($"打开详情失败:{ex.Message}"); + } + } + + protected override void CleanUp() + { + base.CleanUp(); + if (_changedToken != null) + _eventAggregator.GetEvent().Unsubscribe(_changedToken); + } +} diff --git a/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml b/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml index 9dcd6a7c..00a8bca6 100644 --- a/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml +++ b/yy-admin-master/YY.Admin/Views/RubberQuickTest/RubberQuickTestOperationView.xaml @@ -24,25 +24,34 @@ + + - + - - - + BorderBrush="{DynamicResource BorderBrush}" BorderThickness="0,0,0,1" Margin="-12,0,-12,6"> + + + - - + + @@ -55,44 +64,70 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + +