feat(base): 添加设备参数追溯和SPC分析功能

- 新增参数追溯列表查询接口,支持按设备编码、参数编码和时间范围检索
- 实现参数追溯数据导出功能,支持Excel格式导出
- 添加SPC统计过程控制分析接口,提供均值、标准差、CPK等统计指标
- 实现数据库查询优化,增加参数追溯和历史值查询的SQL映射
- 完善参数名称查询功能,支持通过参数编码获取对应名称
- 优化Excel导入工具类,增加表头验证机制防止空指针异常
master
zangch@mesnac.com 2 months ago
parent 40b313aca3
commit 721d1e9a6f

@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.aucma.common.annotation.Log;
import com.aucma.common.core.controller.BaseController;
@ -147,4 +148,48 @@ public class BaseDeviceParamValController extends BaseController {
return success(baseDeviceParamValService.selectDeviceStartTimeList());
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('baseDeviceParamVal:trace:list')" )
@GetMapping("/trace/list" )
public TableDataInfo traceList(
@RequestParam("deviceCode") String deviceCode,
@RequestParam(value = "paramCode", required = false) String paramCode,
@RequestParam("startTime") String startTime,
@RequestParam("endTime") String endTime) {
startPage();
List<BaseDeviceParamVal> list = baseDeviceParamValService.selectTraceList(deviceCode, paramCode, startTime, endTime);
return getDataTable(list);
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('baseDeviceParamVal:trace:export')" )
@Log(title = "参数追溯数据导出" , businessType = BusinessType.EXPORT)
@PostMapping("/trace/export" )
public void traceExport(HttpServletResponse response,
@RequestParam("deviceCode") String deviceCode,
@RequestParam(value = "paramCode", required = false) String paramCode,
@RequestParam("startTime") String startTime,
@RequestParam("endTime") String endTime) {
List<BaseDeviceParamVal> list = baseDeviceParamValService.selectTraceList(deviceCode, paramCode, startTime, endTime);
ExcelUtil<BaseDeviceParamVal> util = new ExcelUtil<BaseDeviceParamVal>(BaseDeviceParamVal.class);
util.exportExcel(response, list, "参数追溯数据");
}
/**
* SPC
*/
@PreAuthorize("@ss.hasPermi('baseDeviceParamVal:trace:list')" )
@GetMapping("/spcData" )
public AjaxResult getSPCData(
@RequestParam("deviceCode") String deviceCode,
@RequestParam("paramCode") String paramCode,
@RequestParam("startTime") String startTime,
@RequestParam("endTime") String endTime) {
return success(baseDeviceParamValService.getSPCData(deviceCode, paramCode, startTime, endTime));
}
}

@ -89,4 +89,28 @@ public interface BaseDeviceParamValMapper
* @return
*/
public List<Map<String, Object>> selectDeviceStartTimeList();
/**
*
*
* @param params deviceCode, paramCode, startTime, endTime
* @return
*/
public List<BaseDeviceParamVal> selectTraceList(Map<String, Object> params);
/**
* SPC
*
* @param params deviceCode, paramCode, startTime, endTime
* @return
*/
public List<Double> selectParamHistoryValues(Map<String, Object> params);
/**
*
*
* @param paramCode
* @return
*/
public String selectParamNameByCode(String paramCode);
}

@ -89,4 +89,26 @@ public interface IBaseDeviceParamValService
* @return
*/
public List<Map<String, Object>> selectDeviceStartTimeList();
/**
*
*
* @param deviceCode
* @param paramCode
* @param startTime
* @param endTime
* @return
*/
public List<BaseDeviceParamVal> selectTraceList(String deviceCode, String paramCode, String startTime, String endTime);
/**
* SPC
*
* @param deviceCode
* @param paramCode
* @param startTime
* @param endTime
* @return SPC
*/
public Map<String, Object> getSPCData(String deviceCode, String paramCode, String startTime, String endTime);
}

