目标策划:获取指标参考数据

This commit is contained in:
huangge1199 2025-08-12 13:22:24 +08:00
parent ece954b468
commit 4eb6562caa
5 changed files with 383 additions and 3 deletions

View File

@ -0,0 +1,36 @@
package iet.ustb.sf.controller;
import com.alibaba.fastjson.JSONObject;
import iet.ustb.sf.common.R;
import iet.ustb.sf.service.TargetDataService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* TargetDataController
*
* @author huangge1199
* @since 2025/8/12 9:19:23
*/
@Tag(name = "目标管控-指标监测")
@RestController
@RequestMapping("/mbgk/data")
public class TargetDataController {
@Resource
private TargetDataService targetDataService;
@Operation(summary = "获取指标参考数据")
@PostMapping("/getExamleData")
public R<Map<String, Object>> getExamleData(@RequestBody JSONObject params) {
return R.ok(targetDataService.getData(params, 1));
}
}

View File

@ -1,5 +1,6 @@
package iet.ustb.sf.service; package iet.ustb.sf.service;
import com.alibaba.fastjson.JSONObject;
import iet.ustb.sf.domain.Target; import iet.ustb.sf.domain.Target;
import iet.ustb.sf.domain.TargetData; import iet.ustb.sf.domain.TargetData;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
@ -25,4 +26,6 @@ public interface TargetDataService extends IService<TargetData> {
TargetData updateHistory(Target target, String[] strArr, Map<String, TargetData> map); TargetData updateHistory(Target target, String[] strArr, Map<String, TargetData> map);
void saveTargetDate(Date date); void saveTargetDate(Date date);
Map<String, Object> getData(JSONObject params, int type);
} }

View File

