rsf-admin/.env
@@ -1,3 +1,3 @@ VITE_BASE_IP=192.168.4.151 VITE_BASE_IP=127.0.0.1 # VITE_BASE_IP=47.76.147.249 VITE_BASE_PORT=8080 rsf-server/src/main/Test/ChineseMD5Util.java
@@ -1,38 +1,68 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.time.LocalDate; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; public class ChineseMD5Util { public static List<Integer> getSelectedIndices(int[] arr) { List<Integer> indices = new ArrayList<>(); int index = 0; int step = 3; while (index < arr.length) { indices.add(index); index += step; step = (step == 3) ? 1 : 3; } return indices; } // public static List<Integer> getSelectedIndices(int[] arr) { // List<Integer> indices = new ArrayList<>(); // int index = 0; // int step = 3; // while (index < arr.length) { // indices.add(index); // index += step; // step = (step == 3) ? 1 : 3; // } // return indices; // } // // public static Integer getNextSelectedValue(int[] arr, int inputIndex) { // List<Integer> selectedIndices = getSelectedIndices(arr); // int currentPos = selectedIndices.indexOf(inputIndex); // if (currentPos != -1 && currentPos + 1 < selectedIndices.size()) { // return arr[selectedIndices.get(currentPos + 1)]; // } // return null; // 或按需处理 // } // // public static void main(String[] args) { // int[] arr = {2, 5, 8, 10, 15, 20, 25, 30, 35, 40, 45, 50, 15, 40, 32, 48}; // System.out.println("输入 0,输出: " + getNextSelectedValue(arr, 0)); // 10 // System.out.println("输入 3,输出: " + getNextSelectedValue(arr, 3)); // 15 // System.out.println("输入 4,输出: " + getNextSelectedValue(arr, 4)); // 30 // System.out.println("输入 4,输出: " + getNextSelectedValue(arr, 5)); // 30 // // } public static Integer getNextSelectedValue(int[] arr, int inputIndex) { List<Integer> selectedIndices = getSelectedIndices(arr); int currentPos = selectedIndices.indexOf(inputIndex); if (currentPos != -1 && currentPos + 1 < selectedIndices.size()) { return arr[selectedIndices.get(currentPos + 1)]; } return null; // 或按需处理 public static List<String> getFormattedDatesOfPreviousMonth(String pattern) { // DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); // YearMonth previousMonth = YearMonth.now().minusMonths(1); // // return IntStream.rangeClosed(1, previousMonth.lengthOfMonth()) // .mapToObj(day -> previousMonth.atDay(day).format(formatter)) // .collect(Collectors.toList()); LocalDate today = LocalDate.now().minusDays(1); LocalDate oneMonthAgo = today.minusMonths(1); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); return IntStream.iterate(0, i -> i + 1) .limit(ChronoUnit.DAYS.between(oneMonthAgo, today) + 1) .mapToObj(oneMonthAgo::plusDays) .map(date -> date.format(formatter)) .collect(Collectors.toList()); } public static void main(String[] args) { int[] arr = {2, 5, 8, 10, 15, 20, 25, 30, 35, 40, 45, 50, 15, 40, 32, 48}; System.out.println("输入 0,输出: " + getNextSelectedValue(arr, 0)); // 10 System.out.println("输入 3,输出: " + getNextSelectedValue(arr, 3)); // 15 System.out.println("输入 4,输出: " + getNextSelectedValue(arr, 4)); // 30 System.out.println("输入 4,输出: " + getNextSelectedValue(arr, 5)); // 30 List<String> formattedDates = getFormattedDatesOfPreviousMonth("yyyy-MM-dd"); formattedDates.forEach(System.out::println); } } rsf-server/src/main/java/com/vincent/rsf/server/common/utils/DateUtils.java
@@ -6,7 +6,10 @@ import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * 日期时间工具类 @@ -232,6 +235,23 @@ } /** * 获取前30天所有日期 * @param pattern * @return */ public static List<String> getLastMonthDays(String pattern) { LocalDate today = LocalDate.now().minusDays(1); LocalDate oneMonthAgo = today.minusMonths(1); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); return IntStream.iterate(0, i -> i + 1) .limit(ChronoUnit.DAYS.between(oneMonthAgo, today) + 1) .mapToObj(oneMonthAgo::plusDays) .map(date -> date.format(formatter)) .collect(Collectors.toList()); } /** * 日期型字符串转化为日期 格式 * { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", * "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WkOrderController.java
@@ -60,6 +60,21 @@ return R.ok().add(asnOrderService.page(pageParam, queryWrapper)); } @ApiOperation("获取首页表头数据") @PostMapping("/asnOrder/dashbord/header") @PreAuthorize("hasAuthority('manager:asnOrder:list')") public R getDashbord() { return R.ok().add(asnOrderService.getDashbord()); } @ApiOperation("获取出入库趋势图") @PostMapping("/asnOrder/stock/trand") @PreAuthorize("hasAuthority('manager:asnOrder:list')") public R getStockTrand() { return R.ok().add(asnOrderService.getStockTrand()); } @PreAuthorize("hasAuthority('manager:asnOrder:list')") @PostMapping("/asnOrder/list") public R list(@RequestBody Map<String, Object> map) { rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/dto/DashboardDto.java
New file @@ -0,0 +1,39 @@ package com.vincent.rsf.server.manager.controller.dto; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModel; import lombok.experimental.Accessors; import lombok.Data; @Data @Accessors(chain = true) @ApiModel(value = "DashboardDto", description = "首页表头数据") public class DashboardDto { @ApiModelProperty("待入库数量") private Integer inAnf; @ApiModelProperty("待出库数量") private Integer outAnf; @ApiModelProperty("实际入库数量") private Integer taskIn; @ApiModelProperty("实际出库数量") private Integer taskOut; @ApiModelProperty("总入库数量") private Integer totalIn; @ApiModelProperty("总出库数量") private Integer totalOut; @ApiModelProperty("任务执行数量") private Integer taskQty; private Integer anfme; private Integer realAnfme; } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/dto/StockTrandDto.java
New file @@ -0,0 +1,24 @@ package com.vincent.rsf.server.manager.controller.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.experimental.Accessors; import lombok.Data; import java.util.List; @Data @Accessors(chain = true) @ApiModel(value = "StockTrandDto", description = "出入库趋势图") public class StockTrandDto { List<StockTransItemDto> trandItem; @ApiModelProperty("最大次数") Integer maxQty; @ApiModelProperty("最大数量") Integer maxAnfme; } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/dto/StockTransItemDto.java
New file @@ -0,0 +1,34 @@ package com.vincent.rsf.server.manager.controller.dto; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModel; import lombok.experimental.Accessors; import lombok.Data; import java.io.Serializable; import java.util.Date; @Data @Accessors(chain = true) @ApiModel(value = "StockTransItemDto", description = "库存趋势图") public class StockTransItemDto implements Serializable { @ApiModelProperty("入库数量") private Integer inAnfme; @ApiModelProperty("出库数量") private Integer outAnfme; @ApiModelProperty("单据时间") private String orderTime; @ApiModelProperty("入库数量") private Integer inQty; @ApiModelProperty("出库数量") private Integer outQty; @ApiModelProperty("任务类型") private Integer taskType; } rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/AsnOrderMapper.java
@@ -1,12 +1,23 @@ package com.vincent.rsf.server.manager.mapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Constants; import com.vincent.rsf.server.manager.controller.dto.DashboardDto; import com.vincent.rsf.server.manager.controller.dto.StockTransItemDto; import com.vincent.rsf.server.manager.entity.StockStatistic; import com.vincent.rsf.server.manager.entity.WkOrder; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; @Mapper @Repository public interface AsnOrderMapper extends BaseMapper<WkOrder> { DashboardDto getDashbord(@Param("type") String type, @Param("taskType") String taskType); List<StockTransItemDto> getStockTrand(@Param(Constants.WRAPPER) LambdaQueryWrapper<StockStatistic> queryWrapper); } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/AsnOrderService.java
@@ -28,4 +28,8 @@ R createByPo(Map<String, Object> params); R removeOrders(List<Long> list); R getDashbord(); R getStockTrand(); } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java
@@ -9,11 +9,14 @@ import com.vincent.rsf.server.api.entity.dto.PoItemsDto; import com.vincent.rsf.server.api.service.ReceiveMsgService; import com.vincent.rsf.server.api.service.ReportMsgService; import com.vincent.rsf.server.common.utils.DateUtils; import com.vincent.rsf.server.manager.controller.dto.DashboardDto; import com.vincent.rsf.server.manager.controller.dto.StockTrandDto; import com.vincent.rsf.server.manager.controller.dto.StockTransItemDto; import com.vincent.rsf.server.manager.controller.params.AsnOrderAndItemsParams; import com.vincent.rsf.server.manager.controller.params.BatchUpdateParam; import com.vincent.rsf.server.manager.entity.*; import com.vincent.rsf.server.manager.enums.AsnExceStatus; import com.vincent.rsf.server.manager.enums.POExceStatus; import com.vincent.rsf.server.manager.enums.*; import com.vincent.rsf.server.manager.mapper.AsnOrderMapper; import com.vincent.rsf.server.manager.service.*; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -27,6 +30,9 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.text.DateFormat; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @@ -59,6 +65,10 @@ private PurchaseService purchaseService; @Autowired private PurchaseItemService purchaseItemService; @Autowired private AsnOrderService asnOrderService; @Autowired private TaskService taskService; @Override public boolean notifyInspect(List<WkOrder> orders) { @@ -392,7 +402,6 @@ throw new CoolException("任务中单据不可删除!!"); } if (!asnOrderItemService.remove(new LambdaQueryWrapper<WkOrderItem>() .in(WkOrderItem::getOrderId, ids))) { // throw new CoolException("Details Delete Fail"); @@ -402,6 +411,65 @@ } /** * 获取首页表头数据 * @return */ @Override public R getDashbord() { DashboardDto dto = new DashboardDto(); //获取入库数量 DashboardDto trandDto = this.baseMapper.getDashbord(OrderType.ORDER_IN.type, TaskType.TASK_TYPE_IN.type + ""); dto.setInAnf(trandDto.getAnfme()).setTaskIn(trandDto.getRealAnfme()).setTotalIn(trandDto.getAnfme() + trandDto.getRealAnfme()); //获取出库单数量 DashboardDto outTrand = this.baseMapper.getDashbord(OrderType.ORDER_OUT.type, TaskType.TASK_TYPE_OUT.type + ""); dto.setOutAnf(outTrand.getAnfme()).setTaskOut(outTrand.getRealAnfme()).setTotalOut(outTrand.getAnfme() + outTrand.getRealAnfme()); //获取执行中任务数量 List<Task> tasks = taskService.list(new LambdaQueryWrapper<>()); if (!tasks.isEmpty()) { outTrand.setTaskQty(tasks.size()); } return R.ok().add(dto); } /** * 获取出入库趋势 * @return */ @Override public R getStockTrand() { List<String> days = DateUtils.getLastMonthDays("yyyy-MM-dd"); LambdaQueryWrapper<StockStatistic> queryWrapper = new LambdaQueryWrapper<StockStatistic>() .in(StockStatistic::getTaskType, Arrays.asList(TaskType.TASK_TYPE_IN.type, TaskType.TASK_TYPE_OUT.type)); List<StockTransItemDto> items = this.baseMapper.getStockTrand(queryWrapper); if (items.isEmpty()) { return R.ok(); } List<StockTransItemDto> stockDtos = new ArrayList<>(); days.forEach(day -> { StockTransItemDto itemDto = new StockTransItemDto(); itemDto.setInQty(0).setOutQty(0).setOutAnfme(0).setOutAnfme(0); items.forEach(item -> { if (item.getOrderTime().equals(day)) { BeanUtils.copyProperties(item, itemDto); } }); itemDto.setOrderTime(day); stockDtos.add(itemDto); }); //获取最大值 Optional<Integer> max = stockDtos.stream().map(StockTransItemDto::getInQty).filter(Objects::nonNull).max(Comparator.naturalOrder()); Optional<Integer> maxOut = stockDtos.stream().map(StockTransItemDto::getOutQty).filter(Objects::nonNull).max(Comparator.naturalOrder()); int maxed = Math.max(max.orElse(Integer.MIN_VALUE), maxOut.orElse(Integer.MIN_VALUE)); StockTrandDto trandDto = new StockTrandDto(); trandDto.setMaxQty(maxed).setTrandItem(stockDtos); return R.ok().add(trandDto); } /** * @param * @return * @author Ryan rsf-server/src/main/resources/mapper/manager/AsnOrderMapper.xml
@@ -1,5 +1,36 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.vincent.rsf.server.manager.mapper.AsnOrderMapper"> <select id="getDashbord" resultType="com.vincent.rsf.server.manager.controller.dto.DashboardDto"> SELECT ( SELECT COUNT( 1 ) FROM man_asn_order WHERE DATE(create_time) = CURRENT_DATE() AND `type` = #{type} ) AS anfme, COUNT( id ) AS real_anfme FROM man_task_log WHERE DATE(create_time) = CURRENT_DATE() AND task_type = #{taskType} </select> <select id="getStockTrand" resultType="com.vincent.rsf.server.manager.controller.dto.StockTransItemDto"> SELECT * FROM ( SELECT id, IF ( task_type = 1, COUNT( 1 ), 0 ) AS in_qty, IF ( task_type = 1, SUM( anfme ), 0 ) AS in_anfme, IF ( task_type = 101, SUM( anfme ), 0 ) AS out_anfme, IF ( task_type = 101, COUNT( 1 ), 0 ) AS out_qty, task_type, day_time AS order_time FROM view_stock_statistic WHERE `day_time` BETWEEN ( CURDATE() - INTERVAL 1 MONTH ) AND CURDATE() GROUP BY `day_time`, task_type ) t ${ew.customSqlSegment} </select> </mapper>