@ -1,5 +1,6 @@
package com.aucma.base.service.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -193,4 +194,115 @@ public class BaseDeviceParamValServiceImpl implements IBaseDeviceParamValService
return Collections.emptyList();
}
}
/**
*
*/
@Override
public List<BaseDeviceParamVal> selectTraceList(String deviceCode, String paramCode, String startTime, String endTime) {
try {
Map<String, Object> params = new HashMap<>();
params.put("deviceCode", deviceCode);
params.put("paramCode", paramCode);
params.put("startTime", startTime);
params.put("endTime", endTime);
List<BaseDeviceParamVal> list = baseDeviceParamValMapper.selectTraceList(params);
return list != null ? list : Collections.emptyList();
} catch (Exception e) {
log.error("参数追溯查询失败: {}", e.getMessage());
return Collections.emptyList();
}
}
/**
* SPC
*/
@Override
public Map<String, Object> getSPCData(String deviceCode, String paramCode, String startTime, String endTime) {
Map<String, Object> result = new HashMap<>();
result.put("deviceCode", deviceCode);
result.put("paramCode", paramCode);
try {
// 查询参数名称
String paramName = baseDeviceParamValMapper.selectParamNameByCode(paramCode);
result.put("paramName", paramName != null ? paramName : paramCode);
// 查询参数历史值
Map<String, Object> params = new HashMap<>();
params.put("deviceCode", deviceCode);
params.put("paramCode", paramCode);
params.put("startTime", startTime);
params.put("endTime", endTime);
List<Double> values = baseDeviceParamValMapper.selectParamHistoryValues(params);
if (values == null || values.isEmpty()) {
result.put("values", new ArrayList<>());
result.put("sampleSize", 0);
result.put("mean", 0.0);
result.put("stdDev", 0.0);
result.put("cpk", 0.0);
result.put("ucl", 0.0);
result.put("lcl", 0.0);
result.put("cl", 0.0);
return result;
}
result.put("values", values);
result.put("sampleSize", values.size());
// 计算统计指标
double mean = calculateMean(values);
double stdDev = calculateStdDev(values, mean);
double ucl = mean + 3 * stdDev;
double lcl = mean - 3 * stdDev;
result.put("mean", Math.round(mean * 1000.0) / 1000.0);
result.put("stdDev", Math.round(stdDev * 1000.0) / 1000.0);
result.put("ucl", Math.round(ucl * 1000.0) / 1000.0);
result.put("lcl", Math.round(lcl * 1000.0) / 1000.0);
result.put("cl", Math.round(mean * 1000.0) / 1000.0);
// 计算CPK假设规格限为均值±10%
double usl = mean * 1.1;
double lsl = mean * 0.9;
double cpk = calculateCPK(mean, stdDev, usl, lsl);
result.put("cpk", Math.round(cpk * 100.0) / 100.0);
result.put("usl", Math.round(usl * 1000.0) / 1000.0);
result.put("lsl", Math.round(lsl * 1000.0) / 1000.0);
return result;
} catch (Exception e) {
log.error("获取SPC分析数据失败: {}", e.getMessage());
result.put("error", e.getMessage());
return result;
}
}
private double calculateMean(List<Double> values) {
if (values == null || values.isEmpty()) return 0.0;
double sum = 0.0;
for (Double v : values) {
if (v != null) sum += v;
}
return sum / values.size();
}
private double calculateStdDev(List<Double> values, double mean) {
if (values == null || values.size() < 2) return 0.0;
double sumSquares = 0.0;
for (Double v : values) {
if (v != null) {
sumSquares += Math.pow(v - mean, 2);
}
}
return Math.sqrt(sumSquares / (values.size() - 1));
}
private double calculateCPK(double mean, double stdDev, double usl, double lsl) {
if (stdDev == 0) return 0.0;
double cpupper = (usl - mean) / (3 * stdDev);
double cplower = (mean - lsl) / (3 * stdDev);
return Math.min(cpupper, cplower);
}
}

@ -202,4 +202,43 @@
WHERE d.is_flag = 1
ORDER BY d.product_line_code, d.device_code
</select>
<!-- 参数追溯查询(按时间范围,必须带设备和时间条件) -->
<select id="selectTraceList" parameterType="java.util.Map" resultMap="BaseDeviceParamValResult">
SELECT * FROM (
SELECT record_id, param_code, device_code, device_id, param_name, param_value,
collect_time, record_time,
ROW_NUMBER() OVER (ORDER BY collect_time DESC) AS rn
FROM base_device_param_val
WHERE device_code = #{deviceCode}
AND collect_time BETWEEN TO_DATE(#{startTime}, 'YYYY-MM-DD HH24:MI:SS')
AND TO_DATE(#{endTime}, 'YYYY-MM-DD HH24:MI:SS')
<if test="paramCode != null and paramCode != ''">
AND param_code = #{paramCode}
</if>
) WHERE rn &lt;= 10000
ORDER BY collect_time DESC
</select>
<!-- SPC分析数据查询参数历史值限制1000条 -->
<select id="selectParamHistoryValues" parameterType="java.util.Map" resultType="java.lang.Double">
SELECT * FROM (
SELECT TO_NUMBER(param_value) AS param_value
FROM base_device_param_val
WHERE device_code = #{deviceCode}
AND param_code = #{paramCode}
AND collect_time BETWEEN TO_DATE(#{startTime}, 'YYYY-MM-DD HH24:MI:SS')
AND TO_DATE(#{endTime}, 'YYYY-MM-DD HH24:MI:SS')
AND REGEXP_LIKE(param_value, '^-?[0-9]+\.?[0-9]*$')
ORDER BY collect_time ASC
) WHERE ROWNUM &lt;= 1000
</select>
<!-- 查询参数名称 -->
<select id="selectParamNameByCode" parameterType="String" resultType="String">
SELECT param_name FROM (
SELECT param_name FROM base_device_param_val
WHERE param_code = #{paramCode} AND ROWNUM = 1
)
</select>
</mapper>

@ -356,6 +356,10 @@ public class ExcelUtil<T>
Map<String, Integer> cellMap = new HashMap<String, Integer>();
// 获取表头
Row heard = sheet.getRow(titleNum);
if (heard == null)
{
throw new IOException("Excel文件格式错误第" + (titleNum + 1) + "行表头行为空请检查Excel文件结构");
}
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
{
Cell cell = heard.getCell(i);

Loading…
Cancel
Save