@ -5,6 +5,7 @@ import iet.ustb.sf.domain.Rule;
import iet.ustb.sf.domain.Target; import iet.ustb.sf.domain.Target;
import iet.ustb.sf.domain.TargetData; import iet.ustb.sf.domain.TargetData;
import java.time.LocalDate;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
@ -25,6 +26,14 @@ public interface UtilService {
*/ */
String[] getCurrentCycleDataByCycle(Date date, String cycle); String[] getCurrentCycleDataByCycle(Date date, String cycle);
/**
* 获取日期所在的年-
*
* @param date 日期
* @return 结果
*/
String getYearWeek(LocalDate date);
/** /**
* 计算表达式结果 * 计算表达式结果
* *

View File

@ -1,22 +1,30 @@
package iet.ustb.sf.service.impl; package iet.ustb.sf.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner; import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import iet.ustb.sf.domain.*; import iet.ustb.sf.domain.*;
import iet.ustb.sf.exception.ErrorCode;
import iet.ustb.sf.exception.MyException;
import iet.ustb.sf.mapper.*; import iet.ustb.sf.mapper.*;
import iet.ustb.sf.service.TargetDataService; import iet.ustb.sf.service.TargetDataService;
import iet.ustb.sf.service.UtilService; import iet.ustb.sf.service.UtilService;
import iet.ustb.sf.util.CheckUtils; import iet.ustb.sf.util.CheckUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAdjusters;
import java.util.*; import java.util.*;
/** /**
@ -54,7 +62,7 @@ public class TargetDataServiceImpl extends ServiceImpl<TargetDataMapper, TargetD
Date now = new Date(); Date now = new Date();
Map<String, String[]> map = utilService.getCurrentCycleData(date); Map<String, String[]> map = utilService.getCurrentCycleData(date);
LocalDate day = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate day = date.toInstant().atZone(ZoneId.of("Asia/Shanghai")).toLocalDate();
for (String cycle : map.keySet()) { for (String cycle : map.keySet()) {
if (day.getDayOfWeek().getValue() > 1 && "lastWeek".equals(cycle)) { if (day.getDayOfWeek().getValue() > 1 && "lastWeek".equals(cycle)) {
continue; continue;
@ -129,6 +137,309 @@ public class TargetDataServiceImpl extends ServiceImpl<TargetDataMapper, TargetD
System.out.println("定时保存指标数据 end:" + endTime); System.out.println("定时保存指标数据 end:" + endTime);
} }
@Override
public Map<String, Object> getData(JSONObject params, int type) {
String targetId = params.getString("id");
String start = params.getString("start");
String end = params.getString("end");
Integer n = params.getInteger("n");
CheckUtils.checkEmpty(targetId, "指标ID");
Target target = targetMapper.selectById(targetId);
if (n == null) {
n = 7;
}
if (StringUtils.isEmpty(start) && StringUtils.isEmpty(end)) {
Map<String, String> cycleDate = getCycleData(target.getCycle(), n);
start = cycleDate.get("start");
end = cycleDate.get("end");
} else if (!StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) {
try {
String[] strArrStart = getDataBySetDateAndCycle(LocalDate.parse(start), target.getCycle());
start = strArrStart[3];
} catch (DateTimeParseException e) {
throw new MyException(ErrorCode.PARAMS_ERROR, "开始日期格式错误或日期非法!");
}
try {
String[] strArrEnd = getDataBySetDateAndCycle(LocalDate.parse(end), target.getCycle());
if (LocalDate.parse(strArrEnd[4]).isBefore(LocalDate.parse(end))) {
end = strArrEnd[4];
}
} catch (DateTimeParseException e) {
throw new MyException(ErrorCode.PARAMS_ERROR, "结束日期格式错误或日期非法!");
}
} else {
throw new MyException(ErrorCode.PARAMS_ERROR, "开始日期和结束日期不能一个有值一个没有值!");
}
QueryWrapper<TargetData> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("target_id", targetId);
queryWrapper.ge("set_date", start);
queryWrapper.lt("set_date", end);
List<TargetData> targetDatas = targetDataMapper.selectList(queryWrapper);
targetDatas = getHistoryData(targetDatas, target, start, end);
List<String> xData = new ArrayList<>();
List<Double> data = new ArrayList<>();
List<Double> oriData = new ArrayList<>();
for (TargetData targetData : targetDatas) {
xData.add(targetData.getXShow());
data.add(targetData.getVal());
oriData.add(targetData.getVal());
}
Map<String, Object> map = new HashMap<>();
map.put("start", start);
map.put("end", end);
map.put("max", Optional.of(data)
.filter(list -> !list.isEmpty())
.map(Collections::max)
.map(value -> "" + CheckUtils.roundToDecimalPlaces(value, 4))
.orElse("-"));
map.put("avg", Optional.of(data)
.filter(list -> !list.isEmpty())
.map(list -> list.stream().mapToDouble(Double::doubleValue).average().orElse(Double.NaN))
.map(value -> "" + CheckUtils.roundToDecimalPlaces(value, 4))
.orElse("-"));
map.put("medium", CheckUtils.roundToDecimalPlaces(getMedian(data), 4));
map.put("min", Optional.of(data)
.filter(list -> !list.isEmpty())
.map(Collections::min)
.map(value -> "" + CheckUtils.roundToDecimalPlaces(value, 4))
.orElse("-"));
map.put("xData", xData);
map.put("data", data);
map.put("cycle", getCycle(target));
map.put("oriData", oriData);
return map;
}
/**
* 获取列表中位数
*
* @param data 列表数据
* @return 中位数
*/
private String getMedian(List<Double> data) {
if (data.isEmpty()) {
return "-";
}
List<Double> sortedData = data.stream()
.sorted()
.toList();
int size = sortedData.size();
double median;
if (size % 2 == 0) {
// 偶数个元素返回中间两个元素的平均值
median = (sortedData.get(size / 2 - 1) + sortedData.get(size / 2)) / 2.0;
} else {
// 奇数个元素返回中间的元素
median = sortedData.get(size / 2);
}
return String.valueOf(median);
}
/**
* 获取指定日期所在周期的 xShow, cycle, setDate, start, end
*
* @param localDate 日期
* @param cycle 周期
* @return 结果
*/
private String[] getDataBySetDateAndCycle(LocalDate localDate, String cycle) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String setDate = localDate.format(dtf);
String xShow, showCycle, start, end;
switch (cycle) {
case "yesterday":
case "nearlyWeek":
case "nearlyMonth":
showCycle = "day";
xShow = localDate.format(dtf);
end = localDate.plusDays(1).format(dtf);
if ("yesterday".equals(cycle)) {
start = localDate.format(dtf);
} else if ("nearlyWeek".equals(cycle)) {
start = localDate.minusDays(7).format(dtf);
} else {
start = localDate.minusDays(30).format(dtf);
}
break;
case "week":
case "lastWeek":
showCycle = "week";
xShow = utilService.getYearWeek(LocalDate.parse(setDate));
start = localDate.format(dtf);
end = localDate.plusDays(7).format(dtf);
break;
case "month":
case "lastMonth":
showCycle = "month";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
xShow = localDate.format(formatter);
start = localDate.format(dtf);
end = localDate.plusMonths(1).format(dtf);
break;
case "product":
case "lastProduct":
showCycle = "product";
DateTimeFormatter productDtf = DateTimeFormatter.ofPattern("yyyy-MM");
xShow = localDate.plusMonths(1).format(productDtf);
start = localDate.format(dtf);
end = localDate.plusMonths(1).format(dtf);
break;
default:
xShow = null;
showCycle = null;
setDate = null;
start = null;
end = null;
break;
}
return new String[]{xShow, showCycle, setDate, start, end};
}
/**
* 补充时间范围内缺失的历史数据
*
* @param targetDataList 现有历史数据
* @param target 指标
* @param start 开始日期
* @param end 结束日期
* @return 补全的历史数据
*/
public List<TargetData> getHistoryData(
List<TargetData> targetDataList,
Target target,
String start,
String end) {
LocalDate compareDate = LocalDate.parse(start);
for (int i = 0; i < targetDataList.size(); i++) {
LocalDate setDate = targetDataList.get(i).getSetDate()
.toInstant().atZone(ZoneId.of("Asia/Shanghai")).toLocalDate();
while (compareDate.isBefore(setDate)) {
String[] strArr = getDataBySetDateAndCycle(compareDate, target.getCycle());
targetDataList.add(i, updateHistory(target, strArr, new HashMap<>()));
compareDate = getCompareDate(target, compareDate);
i++;
setDate = targetDataList.get(i).getSetDate()
.toInstant().atZone(ZoneId.of("Asia/Shanghai")).toLocalDate();
}
compareDate = getCompareDate(target, compareDate);
}
while (compareDate.isBefore(LocalDate.parse(end))) {
String[] strArr = getDataBySetDateAndCycle(compareDate, target.getCycle());
if (LocalDate.parse(end).isBefore(LocalDate.parse(strArr[4]))) {
strArr[4] = end;
}
targetDataList.add(updateHistory(target, strArr, new HashMap<>()));
compareDate = getCompareDate(target, compareDate);
}
return targetDataList;
}
/**
* 获取下一个对比日期
*
* @param target 指标
* @param compareDate 对比日期
* @return 对比日期
*/
private LocalDate getCompareDate(Target target, LocalDate compareDate) {
switch (target.getCycle()) {
case "yesterday":
case "nearlyMonth":
case "nearlyWeek":
compareDate = compareDate.plusDays(1);
break;
case "week":
case "lastWeek":
compareDate = compareDate.plusWeeks(1);
break;
case "month":
case "lastMonth":
case "product":
case "lastProduct":
compareDate = compareDate.plusMonths(1);
break;
}
return compareDate;
}
/**
* 获取周期
*
* @param target 指标
* @return 周期
*/
private String getCycle(Target target) {
String cycle = "";
if (Arrays.asList("yesterday", "nearlyWeek", "nearlyMonth").contains(target.getCycle())) {
cycle = "day";
} else if (Arrays.asList("week", "lastWeek").contains(target.getCycle())) {
cycle = "week";
} else if (Arrays.asList("month", "lastMonth").contains(target.getCycle())) {
cycle = "month";
} else if (Arrays.asList("product", "lastProduct").contains(target.getCycle())) {
cycle = "product";
}
return cycle;
}
/**
* 获取前n个周期的开始结束日期
*
* @param cycle 周期
* @return 结果map
*/
private Map<String, String> getCycleData(String cycle, int n) {
LocalDate localDate = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String end = localDate.format(formatter);
if (Arrays.asList("yesterday", "nearlyWeek", "nearlyMonth").contains(cycle)) {
localDate = localDate.minusDays(n);
} else if (Arrays.asList("week", "lastWeek").contains(cycle)) {
if (localDate.getDayOfWeek() == DayOfWeek.MONDAY) {
localDate = localDate.minusWeeks(1);
}
localDate = localDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
if ("lastWeek".equals(cycle)) {
end = localDate.format(formatter);
localDate = localDate.minusWeeks(1);
}
localDate = localDate.minusWeeks(n - 1);
} else if (Arrays.asList("month", "lastMonth").contains(cycle)) {
if (localDate.getDayOfMonth() == 1) {
localDate = localDate.minusMonths(1);
}
localDate = localDate.withDayOfMonth(1);
if ("lastMonth".equals(cycle)) {
end = localDate.format(formatter);
localDate = localDate.minusMonths(1);
}
localDate = localDate.minusMonths(n - 1);
} else {
if (localDate.getDayOfMonth() == 26) {
localDate = localDate.minusMonths(1);
}
if (localDate.getDayOfMonth() >= 26) {
localDate = localDate.withDayOfMonth(26);
}
if ("lastProduct".equals(cycle)) {
end = localDate.format(formatter);
localDate = localDate.minusMonths(1);
}
localDate = localDate.minusMonths(n - 1);
}
String start = localDate.format(formatter);
Map<String, String> map = new HashMap<>(3);
map.put("start", start);
map.put("end", end);
return map;
}
@Override @Override
public TargetData updateHistory(Target target, String[] strArr, Map<String, TargetData> map) { public TargetData updateHistory(Target target, String[] strArr, Map<String, TargetData> map) {
String xShow = strArr[0]; String xShow = strArr[0];
@ -142,7 +453,11 @@ public class TargetDataServiceImpl extends ServiceImpl<TargetDataMapper, TargetD
double result; double result;
if (target.getType() < 2) { if (target.getType() < 2) {
List<Map<String, Object>> list = SqlRunner.db().selectList(target.getResultSql(), strArr[3], strArr[4]); List<Map<String, Object>> list = SqlRunner.db().selectList(target.getResultSql(), strArr[3], strArr[4]);
if (list.isEmpty() || list.get(0) == null || list.get(0).isEmpty()) {
result = 0f;
} else {
result = Double.parseDouble(list.get(0).get("result").toString()); result = Double.parseDouble(list.get(0).get("result").toString());
}
} else { } else {
String exprStr = target.getResultSql(); String exprStr = target.getResultSql();
String[] expressionList = exprStr.split(","); String[] expressionList = exprStr.split(",");

View File

@ -13,6 +13,8 @@ import net.objecthunter.exp4j.ExpressionBuilder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -86,7 +88,7 @@ public class UtilServiceImpl implements UtilService {
if (calendar.get(Calendar.WEEK_OF_YEAR) == 1) { if (calendar.get(Calendar.WEEK_OF_YEAR) == 1) {
calendar.add(Calendar.YEAR, 1); calendar.add(Calendar.YEAR, 1);
} }
xShow = calendar.get(Calendar.YEAR) + "-" + String.format("%02d", calendar.get(Calendar.WEEK_OF_YEAR)); xShow = getYearWeek(LocalDate.parse(setDate));
showCycle = "week"; showCycle = "week";
break; break;
case "month": case "month":
@ -147,6 +149,21 @@ public class UtilServiceImpl implements UtilService {
return new String[]{xShow, showCycle, setDate, start, end}; return new String[]{xShow, showCycle, setDate, start, end};
} }
@Override
public String getYearWeek(LocalDate date) {
WeekFields wf = WeekFields.ISO;
int weekNumber = date.get(wf.weekOfYear());
int year = date.getYear();
if (date.getMonthValue() == 12 && weekNumber == 1) {
year = year + 1;
}
String weekStr = String.format("%02d", weekNumber);
return year + "-" + weekStr;
}
@Override @Override
public double getEvalResult(String expression) { public double getEvalResult(String expression) {