This commit is contained in:
2026-06-17 15:47:59 +08:00
47 changed files with 2687 additions and 17 deletions

View File

@@ -217,6 +217,12 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/xslmes/mesXslUnit/anon/**", "anon"); filterChainDefinitionMap.put("/xslmes/mesXslUnit/anon/**", "anon");
// MES密炼物料管理免密接口供桌面端调用 // MES密炼物料管理免密接口供桌面端调用
filterChainDefinitionMap.put("/mes/material/mixerMaterial/anon/**", "anon"); filterChainDefinitionMap.put("/mes/material/mixerMaterial/anon/**", "anon");
// MES密炼生产计划维护免密接口供桌面端快检记录调用
filterChainDefinitionMap.put("/xslmes/mesXslMixingProductionPlan/anon/**", "anon");
// MES胶料快检实验标准免密接口供桌面端快检记录调用
filterChainDefinitionMap.put("/xslmes/mesXslRubberQuickTestStd/anon/**", "anon");
// MES胶料快检记录免密接口供桌面端快检记录调用
filterChainDefinitionMap.put("/xslmes/mesXslRubberQuickTestRecord/anon/**", "anon");
// 打印模板免密接口(供桌面端调用) // 打印模板免密接口(供桌面端调用)
filterChainDefinitionMap.put("/print/template/anon/**", "anon"); filterChainDefinitionMap.put("/print/template/anon/**", "anon");
filterChainDefinitionMap.put("/print/bizTemplateBind/anon/**", "anon"); filterChainDefinitionMap.put("/print/bizTemplateBind/anon/**", "anon");

View File

@@ -1093,8 +1093,20 @@ jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/MesXslEquipDowntimeRec
jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/MesXslEquipDowntimeRecordList.vue jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/MesXslEquipDowntimeRecordList.vue
jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/components/MesXslEquipDowntimeRecordModal.vue jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/components/MesXslEquipDowntimeRecordModal.vue
-- author:GHT---date:20260616--for: 【MES上辅机】生产环境 SQL Server 中间库连接池校验 DUAL 报错修复 ---
原因application-prod.yml 全局 druid.validationQuery 为 SELECT 1 FROM DUAL动态创建的 sqlserver_mcs 数据源继承该配置后在 SQL Server 上报「对象名 DUAL 无效」。
修改prod 全局改为 SELECT 1McsDataSourceManager 创建/恢复 SQL Server 数据源时显式设置 validationQuery=SELECT 1。
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/datasource/McsDataSourceManager.java jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/datasource/McsDataSourceManager.java
-- author:GHT---date:20260616--for: 【MES上辅机】重启后中间库配置未自动加载租户ID硬编码为0---
原因McsDataSourceInitializer 启动时只查 tenant_id=0页面保存用当前租户如1002重启后查不到配置连接状态回退为 yml。
修改:新增 loadStartupConfig 按最近更新时间加载任意租户配置isDbConfigActive 同时校验数据源是否已注册。
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/IMesXslMcsDbConfigService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslMcsDbConfigServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/config/McsDataSourceInitializer.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/datasource/McsDataSourceManager.java
-- author:jiangxh---date:20260617--for: 【快检实验标准】补齐 tenant_id 为空的历史数据并恢复租户过滤 ---
原因:一条快检实验标准 tenant_id 为 NULL桌面端按 tenantId=1002 拉取时漏掉该条。
修改Flyway 将 NULL tenant_id 对齐为 1002新增保存时自动写入 tenant_id恢复 anon/list 与桌面端 tenantId 查询参数。
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_152__mes_xsl_rubber_quick_test_std_tenant_backfill.sql
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestStdServiceImpl.java
yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs

View File

@@ -7,6 +7,7 @@ import org.jeecg.modules.xslmes.approval.callback.IApprovalBizCallback;
import org.jeecg.modules.xslmes.common.XslMesBizConstants; import org.jeecg.modules.xslmes.common.XslMesBizConstants;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
@@ -25,9 +26,13 @@ import org.springframework.stereotype.Component;
public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback { public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback {
private final IMesXslRubberQuickTestStdService stdService; private final IMesXslRubberQuickTestStdService stdService;
private final MesXslStompNotifyService stompNotify;
public RubberQuickTestStdApprovalCallback(IMesXslRubberQuickTestStdService stdService) { public RubberQuickTestStdApprovalCallback(
IMesXslRubberQuickTestStdService stdService,
MesXslStompNotifyService stompNotify) {
this.stdService = stdService; this.stdService = stdService;
this.stompNotify = stompNotify;
} }
@Override @Override
@@ -55,5 +60,8 @@ public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback
.eq(MesXslRubberQuickTestStd::getId, bizDataId) .eq(MesXslRubberQuickTestStd::getId, bizDataId)
.set(MesXslRubberQuickTestStd::getAuditStatus, auditStatus) .set(MesXslRubberQuickTestStd::getAuditStatus, auditStatus)
.update(); .update();
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】审批联动 STOMP 同步桌面端-----------
stompNotify.publishRubberQuickTestStdChanged("audit", bizDataId);
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】审批联动 STOMP 同步桌面端-----------
} }
} }

View File

@@ -1,5 +1,6 @@
package org.jeecg.modules.xslmes.controller; package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -21,6 +22,7 @@ import org.jeecg.modules.print.entity.PrintTemplate;
import org.jeecg.modules.print.service.IPrintBizTemplateBindService; import org.jeecg.modules.print.service.IPrintBizTemplateBindService;
import org.jeecg.modules.print.service.IPrintTemplateService; import org.jeecg.modules.print.service.IPrintTemplateService;
import org.jeecg.modules.print.util.PrintBizDataMappingUtil; import org.jeecg.modules.print.util.PrintBizDataMappingUtil;
import org.jeecg.modules.xslmes.common.XslMesBizConstants;
import org.jeecg.modules.xslmes.constant.MesXslCustomerBizStatus; import org.jeecg.modules.xslmes.constant.MesXslCustomerBizStatus;
import org.jeecg.modules.xslmes.constant.MesXslPrintConstants; import org.jeecg.modules.xslmes.constant.MesXslPrintConstants;
import org.jeecg.modules.xslmes.entity.MesXslCustomer; import org.jeecg.modules.xslmes.entity.MesXslCustomer;
@@ -32,6 +34,11 @@ import org.jeecg.modules.xslmes.entity.MesXslUnit;
import org.jeecg.modules.xslmes.entity.MesXslVehicle; import org.jeecg.modules.xslmes.entity.MesXslVehicle;
import org.jeecg.modules.xslmes.entity.MesXslWarehouse; import org.jeecg.modules.xslmes.entity.MesXslWarehouse;
import org.jeecg.modules.xslmes.entity.MesXslWarehouseArea; import org.jeecg.modules.xslmes.entity.MesXslWarehouseArea;
import org.jeecg.modules.xslmes.entity.MesXslMixingProductionPlan;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine;
import org.jeecg.modules.xslmes.entity.MesXslWeightRecord; import org.jeecg.modules.xslmes.entity.MesXslWeightRecord;
import org.jeecg.modules.xslmes.service.IMesXslCustomerService; import org.jeecg.modules.xslmes.service.IMesXslCustomerService;
import org.jeecg.modules.xslmes.service.IMesXslRawMaterialCardService; import org.jeecg.modules.xslmes.service.IMesXslRawMaterialCardService;
@@ -42,6 +49,9 @@ import org.jeecg.modules.xslmes.service.IMesXslUnitService;
import org.jeecg.modules.xslmes.service.IMesXslVehicleService; import org.jeecg.modules.xslmes.service.IMesXslVehicleService;
import org.jeecg.modules.xslmes.service.IMesXslWarehouseAreaService; import org.jeecg.modules.xslmes.service.IMesXslWarehouseAreaService;
import org.jeecg.modules.xslmes.service.IMesXslWarehouseService; import org.jeecg.modules.xslmes.service.IMesXslWarehouseService;
import org.jeecg.modules.xslmes.service.IMesXslMixingProductionPlanService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
import org.jeecg.modules.xslmes.service.IMesXslWeightRecordService; import org.jeecg.modules.xslmes.service.IMesXslWeightRecordService;
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService; import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
import org.jeecg.modules.xslmes.vo.MesXslRawMaterialCardBriefVO; import org.jeecg.modules.xslmes.vo.MesXslRawMaterialCardBriefVO;
@@ -87,6 +97,9 @@ public class MesXslDesktopAnonController {
private final IPrintBizTemplateBindService printBizTemplateBindService; private final IPrintBizTemplateBindService printBizTemplateBindService;
private final IPrintTemplateService printTemplateService; private final IPrintTemplateService printTemplateService;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final IMesXslMixingProductionPlanService mixingProductionPlanService;
private final IMesXslRubberQuickTestStdService rubberQuickTestStdService;
private final IMesXslRubberQuickTestRecordService rubberQuickTestRecordService;
// ═══════════════════════════ 车辆管理 ═══════════════════════════ // ═══════════════════════════ 车辆管理 ═══════════════════════════
@@ -925,6 +938,105 @@ public class MesXslDesktopAnonController {
} }
//update-end---author:cursor ---date:20250602 for【密炼物料皮重策略】桌面端单位下拉只读----------- //update-end---author:cursor ---date:20250602 for【密炼物料皮重策略】桌面端单位下拉只读-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端密炼生产计划只读-----------
@Operation(summary = "密炼生产计划维护-免密分页列表查询(供桌面端快检记录筛选)")
@GetMapping("/xslmes/mesXslMixingProductionPlan/anon/list")
public Result<IPage<MesXslMixingProductionPlan>> mixingProductionPlanAnonList(
MesXslMixingProductionPlan model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "500") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslMixingProductionPlan> qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
qw.orderByAsc("sort_no").orderByAsc("create_time");
IPage<MesXslMixingProductionPlan> page =
mixingProductionPlanService.page(new Page<>(pageNo, pageSize), qw);
return Result.OK(page);
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端密炼生产计划只读-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检实验标准】桌面端只读列表与详情-----------
@Operation(summary = "胶料快检实验标准-免密分页列表")
@GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/list")
public Result<IPage<MesXslRubberQuickTestStd>> rubberQuickTestStdAnonList(
MesXslRubberQuickTestStd model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslRubberQuickTestStd> qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
qw.orderByDesc("create_time");
IPage<MesXslRubberQuickTestStd> page = rubberQuickTestStdService.page(new Page<>(pageNo, pageSize), qw);
return Result.OK(page);
}
@Operation(summary = "胶料快检实验标准-免密通过id查询含明细")
@GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryById")
public Result<MesXslRubberQuickTestStd> rubberQuickTestStdAnonQueryById(@RequestParam(name = "id") String id) {
MesXslRubberQuickTestStd entity = rubberQuickTestStdService.getById(id);
if (entity == null) {
return Result.error("未找到对应数据");
}
entity.setLineList(rubberQuickTestStdService.selectLinesByStdId(id));
return Result.OK(entity);
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检实验标准】桌面端只读列表与详情-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检实验标准查询-----------
private static final String RUBBER_QUICK_TEST_STD_ENABLE_IN_USE = "1";
@Operation(summary = "胶料快检实验标准-免密按胶料名称查询使用中标准及明细")
@GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryByRubberMaterialName")
public Result<MesXslRubberQuickTestStd> rubberQuickTestStdAnonQueryByRubberMaterialName(
@RequestParam(name = "rubberMaterialName") String rubberMaterialName) {
if (oConvertUtils.isEmpty(rubberMaterialName)) {
return Result.error("胶料名称不能为空");
}
String name = rubberMaterialName.trim();
LambdaQueryWrapper<MesXslRubberQuickTestStd> qw = new LambdaQueryWrapper<>();
qw.eq(MesXslRubberQuickTestStd::getRubberMaterialName, name);
qw.eq(MesXslRubberQuickTestStd::getEnableStatus, RUBBER_QUICK_TEST_STD_ENABLE_IN_USE);
qw.eq(MesXslRubberQuickTestStd::getAuditStatus, XslMesBizConstants.RUBBER_QUICK_TEST_STD_AUDIT_APPROVED);
qw.orderByDesc(MesXslRubberQuickTestStd::getCreateTime);
MesXslRubberQuickTestStd std = rubberQuickTestStdService.getOne(qw, false);
if (std == null) {
return Result.error("未找到胶料「" + name + "」对应的使用中且已批准的快检实验标准");
}
std.setLineList(rubberQuickTestStdService.selectLinesByStdId(std.getId()));
return Result.OK(std);
}
@Operation(summary = "胶料快检实验标准-免密查询明细")
@GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryLineListByStdId")
public Result<List<MesXslRubberQuickTestStdLine>> rubberQuickTestStdAnonQueryLineListByStdId(
@RequestParam(name = "id") String id) {
return Result.OK(rubberQuickTestStdService.selectLinesByStdId(id));
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检实验标准查询-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检记录保存-----------
@Operation(summary = "胶料快检记录-免密添加")
@PostMapping("/xslmes/mesXslRubberQuickTestRecord/anon/add")
public Result<String> rubberQuickTestRecordAnonAdd(@RequestBody MesXslRubberQuickTestRecord record) {
if (record == null) {
return Result.error("参数不能为空");
}
if (oConvertUtils.isEmpty(record.getRubberMaterialName())) {
return Result.error("胶料名称不能为空");
}
List<MesXslRubberQuickTestRecordLine> lineList = record.getLineList();
if (lineList == null || lineList.isEmpty()) {
return Result.error("请维护检验明细");
}
try {
rubberQuickTestRecordService.saveMain(record, lineList);
stompNotify.publishRubberQuickTestRecordChanged("add", record.getId());
return Result.OK("添加成功!");
} catch (Exception e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检记录保存-----------
// ─────────────────────────── 车辆私有辅助 ──────────────────────────── // ─────────────────────────── 车辆私有辅助 ────────────────────────────
private void applyWeightNetAndBillType(MesXslWeightRecord record) { private void applyWeightNetAndBillType(MesXslWeightRecord record) {

View File

@@ -24,6 +24,7 @@ import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService; import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
@@ -163,6 +164,15 @@ public class MesXslRubberQuickTestRecordController
return Result.OK(mesXslRubberQuickTestRecordService.selectLinesByRecordId(id)); return Result.OK(mesXslRubberQuickTestRecordService.selectLinesByRecordId(id));
} }
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】查询原始数据明细-----------
@Operation(summary = "MES胶料快检记录-查询原始数据明细")
@GetMapping(value = "/queryRawLineListByRecordId")
public Result<List<MesXslRubberQuickTestRecordRawLine>> queryRawLineListByRecordId(
@RequestParam(name = "id", required = true) String id) {
return Result.OK(mesXslRubberQuickTestRecordService.selectRawLinesByRecordId(id));
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】查询原始数据明细-----------
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_record:exportXls") @RequiresPermissions("mes:mes_xsl_rubber_quick_test_record:exportXls")
@RequestMapping(value = "/exportXls") @RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, MesXslRubberQuickTestRecord model) { public ModelAndView exportXls(HttpServletRequest request, MesXslRubberQuickTestRecord model) {

View File

@@ -36,6 +36,7 @@ import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService; import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestStdPage; import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestStdPage;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -73,6 +74,9 @@ public class MesXslRubberQuickTestStdController
@Autowired @Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService; private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Autowired
private MesXslStompNotifyService stompNotify;
@Operation(summary = "MES胶料快检实验标准-分页列表查询") @Operation(summary = "MES胶料快检实验标准-分页列表查询")
@GetMapping(value = "/list") @GetMapping(value = "/list")
public Result<IPage<MesXslRubberQuickTestStd>> queryPageList( public Result<IPage<MesXslRubberQuickTestStd>> queryPageList(
@@ -107,6 +111,9 @@ public class MesXslRubberQuickTestStdController
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
return Result.error(e.getMessage()); return Result.error(e.getMessage());
} }
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("add", main.getId());
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("添加成功!"); return Result.OK("添加成功!");
} }
@@ -129,6 +136,9 @@ public class MesXslRubberQuickTestStdController
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
return Result.error(e.getMessage()); return Result.error(e.getMessage());
} }
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("edit", main.getId());
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("编辑成功!"); return Result.OK("编辑成功!");
} }
@@ -142,6 +152,9 @@ public class MesXslRubberQuickTestStdController
return Result.error(refErr); return Result.error(refErr);
} }
mesXslRubberQuickTestStdService.delMain(id); mesXslRubberQuickTestStdService.delMain(id);
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("delete", id);
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("删除成功!"); return Result.OK("删除成功!");
} }
@@ -155,6 +168,9 @@ public class MesXslRubberQuickTestStdController
return Result.error(refErr); return Result.error(refErr);
} }
mesXslRubberQuickTestStdService.delBatchMain(Arrays.asList(ids.split(","))); mesXslRubberQuickTestStdService.delBatchMain(Arrays.asList(ids.split(",")));
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("batchDelete", ids);
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("批量删除成功!"); return Result.OK("批量删除成功!");
} }
@@ -196,6 +212,9 @@ public class MesXslRubberQuickTestStdController
.set(MesXslRubberQuickTestStd::getEnableStatus, enableStatus) .set(MesXslRubberQuickTestStd::getEnableStatus, enableStatus)
.update(); .update();
if (updated) { if (updated) {
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("status", id);
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("操作成功"); return Result.OK("操作成功");
} }
MesXslRubberQuickTestStd cur = mesXslRubberQuickTestStdService.getById(id); MesXslRubberQuickTestStd cur = mesXslRubberQuickTestStdService.getById(id);
@@ -272,6 +291,18 @@ public class MesXslRubberQuickTestStdController
if (!XslMesBizConstants.PS_TYPE_RAW_INSPECT_STD.equals(ps.getPsType())) { if (!XslMesBizConstants.PS_TYPE_RAW_INSPECT_STD.equals(ps.getPsType())) {
return "发行编号须选择类型为原材料检验标准的密炼PS"; return "发行编号须选择类型为原材料检验标准的密炼PS";
} }
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】发行编号仅允许选择编制状态密炼PS-----------
boolean psCompileIdChanged = true;
if (oConvertUtils.isNotEmpty(excludeId)) {
MesXslRubberQuickTestStd existingStd = mesXslRubberQuickTestStdService.getById(excludeId);
if (existingStd != null && oConvertUtils.isNotEmpty(existingStd.getPsCompileId())) {
psCompileIdChanged = !existingStd.getPsCompileId().equals(main.getPsCompileId());
}
}
if (psCompileIdChanged && !"compile".equals(ps.getStatus())) {
return "发行编号须选择编制状态的密炼PS";
}
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】发行编号仅允许选择编制状态密炼PS-----------
main.setIssueNumber(ps.getPsCode()); main.setIssueNumber(ps.getPsCode());
if (main.getIssueDate() == null && ps.getIssueDate() != null) { if (main.getIssueDate() == null && ps.getIssueDate() != null) {
main.setIssueDate(ps.getIssueDate()); main.setIssueDate(ps.getIssueDate());

View File

@@ -130,4 +130,8 @@ public class MesXslRubberQuickTestRecord implements Serializable {
@TableField(exist = false) @TableField(exist = false)
private List<MesXslRubberQuickTestRecordLine> lineList; private List<MesXslRubberQuickTestRecordLine> lineList;
@TableField(exist = false)
@Schema(description = "原始数据明细(试验结果全部检测值)")
private List<MesXslRubberQuickTestRecordRawLine> rawLineList;
} }

View File

@@ -0,0 +1,72 @@
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.jeecg.common.aspect.annotation.Dict;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* MES 胶料快检记录原始数据明细(试验结果全部检测值)
*/
@Data
@TableName("mes_xsl_rubber_quick_test_record_raw_line")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES胶料快检记录原始数据明细")
public class MesXslRubberQuickTestRecordRawLine 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 = "编号", width = 14)
@Schema(description = "试验结果编号如1_1")
private String rowNo;
@Schema(description = "数据点ID")
private String dataPointId;
@Excel(name = "数据点", width = 18)
private String inspectItem;
@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 inspectValue;
@Excel(name = "行检验结果", width = 10, dicCode = "xslmes_rubber_quick_test_record_result")
@Dict(dicCode = "xslmes_rubber_quick_test_record_result")
@Schema(description = "行检验结果1合格0不合格")
private String rowInspectResult;
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;
}

View File

@@ -0,0 +1,6 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine;
public interface MesXslRubberQuickTestRecordRawLineMapper extends BaseMapper<MesXslRubberQuickTestRecordRawLine> {}

View File

@@ -28,20 +28,16 @@ public class McsDataSourceInitializer implements ApplicationRunner {
@Override @Override
public void run(ApplicationArguments args) { public void run(ApplicationArguments args) {
try { try {
MesXslMcsDbConfig config = mcsDbConfigService.getOne( MesXslMcsDbConfig config = mcsDbConfigService.loadStartupConfig();
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MesXslMcsDbConfig>()
.eq(MesXslMcsDbConfig::getTenantId, 0)
.orderByDesc(MesXslMcsDbConfig::getUpdateTime)
.last("LIMIT 1"),
false);
if (config != null) { if (config != null) {
mcsDataSourceManager.applyConfig(config); mcsDataSourceManager.applyConfig(config);
log.info("[MCS中间库] 已加载数据库中的中间库配置(含读写开关)"); log.info("[MCS中间库] 已加载数据库中的中间库配置 tenantId={}, status={}, host={}:{}",
config.getTenantId(), config.getStatus(), config.getServerHost(), config.getServerPort());
} else { } else {
log.info("[MCS中间库] 未找到已启用的数据库配置,继续使用 application.yml 中的 sqlserver_mcs"); log.info("[MCS中间库] 数据库中无中间库配置,继续使用 application.yml 中的 sqlserver_mcs");
} }
} catch (Exception e) { } catch (Exception e) {
log.warn("[MCS中间库] 启动加载配置失败,将使用 yml 默认连接: {}", e.getMessage()); log.error("[MCS中间库] 启动加载配置失败,将使用 yml 默认连接", e);
} }
} }
//update-end---author:GHT ---date:20260616 for【MES上辅机】启动时加载中间库可视化配置----------- //update-end---author:GHT ---date:20260616 for【MES上辅机】启动时加载中间库可视化配置-----------

View File

@@ -59,7 +59,11 @@ public class McsDataSourceManager {
public boolean isDbConfigActive() { public boolean isDbConfigActive() {
MesXslMcsDbConfig cfg = cachedConfig.get(); MesXslMcsDbConfig cfg = cachedConfig.get();
return cfg != null && Integer.valueOf(1).equals(cfg.getStatus()); if (cfg == null || !Integer.valueOf(1).equals(cfg.getStatus())) {
return false;
}
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
return routing.getDataSources().containsKey(DS_KEY);
} }
public boolean isReadEnabled() { public boolean isReadEnabled() {
@@ -83,11 +87,11 @@ public class McsDataSourceManager {
* 将配置应用到动态数据源(启用时注册/更新,禁用时移除) * 将配置应用到动态数据源(启用时注册/更新,禁用时移除)
*/ */
public void applyConfig(MesXslMcsDbConfig config) { public void applyConfig(MesXslMcsDbConfig config) {
cachedConfig.set(config);
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource; DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
closeAndRemoveDataSource(routing); closeAndRemoveDataSource(routing);
DataSourceCachePool.removeCache(DS_KEY); DataSourceCachePool.removeCache(DS_KEY);
if (config == null) { if (config == null) {
cachedConfig.set(null);
restoreYmlDataSource(routing); restoreYmlDataSource(routing);
log.info("[MCS中间库] 已清除页面配置"); log.info("[MCS中间库] 已清除页面配置");
return; return;
@@ -98,6 +102,7 @@ public class McsDataSourceManager {
DataSourceProperty property = buildDataSourceProperty(config, plainPassword); DataSourceProperty property = buildDataSourceProperty(config, plainPassword);
DataSource mcsDs = dataSourceCreator.createDataSource(property); DataSource mcsDs = dataSourceCreator.createDataSource(property);
routing.addDataSource(DS_KEY, mcsDs); routing.addDataSource(DS_KEY, mcsDs);
cachedConfig.set(config);
log.info("[MCS中间库] 动态数据源 {} 已热刷新(无需重启): {}:{}/{}", DS_KEY, log.info("[MCS中间库] 动态数据源 {} 已热刷新(无需重启): {}:{}/{}", DS_KEY,
config.getServerHost(), config.getServerPort(), config.getDbName()); config.getServerHost(), config.getServerPort(), config.getDbName());
} catch (Exception e) { } catch (Exception e) {
@@ -107,6 +112,7 @@ public class McsDataSourceManager {
} }
return; return;
} }
cachedConfig.set(config);
restoreYmlDataSource(routing); restoreYmlDataSource(routing);
log.info("[MCS中间库] 连接未启用,读写开关仍按页面配置生效"); log.info("[MCS中间库] 连接未启用,读写开关仍按页面配置生效");
} }

View File

@@ -28,4 +28,9 @@ public interface IMesXslMcsDbConfigService extends IService<MesXslMcsDbConfig> {
* 删除配置并移除动态数据源 * 删除配置并移除动态数据源
*/ */
Result<String> deleteConfig(String id); Result<String> deleteConfig(String id);
/**
* 启动时加载中间库配置(不限定租户,取最近更新的一条)
*/
MesXslMcsDbConfig loadStartupConfig();
} }

View File

@@ -44,6 +44,16 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
return config; return config;
} }
//update-begin---author:GHT ---date:20260616 for【MES上辅机】启动时加载中间库配置不限定租户-----------
@Override
public MesXslMcsDbConfig loadStartupConfig() {
LambdaQueryWrapper<MesXslMcsDbConfig> qw = new LambdaQueryWrapper<>();
qw.orderByDesc(MesXslMcsDbConfig::getUpdateTime);
qw.last("LIMIT 1");
return getOne(qw, false);
}
//update-end---author:GHT ---date:20260616 for【MES上辅机】启动时加载中间库配置不限定租户-----------
//update-begin---author:GHT ---date:20260616 for【MES上辅机】SQL Server中间库可视化配置----------- //update-begin---author:GHT ---date:20260616 for【MES上辅机】SQL Server中间库可视化配置-----------
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)

View File

@@ -6,6 +6,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine;
import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestRecordBatchFromMaterialVO; import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestRecordBatchFromMaterialVO;
public interface IMesXslRubberQuickTestRecordService extends IService<MesXslRubberQuickTestRecord> { public interface IMesXslRubberQuickTestRecordService extends IService<MesXslRubberQuickTestRecord> {
@@ -20,6 +21,8 @@ public interface IMesXslRubberQuickTestRecordService extends IService<MesXslRubb
List<MesXslRubberQuickTestRecordLine> selectLinesByRecordId(String recordId); List<MesXslRubberQuickTestRecordLine> selectLinesByRecordId(String recordId);
List<MesXslRubberQuickTestRecordRawLine> selectRawLinesByRecordId(String recordId);
String generateRecordNo(MesXslRubberQuickTestRecord context); String generateRecordNo(MesXslRubberQuickTestRecord context);
List<String> batchFromMaterial(MesXslRubberQuickTestRecordBatchFromMaterialVO vo); List<String> batchFromMaterial(MesXslRubberQuickTestRecordBatchFromMaterialVO vo);

View File

@@ -83,6 +83,22 @@ public class MesXslStompNotifyService {
} }
//update-end---author:cursor ---date:20250602 for【密炼物料皮重策略】桌面端同步----------- //update-end---author:cursor ---date:20250602 for【密炼物料皮重策略】桌面端同步-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检记录同步-----------
/** 广播胶料快检记录变更事件到 /topic/sync/mes-rubber-quick-test-records */
public void publishRubberQuickTestRecordChanged(String action, String recordId) {
publish("/topic/sync/mes-rubber-quick-test-records", "MES_RUBBER_QUICK_TEST_RECORD_CHANGED",
"recordId", recordId, action);
}
//update-end---author:jiangxh ---date:20260525 for【MES】原材料检验标准密炼PS批准时关联实验标准置已批准-----------
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端只读同步 STOMP-----------
/** 广播胶料快检实验标准变更事件到 /topic/sync/mes-rubber-quick-test-stds */
public void publishRubberQuickTestStdChanged(String action, String stdId) {
publish("/topic/sync/mes-rubber-quick-test-stds", "MES_RUBBER_QUICK_TEST_STD_CHANGED",
"stdId", stdId, action);
}
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端只读同步 STOMP-----------
// ─────────────────────────── 私有辅助 ──────────────────────────── // ─────────────────────────── 私有辅助 ────────────────────────────
private void publish(String topic, String cmd, String idKey, String idValue, String action) { private void publish(String topic, String cmd, String idKey, String idValue, String action) {

View File

@@ -20,11 +20,13 @@ import org.jeecg.modules.xslmes.common.XslMesBizConstants;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestMethod; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestMethod;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType; import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordLineMapper; import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordLineMapper;
import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordMapper; import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordMapper;
import org.jeecg.modules.xslmes.mapper.MesXslRubberQuickTestRecordRawLineMapper;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService; import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
@@ -45,6 +47,9 @@ public class MesXslRubberQuickTestRecordServiceImpl
@Autowired @Autowired
private MesXslRubberQuickTestRecordLineMapper mesXslRubberQuickTestRecordLineMapper; private MesXslRubberQuickTestRecordLineMapper mesXslRubberQuickTestRecordLineMapper;
@Autowired
private MesXslRubberQuickTestRecordRawLineMapper mesXslRubberQuickTestRecordRawLineMapper;
@Autowired @Autowired
private IMesXslRubberQuickTestStdService mesXslRubberQuickTestStdService; private IMesXslRubberQuickTestStdService mesXslRubberQuickTestStdService;
@@ -65,6 +70,9 @@ public class MesXslRubberQuickTestRecordServiceImpl
} }
this.save(main); this.save(main);
insertLines(main.getId(), lineList); insertLines(main.getId(), lineList);
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】保存试验结果原始数据明细-----------
insertRawLines(main.getId(), main.getRawLineList());
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】保存试验结果原始数据明细-----------
} }
@Override @Override
@@ -81,6 +89,12 @@ public class MesXslRubberQuickTestRecordServiceImpl
new LambdaQueryWrapper<MesXslRubberQuickTestRecordLine>() new LambdaQueryWrapper<MesXslRubberQuickTestRecordLine>()
.eq(MesXslRubberQuickTestRecordLine::getRecordId, main.getId())); .eq(MesXslRubberQuickTestRecordLine::getRecordId, main.getId()));
insertLines(main.getId(), lineList); insertLines(main.getId(), lineList);
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】更新时同步原始数据明细-----------
mesXslRubberQuickTestRecordRawLineMapper.delete(
new LambdaQueryWrapper<MesXslRubberQuickTestRecordRawLine>()
.eq(MesXslRubberQuickTestRecordRawLine::getRecordId, main.getId()));
insertRawLines(main.getId(), main.getRawLineList());
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】更新时同步原始数据明细-----------
} }
private void insertLines(String recordId, List<MesXslRubberQuickTestRecordLine> lineList) { private void insertLines(String recordId, List<MesXslRubberQuickTestRecordLine> lineList) {
@@ -96,11 +110,31 @@ public class MesXslRubberQuickTestRecordServiceImpl
} }
} }
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】原始数据明细入库-----------
private void insertRawLines(String recordId, List<MesXslRubberQuickTestRecordRawLine> rawLineList) {
if (CollectionUtils.isEmpty(rawLineList)) {
return;
}
int sort = 0;
for (MesXslRubberQuickTestRecordRawLine line : rawLineList) {
if (line == null) {
continue;
}
line.setId(null);
line.setRecordId(recordId);
line.setSortNo(sort++);
mesXslRubberQuickTestRecordRawLineMapper.insert(line);
}
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】原始数据明细入库-----------
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void delMain(String id) { public void delMain(String id) {
mesXslRubberQuickTestRecordLineMapper.delete( mesXslRubberQuickTestRecordLineMapper.delete(
new LambdaQueryWrapper<MesXslRubberQuickTestRecordLine>().eq(MesXslRubberQuickTestRecordLine::getRecordId, id)); new LambdaQueryWrapper<MesXslRubberQuickTestRecordLine>().eq(MesXslRubberQuickTestRecordLine::getRecordId, id));
mesXslRubberQuickTestRecordRawLineMapper.delete(
new LambdaQueryWrapper<MesXslRubberQuickTestRecordRawLine>().eq(MesXslRubberQuickTestRecordRawLine::getRecordId, id));
this.removeById(id); this.removeById(id);
} }
@@ -120,6 +154,14 @@ public class MesXslRubberQuickTestRecordServiceImpl
.orderByAsc(MesXslRubberQuickTestRecordLine::getSortNo)); .orderByAsc(MesXslRubberQuickTestRecordLine::getSortNo));
} }
@Override
public List<MesXslRubberQuickTestRecordRawLine> selectRawLinesByRecordId(String recordId) {
return mesXslRubberQuickTestRecordRawLineMapper.selectList(
new LambdaQueryWrapper<MesXslRubberQuickTestRecordRawLine>()
.eq(MesXslRubberQuickTestRecordRawLine::getRecordId, recordId)
.orderByAsc(MesXslRubberQuickTestRecordRawLine::getSortNo));
}
//update-begin---author:jiangxh ---date:20260528 for【MES】胶料快检记录单号JL+日期+4位流水自动生成----------- //update-begin---author:jiangxh ---date:20260528 for【MES】胶料快检记录单号JL+日期+4位流水自动生成-----------
@Override @Override
public String generateRecordNo(MesXslRubberQuickTestRecord context) { public String generateRecordNo(MesXslRubberQuickTestRecord context) {

View File

@@ -87,6 +87,11 @@ public class MesXslRubberQuickTestStdServiceImpl
if (oConvertUtils.isEmpty(main.getAuditStatus())) { if (oConvertUtils.isEmpty(main.getAuditStatus())) {
main.setAuditStatus("0"); main.setAuditStatus("0");
} }
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】新增时补齐 tenant_id-----------
if (main.getTenantId() == null) {
main.setTenantId(MesXslTenantUtils.resolveTenantId(null));
}
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】新增时补齐 tenant_id-----------
} }
private void insertLines(String stdId, List<MesXslRubberQuickTestStdLine> lineList) { private void insertLines(String stdId, List<MesXslRubberQuickTestStdLine> lineList) {

View File

@@ -0,0 +1,21 @@
-- MES 胶料快检记录原始数据明细存储桌面端试验结果全部检测值
SET NAMES utf8mb4;
CREATE TABLE IF NOT EXISTS `mes_xsl_rubber_quick_test_record_raw_line` (
`id` varchar(32) NOT NULL COMMENT '主键',
`record_id` varchar(32) NOT NULL COMMENT '主表 mes_xsl_rubber_quick_test_record.id',
`row_no` varchar(32) DEFAULT NULL COMMENT '试验结果编号如1_1',
`data_point_id` varchar(32) DEFAULT NULL COMMENT '数据点ID',
`inspect_item` varchar(128) DEFAULT NULL COMMENT '数据点名称',
`lower_limit` decimal(18,6) DEFAULT NULL COMMENT '下限值',
`upper_limit` decimal(18,6) DEFAULT NULL COMMENT '上限值',
`inspect_value` decimal(18,6) DEFAULT NULL COMMENT '检测值',
`row_inspect_result` varchar(2) DEFAULT NULL COMMENT '行检验结果字典xslmes_rubber_quick_test_record_result1合格0不合格',
`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_raw_record_id` (`record_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES胶料快检记录原始数据明细';

View File

@@ -0,0 +1,11 @@
-- 胶料快检实验标准补齐 tenant_id 为空的记录 MES 默认租户 1002 一致
-- 说明桌面端按 tenantId 拉取列表tenant_id NULL 的记录会被过滤导致条数不一致
SET NAMES utf8mb4;
SET @mes_tenant_id = 1002;
UPDATE `mes_xsl_rubber_quick_test_std`
SET `tenant_id` = @mes_tenant_id
WHERE `tenant_id` IS NULL
AND (`del_flag` = 0 OR `del_flag` IS NULL);

View File

@@ -18,6 +18,8 @@
/** 密炼PS类型原材料检验标准 */ /** 密炼PS类型原材料检验标准 */
const PS_TYPE_RAW_INSPECT_STD = 'raw_inspect_std'; const PS_TYPE_RAW_INSPECT_STD = 'raw_inspect_std';
/** 密炼PS状态编制 */
const COMPILE_STATUS = 'compile';
const selectSearchSchema: FormSchema[] = [ const selectSearchSchema: FormSchema[] = [
{ label: 'PS编码', field: 'psCode', component: 'JInput', colProps: { span: 8 } }, { label: 'PS编码', field: 'psCode', component: 'JInput', colProps: { span: 8 } },
@@ -42,6 +44,7 @@
beforeFetch: (params) => ({ beforeFetch: (params) => ({
...params, ...params,
psType: PS_TYPE_RAW_INSPECT_STD, psType: PS_TYPE_RAW_INSPECT_STD,
status: COMPILE_STATUS,
}), }),
rowSelection: { rowSelection: {
type: 'radio', type: 'radio',
@@ -85,7 +88,11 @@
} }
} }
if (!row?.id) { if (!row?.id) {
createMessage.warning('请选择一条密炼PS'); createMessage.warning('请选择一条编制状态的密炼PS');
return;
}
if (row.status && row.status !== COMPILE_STATUS) {
createMessage.warning('仅可选择编制状态的密炼PS');
return; return;
} }
if (row.psType && row.psType !== PS_TYPE_RAW_INSPECT_STD) { if (row.psType && row.psType !== PS_TYPE_RAW_INSPECT_STD) {

View File

@@ -0,0 +1,11 @@
using Prism.Events;
namespace YY.Admin.Core.Events;
public class RubberQuickTestStdChangedPayload
{
public string Action { get; set; } = string.Empty;
public string? StdId { get; set; }
}
public class RubberQuickTestStdChangedEvent : PubSubEvent<RubberQuickTestStdChangedPayload> { }

View File

@@ -0,0 +1,13 @@
using YY.Admin.Core.Entity;
namespace YY.Admin.Core.Services;
/// <summary>胶料快检记录操作台:密炼计划筛选、实验标准匹配、记录保存</summary>
public interface IRubberQuickTestOperationService
{
Task<List<MesXslMixingProductionPlan>> GetMixingProductionPlansAsync(CancellationToken ct = default);
Task<MesXslRubberQuickTestStd?> GetStdByRubberMaterialNameAsync(string rubberMaterialName, CancellationToken ct = default);
Task<string?> SaveRecordAsync(MesXslRubberQuickTestRecord record, CancellationToken ct = default);
}

View File

@@ -0,0 +1,24 @@
using YY.Admin.Core.Entity;
namespace YY.Admin.Core.Services;
/// <summary>胶料快检实验标准MES 只读同步)</summary>
public interface IRubberQuickTestStdService
{
Task<RubberQuickTestStdPageResult> PageAsync(
int pageNo, int pageSize,
string? stdName = null,
string? rubberMaterialName = null,
string? enableStatus = null,
CancellationToken ct = default);
Task<MesXslRubberQuickTestStd?> GetByIdAsync(string id, CancellationToken ct = default);
Task SyncFromRemoteAsync(CancellationToken ct = default);
}
public record RubberQuickTestStdPageResult(
List<MesXslRubberQuickTestStd> Records,
long Total,
int PageNo,
int PageSize);

View File

@@ -0,0 +1,28 @@
namespace YY.Admin.Core.Entity;
/// <summary>密炼生产计划维护(桌面端快检记录筛选用)</summary>
public class MesXslMixingProductionPlan
{
public string? Id { get; set; }
public int? SortNo { get; set; }
public string? MachineId { get; set; }
public string? MachineName { get; set; }
public string? MorningPlanId { get; set; }
public string? MorningPlanType { get; set; }
public string? MorningOrderNo { get; set; }
public DateTime? MorningOrderDate { get; set; }
public string? MorningFormulaName { get; set; }
public string? NoonPlanId { get; set; }
public string? NoonPlanType { get; set; }
public string? NoonOrderNo { get; set; }
public DateTime? NoonOrderDate { get; set; }
public string? NoonFormulaName { get; set; }
public string? NightPlanId { get; set; }
public string? NightPlanType { get; set; }
public string? NightOrderNo { get; set; }
public DateTime? NightOrderDate { get; set; }
public string? NightFormulaName { get; set; }
}

View File

@@ -0,0 +1,24 @@
namespace YY.Admin.Core.Entity;
public class MesXslRubberQuickTestRecord
{
public string? Id { get; set; }
public string? RecordNo { get; set; }
public string? RubberMaterialId { get; set; }
public string? RubberMaterialName { get; set; }
public string? StdId { get; set; }
public string? ProdEquipmentLedgerId { get; set; }
public string? ProdEquipmentName { get; set; }
public DateTime? ProductionDate { get; set; }
public string? TrainNo { get; set; }
public string? WorkShift { get; set; }
public int? InspectTimes { get; set; }
public DateTime? InspectTime { get; set; }
public string? InspectorUserId { get; set; }
public string? InspectorUsername { get; set; }
public string? InspectorRealname { get; set; }
public string? InspectResult { get; set; }
public string? ProductionPlanNo { get; set; }
public List<MesXslRubberQuickTestRecordLine>? LineList { get; set; }
public List<MesXslRubberQuickTestRecordRawLine>? RawLineList { get; set; }
}

View File

@@ -0,0 +1,13 @@
namespace YY.Admin.Core.Entity;
public class MesXslRubberQuickTestRecordLine
{
public string? Id { get; set; }
public string? RecordId { get; set; }
public string? DataPointId { get; set; }
public string? InspectItem { get; set; }
public decimal? LowerLimit { get; set; }
public decimal? InspectValue { get; set; }
public decimal? UpperLimit { get; set; }
public int? SortNo { get; set; }
}

View File

@@ -0,0 +1,17 @@
namespace YY.Admin.Core.Entity;
/// <summary>MES 胶料快检记录原始数据明细</summary>
public class MesXslRubberQuickTestRecordRawLine
{
public string? Id { get; set; }
public string? RecordId { get; set; }
public string? RowNo { get; set; }
public string? DataPointId { get; set; }
public string? InspectItem { get; set; }
public decimal? LowerLimit { get; set; }
public decimal? UpperLimit { get; set; }
public decimal? InspectValue { get; set; }
/// <summary>行检验结果1合格 0不合格</summary>
public string? RowInspectResult { get; set; }
public int? SortNo { get; set; }
}

View File

@@ -0,0 +1,32 @@
using System;
namespace YY.Admin.Core.Entity;
/// <summary>MES 胶料快检实验标准主表(桌面端只读同步)</summary>
public class MesXslRubberQuickTestStd
{
public string? Id { get; set; }
public string? StdName { get; set; }
public string? TestMethodId { get; set; }
public string? TestMethodName { get; set; }
public string? MixerType { get; set; }
public string? RubberMaterialId { get; set; }
public string? RubberMaterialName { get; set; }
public string? PsCompileId { get; set; }
public string? IssueNumber { get; set; }
public DateTime? IssueDate { get; set; }
public string? IssueDeptId { get; set; }
public string? IssueDeptName { get; set; }
public string? EnableStatus { get; set; }
public string? AuditStatus { get; set; }
public int? TenantId { get; set; }
public string? SysOrgCode { get; set; }
public string? CreateBy { get; set; }
public DateTime? CreateTime { get; set; }
public string? UpdateBy { get; set; }
public DateTime? UpdateTime { get; set; }
public List<MesXslRubberQuickTestStdLine>? LineList { get; set; }
public string EnableStatusText => EnableStatus == "0" ? "已停用" : EnableStatus == "1" ? "使用中" : EnableStatus ?? string.Empty;
public string AuditStatusText => AuditStatus == "1" ? "已批准" : AuditStatus == "0" ? "草稿" : AuditStatus ?? string.Empty;
}

View File

@@ -0,0 +1,15 @@
namespace YY.Admin.Core.Entity;
public class MesXslRubberQuickTestStdLine
{
public string? Id { get; set; }
public string? StdId { 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; }
}

View File

@@ -48,6 +48,10 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
new SysMenu{ Id=1300150011001, Pid=1300150000101, Title="库区管理", Path="/xslmes/mesXslWarehouseArea", Name="mesXslWarehouseArea", Component="WarehouseAreaListView", Icon="&#xe7ce;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=109 }, new SysMenu{ Id=1300150011001, Pid=1300150000101, Title="库区管理", Path="/xslmes/mesXslWarehouseArea", Name="mesXslWarehouseArea", Component="WarehouseAreaListView", Icon="&#xe7ce;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=109 },
// 密炼物料皮重策略 // 密炼物料皮重策略
new SysMenu{ Id=1300150011101, Pid=1300150000101, Title="密炼物料皮重策略", Path="/xslmes/mesXslMixerMaterialTareStrategy", Name="mesXslMixerMaterialTareStrategy", Component="MixerMaterialTareStrategyListView", Icon="&#xe7ce;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 }, new SysMenu{ Id=1300150011101, Pid=1300150000101, Title="密炼物料皮重策略", Path="/xslmes/mesXslMixerMaterialTareStrategy", Name="mesXslMixerMaterialTareStrategy", Component="MixerMaterialTareStrategyListView", Icon="&#xe7ce;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 },
// 快检记录
new SysMenu{ Id=1300150011201, Pid=1300150000101, Title="快检记录", Path="/xslmes/rubberQuickTestOperation", Name="rubberQuickTestOperation", Component="RubberQuickTestOperationView", Icon="&#xe7de;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=111 },
// 胶料快检实验标准(桌面端只读)
new SysMenu{ Id=1300150011301, Pid=1300150000101, Title="胶料快检实验标准", Path="/xslmes/mesXslRubberQuickTestStd", Name="mesXslRubberQuickTestStd", Component="RubberQuickTestStdListView", Icon="&#xe7ce;", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=112 },
#endregion #endregion

View File

@@ -32,6 +32,8 @@ public class SysTenantMenuSeedData : ISqlSugarEntitySeedData<SysTenantMenu>
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010901}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010901},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011001}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011001},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011101}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011101},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011201},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011301},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012101}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012101},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012111}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012111},
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012121}, new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012121},

View File

@@ -0,0 +1,117 @@
using Microsoft.Extensions.Configuration;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using YY.Admin.Core;
using YY.Admin.Core.Entity;
using YY.Admin.Core.Services;
namespace YY.Admin.Services.Service.RubberQuickTest;
public class RubberQuickTestOperationService : IRubberQuickTestOperationService, ISingletonDependency
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfiguration _configuration;
private readonly INetworkMonitor _networkMonitor;
private readonly ILoggerService _logger;
private static readonly JsonSerializerOptions _jsonOpts = new()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
public RubberQuickTestOperationService(
IHttpClientFactory httpClientFactory,
IConfiguration configuration,
INetworkMonitor networkMonitor,
ILoggerService logger)
{
_httpClientFactory = httpClientFactory;
_configuration = configuration;
_networkMonitor = networkMonitor;
_logger = logger;
}
private string BaseUrl => (_configuration.GetValue<string>("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/');
private int DefaultTenantId => (int?)_configuration.GetValue<long?>("JeecgIntegration:DefaultTenantId") ?? 1002;
public async Task<List<MesXslMixingProductionPlan>> GetMixingProductionPlansAsync(CancellationToken ct = default)
{
if (!_networkMonitor.IsOnline)
throw new InvalidOperationException("网络未连接,无法加载密炼生产计划");
var result = new List<MesXslMixingProductionPlan>();
int pageNo = 1;
const int pageSize = 500;
while (true)
{
var url = $"{BaseUrl}/xslmes/mesXslMixingProductionPlan/anon/list?pageNo={pageNo}&pageSize={pageSize}&tenantId={DefaultTenantId}";
using var client = _httpClientFactory.CreateClient("JeecgApi");
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);
if (!doc.RootElement.TryGetProperty("result", out var resultEl)) break;
if (resultEl.TryGetProperty("records", out var recordsEl))
{
var page = recordsEl.Deserialize<List<MesXslMixingProductionPlan>>(_jsonOpts);
if (page != null) result.AddRange(page);
}
long total = 0;
if (resultEl.TryGetProperty("total", out var totalEl)) total = totalEl.GetInt64();
if (result.Count >= total || (resultEl.TryGetProperty("records", out var r2) && r2.GetArrayLength() < pageSize)) break;
pageNo++;
}
_logger.Information($"[快检记录] 加载密炼生产计划 {result.Count} 条");
return result;
}
public async Task<MesXslRubberQuickTestStd?> GetStdByRubberMaterialNameAsync(string rubberMaterialName, CancellationToken ct = default)
{
if (string.IsNullOrWhiteSpace(rubberMaterialName))
return null;
if (!_networkMonitor.IsOnline)
throw new InvalidOperationException("网络未连接,无法加载实验标准");
var encoded = Uri.EscapeDataString(rubberMaterialName.Trim());
var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/anon/queryByRubberMaterialName?rubberMaterialName={encoded}";
using var client = _httpClientFactory.CreateClient("JeecgApi");
var resp = await client.GetAsync(url, 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() : "查询实验标准失败";
_logger.Warning($"[快检记录] 实验标准查询失败: {msg}");
return null;
}
if (!doc.RootElement.TryGetProperty("result", out var resultEl) || resultEl.ValueKind == JsonValueKind.Null)
return null;
return resultEl.Deserialize<MesXslRubberQuickTestStd>(_jsonOpts);
}
public async Task<string?> SaveRecordAsync(MesXslRubberQuickTestRecord record, CancellationToken ct = default)
{
if (!_networkMonitor.IsOnline)
throw new InvalidOperationException("网络未连接,无法保存快检记录");
var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestRecord/anon/add";
using var client = _httpClientFactory.CreateClient("JeecgApi");
var body = JsonSerializer.Serialize(record, _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 ?? "保存失败");
}
_logger.Information($"[快检记录] 保存成功 recordNo={record.RecordNo}");
return doc.RootElement.TryGetProperty("message", out var m) ? m.GetString() : "保存成功";
}
}

View File

@@ -0,0 +1,302 @@
using Microsoft.Extensions.Configuration;
using Prism.Events;
using System.IO;
using System.Net.Http;
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.RubberQuickTestStd;
/// <summary>胶料快检实验标准MES 只读拉取 + 本地缓存,断网读缓存,联网刷新</summary>
public class RubberQuickTestStdService : IRubberQuickTestStdService, 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<MesXslRubberQuickTestStd> _localCache = new();
private static readonly JsonSerializerOptions _jsonOpts = new()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new NullableDateTimeJsonConverter() }
};
public RubberQuickTestStdService(
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, "mes-xsl-rubber-quick-test-std-cache.json");
LoadCacheFromDisk();
_logger.Information($"[快检实验标准] 服务初始化,缓存={_localCache.Count},在线={_networkMonitor.IsOnline}");
_networkMonitor.StatusChanged += OnNetworkStatusChanged;
if (_networkMonitor.IsOnline)
_ = Task.Run(() => SyncFromRemoteAsync(CancellationToken.None));
}
private string BaseUrl => (_configuration.GetValue<string>("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/');
private int DefaultTenantId => (int?)_configuration.GetValue<long?>("JeecgIntegration:DefaultTenantId") ?? 1002;
private HttpClient CreateClient() => _httpClientFactory.CreateClient("JeecgApi");
public async Task<RubberQuickTestStdPageResult> PageAsync(
int pageNo, int pageSize,
string? stdName = null,
string? rubberMaterialName = null,
string? enableStatus = null,
CancellationToken ct = default)
{
if (_networkMonitor.IsOnline)
{
try
{
await SyncFromRemoteAsync(ct).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.Warning($"[快检实验标准] 列表拉取失败,使用本地缓存:{ex.Message}");
}
}
List<MesXslRubberQuickTestStd> source;
lock (_cacheLock)
source = _localCache.Select(CloneMain).ToList();
var filtered = ApplyFilters(source, stdName, rubberMaterialName, enableStatus);
var total = filtered.Count;
var records = filtered
.Skip(Math.Max(0, (pageNo - 1) * pageSize))
.Take(pageSize)
.ToList();
return new RubberQuickTestStdPageResult(records, total, pageNo, pageSize);
}
public async Task<MesXslRubberQuickTestStd?> GetByIdAsync(string id, CancellationToken ct = default)
{
if (string.IsNullOrWhiteSpace(id)) return null;
if (_networkMonitor.IsOnline)
{
try
{
var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/anon/queryById?id={Uri.EscapeDataString(id)}";
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))
{
var entity = resultEl.Deserialize<MesXslRubberQuickTestStd>(_jsonOpts);
if (entity != null)
{
UpsertLocalCacheMain(entity);
return CloneMain(entity);
}
}
}
}
catch (Exception ex)
{
_logger.Warning($"[快检实验标准] 详情拉取失败 id={id},回退缓存:{ex.Message}");
}
}
lock (_cacheLock)
{
var found = _localCache.FirstOrDefault(x => string.Equals(x.Id, id, StringComparison.OrdinalIgnoreCase));
return found != null ? CloneMain(found) : null;
}
}
public async Task SyncFromRemoteAsync(CancellationToken ct = default)
{
await _syncLock.WaitAsync(ct).ConfigureAwait(false);
try
{
if (!_networkMonitor.IsOnline)
return;
var query = HttpUtility.ParseQueryString(string.Empty);
query["pageNo"] = "1";
query["pageSize"] = "10000";
query["tenantId"] = DefaultTenantId.ToString();
var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/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 records = doc.RootElement.GetProperty("result").GetProperty("records")
.Deserialize<List<MesXslRubberQuickTestStd>>(_jsonOpts) ?? new();
lock (_cacheLock)
{
_localCache = records.Select(CloneMain).ToList();
SaveCacheToDiskUnsafe();
}
_logger.Information($"[快检实验标准] 同步完成 count={records.Count}");
}
catch (Exception ex)
{
_logger.Warning($"[快检实验标准] 远程同步失败:{ex.Message}");
}
finally
{
_syncLock.Release();
}
}
private void OnNetworkStatusChanged(bool isOnline)
{
if (!isOnline) return;
_ = Task.Run(async () =>
{
await SyncFromRemoteAsync(CancellationToken.None).ConfigureAwait(false);
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>()
.Publish(new RubberQuickTestStdChangedPayload { Action = "reconnect" });
});
}
private static List<MesXslRubberQuickTestStd> ApplyFilters(
List<MesXslRubberQuickTestStd> source,
string? stdName,
string? rubberMaterialName,
string? enableStatus)
{
IEnumerable<MesXslRubberQuickTestStd> q = source;
if (!string.IsNullOrWhiteSpace(stdName))
q = q.Where(x => (x.StdName ?? "").Contains(stdName.Trim(), StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(rubberMaterialName))
q = q.Where(x => (x.RubberMaterialName ?? "").Contains(rubberMaterialName.Trim(), StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(enableStatus))
q = q.Where(x => string.Equals(x.EnableStatus, enableStatus.Trim(), StringComparison.OrdinalIgnoreCase));
return q.OrderByDescending(x => x.CreateTime ?? DateTime.MinValue).ToList();
}
private void UpsertLocalCacheMain(MesXslRubberQuickTestStd entity)
{
if (string.IsNullOrWhiteSpace(entity.Id)) return;
lock (_cacheLock)
{
var idx = _localCache.FindIndex(x => string.Equals(x.Id, entity.Id, StringComparison.OrdinalIgnoreCase));
var copy = CloneMain(entity);
if (idx >= 0) _localCache[idx] = copy;
else _localCache.Insert(0, copy);
SaveCacheToDiskUnsafe();
}
}
private void LoadCacheFromDisk()
{
try
{
if (!File.Exists(_cacheFilePath)) return;
_localCache = JsonSerializer.Deserialize<List<MesXslRubberQuickTestStd>>(
File.ReadAllText(_cacheFilePath), _jsonOpts) ?? new();
}
catch
{
_localCache = new();
}
}
private void SaveCacheToDiskUnsafe() =>
File.WriteAllText(_cacheFilePath, JsonSerializer.Serialize(_localCache, _jsonOpts));
private static MesXslRubberQuickTestStd CloneMain(MesXslRubberQuickTestStd x) => new()
{
Id = x.Id,
StdName = x.StdName,
TestMethodId = x.TestMethodId,
TestMethodName = x.TestMethodName,
MixerType = x.MixerType,
RubberMaterialId = x.RubberMaterialId,
RubberMaterialName = x.RubberMaterialName,
PsCompileId = x.PsCompileId,
IssueNumber = x.IssueNumber,
IssueDate = x.IssueDate,
IssueDeptId = x.IssueDeptId,
IssueDeptName = x.IssueDeptName,
EnableStatus = x.EnableStatus,
AuditStatus = x.AuditStatus,
TenantId = x.TenantId,
SysOrgCode = x.SysOrgCode,
CreateBy = x.CreateBy,
CreateTime = x.CreateTime,
UpdateBy = x.UpdateBy,
UpdateTime = x.UpdateTime,
LineList = x.LineList?.Select(l => new MesXslRubberQuickTestStdLine
{
Id = l.Id,
StdId = l.StdId,
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()
};
private sealed class NullableDateTimeJsonConverter : JsonConverter<DateTime?>
{
private static readonly string[] Formats =
[
"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, Formats, System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AssumeLocal, out var dt)) return dt;
if (DateTime.TryParse(raw, out var fb)) return fb;
}
throw new JsonException($"无法转换为 DateTime?token={reader.TokenType}");
}
public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
{
if (value.HasValue) writer.WriteStringValue(value.Value.ToString("yyyy-MM-dd HH:mm:ss"));
else writer.WriteNullValue();
}
}
}

View File

@@ -0,0 +1,73 @@
using Prism.Events;
using System.Text.Json;
using YY.Admin.Core;
using YY.Admin.Core.Events;
using YY.Admin.Core.Events;
namespace YY.Admin.Services.Service.RubberQuickTestStd;
public class RubberQuickTestStdSyncCoordinator : ISingletonDependency
{
private readonly IEventAggregator _eventAggregator;
private readonly ILoggerService _logger;
public RubberQuickTestStdSyncCoordinator(
IEventAggregator eventAggregator,
SyncPollManager pollManager,
ILoggerService logger)
{
_eventAggregator = eventAggregator;
_logger = logger;
_eventAggregator.GetEvent<RemoteCommandReceivedEvent>()
.Subscribe(OnRemoteCommand, ThreadOption.BackgroundThread);
_eventAggregator.GetEvent<NetworkStatusChangedEvent>()
.Subscribe(OnNetworkStatusChanged, ThreadOption.BackgroundThread);
pollManager.Register("胶料快检实验标准", () =>
{
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>()
.Publish(new RubberQuickTestStdChangedPayload { Action = "poll" });
return Task.CompletedTask;
});
_logger.Information("[快检实验标准] RubberQuickTestStdSyncCoordinator 已启动");
}
private void OnNetworkStatusChanged(NetworkStatusChangedPayload payload)
{
if (!payload.IsOnline) return;
_logger.Information("[快检实验标准] 网络恢复,触发补偿刷新");
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>()
.Publish(new RubberQuickTestStdChangedPayload { Action = "reconnect" });
}
private void OnRemoteCommand(RemoteCommandPayload payload)
{
try
{
var json = payload.CommandJson ?? string.Empty;
if (string.IsNullOrWhiteSpace(json)) return;
using var doc = JsonDocument.Parse(json);
if (!doc.RootElement.TryGetProperty("cmd", out var cmdEl)) return;
if (!cmdEl.GetString()?.Equals("MES_RUBBER_QUICK_TEST_STD_CHANGED", StringComparison.OrdinalIgnoreCase) ?? true)
return;
doc.RootElement.TryGetProperty("action", out var actionEl);
doc.RootElement.TryGetProperty("stdId", out var idEl);
var changed = new RubberQuickTestStdChangedPayload
{
Action = actionEl.GetString() ?? string.Empty,
StdId = idEl.ValueKind == JsonValueKind.String ? idEl.GetString() : null
};
_logger.Information($"[快检实验标准] STOMP action={changed.Action}, stdId={changed.StdId}");
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>().Publish(changed);
}
catch (Exception ex)
{
_logger.Warning($"[快检实验标准] 处理 STOMP 命令失败:{ex.Message}");
}
}
}

View File

@@ -174,6 +174,10 @@ public class StompWebSocketService : ISignalRService
await SendFrameAsync( await SendFrameAsync(
BuildSubscribeFrame("sub-print-biz-binds", "/topic/sync/print-biz-binds"), BuildSubscribeFrame("sub-print-biz-binds", "/topic/sync/print-biz-binds"),
cancellationToken).ConfigureAwait(false); cancellationToken).ConfigureAwait(false);
// 胶料快检实验标准变更:订阅 /topic/sync/mes-rubber-quick-test-stds
await SendFrameAsync(
BuildSubscribeFrame("sub-mes-rubber-quick-test-stds", "/topic/sync/mes-rubber-quick-test-stds"),
cancellationToken).ConfigureAwait(false);
// 订阅服务端 PONG 回复(应用层假在线检测) // 订阅服务端 PONG 回复(应用层假在线检测)
await SendFrameAsync( await SendFrameAsync(

View File

@@ -18,6 +18,8 @@ using YY.Admin.Views.WarehouseArea;
using YY.Admin.Views.RawMaterialEntry; using YY.Admin.Views.RawMaterialEntry;
using YY.Admin.Views.Print; using YY.Admin.Views.Print;
using YY.Admin.Views.MixerMaterialTareStrategy; using YY.Admin.Views.MixerMaterialTareStrategy;
using YY.Admin.Views.RubberQuickTest;
using YY.Admin.Views.RubberQuickTestStd;
namespace YY.Admin namespace YY.Admin
{ {
@@ -95,6 +97,10 @@ namespace YY.Admin
containerRegistry.RegisterForNavigation<WarehouseAreaListView>(); containerRegistry.RegisterForNavigation<WarehouseAreaListView>();
// 密炼物料皮重策略 // 密炼物料皮重策略
containerRegistry.RegisterForNavigation<MixerMaterialTareStrategyListView>(); containerRegistry.RegisterForNavigation<MixerMaterialTareStrategyListView>();
// 快检记录操作台
containerRegistry.RegisterForNavigation<RubberQuickTestOperationView>();
// 胶料快检实验标准(只读)
containerRegistry.RegisterForNavigation<RubberQuickTestStdListView>();
// 打印设置 // 打印设置
containerRegistry.RegisterForNavigation<PrintSettingsView>(); containerRegistry.RegisterForNavigation<PrintSettingsView>();
// 打印模板列表 // 打印模板列表

View File

@@ -27,6 +27,8 @@ using YY.Admin.Services.Service.Warehouse;
using YY.Admin.Services.Service.WarehouseArea; using YY.Admin.Services.Service.WarehouseArea;
using YY.Admin.Services.Service.WeightRecord; using YY.Admin.Services.Service.WeightRecord;
using YY.Admin.Services.Service.Print; using YY.Admin.Services.Service.Print;
using YY.Admin.Services.Service.RubberQuickTest;
using YY.Admin.Services.Service.RubberQuickTestStd;
namespace YY.Admin.Module; namespace YY.Admin.Module;
@@ -86,6 +88,13 @@ public class SyncModule : IModule
containerRegistry.RegisterSingleton<PrintTemplateSyncCoordinator>(); containerRegistry.RegisterSingleton<PrintTemplateSyncCoordinator>();
containerRegistry.RegisterSingleton<PrintBizTemplateBindSyncCoordinator>(); containerRegistry.RegisterSingleton<PrintBizTemplateBindSyncCoordinator>();
// 胶料快检记录操作台
containerRegistry.RegisterSingleton<IRubberQuickTestOperationService, RubberQuickTestOperationService>();
// 胶料快检实验标准MES 只读同步)
containerRegistry.RegisterSingleton<IRubberQuickTestStdService, RubberQuickTestStdService>();
containerRegistry.RegisterSingleton<RubberQuickTestStdSyncCoordinator>();
var serviceCollection = new ServiceCollection(); var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<DisconnectGuardHandler>(); serviceCollection.AddTransient<DisconnectGuardHandler>();
serviceCollection.AddHttpClient("JeecgApi", (sp, client) => serviceCollection.AddHttpClient("JeecgApi", (sp, client) =>
@@ -156,6 +165,8 @@ public class SyncModule : IModule
// 强制实例化打印模板同步协调器 // 强制实例化打印模板同步协调器
_ = containerProvider.Resolve<PrintTemplateSyncCoordinator>(); _ = containerProvider.Resolve<PrintTemplateSyncCoordinator>();
_ = containerProvider.Resolve<PrintBizTemplateBindSyncCoordinator>(); _ = containerProvider.Resolve<PrintBizTemplateBindSyncCoordinator>();
// 胶料快检实验标准只读同步协调器
_ = containerProvider.Resolve<RubberQuickTestStdSyncCoordinator>();
} }
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()

View File

@@ -152,6 +152,16 @@ namespace YY.Admin.ViewModels.Control
["/xslmes/mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView", ["/xslmes/mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView",
["mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView", ["mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView",
// 已实现页面:快检记录操作台
["RubberQuickTestOperationView"] = "RubberQuickTestOperationView",
["/xslmes/rubberQuickTestOperation"] = "RubberQuickTestOperationView",
["rubberQuickTestOperation"] = "RubberQuickTestOperationView",
// 已实现页面:胶料快检实验标准(只读)
["RubberQuickTestStdListView"] = "RubberQuickTestStdListView",
["/xslmes/mesXslRubberQuickTestStd"] = "RubberQuickTestStdListView",
["mesXslRubberQuickTestStd"] = "RubberQuickTestStdListView",
// 已实现页面:打印设置 // 已实现页面:打印设置
["PrintSettingsView"] = "PrintSettingsView", ["PrintSettingsView"] = "PrintSettingsView",
["/system/printSettings"] = "PrintSettingsView", ["/system/printSettings"] = "PrintSettingsView",

View File

@@ -0,0 +1,755 @@
using HandyControl.Controls;
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using Prism.Mvvm;
using SkiaSharp;
using System.Collections.ObjectModel;
using YY.Admin.Core;
using YY.Admin.Core.Entity;
using YY.Admin.Core.Services;
using YY.Admin.Core.Session;
namespace YY.Admin.ViewModels.RubberQuickTest;
/// <summary>密炼生产计划班次展开项(桌面端筛选用)</summary>
public class MixingPlanShiftOption
{
public string PlanRowId { get; set; } = string.Empty;
public string? MachineId { get; set; }
public string? MachineName { get; set; }
public string ShiftKey { get; set; } = string.Empty;
public string ShiftCode { get; set; } = string.Empty;
public string ShiftName { get; set; } = string.Empty;
public DateTime? OrderDate { get; set; }
public string? PlanId { get; set; }
public string? OrderNo { get; set; }
public string? FormulaName { get; set; }
public string DisplayText => string.IsNullOrWhiteSpace(OrderNo)
? FormulaName ?? string.Empty
: $"{OrderNo} | {FormulaName}";
}
public class QuickTestInspectCellViewModel : BindableBase
{
public string? DataPointId { get; set; }
public string PointName { get; set; } = string.Empty;
public decimal? LowerLimit { get; set; }
public decimal? UpperLimit { get; set; }
private decimal? _value;
public decimal? Value
{
get => _value;
set
{
if (SetProperty(ref _value, value))
ValueChanged?.Invoke(this);
}
}
public event Action<QuickTestInspectCellViewModel>? ValueChanged;
}
public class QuickTestInspectRowViewModel : BindableBase
{
public string RowNo { get; set; } = string.Empty;
public ObservableCollection<QuickTestInspectCellViewModel> Cells { get; } = new();
private string _inspectResultText = string.Empty;
public string InspectResultText
{
get => _inspectResultText;
set => SetProperty(ref _inspectResultText, value);
}
public string InspectResultCode { get; private set; } = "0";
public void RecalculateResult()
{
if (Cells.Count == 0)
{
InspectResultCode = "0";
InspectResultText = string.Empty;
RaisePropertyChanged(nameof(InspectResultText));
return;
}
if (Cells.Any(c => c.Value == null))
{
InspectResultCode = "0";
InspectResultText = "待填写";
RaisePropertyChanged(nameof(InspectResultText));
return;
}
var pass = Cells.All(c =>
{
if (c.LowerLimit != null && c.Value < c.LowerLimit) return false;
if (c.UpperLimit != null && c.Value > c.UpperLimit) return false;
return true;
});
InspectResultCode = pass ? "1" : "0";
InspectResultText = pass ? "合格" : "不合格";
RaisePropertyChanged(nameof(InspectResultText));
}
}
/// <summary>胶料快检记录操作台 ViewModel</summary>
public class RubberQuickTestOperationViewModel : BaseViewModel
{
private readonly IRubberQuickTestOperationService _operationService;
private readonly Random _rnd = new();
private List<MesXslMixingProductionPlan> _allPlans = new();
private List<MixingPlanShiftOption> _allShiftOptions = new();
private MesXslRubberQuickTestStd? _currentStd;
private const int ChartPointCount = 5;
public event Action? InspectColumnsChanged;
public RubberQuickTestOperationViewModel(
IRubberQuickTestOperationService operationService,
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
{
_operationService = operationService;
_inspectTimesText = "1";
AddInspectRowCommand = new DelegateCommand(AddInspectRow, () => DataPointColumns.Count > 0);
RemoveInspectRowCommand = new DelegateCommand(() => RemoveInspectRow(SelectedInspectRow), () => SelectedInspectRow != null);
SaveCommand = new DelegateCommand(async () => await SaveAsync(), () => InspectRows.Count > 0);
RefreshPlansCommand = new DelegateCommand(async () => await LoadPlansAsync());
RefreshChartDemoCommand = new DelegateCommand(FillRandomChartData);
TemperatureSeries = new ObservableCollection<ISeries>
{
new LineSeries<double> { Name = "上模温度", Values = UpperTempValues, GeometrySize = 4, LineSmoothness = 0.3 },
new LineSeries<double> { Name = "下模温度", Values = LowerTempValues, GeometrySize = 4, LineSmoothness = 0.3 }
};
TorqueSeries = new ObservableCollection<ISeries>
{
new LineSeries<double> { Name = "S'(dNm)", Values = TorqueValues, GeometrySize = 4, LineSmoothness = 0.3 }
};
FillRandomChartData();
_ = LoadPlansAsync();
}
/// <summary>中间库未接入时的曲线演示说明</summary>
public string ChartDemoHint => "演示数据(中间库未接入,打开页面自动生成;接入后将显示实测曲线)";
public ObservableCollection<ISeries> TemperatureSeries { get; }
public ObservableCollection<ISeries> TorqueSeries { get; }
public ObservableCollection<double> UpperTempValues { get; } = new();
public ObservableCollection<double> LowerTempValues { get; } = new();
public ObservableCollection<double> TorqueValues { get; } = new();
public Axis[] TemperatureXAxes { get; } = BuildTimeAxis();
public Axis[] TemperatureYAxes { get; } = BuildTempYAxis();
public Axis[] TorqueXAxes { get; } = BuildTimeAxis();
public Axis[] TorqueYAxes { get; } = BuildTorqueYAxis();
public ObservableCollection<string> MachineOptions { get; } = new();
public ObservableCollection<WorkShiftOption> ShiftOptions { get; } = new();
public ObservableCollection<MixingPlanShiftOption> PlanOptions { get; } = new();
public ObservableCollection<MesXslRubberQuickTestStdLine> DataPointColumns { get; } = new();
public ObservableCollection<QuickTestInspectRowViewModel> InspectRows { get; } = new();
private QuickTestInspectRowViewModel? _selectedInspectRow;
public QuickTestInspectRowViewModel? SelectedInspectRow
{
get => _selectedInspectRow;
set
{
if (SetProperty(ref _selectedInspectRow, value))
RemoveInspectRowCommand.RaiseCanExecuteChanged();
}
}
private DateTime _mixingDate = DateTime.Today;
public DateTime MixingDate
{
get => _mixingDate;
set
{
if (!SetProperty(ref _mixingDate, value)) return;
RefreshMachineOptions();
ClearPlanSelection();
}
}
private string? _selectedMachine;
public string? SelectedMachine
{
get => _selectedMachine;
set
{
if (!SetProperty(ref _selectedMachine, value)) return;
RefreshShiftOptions();
ClearPlanSelection();
}
}
private WorkShiftOption? _selectedShift;
public WorkShiftOption? SelectedShift
{
get => _selectedShift;
set
{
if (!SetProperty(ref _selectedShift, value)) return;
RefreshPlanOptions();
ClearPlanSelection();
}
}
private MixingPlanShiftOption? _selectedPlan;
public MixingPlanShiftOption? SelectedPlan
{
get => _selectedPlan;
set
{
if (!SetProperty(ref _selectedPlan, value)) return;
ApplySelectedPlan();
}
}
public string? ProductionOrderNo => _selectedPlan?.OrderNo;
public string? MachineName => _selectedPlan?.MachineName ?? SelectedMachine;
public string? WorkShiftDisplay => SelectedShift?.Name ?? string.Empty;
public string? RubberMaterialName => _selectedPlan?.FormulaName;
private string? _trainNo;
public string? TrainNo
{
get => _trainNo;
set => SetProperty(ref _trainNo, value);
}
private string? _inspectTimesText;
/// <summary>试验次数(手填正整数)</summary>
public string? InspectTimesText
{
get => _inspectTimesText;
set => SetProperty(ref _inspectTimesText, value);
}
private double _upperMoldTemp;
public double UpperMoldTemp
{
get => _upperMoldTemp;
set => SetProperty(ref _upperMoldTemp, value);
}
private double _lowerMoldTemp;
public double LowerMoldTemp
{
get => _lowerMoldTemp;
set => SetProperty(ref _lowerMoldTemp, value);
}
private double _torqueS;
public double TorqueS
{
get => _torqueS;
set => SetProperty(ref _torqueS, value);
}
public DelegateCommand AddInspectRowCommand { get; }
public DelegateCommand RemoveInspectRowCommand { get; }
public DelegateCommand SaveCommand { get; }
public DelegateCommand RefreshPlansCommand { get; }
public DelegateCommand RefreshChartDemoCommand { get; }
private async Task LoadPlansAsync()
{
IsLoading = true;
try
{
_allPlans = await _operationService.GetMixingProductionPlansAsync();
BuildAllShiftOptions();
RefreshMachineOptions();
Growl.Success("密炼生产计划已刷新");
}
catch (Exception ex)
{
Growl.Error($"加载密炼生产计划失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
private void BuildAllShiftOptions()
{
_allShiftOptions.Clear();
foreach (var row in _allPlans)
{
AddShiftOption(row, "morning", "1", "早班", row.MorningPlanId, row.MorningOrderDate, row.MorningOrderNo, row.MorningFormulaName);
AddShiftOption(row, "noon", "2", "中班", row.NoonPlanId, row.NoonOrderDate, row.NoonOrderNo, row.NoonFormulaName);
AddShiftOption(row, "night", "3", "晚班", row.NightPlanId, row.NightOrderDate, row.NightOrderNo, row.NightFormulaName);
}
}
private void AddShiftOption(
MesXslMixingProductionPlan row, string shiftKey, string shiftCode, string shiftName,
string? planId, DateTime? orderDate, string? orderNo, string? formulaName)
{
if (string.IsNullOrWhiteSpace(planId) || string.IsNullOrWhiteSpace(orderNo)) return;
_allShiftOptions.Add(new MixingPlanShiftOption
{
PlanRowId = row.Id ?? string.Empty,
MachineId = row.MachineId,
MachineName = row.MachineName,
ShiftKey = shiftKey,
ShiftCode = shiftCode,
ShiftName = shiftName,
OrderDate = orderDate,
PlanId = planId,
OrderNo = orderNo,
FormulaName = formulaName
});
}
private IEnumerable<MixingPlanShiftOption> FilteredByDate =>
_allShiftOptions.Where(o => o.OrderDate?.Date == MixingDate.Date);
private void RefreshMachineOptions()
{
MachineOptions.Clear();
foreach (var name in FilteredByDate.Select(o => o.MachineName).Where(n => !string.IsNullOrWhiteSpace(n)).Distinct().OrderBy(n => n))
MachineOptions.Add(name!);
if (SelectedMachine != null && !MachineOptions.Contains(SelectedMachine))
SelectedMachine = null;
if (SelectedMachine == null && MachineOptions.Count > 0)
SelectedMachine = MachineOptions[0];
else
RefreshShiftOptions();
}
private void RefreshShiftOptions()
{
ShiftOptions.Clear();
var machine = SelectedMachine;
var shifts = FilteredByDate
.Where(o => string.IsNullOrWhiteSpace(machine) || o.MachineName == machine)
.GroupBy(o => o.ShiftCode)
.Select(g => g.First())
.OrderBy(o => o.ShiftCode);
foreach (var s in shifts)
ShiftOptions.Add(new WorkShiftOption(s.ShiftCode, s.ShiftName));
if (SelectedShift != null && !ShiftOptions.Any(x => x.Code == SelectedShift.Code))
SelectedShift = null;
if (SelectedShift == null && ShiftOptions.Count > 0)
SelectedShift = ShiftOptions[0];
else
RefreshPlanOptions();
}
private void RefreshPlanOptions()
{
PlanOptions.Clear();
var machine = SelectedMachine;
var shiftCode = SelectedShift?.Code;
foreach (var o in FilteredByDate
.Where(x => string.IsNullOrWhiteSpace(machine) || x.MachineName == machine)
.Where(x => string.IsNullOrWhiteSpace(shiftCode) || x.ShiftCode == shiftCode)
.OrderBy(x => x.OrderNo))
PlanOptions.Add(o);
if (SelectedPlan != null && PlanOptions.All(p => p.PlanId != SelectedPlan.PlanId))
SelectedPlan = null;
if (SelectedPlan == null && PlanOptions.Count > 0)
SelectedPlan = PlanOptions[0];
}
private void ClearPlanSelection()
{
_selectedPlan = null;
RaisePropertyChanged(nameof(SelectedPlan));
RaisePropertyChanged(nameof(ProductionOrderNo));
RaisePropertyChanged(nameof(MachineName));
RaisePropertyChanged(nameof(WorkShiftDisplay));
RaisePropertyChanged(nameof(RubberMaterialName));
ClearStdAndResults();
}
private void ApplySelectedPlan()
{
RaisePropertyChanged(nameof(ProductionOrderNo));
RaisePropertyChanged(nameof(MachineName));
RaisePropertyChanged(nameof(WorkShiftDisplay));
RaisePropertyChanged(nameof(RubberMaterialName));
_ = LoadStdAsync();
}
private async Task LoadStdAsync()
{
DataPointColumns.Clear();
InspectRows.Clear();
_currentStd = null;
InspectColumnsChanged?.Invoke();
var rubberName = RubberMaterialName;
if (string.IsNullOrWhiteSpace(rubberName)) return;
IsLoading = true;
try
{
_currentStd = await _operationService.GetStdByRubberMaterialNameAsync(rubberName);
if (_currentStd?.LineList == null || _currentStd.LineList.Count == 0)
{
Growl.Warning($"未找到胶料「{rubberName}」的使用中且已批准的快检实验标准");
return;
}
foreach (var line in _currentStd.LineList.OrderBy(l => l.SortNo ?? 0))
DataPointColumns.Add(line);
InspectColumnsChanged?.Invoke();
AddInspectRow();
AddInspectRowCommand.RaiseCanExecuteChanged();
}
catch (Exception ex)
{
Growl.Error($"加载实验标准失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
private void ClearStdAndResults()
{
DataPointColumns.Clear();
InspectRows.Clear();
_currentStd = null;
InspectColumnsChanged?.Invoke();
}
/// <summary>打开页面或中间库无数据时填充曲线演示数据5 点对应 02min</summary>
private void FillRandomChartData()
{
UpperTempValues.Clear();
LowerTempValues.Clear();
TorqueValues.Clear();
for (int i = 0; i < ChartPointCount; i++)
{
var upper = 192 + _rnd.NextDouble() * 8;
var lower = upper - 2 - _rnd.NextDouble() * 2;
var torque = Math.Min(14, i * 2.5 + _rnd.NextDouble() * 2.5);
UpperTempValues.Add(Math.Round(upper, 2));
LowerTempValues.Add(Math.Round(lower, 2));
TorqueValues.Add(Math.Round(torque, 2));
}
UpperMoldTemp = UpperTempValues[^1];
LowerMoldTemp = LowerTempValues[^1];
TorqueS = TorqueValues[^1];
}
private void AddInspectRow()
{
var rowIndex = InspectRows.Count + 1;
var row = new QuickTestInspectRowViewModel { RowNo = $"{rowIndex}_1" };
foreach (var col in DataPointColumns)
{
var cell = new QuickTestInspectCellViewModel
{
DataPointId = col.DataPointId,
PointName = col.PointName ?? string.Empty,
LowerLimit = col.LowerLimit,
UpperLimit = col.UpperLimit
};
cell.ValueChanged += _ => row.RecalculateResult();
row.Cells.Add(cell);
}
row.RecalculateResult();
InspectRows.Add(row);
SaveCommand.RaiseCanExecuteChanged();
}
private void RemoveInspectRow(QuickTestInspectRowViewModel? row)
{
if (row == null) return;
InspectRows.Remove(row);
SelectedInspectRow = null;
SaveCommand.RaiseCanExecuteChanged();
}
private async Task SaveAsync()
{
if (string.IsNullOrWhiteSpace(TrainNo))
{
Growl.Warning("请填写车次");
return;
}
if (string.IsNullOrWhiteSpace(ProductionOrderNo))
{
Growl.Warning("请选择密炼计划以带出生产订单号");
return;
}
if (string.IsNullOrWhiteSpace(RubberMaterialName))
{
Growl.Warning("请先选择密炼计划以带出胶料名称");
return;
}
if (_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;
try
{
var record = BuildSaveRecord(lineList, rawLineList, inspectTimes, user);
await _operationService.SaveRecordAsync(record);
Growl.Success("快检记录已保存到 MES");
InspectRows.Clear();
SaveCommand.RaiseCanExecuteChanged();
}
catch (Exception ex)
{
Growl.Error($"保存失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
private bool TryParseInspectTimes(out int value, out string error)
{
error = string.Empty;
var text = string.IsNullOrWhiteSpace(InspectTimesText) ? "1" : InspectTimesText.Trim();
if (!int.TryParse(text, out var n) || n <= 0)
{
error = "试验次数须填写正整数";
value = 0;
return false;
}
value = n;
return true;
}
/// <summary>试验结果各数据点检测值取平均,写入快检记录明细</summary>
private List<MesXslRubberQuickTestRecordLine> BuildAveragedLineList()
{
var lines = new List<MesXslRubberQuickTestRecordLine>();
for (int i = 0; i < DataPointColumns.Count; i++)
{
var col = DataPointColumns[i];
var values = InspectRows
.Where(r => i < r.Cells.Count && r.Cells[i].Value != null)
.Select(r => r.Cells[i].Value!.Value)
.ToList();
if (values.Count == 0)
continue;
var avg = values.Average(v => (double)v);
var avgDecimal = Math.Round((decimal)avg, 6);
var line = new MesXslRubberQuickTestRecordLine { SortNo = i };
if (!string.IsNullOrWhiteSpace(col.DataPointId))
line.DataPointId = col.DataPointId;
if (!string.IsNullOrWhiteSpace(col.PointName))
line.InspectItem = col.PointName;
if (col.LowerLimit != null)
line.LowerLimit = col.LowerLimit;
if (col.UpperLimit != null)
line.UpperLimit = col.UpperLimit;
line.InspectValue = avgDecimal;
lines.Add(line);
}
return lines;
}
/// <summary>试验结果全部检测值写入原始数据明细</summary>
private List<MesXslRubberQuickTestRecordRawLine> BuildRawLineList()
{
var rawLines = new List<MesXslRubberQuickTestRecordRawLine>();
int sort = 0;
foreach (var row in InspectRows)
{
for (int i = 0; i < row.Cells.Count; i++)
{
var cell = row.Cells[i];
if (cell.Value == null)
continue;
var raw = new MesXslRubberQuickTestRecordRawLine { SortNo = sort++ };
if (!string.IsNullOrWhiteSpace(row.RowNo))
raw.RowNo = row.RowNo;
if (!string.IsNullOrWhiteSpace(cell.DataPointId))
raw.DataPointId = cell.DataPointId;
if (!string.IsNullOrWhiteSpace(cell.PointName))
raw.InspectItem = cell.PointName;
if (cell.LowerLimit != null)
raw.LowerLimit = cell.LowerLimit;
if (cell.UpperLimit != null)
raw.UpperLimit = cell.UpperLimit;
raw.InspectValue = cell.Value;
raw.RowInspectResult = row.InspectResultCode;
rawLines.Add(raw);
}
}
return rawLines;
}
/// <summary>主表检验结果:任一行不合格则不合格</summary>
private static string JudgeInspectResultFromRows(IEnumerable<QuickTestInspectRowViewModel> rows)
{
if (!rows.Any())
return "0";
return rows.Any(r => r.InspectResultCode != "1") ? "0" : "1";
}
private MesXslRubberQuickTestRecord BuildSaveRecord(
List<MesXslRubberQuickTestRecordLine> lineList,
List<MesXslRubberQuickTestRecordRawLine> rawLineList,
int inspectTimes,
SysUser? user)
{
var record = new MesXslRubberQuickTestRecord
{
LineList = lineList,
RawLineList = rawLineList,
InspectTime = DateTime.Now,
InspectResult = JudgeInspectResultFromRows(InspectRows)
};
if (!string.IsNullOrWhiteSpace(_currentStd?.RubberMaterialId))
record.RubberMaterialId = _currentStd.RubberMaterialId;
if (!string.IsNullOrWhiteSpace(RubberMaterialName))
record.RubberMaterialName = RubberMaterialName;
if (!string.IsNullOrWhiteSpace(_currentStd?.Id))
record.StdId = _currentStd.Id;
if (!string.IsNullOrWhiteSpace(_selectedPlan?.MachineId))
record.ProdEquipmentLedgerId = _selectedPlan.MachineId;
if (!string.IsNullOrWhiteSpace(MachineName))
record.ProdEquipmentName = MachineName;
record.ProductionDate = MixingDate;
if (!string.IsNullOrWhiteSpace(TrainNo))
record.TrainNo = TrainNo.Trim();
if (SelectedShift != null && !string.IsNullOrWhiteSpace(SelectedShift.Code))
record.WorkShift = SelectedShift.Code;
record.InspectTimes = inspectTimes;
if (!string.IsNullOrWhiteSpace(ProductionOrderNo))
record.ProductionPlanNo = ProductionOrderNo;
var inspectorId = user?.JeecgBizUserId ?? (user != null ? user.Id.ToString() : null);
if (!string.IsNullOrWhiteSpace(inspectorId))
record.InspectorUserId = inspectorId;
if (!string.IsNullOrWhiteSpace(user?.Account))
record.InspectorUsername = user.Account;
if (!string.IsNullOrWhiteSpace(user?.RealName))
record.InspectorRealname = user.RealName;
return record;
}
private static Axis[] BuildTimeAxis() => new[]
{
new Axis
{
Name = "时间(min)",
MinLimit = 0,
MaxLimit = 2,
Labels = new[] { "0", "0.5", "1", "1.5", "2" },
LabelsPaint = new SolidColorPaint(SKColors.Gray),
NamePaint = new SolidColorPaint(SKColors.Gray)
}
};
private static Axis[] BuildTempYAxis() => new[]
{
new Axis
{
Name = "温度(℃)",
MinLimit = 189,
MaxLimit = 201,
Labeler = v => v switch
{
189 => "189",
192 => "192",
195 => "195",
198 => "198",
201 => "201",
_ => string.Empty
},
LabelsPaint = new SolidColorPaint(SKColors.Gray),
NamePaint = new SolidColorPaint(SKColors.Gray)
}
};
private static Axis[] BuildTorqueYAxis() => new[]
{
new Axis
{
Name = "S'(dNm)",
MinLimit = 0,
MaxLimit = 14,
Labeler = v => v switch
{
0 => "0",
3 => "3",
6 => "6",
8 => "8",
11 => "11",
14 => "14",
_ => string.Empty
},
LabelsPaint = new SolidColorPaint(SKColors.Gray),
NamePaint = new SolidColorPaint(SKColors.Gray)
}
};
public new void Destroy() => base.Destroy();
}
public class WorkShiftOption
{
public WorkShiftOption(string code, string name)
{
Code = code;
Name = name;
}
public string Code { get; }
public string Name { get; }
}

View File

@@ -0,0 +1,40 @@
using HandyControl.Tools.Extension;
using Prism.Commands;
using System.Collections.ObjectModel;
using YY.Admin.Core.Entity;
using YY.Admin.ViewModels;
namespace YY.Admin.ViewModels.RubberQuickTestStd;
public class RubberQuickTestStdDetailDialogViewModel : BaseViewModel, IDialogResultable<bool>
{
private MesXslRubberQuickTestStd? _std;
public MesXslRubberQuickTestStd? Std
{
get => _std;
private set => SetProperty(ref _std, value);
}
public ObservableCollection<MesXslRubberQuickTestStdLine> Lines { get; } = new();
private bool _result;
public bool Result { get => _result; set => SetProperty(ref _result, value); }
public Action? CloseAction { get; set; }
public RubberQuickTestStdDetailDialogViewModel(
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
{
CloseCommand = new DelegateCommand(() => CloseAction?.Invoke());
}
public DelegateCommand CloseCommand { get; }
public void Initialize(MesXslRubberQuickTestStd std)
{
Std = std;
Lines.Clear();
foreach (var line in std.LineList ?? [])
Lines.Add(line);
}
}

View File

@@ -0,0 +1,166 @@
using HandyControl.Controls;
using HandyControl.Tools.Extension;
using Prism.Events;
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.Services.Service;
using YY.Admin.Views.RubberQuickTestStd;
namespace YY.Admin.ViewModels.RubberQuickTestStd;
public class RubberQuickTestStdListViewModel : BaseViewModel
{
private readonly IRubberQuickTestStdService _stdService;
private readonly IJeecgDictSyncService _dictSyncService;
private SubscriptionToken? _changedToken;
private ObservableCollection<MesXslRubberQuickTestStd> _items = new();
public ObservableCollection<MesXslRubberQuickTestStd> Items
{
get => _items;
set => SetProperty(ref _items, 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? _filterStdName;
public string? FilterStdName { get => _filterStdName; set => SetProperty(ref _filterStdName, value); }
private string? _filterRubberMaterialName;
public string? FilterRubberMaterialName { get => _filterRubberMaterialName; set => SetProperty(ref _filterRubberMaterialName, value); }
private string? _filterEnableStatus;
public string? FilterEnableStatus { get => _filterEnableStatus; set => SetProperty(ref _filterEnableStatus, value); }
public ObservableCollection<KeyValuePair<string, string>> EnableStatusOptions { get; } = new();
public DelegateCommand SearchCommand { get; }
public DelegateCommand ResetCommand { get; }
public DelegateCommand<MesXslRubberQuickTestStd> ViewDetailCommand { get; }
public DelegateCommand PrevPageCommand { get; }
public DelegateCommand NextPageCommand { get; }
public RubberQuickTestStdListViewModel(
IRubberQuickTestStdService stdService,
IJeecgDictSyncService dictSyncService,
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
{
_stdService = stdService;
_dictSyncService = dictSyncService;
SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); });
ResetCommand = new DelegateCommand(async () =>
{
FilterStdName = null;
FilterRubberMaterialName = null;
FilterEnableStatus = null;
PageNo = 1;
await LoadAsync();
});
ViewDetailCommand = new DelegateCommand<MesXslRubberQuickTestStd>(async x => await ShowDetailAsync(x));
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<RubberQuickTestStdChangedEvent>()
.Subscribe(async _ => await LoadAsync(), ThreadOption.UIThread);
_ = InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
await LoadDictOptionsAsync();
await UIHelper.WaitForRenderAsync();
await LoadAsync();
}
catch (Exception ex)
{
Debug.WriteLine($"快检实验标准列表初始化失败: {ex.Message}");
}
}
private async Task LoadDictOptionsAsync()
{
try
{
var opts = await _dictSyncService.GetDictOptionsAsync("xslmes_rubber_quick_test_std_enable_status", includeAll: true);
EnableStatusOptions.Clear();
foreach (var item in opts) EnableStatusOptions.Add(item);
}
catch
{
EnableStatusOptions.Clear();
EnableStatusOptions.Add(new KeyValuePair<string, string>("全部", ""));
EnableStatusOptions.Add(new KeyValuePair<string, string>("使用中", "1"));
EnableStatusOptions.Add(new KeyValuePair<string, string>("已停用", "0"));
}
}
public async Task LoadAsync()
{
try
{
IsLoading = true;
var result = await _stdService.PageAsync(
PageNo, PageSize, FilterStdName, FilterRubberMaterialName, FilterEnableStatus);
Items = new ObservableCollection<MesXslRubberQuickTestStd>(result.Records);
Total = result.Total;
}
catch (Exception ex)
{
Growl.Error($"加载快检实验标准失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
private async Task ShowDetailAsync(MesXslRubberQuickTestStd? row)
{
if (row?.Id == null) return;
try
{
var detail = await _stdService.GetByIdAsync(row.Id);
if (detail == null)
{
Growl.Warning("未找到该实验标准,可能已被删除");
await LoadAsync();
return;
}
await HandyControl.Controls.Dialog.Show<RubberQuickTestStdDetailDialogView>()
.Initialize<RubberQuickTestStdDetailDialogViewModel>(vm => vm.Initialize(detail))
.GetResultAsync<bool>();
}
catch (Exception ex)
{
Growl.Error($"打开详情失败:{ex.Message}");
}
}
protected override void CleanUp()
{
base.CleanUp();
if (_changedToken != null)
{
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>().Unsubscribe(_changedToken);
_changedToken = null;
}
}
}

View File

@@ -0,0 +1,301 @@
<UserControl x:Class="YY.Admin.Views.RubberQuickTest.RubberQuickTestOperationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="SectionBorderStyle" TargetType="Border">
<Setter Property="CornerRadius" Value="8"/>
<Setter Property="Background" Value="{DynamicResource ThirdlyRegionBrush}"/>
<Setter Property="Padding" Value="12"/>
<Setter Property="Margin" Value="0,0,0,10"/>
</Style>
<Style x:Key="SectionTitleStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}"/>
<Setter Property="Margin" Value="8,0,0,0"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</UserControl.Resources>
<Grid Margin="12">
<Grid.RowDefinitions>
<RowDefinition Height="64"/>
<RowDefinition Height="*"/>
<RowDefinition Height="56"/>
</Grid.RowDefinitions>
<!-- 标题 -->
<Border Grid.Row="0" Background="{DynamicResource RegionBrush}"
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="0,0,0,1" Margin="-12,0,-12,8">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="20,0">
<Border Width="40" Height="40" CornerRadius="8" Background="{DynamicResource PrimaryBrush}" Margin="0,0,12,0">
<md:PackIcon Kind="Flask" Width="22" Height="22" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<StackPanel>
<TextBlock Text="快检记录" FontSize="18" FontWeight="Bold"/>
<TextBlock Text="密炼快检试验操作台" FontSize="12" Foreground="{DynamicResource SecondaryTextBrush}"/>
</StackPanel>
</StackPanel>
</Border>
<!-- 主体 2:1 -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- 左侧:曲线 + 试验结果 -->
<ScrollViewer Grid.Column="0" VerticalScrollBarVisibility="Auto">
<StackPanel>
<Border Style="{StaticResource SectionBorderStyle}">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
<Border Width="4" Height="18" CornerRadius="2" Background="#1890ff"/>
<TextBlock Text="温度(℃)曲线" Style="{StaticResource SectionTitleStyle}"/>
<Button Content="刷新演示" Command="{Binding RefreshChartDemoCommand}" Style="{StaticResource ButtonDefault}" Height="28" Padding="10,0" Margin="12,0,0,0"/>
</StackPanel>
<TextBlock Text="{Binding ChartDemoHint}" FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,0,0,6"/>
<Border Height="220" CornerRadius="4">
<lvc:CartesianChart Series="{Binding TemperatureSeries}"
XAxes="{Binding TemperatureXAxes}"
YAxes="{Binding TemperatureYAxes}"
LegendPosition="Top"/>
</Border>
</StackPanel>
</Border>
<Border Style="{StaticResource SectionBorderStyle}">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
<Border Width="4" Height="18" CornerRadius="2" Background="#1890ff"/>
<TextBlock Text="S'(dNm)曲线" Style="{StaticResource SectionTitleStyle}"/>
</StackPanel>
<Border Height="200" CornerRadius="4">
<lvc:CartesianChart Series="{Binding TorqueSeries}"
XAxes="{Binding TorqueXAxes}"
YAxes="{Binding TorqueYAxes}"
LegendPosition="Top"/>
</Border>
</StackPanel>
</Border>
<Border Style="{StaticResource SectionBorderStyle}">
<StackPanel>
<Grid Margin="0,0,0,8">
<StackPanel Orientation="Horizontal">
<Border Width="4" Height="18" CornerRadius="2" Background="#1890ff"/>
<TextBlock Text="试验结果" Style="{StaticResource SectionTitleStyle}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="新增检验行" Command="{Binding AddInspectRowCommand}" Style="{StaticResource ButtonPrimary}" Height="28" Padding="10,0" Margin="0,0,8,0"/>
<Button Content="删除选中行" Command="{Binding RemoveInspectRowCommand}" Style="{StaticResource ButtonDanger}" Height="28" Padding="10,0"/>
</StackPanel>
</Grid>
<DataGrid x:Name="InspectResultGrid"
ItemsSource="{Binding InspectRows}"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
HeadersVisibility="Column"
MinHeight="160"
SelectionMode="Single"
IsReadOnly="False"
SelectionChanged="InspectResultGrid_SelectionChanged">
</DataGrid>
<TextBlock Text="请手填各数据点检测值,系统将根据数据标准上下限自动判定合格/不合格" FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,6,0,0"/>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<!-- 右侧 -->
<ScrollViewer Grid.Column="2" VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- 实时数据 -->
<Border Style="{StaticResource SectionBorderStyle}">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,12">
<Border Width="4" Height="18" CornerRadius="2" Background="#52c41a"/>
<TextBlock Text="实时数据" Style="{StaticResource SectionTitleStyle}"/>
</StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="上模温度(℃)" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,0,0,4"/>
<TextBlock Grid.Row="1" Text="{Binding UpperMoldTemp, StringFormat={}{0:N2}}" FontSize="28" FontWeight="Bold" FontFamily="Consolas"/>
<TextBlock Grid.Column="1" Text="下模温度(℃)" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,0,0,4"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding LowerMoldTemp, StringFormat={}{0:N2}}" FontSize="28" FontWeight="Bold" FontFamily="Consolas"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="S'(dNm)" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,12,0,4"/>
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,32,0,0" Text="{Binding TorqueS, StringFormat={}{0:N2}}" FontSize="28" FontWeight="Bold" FontFamily="Consolas"/>
</Grid>
</StackPanel>
</Border>
<!-- 试验信息 -->
<Border Style="{StaticResource SectionBorderStyle}">
<StackPanel>
<Grid Margin="0,0,0,12">
<StackPanel Orientation="Horizontal">
<Border Width="4" Height="18" CornerRadius="2" Background="#1890ff"/>
<TextBlock Text="试验信息" Style="{StaticResource SectionTitleStyle}"/>
</StackPanel>
<Button Content="刷新计划" Command="{Binding RefreshPlansCommand}"
Style="{StaticResource ButtonDefault}" Height="26" Padding="8,0"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
<hc:Row Gutter="10">
<!-- 密炼日期 -->
<hc:Col Span="12">
<hc:DatePicker SelectedDate="{Binding MixingDate}"
hc:InfoElement.Title="密炼日期"
hc:InfoElement.TitleWidth="90"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Necessary="True"
hc:InfoElement.Symbol="*"
Margin="0,0,0,8"/>
</hc:Col>
<!-- 密炼机台 -->
<hc:Col Span="12">
<hc:ComboBox ItemsSource="{Binding MachineOptions}"
SelectedItem="{Binding SelectedMachine}"
hc:InfoElement.Title="密炼机台"
hc:InfoElement.TitleWidth="90"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Placeholder="请先选择密炼日期"
hc:InfoElement.Necessary="True"
hc:InfoElement.Symbol="*"
Margin="0,0,0,8"/>
</hc:Col>
<!-- 班次 -->
<hc:Col Span="12">
<hc:ComboBox ItemsSource="{Binding ShiftOptions}"
SelectedItem="{Binding SelectedShift}"
DisplayMemberPath="Name"
hc:InfoElement.Title="班次"
hc:InfoElement.TitleWidth="90"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Placeholder="请先选择机台"
hc:InfoElement.Necessary="True"
hc:InfoElement.Symbol="*"
Margin="0,0,0,8"/>
</hc:Col>
<!-- 密炼生产计划 -->
<hc:Col Span="24">
<hc:ComboBox ItemsSource="{Binding PlanOptions}"
SelectedItem="{Binding SelectedPlan}"
DisplayMemberPath="DisplayText"
hc:InfoElement.Title="密炼计划"
hc:InfoElement.TitleWidth="90"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Placeholder="按日期、机台、班次筛选后选择"
hc:InfoElement.Necessary="True"
hc:InfoElement.Symbol="*"
Margin="0,0,0,8"/>
</hc:Col>
<!-- 生产订单号 -->
<hc:Col Span="12">
<hc:TextBox Text="{Binding ProductionOrderNo, Mode=OneWay}"
IsReadOnly="True"
hc:InfoElement.Title="生产订单号"
hc:InfoElement.TitleWidth="90"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Placeholder="选择计划后自动带出"
hc:InfoElement.Necessary="True"
hc:InfoElement.Symbol="*"
Margin="0,0,0,8"/>
</hc:Col>
<!-- 胶料名称 -->
<hc:Col Span="12">
<hc:TextBox Text="{Binding RubberMaterialName, Mode=OneWay}"
IsReadOnly="True"
hc:InfoElement.Title="胶料名称"
hc:InfoElement.TitleWidth="90"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Placeholder="选择计划后自动带出"
Margin="0,0,0,8"/>
</hc:Col>
<!-- 车次 -->
<hc:Col Span="12">
<hc:TextBox Text="{Binding TrainNo, UpdateSourceTrigger=PropertyChanged}"
hc:InfoElement.Title="车次"
hc:InfoElement.TitleWidth="90"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Placeholder="手填车次"
hc:InfoElement.Necessary="True"
hc:InfoElement.Symbol="*"
hc:InfoElement.ShowClearButton="True"
Margin="0,0,0,8"/>
</hc:Col>
<!-- 试验次数 -->
<hc:Col Span="12">
<hc:TextBox Text="{Binding InspectTimesText, UpdateSourceTrigger=PropertyChanged}"
hc:InfoElement.Title="试验次数"
hc:InfoElement.TitleWidth="90"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Placeholder="默认 1可修改"
hc:InfoElement.Necessary="True"
hc:InfoElement.Symbol="*"
hc:InfoElement.ShowClearButton="True"
Margin="0,0,0,0"/>
</hc:Col>
</hc:Row>
<TextBlock Text="按密炼日期 → 机台 → 班次筛选生产计划;胶料名称用于匹配快检实验标准"
FontSize="11"
Foreground="{DynamicResource SecondaryTextBrush}"
Margin="0,8,0,0"
TextWrapping="Wrap"/>
</StackPanel>
</Border>
<!-- 数据标准 -->
<Border Style="{StaticResource SectionBorderStyle}">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
<Border Width="4" Height="18" CornerRadius="2" Background="#faad14"/>
<TextBlock Text="数据标准" Style="{StaticResource SectionTitleStyle}"/>
</StackPanel>
<DataGrid ItemsSource="{Binding DataPointColumns}"
AutoGenerateColumns="False"
IsReadOnly="True"
HeadersVisibility="Column"
MaxHeight="240">
<DataGrid.Columns>
<DataGridTextColumn Header="数据点" Binding="{Binding PointName}" Width="*"/>
<DataGridTextColumn Header="下限值" Binding="{Binding LowerLimit}" Width="70"/>
<DataGridTextColumn Header="上限值" Binding="{Binding UpperLimit}" Width="70"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Grid>
<!-- 底部操作 -->
<Border Grid.Row="2" Background="{DynamicResource RegionBrush}" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="0,1,0,0" Margin="-12,8,-12,-12">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="20,0">
<Button Content="保存快检记录" Command="{Binding SaveCommand}" Style="{StaticResource ButtonPrimary}" Height="36" Width="140"/>
</StackPanel>
</Border>
</Grid>
</UserControl>

View File

@@ -0,0 +1,72 @@
using System.Windows.Controls;
using YY.Admin.ViewModels.RubberQuickTest;
namespace YY.Admin.Views.RubberQuickTest;
public partial class RubberQuickTestOperationView : UserControl
{
private RubberQuickTestOperationViewModel? _vm;
public RubberQuickTestOperationView()
{
InitializeComponent();
DataContextChanged += OnDataContextChanged;
}
private void OnDataContextChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
if (_vm != null)
_vm.InspectColumnsChanged -= RebuildInspectColumns;
_vm = DataContext as RubberQuickTestOperationViewModel;
if (_vm != null)
{
_vm.InspectColumnsChanged += RebuildInspectColumns;
RebuildInspectColumns();
}
}
private void RebuildInspectColumns()
{
if (_vm == null) return;
InspectResultGrid.Columns.Clear();
InspectResultGrid.Columns.Add(new DataGridTextColumn
{
Header = "编号",
Binding = new System.Windows.Data.Binding("RowNo"),
IsReadOnly = true,
Width = 80
});
for (int i = 0; i < _vm.DataPointColumns.Count; i++)
{
var col = _vm.DataPointColumns[i];
var binding = new System.Windows.Data.Binding($"Cells[{i}].Value")
{
UpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
Mode = System.Windows.Data.BindingMode.TwoWay
};
InspectResultGrid.Columns.Add(new DataGridTextColumn
{
Header = col.PointName ?? $"点{i + 1}",
Binding = binding,
Width = 90,
IsReadOnly = false
});
}
InspectResultGrid.Columns.Add(new DataGridTextColumn
{
Header = "实验结果",
Binding = new System.Windows.Data.Binding("InspectResultText"),
IsReadOnly = true,
Width = 90
});
}
private void InspectResultGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_vm == null) return;
_vm.SelectedInspectRow = InspectResultGrid.SelectedItem as QuickTestInspectRowViewModel;
}
}

View File

@@ -0,0 +1,97 @@
<UserControl x:Class="YY.Admin.Views.RubberQuickTestStd.RubberQuickTestStdDetailDialogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Width="900"
MinHeight="520">
<Grid Background="{DynamicResource ThirdlyRegionBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<hc:SimplePanel Margin="20">
<TextBlock FontSize="18" Foreground="{DynamicResource PrimaryTextBrush}"
Text="胶料快检实验标准详情" HorizontalAlignment="Left"/>
<Button Width="22" Height="22" Command="hc:ControlCommands.Close"
Style="{StaticResource ButtonIcon}" Foreground="{DynamicResource PrimaryBrush}"
hc:IconElement.Geometry="{StaticResource ErrorGeometry}"
Padding="0" HorizontalAlignment="Right" VerticalAlignment="Top"/>
</hc:SimplePanel>
<hc:ScrollViewer Grid.Row="1" IsInertiaEnabled="True">
<StackPanel Margin="20,0,20,0">
<hc:Row Gutter="10">
<hc:Col Span="12">
<hc:TextBox Text="{Binding Std.StdName, Mode=OneWay}" IsReadOnly="True"
hc:InfoElement.Title="标准名称" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
Margin="0,0,0,12"/>
</hc:Col>
<hc:Col Span="12">
<hc:TextBox Text="{Binding Std.TestMethodName, Mode=OneWay}" IsReadOnly="True"
hc:InfoElement.Title="实验方法" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
Margin="0,0,0,12"/>
</hc:Col>
<hc:Col Span="12">
<hc:TextBox Text="{Binding Std.RubberMaterialName, Mode=OneWay}" IsReadOnly="True"
hc:InfoElement.Title="胶料名称" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
Margin="0,0,0,12"/>
</hc:Col>
<hc:Col Span="12">
<hc:TextBox Text="{Binding Std.IssueNumber, Mode=OneWay}" IsReadOnly="True"
hc:InfoElement.Title="发行编号" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
Margin="0,0,0,12"/>
</hc:Col>
<hc:Col Span="12">
<hc:TextBox Text="{Binding Std.IssueDate, Mode=OneWay, StringFormat={}{0:yyyy-MM-dd}}" IsReadOnly="True"
hc:InfoElement.Title="发行日期" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
Margin="0,0,0,12"/>
</hc:Col>
<hc:Col Span="12">
<hc:TextBox Text="{Binding Std.IssueDeptName, Mode=OneWay}" IsReadOnly="True"
hc:InfoElement.Title="发行部门" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
Margin="0,0,0,12"/>
</hc:Col>
<hc:Col Span="12">
<hc:TextBox Text="{Binding Std.EnableStatusText, Mode=OneWay}" IsReadOnly="True"
hc:InfoElement.Title="启用状态" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
Margin="0,0,0,12"/>
</hc:Col>
<hc:Col Span="12">
<hc:TextBox Text="{Binding Std.AuditStatusText, Mode=OneWay}" IsReadOnly="True"
hc:InfoElement.Title="审核状态" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
Margin="0,0,0,12"/>
</hc:Col>
</hc:Row>
<TextBlock Text="标准明细(数据点上下限)" FontWeight="SemiBold" Margin="0,8,0,8"/>
<DataGrid ItemsSource="{Binding Lines}"
AutoGenerateColumns="False"
IsReadOnly="True"
HeadersVisibility="Column"
MaxHeight="280"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="数据点" Binding="{Binding PointName}" Width="*"/>
<DataGridTextColumn Header="下限值" Binding="{Binding LowerLimit}" Width="90"/>
<DataGridTextColumn Header="下警告" Binding="{Binding LowerWarn}" Width="90"/>
<DataGridTextColumn Header="目标值" Binding="{Binding TargetValue}" Width="90"/>
<DataGridTextColumn Header="上警告" Binding="{Binding UpperWarn}" Width="90"/>
<DataGridTextColumn Header="上限值" Binding="{Binding UpperLimit}" Width="90"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</hc:ScrollViewer>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="20">
<Button Content="关闭" Command="{Binding CloseCommand}" Style="{StaticResource ButtonPrimary}" Width="100"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.RubberQuickTestStd;
public partial class RubberQuickTestStdDetailDialogView : UserControl
{
public RubberQuickTestStdDetailDialogView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,128 @@
<UserControl x:Class="YY.Admin.Views.RubberQuickTestStd.RubberQuickTestStdListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" CornerRadius="4" Margin="0 0 -10 0">
<hc:Row>
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
<hc:TextBox Text="{Binding FilterStdName, UpdateSourceTrigger=PropertyChanged}"
Margin="0 0 10 10"
hc:InfoElement.Title="标准名称"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.TitleWidth="75"
hc:InfoElement.Placeholder="实验标准名称"
hc:InfoElement.ShowClearButton="True"/>
</hc:Col>
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
<hc:TextBox Text="{Binding FilterRubberMaterialName, UpdateSourceTrigger=PropertyChanged}"
Margin="0 0 10 10"
hc:InfoElement.Title="胶料名称"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.TitleWidth="75"
hc:InfoElement.Placeholder="胶料名称"
hc:InfoElement.ShowClearButton="True"/>
</hc:Col>
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
<hc:ComboBox SelectedValuePath="Value"
DisplayMemberPath="Key"
ItemsSource="{Binding EnableStatusOptions}"
SelectedValue="{Binding FilterEnableStatus}"
Margin="0 0 10 10"
hc:InfoElement.Title="启用状态"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.TitleWidth="75"
hc:InfoElement.Placeholder="全部"
hc:InfoElement.ShowClearButton="True"/>
</hc:Col>
</hc:Row>
</Border>
<Border Grid.Row="1" Margin="0,10">
<hc:UniformSpacingPanel Spacing="10">
<Button Style="{StaticResource ButtonPrimary}" Command="{Binding SearchCommand}">
<StackPanel Orientation="Horizontal">
<md:PackIcon Kind="Search"/>
<TextBlock Text="搜索" Style="{StaticResource IconButtonStyle}"/>
</StackPanel>
</Button>
<Button Style="{StaticResource ButtonDefault}" Command="{Binding ResetCommand}">
<StackPanel Orientation="Horizontal">
<md:PackIcon Kind="Refresh"/>
<TextBlock Text="重置" Style="{StaticResource IconButtonStyle}"/>
</StackPanel>
</Button>
<TextBlock Text="数据来自 MES桌面端只读断网时显示本地缓存"
VerticalAlignment="Center"
Foreground="{DynamicResource SecondaryTextBrush}"
FontSize="12"/>
</hc:UniformSpacingPanel>
</Border>
<DataGrid Grid.Row="2"
ItemsSource="{Binding Items}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserAddRows="False"
SelectionMode="Single"
GridLinesVisibility="Horizontal"
HorizontalGridLinesBrush="#FFEDEDED"
VerticalGridLinesBrush="Transparent"
HeadersVisibility="All"
ColumnHeaderStyle="{StaticResource CusDataGridColumnHeaderStyle}"
Style="{StaticResource CusDataGridStyle}"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="实验标准名称" Binding="{Binding StdName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="180"/>
<DataGridTextColumn Header="实验方法" Binding="{Binding TestMethodName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="140"/>
<DataGridTextColumn Header="胶料名称" Binding="{Binding RubberMaterialName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="140"/>
<DataGridTextColumn Header="发行编号" Binding="{Binding IssueNumber}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
<DataGridTextColumn Header="发行部门" Binding="{Binding IssueDeptName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
<DataGridTextColumn Header="启用状态" Binding="{Binding EnableStatusText}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="90"/>
<DataGridTextColumn Header="审核状态" Binding="{Binding AuditStatusText}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="90"/>
<DataGridTextColumn Header="创建人" Binding="{Binding CreateBy}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="100"/>
<DataGridTextColumn Header="创建时间" Binding="{Binding CreateTime, StringFormat={}{0:yyyy-MM-dd HH:mm}}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="150"/>
<DataGridTemplateColumn Header="操作" Width="100" CellStyle="{StaticResource CusOperDataGridCellStyle}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border Style="{DynamicResource DataGridOpeButtonStyle}">
<Border.InputBindings>
<MouseBinding Command="{Binding DataContext.ViewDetailCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"
CommandParameter="{Binding}" MouseAction="LeftClick"/>
</Border.InputBindings>
<StackPanel Orientation="Horizontal">
<md:PackIcon Kind="EyeOutline" VerticalAlignment="Center"/>
<TextBlock Text="详情" VerticalAlignment="Center"/>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
<TextBlock Text="{Binding Total, StringFormat=共 {0} 条}" VerticalAlignment="Center" Margin="0,0,16,0"
Foreground="{DynamicResource SecondaryTextBrush}"/>
<Button Content="上一页" Command="{Binding PrevPageCommand}" Style="{StaticResource ButtonDefault}" Margin="0,0,4,0" Width="80"/>
<TextBlock Text="{Binding PageNo, StringFormat=第 {0} 页}" VerticalAlignment="Center" Margin="8,0"
Foreground="{DynamicResource PrimaryTextBrush}"/>
<Button Content="下一页" Command="{Binding NextPageCommand}" Style="{StaticResource ButtonDefault}" Width="80"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.RubberQuickTestStd;
public partial class RubberQuickTestStdListView : UserControl
{
public RubberQuickTestStdListView()
{
InitializeComponent();
}
}