首页接口重构
This commit is contained in:
@@ -1,188 +1,29 @@
|
|||||||
package com.zg.project.wisdom.controller;
|
package com.zg.project.wisdom.controller;
|
||||||
|
|
||||||
import com.zg.framework.web.domain.AjaxResult;
|
import com.zg.framework.web.domain.AjaxResult;
|
||||||
import com.zg.project.wisdom.domain.dto.RkInfoQueryDTO;
|
import com.zg.project.wisdom.domain.dto.HomeStatQueryDTO;
|
||||||
import com.zg.project.wisdom.domain.vo.*;
|
|
||||||
import com.zg.project.wisdom.service.RkStatisticsService;
|
import com.zg.project.wisdom.service.RkStatisticsService;
|
||||||
import com.zg.project.wisdom.service.WarehouseStatService;
|
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Api(tags = "库存统计")
|
@Api(tags = "库存统计")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/stat")
|
@RequestMapping("/stat")
|
||||||
public class RkStatisticsController {
|
public class RkStatisticsController {
|
||||||
|
|
||||||
@Resource
|
@Autowired
|
||||||
private RkStatisticsService rkStatisticsService;
|
private RkStatisticsService rkStatisticsService;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private WarehouseStatService warehouseStatService;
|
|
||||||
|
|
||||||
|
|
||||||
/** 库龄统计(未出库:>10 / >20 / >30 天),value 为项目数(按 xm_no 去重) */
|
|
||||||
@ApiOperation("库龄统计(未出库:>10 / >20 / >30 天)")
|
|
||||||
@GetMapping("/age")
|
|
||||||
public AjaxResult ageStats() {
|
|
||||||
List<Map<String, Object>> stats = rkStatisticsService.getAgeStatsAsList();
|
|
||||||
return AjaxResult.success(stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 仓库-场景库位使用统计(总仓库数、每仓库场景数、每场景库位/使用率/空闲率)
|
* 首页统计(一次返回所有模块)
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
@GetMapping("/warehouseScene")
|
@ApiOperation("首页统计")
|
||||||
public AjaxResult warehouseScene() {
|
@PostMapping("/home")
|
||||||
WarehouseSceneStatsResp resp = warehouseStatService.getWarehouseSceneStats();
|
public AjaxResult home(@RequestBody(required = false) HomeStatQueryDTO query) {
|
||||||
return AjaxResult.success(resp);
|
return AjaxResult.success(rkStatisticsService.getHomeStatistics(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 按仓库查询:场景列表 + 每个场景的可用库位明细
|
|
||||||
* 示例:GET /warehouse/positions/available?warehouseCode=CK001
|
|
||||||
*/
|
|
||||||
@ApiOperation("按仓库查询各场景的可用库位(排除未出库占用)")
|
|
||||||
@GetMapping("/warehouse/available")
|
|
||||||
public AjaxResult listAvailableByWarehouse(@RequestParam String warehouseCode) {
|
|
||||||
List<SceneAvailableVO> data = rkStatisticsService.listAvailableByWarehouse(warehouseCode);
|
|
||||||
return AjaxResult.success(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前库存根据入库类型统计项目数,每个项目的条目数,实际入库总数,金额总和(仅未出库)
|
|
||||||
*/
|
|
||||||
@GetMapping("/type/summary")
|
|
||||||
public AjaxResult typeSummary() {
|
|
||||||
List<RkSummaryVO> list = rkStatisticsService.getTypeSummary();
|
|
||||||
return AjaxResult.success(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 县局汇总(仅未出库,county 非空)
|
|
||||||
*/
|
|
||||||
@GetMapping("/county/summary")
|
|
||||||
public AjaxResult countySummary() {
|
|
||||||
List<RkSummaryVO> list = rkStatisticsService.getCountySummary();
|
|
||||||
return AjaxResult.success(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一个接口:一周天级统计(返回入库+出库)根据供电中心统计
|
|
||||||
* - 如果 start/end 都传了,就用传入值;
|
|
||||||
* - 否则:end=今天,start=本周周一;
|
|
||||||
*/
|
|
||||||
@ApiOperation("一周天级统计(入库+出库合并返回)")
|
|
||||||
@GetMapping("/week/daily")
|
|
||||||
public AjaxResult weekDaily(@RequestParam(required = false) String start,
|
|
||||||
@RequestParam(required = false) String end) {
|
|
||||||
Map<String, Object> data = rkStatisticsService.weekDaily(start, end);
|
|
||||||
return AjaxResult.success(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 库龄统计(>30天 & >60天):项目数、条目数、总金额 + 明细列表
|
|
||||||
*/
|
|
||||||
@ApiOperation("库龄统计:>30天 & >60天(含汇总与明细)")
|
|
||||||
@GetMapping("/age/count")
|
|
||||||
public AjaxResult age3060() {
|
|
||||||
List<Map<String, Object>> data = rkStatisticsService.getAge3060();
|
|
||||||
return AjaxResult.success(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("导出库龄明细(>30天与>60天,合并导出)")
|
|
||||||
@PostMapping("/age/export")
|
|
||||||
public void exportAge3060(HttpServletResponse response) {
|
|
||||||
rkStatisticsService.exportAge3060(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 入库类型饼图数据接口
|
|
||||||
* 返回每个入库类型的项目数、条目数、总数量、总金额
|
|
||||||
*/
|
|
||||||
@ApiOperation("入库类型饼图数据")
|
|
||||||
@GetMapping("/type/pie")
|
|
||||||
public AjaxResult typePie() {
|
|
||||||
List<RkTypePieVO> list = rkStatisticsService.getTypePie();
|
|
||||||
return AjaxResult.success(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按入库类型统计(带时间范围)
|
|
||||||
* 统计维度:项目数、条目数、总数量、总金额
|
|
||||||
* 时间字段:rk_time(自然日闭区间 [start, end])
|
|
||||||
* 参数格式:推荐 yyyy-MM-dd(如 2025-01-01)
|
|
||||||
*/
|
|
||||||
@ApiOperation("按入库类型统计(带时间范围:项目数/条目数/总数量/总金额)")
|
|
||||||
@GetMapping("/type/range")
|
|
||||||
public AjaxResult typeSummaryRange(@RequestParam(required = false) String start,
|
|
||||||
@RequestParam(required = false) String end) {
|
|
||||||
List<RkTypePieVO> list = rkStatisticsService.getTypeSummaryByRange(start, end);
|
|
||||||
return AjaxResult.success(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("按出库类型统计(带时间范围:项目数/条目数/总数量/总金额)")
|
|
||||||
@GetMapping("/type/out/range")
|
|
||||||
public AjaxResult outTypeSummaryRange(@RequestParam(required = false) String start,
|
|
||||||
@RequestParam(required = false) String end) {
|
|
||||||
List<RkTypePieVO> list = rkStatisticsService.getOutTypeSummaryByRange(start, end);
|
|
||||||
return AjaxResult.success(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation("本月出入库汇总(项目数/条目数/总数量/总金额)")
|
|
||||||
@GetMapping("/month/summary")
|
|
||||||
public AjaxResult monthSummary() {
|
|
||||||
RkMonthInOutSummaryVO vo = rkStatisticsService.getThisMonthInOutSummary();
|
|
||||||
return AjaxResult.success(vo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("应到未到统计(未到/部分未到)")
|
|
||||||
@GetMapping("/undelivered")
|
|
||||||
public AjaxResult undelivered() {
|
|
||||||
GysJhUndeliveredVO vo = rkStatisticsService.getUndeliveredSummary();
|
|
||||||
return AjaxResult.success(vo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("当前库存按物资类型统计(项目数/条目数/总数量/总金额)")
|
|
||||||
@GetMapping("/stock/wlType")
|
|
||||||
public AjaxResult stockByWlType() {
|
|
||||||
List<WlTypeStockStatVO> list = rkStatisticsService.getCurrentStockByWlType();
|
|
||||||
return AjaxResult.success(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前库存:入库时间 >30天(项目数 / 条目数 / 总数量 / 总金额)
|
|
||||||
* 口径:仅统计未删除、未出库(is_chuku=0 或 NULL)、rk_time 非空且 DATEDIFF(CURDATE(), DATE(rk_time)) > 30 的记录
|
|
||||||
*/
|
|
||||||
@ApiOperation("当前库存:入库时间>30天(项目数/条目数/总数量/总金额)")
|
|
||||||
@GetMapping("/age/gt30")
|
|
||||||
public AjaxResult ageGt30() {
|
|
||||||
RkTypePieVO vo = rkStatisticsService.getAgeGt30Summary();
|
|
||||||
return AjaxResult.success(vo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* range: 0=最近一周(7天, 按日);2=最近半年(6个月, 按月)
|
|
||||||
* 返回:每个时间桶一行(bucket, 入/出库项目数&条目数)
|
|
||||||
*/
|
|
||||||
@ApiOperation("出/入库项目数与条目数(按时间桶返回)")
|
|
||||||
@GetMapping("/io/buckets")
|
|
||||||
public AjaxResult ioBuckets(@RequestParam Integer range) {
|
|
||||||
List<IOBucketVO> rows = rkStatisticsService.getIOBuckets(range);
|
|
||||||
return AjaxResult.success(rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @PostMapping("/statistics")
|
|
||||||
// public Map<String, Object> statistics(@RequestBody RkInfoQueryDTO dto) {
|
|
||||||
// // 调用新的合并查询方法
|
|
||||||
// return rkStatisticsService.selectStockStatistics(dto);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.zg.project.wisdom.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HomeStatQueryDTO {
|
||||||
|
|
||||||
|
/** 开始时间(可空) */
|
||||||
|
private Date startDate;
|
||||||
|
|
||||||
|
/** 结束时间(可空) */
|
||||||
|
private Date endDate;
|
||||||
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/** 最终返回结构(汇总 + 明细) */
|
|
||||||
@Data
|
|
||||||
public class Age3060ResultVO {
|
|
||||||
/** >30 天的汇总 */
|
|
||||||
private AgeSummaryVO.Slot gt30;
|
|
||||||
/** >60 天的汇总 */
|
|
||||||
private AgeSummaryVO.Slot gt60;
|
|
||||||
/** >30 天明细 */
|
|
||||||
private List<RkAgeDetailVO> gt30List;
|
|
||||||
/** >60 天明细 */
|
|
||||||
private List<RkAgeDetailVO> gt60List;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/** 汇总 VO(包含两个 Slot:gt30 / gt60) */
|
|
||||||
@Data
|
|
||||||
public class AgeSummaryVO {
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class Slot {
|
|
||||||
/** 仅用于 resultMap 绑定(无业务含义) */
|
|
||||||
private Integer dummyId;
|
|
||||||
/** 项目数(DISTINCT xm_no) */
|
|
||||||
private Integer projectCount;
|
|
||||||
/** 条目数(COUNT(*)) */
|
|
||||||
private Integer goodsCount;
|
|
||||||
/** 总金额(SUM(ht_dj * real_qty)) */
|
|
||||||
private BigDecimal sumAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Slot gt30;
|
|
||||||
private Slot gt60;
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import com.zg.framework.aspectj.lang.annotation.Excel;
|
|
||||||
import com.zg.project.wisdom.domain.AuditSignature;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 审核记录封装VO(包含一条审核记录 + 多张现场照片)
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class AuditSignatureReviewVO {
|
|
||||||
|
|
||||||
/** 主键ID(审核记录的ID) */
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/** 单据编号 */
|
|
||||||
private String billNo;
|
|
||||||
|
|
||||||
/** 入库记录ID(对应rk_info.id) */
|
|
||||||
private Long rkId;
|
|
||||||
|
|
||||||
/** 单据类型(0入库,1出库) */
|
|
||||||
private String billType;
|
|
||||||
|
|
||||||
/** 审核人ID */
|
|
||||||
private String approverId;
|
|
||||||
|
|
||||||
/** 审核人签字图片URL(签字图) */
|
|
||||||
private String approverSignUrl;
|
|
||||||
|
|
||||||
/** 审核结果(0通过,1驳回) */
|
|
||||||
private String auditResult;
|
|
||||||
|
|
||||||
/** 是否当前记录(1是,0否) */
|
|
||||||
private String isCurrent;
|
|
||||||
|
|
||||||
private String ckType;
|
|
||||||
|
|
||||||
private String ckTypeName;
|
|
||||||
|
|
||||||
private String teamCode;
|
|
||||||
|
|
||||||
private String teamName;
|
|
||||||
|
|
||||||
/** 审核时间 */
|
|
||||||
private Date signTime;
|
|
||||||
|
|
||||||
/** 审核备注 */
|
|
||||||
private String remark;
|
|
||||||
|
|
||||||
/** 创建人 */
|
|
||||||
private String createBy;
|
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
private Date createTime;
|
|
||||||
|
|
||||||
/** 更新人 */
|
|
||||||
private String updateBy;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
private Date updateTime;
|
|
||||||
|
|
||||||
/** 逻辑删除标记(0正常,1删除) */
|
|
||||||
private String isDelete;
|
|
||||||
|
|
||||||
/** 携带入库信息的现场图片列表 */
|
|
||||||
private List<AuditSignatureVo> scenePhotos;
|
|
||||||
|
|
||||||
/** 入库类型名称(中文) */
|
|
||||||
private String rkTypeName;
|
|
||||||
|
|
||||||
/** 所属仓库名称(中文) */
|
|
||||||
private String cangkuName;
|
|
||||||
|
|
||||||
/** 物资类型名称(中文) */
|
|
||||||
private String wlTypeName;
|
|
||||||
|
|
||||||
/** 理货员名称(原本就是中文) */
|
|
||||||
private String lihuoY;
|
|
||||||
|
|
||||||
/** 理货员名称(联查显示用,导出专用) */
|
|
||||||
private String lihuoYName;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/** 周天级统计(按县局) */
|
|
||||||
@Data
|
|
||||||
public class DayCountyStatVO {
|
|
||||||
/**
|
|
||||||
* 日期(如果 SQL 未分日统计,该字段可能为 null)
|
|
||||||
* 示例:2025-08-19
|
|
||||||
*/
|
|
||||||
private String day;
|
|
||||||
|
|
||||||
/** 县局(若为空或空串会被归类为“未知县局”) */
|
|
||||||
private String xj;
|
|
||||||
|
|
||||||
/** 项目数(去重 xm_no 计数) */
|
|
||||||
private Integer projectCount;
|
|
||||||
|
|
||||||
/** 条目数(明细记录总数,COUNT(*)) */
|
|
||||||
private Integer itemCount;
|
|
||||||
|
|
||||||
/** 数量总和(SUM(real_qty)) */
|
|
||||||
private Long totalQty;
|
|
||||||
|
|
||||||
/** 合同金额总和(SUM(ht_dj * real_qty)) */
|
|
||||||
private BigDecimal amountHt;
|
|
||||||
|
|
||||||
/** 计划金额总和(仅入库时有值,出库恒为 0) */
|
|
||||||
private BigDecimal amountPlan;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import com.zg.project.wisdom.domain.RkInfo;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 待配送出库单据 VO(1 对多:一个出库单据 + 多条货物明细)
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class DeliveryBillVO implements Serializable {
|
|
||||||
|
|
||||||
/** 出库单据号(rk_info.bill_no_ck) */
|
|
||||||
private String billNoCk;
|
|
||||||
|
|
||||||
/** 领货人(出库理货员) */
|
|
||||||
private String ckLihuoY;
|
|
||||||
|
|
||||||
/** 施工队/出库班组 */
|
|
||||||
private String teamCode;
|
|
||||||
|
|
||||||
/** 领用时间(出库时间) */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Date lyTime;
|
|
||||||
|
|
||||||
/** 该出库单据下的所有货物明细 */
|
|
||||||
private List<RkInfo> detailList;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// com.zg.project.wisdom.domain.vo.GysJhUndeliveredVO
|
|
||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/** 返回体:未到 + 部分未到 + 合计 */
|
|
||||||
@Data
|
|
||||||
public class GysJhUndeliveredVO {
|
|
||||||
/** 未到货(status='0') */
|
|
||||||
private GysJhUndeliveredSummaryVO undelivered;
|
|
||||||
/** 部分未到货(status='2') */
|
|
||||||
private GysJhUndeliveredSummaryVO partialUndelivered;
|
|
||||||
}
|
|
||||||
30
src/main/java/com/zg/project/wisdom/domain/vo/HomeKpiVO.java
Normal file
30
src/main/java/com/zg/project/wisdom/domain/vo/HomeKpiVO.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package com.zg.project.wisdom.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页顶部 KPI 统计
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class HomeKpiVO {
|
||||||
|
|
||||||
|
/** 月入库条数 */
|
||||||
|
private Integer monthInCount;
|
||||||
|
|
||||||
|
/** 月入库项目数 */
|
||||||
|
private Integer monthInProjectCount;
|
||||||
|
|
||||||
|
/** 月入库金额 */
|
||||||
|
private BigDecimal monthInAmount;
|
||||||
|
|
||||||
|
/** 月出库条数 */
|
||||||
|
private Integer monthOutCount;
|
||||||
|
|
||||||
|
/** 月出库项目数 */
|
||||||
|
private Integer monthOutProjectCount;
|
||||||
|
|
||||||
|
/** 月出库金额 */
|
||||||
|
private BigDecimal monthOutAmount;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.zg.project.wisdom.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页统计返回 VO(最终版)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class HomeStatVO {
|
||||||
|
|
||||||
|
/** 顶部 KPI */
|
||||||
|
private HomeKpiVO kpi;
|
||||||
|
|
||||||
|
/** 当前入库类型统计 */
|
||||||
|
private List<StockStatisticGroupVO> currentInType;
|
||||||
|
|
||||||
|
/** 物资类型统计 */
|
||||||
|
private List<StockStatisticGroupVO> materialType;
|
||||||
|
|
||||||
|
/** 入库类型统计(时间) */
|
||||||
|
private List<StockStatisticGroupVO> inTypeByTime;
|
||||||
|
|
||||||
|
/** 出库类型统计(时间) */
|
||||||
|
private List<StockStatisticGroupVO> outTypeByTime;
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 出/入库统计结果 VO
|
|
||||||
* 每个时间桶(按日/按月)一行
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class IOBucketVO {
|
|
||||||
|
|
||||||
/** 时间桶:
|
|
||||||
* range=0(最近一周):返回 MM-dd;
|
|
||||||
* range=2(最近半年):返回 yyyy-MM
|
|
||||||
*/
|
|
||||||
private String bucket;
|
|
||||||
|
|
||||||
/** 入库项目数 */
|
|
||||||
private Integer inProjectCount;
|
|
||||||
/** 入库条目数 */
|
|
||||||
private Integer inItemCount;
|
|
||||||
/** 出库项目数 */
|
|
||||||
private Integer outProjectCount;
|
|
||||||
/** 出库条目数 */
|
|
||||||
private Integer outItemCount;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
// vo/PcodeQtyVO.java
|
|
||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class PcodeQtyVO {
|
|
||||||
/** 库位码 */
|
|
||||||
private String pcode;
|
|
||||||
|
|
||||||
/** 在库总数量(real_qty 之和) */
|
|
||||||
private BigDecimal totalQty;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import com.zg.framework.aspectj.lang.annotation.Excel;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class RkAgeDetailVO {
|
|
||||||
/* ---------- 仅用于导出分组显示,不落库 ---------- */
|
|
||||||
@Excel(name = "库龄分组") // “>30天”/“>60天”
|
|
||||||
private String ageBucket;
|
|
||||||
|
|
||||||
@Excel(name = "ID")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/** 项目号 / 项目描述 */
|
|
||||||
@Excel(name = "项目号")
|
|
||||||
private String xmNo;
|
|
||||||
|
|
||||||
@Excel(name = "项目描述")
|
|
||||||
private String xmMs;
|
|
||||||
|
|
||||||
/** 入库时间 & 库龄天数 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
|
||||||
@Excel(name = "入库时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Date rkTime;
|
|
||||||
|
|
||||||
@Excel(name = "库龄(天)")
|
|
||||||
private Integer kuLingDays;
|
|
||||||
|
|
||||||
/** 单价、数量、行金额 */
|
|
||||||
@Excel(name = "单价")
|
|
||||||
private BigDecimal htDj;
|
|
||||||
|
|
||||||
@Excel(name = "数量")
|
|
||||||
private BigDecimal realQty;
|
|
||||||
|
|
||||||
@Excel(name = "行金额")
|
|
||||||
private BigDecimal amount;
|
|
||||||
|
|
||||||
/** 库位 / 托盘 / 单据号(便于追踪) */
|
|
||||||
@Excel(name = "库位")
|
|
||||||
private String pcode;
|
|
||||||
|
|
||||||
@Excel(name = "托盘")
|
|
||||||
private String trayCode;
|
|
||||||
|
|
||||||
@Excel(name = "单据号")
|
|
||||||
private String billNo;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// com/zg/project/wisdom/vo/stat/RkAgeStatVO.java
|
|
||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import io.swagger.annotations.ApiModel;
|
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@ApiModel(value = "RkAgeStatVO", description = "库龄统计结果(仅未出库)")
|
|
||||||
public class RkAgeStatVO {
|
|
||||||
|
|
||||||
@ApiModelProperty("大于10天的数量")
|
|
||||||
private Integer gt10;
|
|
||||||
|
|
||||||
@ApiModelProperty("大于20天的数量")
|
|
||||||
private Integer gt20;
|
|
||||||
|
|
||||||
@ApiModelProperty("大于30天的数量")
|
|
||||||
private Integer gt30;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import com.zg.framework.aspectj.lang.annotation.Excel;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 出入库统计明细 VO
|
|
||||||
* 仅用于查询与展示,不参与落库
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class RkCkStatisticVO implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/** 操作类型:入库 / 出库 */
|
|
||||||
@Excel(name = "操作类型")
|
|
||||||
private String operationType;
|
|
||||||
|
|
||||||
/** 详细类型:入库类型名 / 出库类型名 */
|
|
||||||
@Excel(name = "详细类型")
|
|
||||||
private String detailType;
|
|
||||||
|
|
||||||
/** 库存状态(在库 / 已出库 / 借料等) */
|
|
||||||
@Excel(name = "库存状态")
|
|
||||||
private String stockStatus;
|
|
||||||
|
|
||||||
/** 单据号(入库单号或出库单号) */
|
|
||||||
@Excel(name = "单据号")
|
|
||||||
private String billNo;
|
|
||||||
|
|
||||||
/** 物料号 */
|
|
||||||
@Excel(name = "物料号")
|
|
||||||
private String materialCode;
|
|
||||||
|
|
||||||
/** 物料描述 */
|
|
||||||
@Excel(name = "物料描述")
|
|
||||||
private String materialName;
|
|
||||||
|
|
||||||
/** 单位 */
|
|
||||||
@Excel(name = "单位")
|
|
||||||
private String unit;
|
|
||||||
|
|
||||||
/** 数量(实际数量) */
|
|
||||||
@Excel(name = "数量")
|
|
||||||
private BigDecimal quantity;
|
|
||||||
|
|
||||||
/** 项目号 */
|
|
||||||
@Excel(name = "项目号")
|
|
||||||
private String projectCode;
|
|
||||||
|
|
||||||
/** 项目描述 */
|
|
||||||
@Excel(name = "项目描述")
|
|
||||||
private String projectName;
|
|
||||||
|
|
||||||
/** 库位码 */
|
|
||||||
@Excel(name = "库位码")
|
|
||||||
private String locationCode;
|
|
||||||
|
|
||||||
/** 订单编号(SAP 订单号) */
|
|
||||||
@Excel(name = "订单编号")
|
|
||||||
private String orderNo;
|
|
||||||
|
|
||||||
/** 供应商名称 */
|
|
||||||
@Excel(name = "供应商名称")
|
|
||||||
private String supplierName;
|
|
||||||
|
|
||||||
/** 备注 */
|
|
||||||
@Excel(name = "备注")
|
|
||||||
private String remark;
|
|
||||||
|
|
||||||
/** 入库时间(用户操作入库的日期) */
|
|
||||||
@Excel(name = "操作时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Date operationTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/** 入库原始数据(用于代码侧分桶) */
|
|
||||||
@Data
|
|
||||||
public class RkInVO {
|
|
||||||
private String xmNo;
|
|
||||||
private LocalDateTime rkTime;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/** 月度入/出库两段结果 */
|
|
||||||
@Data
|
|
||||||
public class RkMonthInOutSummaryVO {
|
|
||||||
/** 入库汇总(rk_time) */
|
|
||||||
private RkMonthSummaryVO inSummary;
|
|
||||||
/** 出库汇总(ly_time, is_chuku=1) */
|
|
||||||
private RkMonthSummaryVO outSummary;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// com.zg.project.wisdom.domain.vo.RkMonthSummaryVO
|
|
||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/** 月度汇总(项目数/条目数/总数量/总金额) */
|
|
||||||
@Data
|
|
||||||
public class RkMonthSummaryVO {
|
|
||||||
/** 去重项目数(按 xm_no 去重) */
|
|
||||||
private Integer projectCount;
|
|
||||||
/** 条目数(明细行数) */
|
|
||||||
private Integer itemCount;
|
|
||||||
/** 总数量(real_qty 合计) */
|
|
||||||
private Long totalQty;
|
|
||||||
/** 总金额(ht_dj * real_qty 合计) */
|
|
||||||
private BigDecimal amountHt;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/** 出库原始数据(用于代码侧分桶) */
|
|
||||||
@Data
|
|
||||||
public class RkOutVO {
|
|
||||||
private String xmNoCk;
|
|
||||||
private String xmNo;
|
|
||||||
private LocalDateTime lyTime;
|
|
||||||
private LocalDateTime updateTime;
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 入库提交返回 VO
|
|
||||||
* 返回入库单据号、是否需要审核、及托盘信息
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class RkSubmitResultVO {
|
|
||||||
|
|
||||||
/** 单据号 */
|
|
||||||
private String billNo;
|
|
||||||
|
|
||||||
/** 是否需要审核流程 */
|
|
||||||
private boolean needAudit;
|
|
||||||
|
|
||||||
/** 所有库位码 */
|
|
||||||
private List<String> pcodeList;
|
|
||||||
|
|
||||||
/** 所有托盘码 */
|
|
||||||
private List<String> trayCodeList;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/** 县局维度汇总结果 */
|
|
||||||
@Data
|
|
||||||
public class RkSummaryVO {
|
|
||||||
|
|
||||||
/** 分组名称(如县局名、入库类型等) */
|
|
||||||
private String groupName;
|
|
||||||
|
|
||||||
/** 项目数(去重 xm_no) */
|
|
||||||
private Integer projectCount;
|
|
||||||
|
|
||||||
/** 条目总数(COUNT(*)) */
|
|
||||||
private Integer goodsCountTotal;
|
|
||||||
|
|
||||||
/** 总金额 = SUM(ht_dj * real_qty) */
|
|
||||||
private BigDecimal sumAmount;
|
|
||||||
|
|
||||||
/** 总数量 = SUM(real_qty) */
|
|
||||||
private BigDecimal sumQty;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 入库类型饼状图统计 VO
|
|
||||||
* 每个入库类型对应一条记录,用于前端饼状图展示
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class RkTypePieVO {
|
|
||||||
|
|
||||||
/** 入库类型编码(stock_in_type.type_code) */
|
|
||||||
private String rkTypeCode;
|
|
||||||
|
|
||||||
/** 入库类型名称(stock_in_type.type_name) */
|
|
||||||
private String rkTypeName;
|
|
||||||
|
|
||||||
/** 项目数量(去重 xm_no) */
|
|
||||||
private Integer projectCount;
|
|
||||||
|
|
||||||
/** 条目总数(COUNT(*)) */
|
|
||||||
private Integer goodsCountTotal;
|
|
||||||
|
|
||||||
/** 总数量(SUM real_qty) */
|
|
||||||
private BigDecimal sumQty;
|
|
||||||
|
|
||||||
/** 总金额(SUM ht_dj * real_qty) */
|
|
||||||
private BigDecimal sumAmount;
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 入库类型 + 项目 明细VO
|
|
||||||
* 用于统计每种入库类型下的每个项目:
|
|
||||||
* - 项目信息
|
|
||||||
* - 货物数量
|
|
||||||
* - 合同单价合计
|
|
||||||
* - 实际入库数量合计
|
|
||||||
* - 金额合计
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class RkTypeProjectDetailVO {
|
|
||||||
/** 入库类型(rk_type) */
|
|
||||||
private Integer rkType;
|
|
||||||
/** 项目号(xm_no) */
|
|
||||||
private String projectNo;
|
|
||||||
/** 项目名称/描述(xm_ms) */
|
|
||||||
private String projectName;
|
|
||||||
/** 该项目下的货物条数 */
|
|
||||||
private Integer goodsCount;
|
|
||||||
/** 合同单价合计 */
|
|
||||||
private BigDecimal sumHtDj;
|
|
||||||
/** 实际入库数量合计 */
|
|
||||||
private BigDecimal sumRealQty;
|
|
||||||
/** 金额合计 = ht_dj * real_qty */
|
|
||||||
private BigDecimal sumAmount;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 某入库类型下,单个项目的货物条目数
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class RkTypeProjectGoodsCountVO {
|
|
||||||
/** 入库类型(冗余用于归并) */
|
|
||||||
private Integer rkType;
|
|
||||||
|
|
||||||
/** 县局,类型统计时可为null */
|
|
||||||
private String county;
|
|
||||||
|
|
||||||
/** 项目号(xm_no) */
|
|
||||||
private String projectNo;
|
|
||||||
|
|
||||||
/** 项目名称/描述(xm_ms),取一个示例值 */
|
|
||||||
private String projectName;
|
|
||||||
|
|
||||||
/** 该项目的货物条目数(COUNT(*)) */
|
|
||||||
private Integer goodsCount;
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 入库类型汇总VO(仅统计未出库 is_chuku = 0)
|
|
||||||
* 每种入库类型下聚合:
|
|
||||||
* - projectCount:项目数量(去重xm_no)
|
|
||||||
* - goodsCountTotal:货物条目总数(记录条数)
|
|
||||||
* - sumHtDj:合同单价合计
|
|
||||||
* - sumRealQty:实际入库数量合计
|
|
||||||
* - sumAmount:金额合计 = ht_dj * real_qty
|
|
||||||
* - avgGoodsPerProject:每项目平均条目数 = goodsCountTotal / projectCount(保留2位小数)
|
|
||||||
* - projectGoodsCounts:每个项目的“条目数清单”(你要的关键补充)
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class RkTypeSummaryVO {
|
|
||||||
/** 入库类型(rk_type) */
|
|
||||||
private String rkType;
|
|
||||||
|
|
||||||
/** 县局,类型统计时可为null */
|
|
||||||
private String county;
|
|
||||||
|
|
||||||
/** 项目数量(去重xm_no) */
|
|
||||||
private Integer projectCount;
|
|
||||||
|
|
||||||
/** 货物条目总数(该类型下的记录条数) */
|
|
||||||
private Integer goodsCountTotal;
|
|
||||||
|
|
||||||
/** 合同单价合计 */
|
|
||||||
private BigDecimal sumHtDj;
|
|
||||||
|
|
||||||
/** 实际入库数量合计 */
|
|
||||||
private BigDecimal sumRealQty;
|
|
||||||
|
|
||||||
/** 金额合计 = ht_dj * real_qty */
|
|
||||||
private BigDecimal sumAmount;
|
|
||||||
|
|
||||||
/** 每个项目的条目数清单(仅含条目数;如需金额/数量可再扩展) */
|
|
||||||
private List<RkTypeProjectGoodsCountVO> projectGoodsCounts;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景下的可用库位
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class SceneAvailableVO {
|
|
||||||
/** 场景编码(pcde_detail.scene,对应 scene_mapping.scene_code) */
|
|
||||||
private String sceneCode;
|
|
||||||
/** 场景名称(scene_mapping.scene_name) */
|
|
||||||
private String sceneName;
|
|
||||||
/** 可用库位数量 */
|
|
||||||
private Integer availableCount;
|
|
||||||
/** 可用库位明细 */
|
|
||||||
private List<PcdeDetailSimpleVO> positions;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.zg.project.wisdom.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页分组统计 VO(通用)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class StockStatisticGroupVO {
|
||||||
|
|
||||||
|
/** 分组值(类型编码,如 operation_type / wl_type) */
|
||||||
|
private String groupValue;
|
||||||
|
|
||||||
|
/** 总金额 */
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
|
/** 使用库位数 */
|
||||||
|
private Integer locationCount;
|
||||||
|
|
||||||
|
/** 总数量 */
|
||||||
|
private BigDecimal totalQuantity;
|
||||||
|
|
||||||
|
/** 项目数(去重 xm_no) */
|
||||||
|
private Integer projectCount;
|
||||||
|
}
|
||||||
@@ -13,6 +13,9 @@ public class StockStatisticVO {
|
|||||||
/** 使用库位数量 */
|
/** 使用库位数量 */
|
||||||
private Integer locationCount;
|
private Integer locationCount;
|
||||||
|
|
||||||
/** 货物总数量 */
|
/** 库存总数量 */
|
||||||
private BigDecimal totalQuantity;
|
private BigDecimal totalQuantity;
|
||||||
|
|
||||||
|
/** 项目总数(去重 xm_no) */
|
||||||
|
private Integer projectCount;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// com.zg.project.wisdom.domain.vo.WlTypeStockStatVO
|
|
||||||
package com.zg.project.wisdom.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/** 当前库存-按物资类型统计 */
|
|
||||||
@Data
|
|
||||||
public class WlTypeStockStatVO {
|
|
||||||
/** 物资类型(wl_type) */
|
|
||||||
private String typeName;
|
|
||||||
/** 去重项目数(按 xm_no) */
|
|
||||||
private Integer projectCount;
|
|
||||||
/** 条目数(明细行数) */
|
|
||||||
private Integer itemCount;
|
|
||||||
/** 总数量(real_qty 合计) */
|
|
||||||
private Long totalQty;
|
|
||||||
/** 总金额(ht_dj * real_qty 合计) */
|
|
||||||
private BigDecimal amountHt;
|
|
||||||
}
|
|
||||||
@@ -1,114 +1,35 @@
|
|||||||
package com.zg.project.wisdom.mapper;
|
package com.zg.project.wisdom.mapper;
|
||||||
|
|
||||||
import com.zg.project.wisdom.domain.vo.*;
|
import com.zg.project.wisdom.domain.vo.HomeKpiVO;
|
||||||
|
import com.zg.project.wisdom.domain.vo.StockStatisticGroupVO;
|
||||||
|
import io.lettuce.core.dynamic.annotation.Param;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface RkStatisticsMapper {
|
public interface RkStatisticsMapper {
|
||||||
|
|
||||||
/** 库龄统计(未出库):按项目数计数(去重 xm_no) */
|
|
||||||
RkAgeStatVO selectAgeStats();
|
|
||||||
|
|
||||||
|
/** 当前入库类型统计 */
|
||||||
|
List<StockStatisticGroupVO> statCurrentInByOperationType();
|
||||||
|
|
||||||
/**
|
/** 当前物资类型统计 */
|
||||||
* 入库类型汇总(仅未出库)
|
List<StockStatisticGroupVO> statCurrentByMaterialType();
|
||||||
* @return 汇总结果列表
|
|
||||||
*/
|
|
||||||
List<RkTypeSummaryVO> selectRkTypeSummary();
|
|
||||||
|
|
||||||
|
/** 入库类型统计(时间) */
|
||||||
|
List<StockStatisticGroupVO> statInByOperationType(
|
||||||
|
@Param("startDate") Date startDate,
|
||||||
|
@Param("endDate") Date endDate
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/** 出库类型统计(时间) */
|
||||||
* 按入库类型 + 项目 统计【每项目的条目数】
|
List<StockStatisticGroupVO> statOutByOperationType(
|
||||||
* (用于回填到类型汇总的 projectGoodsCounts 中)
|
@Param("startDate") Date startDate,
|
||||||
*/
|
@Param("endDate") Date endDate
|
||||||
List<RkTypeProjectGoodsCountVO> selectProjectGoodsCountByType();
|
);
|
||||||
|
|
||||||
|
/** 首页 KPI */
|
||||||
/** 入库类型汇总(未出库,rk_type 非空) */
|
HomeKpiVO statHomeKpi();
|
||||||
List<RkSummaryVO> selectTypeSummary();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 县局汇总(未出库,县局非空)
|
|
||||||
*/
|
|
||||||
List<RkSummaryVO> selectCountySummary();
|
|
||||||
|
|
||||||
/** 入库(每天+县局):按 rk_time */
|
|
||||||
List<DayCountyStatVO> selectWeekDailyIn(@Param("startDate") String startDate,
|
|
||||||
@Param("endDate") String endDate);
|
|
||||||
|
|
||||||
/** 出库(每天+县局):按 ly_time */
|
|
||||||
List<DayCountyStatVO> selectWeekDailyOut(@Param("startDate") String startDate,
|
|
||||||
@Param("endDate") String endDate);
|
|
||||||
|
|
||||||
/** 汇总(>30 & >60):项目数、条目数、总金额 */
|
|
||||||
AgeSummaryVO selectAge3060Summary();
|
|
||||||
|
|
||||||
/** 明细列表:返回超过 minDays 天的明细(minDays 取 30 或 60) */
|
|
||||||
List<RkAgeDetailVO> selectAgeDetails(@Param("minDays") int minDays);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按入库类型统计饼状图数据
|
|
||||||
* @return 每个入库类型的项目数、条目数、总数量、总金额
|
|
||||||
*/
|
|
||||||
List<RkTypePieVO> selectTypePie();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按入库类型统计(联查 stock_in_type,时间范围过滤)
|
|
||||||
* 仅统计未删除、未出库
|
|
||||||
*/
|
|
||||||
List<RkTypePieVO> selectTypeSummaryByRange(@Param("start") String start,
|
|
||||||
@Param("end") String end);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按出库类型统计(时间范围;仅 is_chuku=1)
|
|
||||||
* 维度:项目数、条目数、总数量、总金额
|
|
||||||
*/
|
|
||||||
List<RkTypePieVO> selectOutTypeSummaryByRange(@Param("start") String start,
|
|
||||||
@Param("end") String end);
|
|
||||||
|
|
||||||
|
|
||||||
/** 本月入库汇总(按 rk_time 过滤) */
|
|
||||||
RkMonthSummaryVO selectMonthlyInSummary(@Param("start") String start,
|
|
||||||
@Param("end") String end);
|
|
||||||
|
|
||||||
/** 本月出库汇总(is_chuku=1 且按 ly_time 过滤) */
|
|
||||||
RkMonthSummaryVO selectMonthlyOutSummary(@Param("start") String start,
|
|
||||||
@Param("end") String end);
|
|
||||||
|
|
||||||
|
|
||||||
/** 应到未到(status='0') */
|
|
||||||
GysJhUndeliveredSummaryVO selectUndelivered();
|
|
||||||
|
|
||||||
/** 部分未到(status='2') */
|
|
||||||
GysJhUndeliveredSummaryVO selectPartialUndelivered();
|
|
||||||
|
|
||||||
/** 当前库存:按物资类型统计(过滤 wl_type 空/无) */
|
|
||||||
List<WlTypeStockStatVO> selectCurrentStockByWlType();
|
|
||||||
|
|
||||||
/** 当前库存:入库时间 >30 天的四项汇总(SQL 聚合计算) */
|
|
||||||
RkTypePieVO selectAgeGt30Summary();
|
|
||||||
|
|
||||||
/** 入库:在 [startTs, endTs) 时间范围内的原始行(仅最小过滤) */
|
|
||||||
List<RkInVO> selectInRange(@Param("startTs") String startTs,
|
|
||||||
@Param("endTs") String endTs);
|
|
||||||
|
|
||||||
/** 出库:在 [startTs, endTs) 时间范围内、is_chuku=1 的原始行(仅最小过滤) */
|
|
||||||
List<RkOutVO> selectOutRange(@Param("startTs") String startTs,
|
|
||||||
@Param("endTs") String endTs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 外层:按场景汇总可用数量,并级联查询可用库位明细(返回 SceneAvailableVO 列表)
|
|
||||||
*/
|
|
||||||
List<SceneAvailableVO> selectAvailableByWarehouse(@Param("warehouseCode") String warehouseCode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 内层:指定仓库 + 场景,查询该场景下的可用库位明细
|
|
||||||
*/
|
|
||||||
List<PcdeDetailSimpleVO> selectAvailablePositionsByWarehouseAndScene(
|
|
||||||
@Param("warehouseCode") String warehouseCode,
|
|
||||||
@Param("sceneCode") String sceneCode);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,98 +1,15 @@
|
|||||||
package com.zg.project.wisdom.service;
|
package com.zg.project.wisdom.service;
|
||||||
|
|
||||||
import com.zg.project.wisdom.domain.dto.RkInfoQueryDTO;
|
import com.zg.project.wisdom.domain.dto.HomeStatQueryDTO;
|
||||||
import com.zg.project.wisdom.domain.vo.*;
|
import com.zg.project.wisdom.domain.vo.HomeStatVO;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/** 首页统计服务 */
|
/** 首页统计服务 */
|
||||||
public interface RkStatisticsService {
|
public interface RkStatisticsService {
|
||||||
|
|
||||||
/** 库龄统计(仅未出库) */
|
|
||||||
// RkAgeStatVO getAgeStats();
|
|
||||||
|
|
||||||
/** 新增:返回 Map */
|
|
||||||
List<Map<String, Object>> getAgeStatsAsList();
|
|
||||||
|
|
||||||
/** 入库类型汇总(未出库) */
|
|
||||||
List<RkSummaryVO> getTypeSummary();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 县局汇总(未出库)
|
* 首页统计
|
||||||
*/
|
*/
|
||||||
List<RkSummaryVO> getCountySummary();
|
HomeStatVO getHomeStatistics(HomeStatQueryDTO query);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一周天级统计(一个接口返回入库+出库)
|
|
||||||
* @param start 可空(yyyy-MM-dd)
|
|
||||||
* @param end 可空(yyyy-MM-dd)
|
|
||||||
* @return { "in": List<DayCountyStatVO>, "out": List<DayCountyStatVO> }
|
|
||||||
*/
|
|
||||||
Map<String, Object> weekDaily(String start, String end);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 库龄统计(>30天 & >60天):项目数、条目数、总金额 + 两个明细列表
|
|
||||||
*/
|
|
||||||
Age3060ResultVO getAge3060Detail();
|
|
||||||
|
|
||||||
List<Map<String, Object>> getAge3060();
|
|
||||||
|
|
||||||
/** 导出库龄明细(>30 与 >60 合并导出) */
|
|
||||||
void exportAge3060(HttpServletResponse response);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取入库类型饼状图数据
|
|
||||||
* @return 入库类型饼图统计列表
|
|
||||||
*/
|
|
||||||
List<RkTypePieVO> getTypePie();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按入库类型统计(时间范围)
|
|
||||||
* @param start 开始日期(建议 yyyy-MM-dd)
|
|
||||||
* @param end 结束日期(建议 yyyy-MM-dd)
|
|
||||||
* @return 每个入库类型的项目数、条目数、总数量、总金额
|
|
||||||
*/
|
|
||||||
List<RkTypePieVO> getTypeSummaryByRange(String start, String end);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按出库类型统计(时间范围)
|
|
||||||
* 口径:仅统计已出库(is_chuku = 1),排除删除;出库类型非空
|
|
||||||
* 时间字段:ly_time(自然日闭区间 [start, end],参数建议 yyyy-MM-dd)
|
|
||||||
*/
|
|
||||||
List<RkTypePieVO> getOutTypeSummaryByRange(String start, String end);
|
|
||||||
|
|
||||||
/** 本月入/出库汇总(项目数/条目数/总数量/总金额) */
|
|
||||||
RkMonthInOutSummaryVO getThisMonthInOutSummary();
|
|
||||||
|
|
||||||
/** 供应计划:应到未到统计(未到、部分未到、合计) */
|
|
||||||
GysJhUndeliveredVO getUndeliveredSummary();
|
|
||||||
|
|
||||||
/** 当前库存:按物资类型统计 */
|
|
||||||
List<WlTypeStockStatVO> getCurrentStockByWlType();
|
|
||||||
|
|
||||||
/** 当前库存 “入库时间 >30 天”的四项汇总 */
|
|
||||||
RkTypePieVO getAgeGt30Summary();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* range: 0=最近一周(日);2=最近半年(月)
|
|
||||||
* 返回每个时间桶的一行数据(固定 7 行或 6 行)
|
|
||||||
*/
|
|
||||||
List<IOBucketVO> getIOBuckets(Integer range);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据仓库编码,返回各场景的可用库位(含数量与明细)
|
|
||||||
* 规则:排除 rk_info 中未出库(is_chuku=0 或 NULL)的占用库位
|
|
||||||
*/
|
|
||||||
List<SceneAvailableVO> listAvailableByWarehouse(String warehouseCode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 库存统计
|
|
||||||
* @param dto 查询参数
|
|
||||||
* @return { "total": 0, "rows": List<StockStatVO> }
|
|
||||||
*/
|
|
||||||
// Map<String, Object> selectStockStatistics(RkInfoQueryDTO dto);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ public class RkBillServiceImpl implements IRkBillService
|
|||||||
Date now = DateUtils.getNowDate();
|
Date now = DateUtils.getNowDate();
|
||||||
String userId = String.valueOf(SecurityUtils.getUserId());
|
String userId = String.valueOf(SecurityUtils.getUserId());
|
||||||
|
|
||||||
// ================== 1. 主单 rk_bill ==================
|
/* ================== 1. 主单 rk_bill ================== */
|
||||||
RkBill bill = new RkBill();
|
RkBill bill = new RkBill();
|
||||||
if (dto.getRkBill() != null) {
|
if (dto.getRkBill() != null) {
|
||||||
BeanUtils.copyProperties(dto.getRkBill(), bill);
|
BeanUtils.copyProperties(dto.getRkBill(), bill);
|
||||||
@@ -525,16 +525,14 @@ public class RkBillServiceImpl implements IRkBillService
|
|||||||
|
|
||||||
boolean isPreOut = "0".equals(bill.getExecStatus());
|
boolean isPreOut = "0".equals(bill.getExecStatus());
|
||||||
|
|
||||||
// ===== 借料出库字段 =====
|
// 借料出库字段
|
||||||
if ("2".equals(bill.getBizType())) {
|
if ("2".equals(bill.getBizType())) {
|
||||||
bill.setBorrowTime(bill.getBorrowTime() != null ? bill.getBorrowTime() : now);
|
bill.setBorrowTime(bill.getBorrowTime() != null ? bill.getBorrowTime() : now);
|
||||||
bill.setXmNoCk(bill.getXmNoCk());
|
|
||||||
bill.setXmMsCk(bill.getXmMsCk());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rkBillMapper.insertRkBill(bill);
|
rkBillMapper.insertRkBill(bill);
|
||||||
|
|
||||||
// ================== 2. 出库处理 ==================
|
/* ================== 2. 出库处理 ================== */
|
||||||
for (RkInfo outInfo : dto.getRkInfoList()) {
|
for (RkInfo outInfo : dto.getRkInfoList()) {
|
||||||
|
|
||||||
if (outInfo.getId() == null) {
|
if (outInfo.getId() == null) {
|
||||||
@@ -556,18 +554,17 @@ public class RkBillServiceImpl implements IRkBillService
|
|||||||
throw new RuntimeException("出库数量不能大于库存数量,库存ID:" + dbInfo.getId());
|
throw new RuntimeException("出库数量不能大于库存数量,库存ID:" + dbInfo.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== ① 非预出库才扣库存 =====
|
// ① 非预出库才扣库存
|
||||||
if (!isPreOut) {
|
if (!isPreOut) {
|
||||||
BigDecimal newQty = remainQty.subtract(outQty);
|
BigDecimal newQty = remainQty.subtract(outQty);
|
||||||
rkInfoMapper.updateRealQtyById(dbInfo.getId(), newQty);
|
rkInfoMapper.updateRealQtyById(dbInfo.getId(), newQty);
|
||||||
|
|
||||||
rkInfoMapper.updateIsChukuById(
|
rkInfoMapper.updateIsChukuById(
|
||||||
dbInfo.getId(),
|
dbInfo.getId(),
|
||||||
newQty.compareTo(BigDecimal.ZERO) == 0 ? "1" : "0"
|
newQty.compareTo(BigDecimal.ZERO) == 0 ? "1" : "0"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== ② 出库记录(重点:传 outInfo)=====
|
// ② 写出库记录(已修复 cangku)
|
||||||
RkRecord record = buildOutRkRecord(bill, dbInfo, outInfo, outQty, now);
|
RkRecord record = buildOutRkRecord(bill, dbInfo, outInfo, outQty, now);
|
||||||
record.setExecStatus(isPreOut ? "0" : "1");
|
record.setExecStatus(isPreOut ? "0" : "1");
|
||||||
|
|
||||||
@@ -577,6 +574,7 @@ public class RkBillServiceImpl implements IRkBillService
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private RkRecord buildOutRkRecord(
|
private RkRecord buildOutRkRecord(
|
||||||
RkBill bill,
|
RkBill bill,
|
||||||
RkInfo dbInfo,
|
RkInfo dbInfo,
|
||||||
@@ -586,26 +584,29 @@ public class RkBillServiceImpl implements IRkBillService
|
|||||||
|
|
||||||
RkRecord record = new RkRecord();
|
RkRecord record = new RkRecord();
|
||||||
|
|
||||||
// ① 库存快照
|
/* ① 库存快照 */
|
||||||
BeanUtils.copyProperties(dbInfo, record);
|
BeanUtils.copyProperties(dbInfo, record);
|
||||||
record.setId(null);
|
record.setId(null);
|
||||||
|
|
||||||
// ② 本次出库数量
|
/* ② 本次出库数量 */
|
||||||
record.setRealQty(outQty);
|
record.setRealQty(outQty);
|
||||||
|
|
||||||
// ③ 主单上下文
|
/* ③ 主单上下文 */
|
||||||
record.setBillNo(bill.getBillNo());
|
record.setBillNo(bill.getBillNo());
|
||||||
record.setBizType(bill.getBizType());
|
record.setBizType(bill.getBizType());
|
||||||
record.setOperationType(bill.getOperationType());
|
record.setOperationType(bill.getOperationType());
|
||||||
record.setOperationTime(bill.getOperationTime());
|
record.setOperationTime(bill.getOperationTime());
|
||||||
record.setOperator(bill.getOperator());
|
record.setOperator(bill.getOperator());
|
||||||
record.setCangku(bill.getCangku());
|
|
||||||
record.setTeamCode(bill.getTeamCode());
|
record.setTeamCode(bill.getTeamCode());
|
||||||
|
|
||||||
// ===== ★ 关键:备注来自【出库明细 outInfo】=====
|
/* ================== ✅ 关键修复 ================== */
|
||||||
|
// 仓库必须来源于【库存快照】,而不是 bill
|
||||||
|
record.setCangku(dbInfo.getCangku());
|
||||||
|
|
||||||
|
/* ④ 备注来自出库明细 */
|
||||||
record.setRemark(outInfo.getRemark());
|
record.setRemark(outInfo.getRemark());
|
||||||
|
|
||||||
// ④ 借料专属字段
|
/* ⑤ 借料字段 */
|
||||||
if ("2".equals(bill.getBizType())) {
|
if ("2".equals(bill.getBizType())) {
|
||||||
record.setIsBorrowed("1");
|
record.setIsBorrowed("1");
|
||||||
record.setBorrowTime(bill.getBorrowTime());
|
record.setBorrowTime(bill.getBorrowTime());
|
||||||
@@ -616,17 +617,17 @@ public class RkBillServiceImpl implements IRkBillService
|
|||||||
record.setIsBorrowed("0");
|
record.setIsBorrowed("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ⑤ 状态字段
|
/* ⑥ 状态字段 */
|
||||||
record.setIsChuku("1");
|
record.setIsChuku("1");
|
||||||
record.setHasMoved("0");
|
record.setHasMoved("0");
|
||||||
record.setIsDelete("0");
|
record.setIsDelete("0");
|
||||||
record.setExecStatus(bill.getExecStatus());
|
record.setExecStatus(bill.getExecStatus());
|
||||||
|
|
||||||
// ⑥ 审计字段
|
/* ⑦ 审计字段 */
|
||||||
record.setCreateTime(now);
|
record.setCreateTime(now);
|
||||||
record.setCreateBy(bill.getCreateBy());
|
record.setCreateBy(bill.getCreateBy());
|
||||||
|
|
||||||
// ⑦ 关联库存
|
/* ⑧ 关联库存 */
|
||||||
record.setRkInfoId(dbInfo.getId());
|
record.setRkInfoId(dbInfo.getId());
|
||||||
record.setRdid(dbInfo.getId());
|
record.setRdid(dbInfo.getId());
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
package com.zg.project.wisdom.service.impl;
|
package com.zg.project.wisdom.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.zg.project.wisdom.domain.dto.HomeStatQueryDTO;
|
||||||
import com.zg.common.exception.ServiceException;
|
import com.zg.project.wisdom.domain.vo.HomeStatVO;
|
||||||
import com.zg.common.utils.DateUtils;
|
|
||||||
import com.zg.common.utils.StringUtils;
|
|
||||||
import com.zg.common.utils.poi.ExcelUtil;
|
|
||||||
import com.zg.project.wisdom.domain.dto.RkInfoQueryDTO;
|
|
||||||
import com.zg.project.wisdom.domain.vo.*;
|
|
||||||
import com.zg.project.wisdom.mapper.RkInfoMapper;
|
|
||||||
import com.zg.project.wisdom.mapper.RkStatisticsMapper;
|
import com.zg.project.wisdom.mapper.RkStatisticsMapper;
|
||||||
import com.zg.project.wisdom.service.RkStatisticsService;
|
import com.zg.project.wisdom.service.RkStatisticsService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import java.util.Date;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.time.*;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class RkStatisticsServiceImpl implements RkStatisticsService {
|
public class RkStatisticsServiceImpl implements RkStatisticsService {
|
||||||
@@ -25,427 +15,26 @@ public class RkStatisticsServiceImpl implements RkStatisticsService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private RkStatisticsMapper rkStatisticsMapper;
|
private RkStatisticsMapper rkStatisticsMapper;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RkInfoMapper rkInfoMapper;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Map<String, Object>> getAgeStatsAsList() {
|
public HomeStatVO getHomeStatistics(HomeStatQueryDTO query) {
|
||||||
// 这里的 gt10/gt20/gt30 均为“项目数”(COUNT DISTINCT xm_no)
|
|
||||||
RkAgeStatVO vo = rkStatisticsMapper.selectAgeStats();
|
|
||||||
|
|
||||||
List<Map<String, Object>> list = new ArrayList<>(3);
|
HomeStatVO vo = new HomeStatVO();
|
||||||
Map<String, Object> m1 = new HashMap<>();
|
|
||||||
m1.put("name", ">10天");
|
|
||||||
m1.put("value", vo.getGt10());
|
|
||||||
list.add(m1);
|
|
||||||
|
|
||||||
Map<String, Object> m2 = new HashMap<>();
|
// ========== 1. 顶部 KPI ==========
|
||||||
m2.put("name", ">20天");
|
vo.setKpi(rkStatisticsMapper.statHomeKpi());
|
||||||
m2.put("value", vo.getGt20());
|
|
||||||
list.add(m2);
|
|
||||||
|
|
||||||
Map<String, Object> m3 = new HashMap<>();
|
// ========== 2. 当前库存统计 ==========
|
||||||
m3.put("name", ">30天");
|
vo.setCurrentInType(rkStatisticsMapper.statCurrentInByOperationType());
|
||||||
m3.put("value", vo.getGt30());
|
vo.setMaterialType(rkStatisticsMapper.statCurrentByMaterialType());
|
||||||
list.add(m3);
|
|
||||||
|
|
||||||
return list;
|
// ========== 3. 时间维度统计 ==========
|
||||||
}
|
Date start = query == null ? null : query.getStartDate();
|
||||||
/**
|
Date end = query == null ? null : query.getEndDate();
|
||||||
* 库存类型统计(仅未出库)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<RkSummaryVO> getTypeSummary() {
|
|
||||||
List<RkSummaryVO> list = rkStatisticsMapper.selectTypeSummary();
|
|
||||||
return CollectionUtils.isEmpty(list) ? Collections.emptyList() : list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
vo.setInTypeByTime(rkStatisticsMapper.statInByOperationType(start, end));
|
||||||
* 县局统计(仅未出库)
|
vo.setOutTypeByTime(rkStatisticsMapper.statOutByOperationType(start, end));
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<RkSummaryVO> getCountySummary() {
|
|
||||||
List<RkSummaryVO> list = rkStatisticsMapper.selectCountySummary();
|
|
||||||
return CollectionUtils.isEmpty(list) ? Collections.emptyList() : list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> weekDaily(String start, String end) {
|
|
||||||
// 如果携带了 start 和 end,就直接用;否则:end=今天,start=本周周一
|
|
||||||
if (StringUtils.isBlank(start) || StringUtils.isBlank(end)) {
|
|
||||||
LocalDate today = LocalDate.now();
|
|
||||||
LocalDate monday = today.with(DayOfWeek.MONDAY);
|
|
||||||
start = monday.format(F);
|
|
||||||
end = today.format(F);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> ret = new HashMap<>(2);
|
|
||||||
ret.put("in", rkStatisticsMapper.selectWeekDailyIn(start, end));
|
|
||||||
ret.put("out", rkStatisticsMapper.selectWeekDailyOut(start, end));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Age3060ResultVO getAge3060Detail() {
|
|
||||||
// 1) 汇总(同时返回 >30 / >60 的项目数、条目数、总金额)
|
|
||||||
AgeSummaryVO summary = rkStatisticsMapper.selectAge3060Summary();
|
|
||||||
|
|
||||||
// 2) 明细(>30)
|
|
||||||
List<RkAgeDetailVO> gt30List = rkStatisticsMapper.selectAgeDetails(30);
|
|
||||||
|
|
||||||
// 3) 明细(>60)
|
|
||||||
List<RkAgeDetailVO> gt60List = rkStatisticsMapper.selectAgeDetails(60);
|
|
||||||
|
|
||||||
// 4) 组装返回
|
|
||||||
Age3060ResultVO vo = new Age3060ResultVO();
|
|
||||||
vo.setGt30(summary.getGt30());
|
|
||||||
vo.setGt60(summary.getGt60());
|
|
||||||
vo.setGt30List(gt30List);
|
|
||||||
vo.setGt60List(gt60List);
|
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Map<String, Object>> getAge3060() {
|
|
||||||
// 1) 汇总(同时返回 >30 / >60 的项目数、条目数、总金额)
|
|
||||||
AgeSummaryVO summary = rkStatisticsMapper.selectAge3060Summary();
|
|
||||||
|
|
||||||
// 2) 用 List<Map> 封装成数组结构
|
|
||||||
List<Map<String, Object>> list = new ArrayList<>();
|
|
||||||
|
|
||||||
Map<String, Object> gt30 = new HashMap<>();
|
|
||||||
gt30.put("name", ">30天");
|
|
||||||
gt30.put("value", summary.getGt30().getGoodsCount()); // 这里取“货物数量”作 value
|
|
||||||
list.add(gt30);
|
|
||||||
|
|
||||||
Map<String, Object> gt60 = new HashMap<>();
|
|
||||||
gt60.put("name", ">60天");
|
|
||||||
gt60.put("value", summary.getGt60().getGoodsCount());
|
|
||||||
list.add(gt60);
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出库龄明细(>30天 与 >60天 合并导出为一张表)
|
|
||||||
* - 所有业务逻辑均在 Service 层完成
|
|
||||||
* - 使用若依 ExcelUtil + @Excel 注解导出
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void exportAge3060(HttpServletResponse response) {
|
|
||||||
// 1) 调用已有统计逻辑
|
|
||||||
Age3060ResultVO res = this.getAge3060Detail();
|
|
||||||
|
|
||||||
// 2) 合并两组明细,加上导出用的分组字段
|
|
||||||
List<RkAgeDetailVO> out = new ArrayList<>();
|
|
||||||
if (res.getGt30List() != null) {
|
|
||||||
for (RkAgeDetailVO row : res.getGt30List()) {
|
|
||||||
normalizeRowForExport(row, ">30天");
|
|
||||||
out.add(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (res.getGt60List() != null) {
|
|
||||||
for (RkAgeDetailVO row : res.getGt60List()) {
|
|
||||||
normalizeRowForExport(row, ">60天");
|
|
||||||
out.add(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) 导出 Excel
|
|
||||||
ExcelUtil<RkAgeDetailVO> util = new ExcelUtil<>(RkAgeDetailVO.class);
|
|
||||||
util.exportExcel(response, out, "库龄明细");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void normalizeRowForExport(RkAgeDetailVO row, String bucket) {
|
|
||||||
row.setAgeBucket(bucket);
|
|
||||||
if (row.getAmount() == null) {
|
|
||||||
BigDecimal dj = row.getHtDj() == null ? BigDecimal.ZERO : row.getHtDj();
|
|
||||||
BigDecimal qty = row.getRealQty() == null ? BigDecimal.ZERO : row.getRealQty();
|
|
||||||
row.setAmount(dj.multiply(qty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取入库类型饼状图数据
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<RkTypePieVO> getTypePie() {
|
|
||||||
return rkStatisticsMapper.selectTypePie();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RkTypePieVO> getTypeSummaryByRange(String start, String end) {
|
|
||||||
// 基础入参校验(避免全表扫描/人为误操作)
|
|
||||||
if (StringUtils.isBlank(start) || StringUtils.isBlank(end)) {
|
|
||||||
throw new ServiceException("start/end 不能为空,建议格式:yyyy-MM-dd");
|
|
||||||
}
|
|
||||||
return rkStatisticsMapper.selectTypeSummaryByRange(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RkTypePieVO> getOutTypeSummaryByRange(String start, String end) {
|
|
||||||
if (StringUtils.isBlank(start) || StringUtils.isBlank(end)) {
|
|
||||||
throw new ServiceException("start/end 不能为空,建议格式:yyyy-MM-dd");
|
|
||||||
}
|
|
||||||
return rkStatisticsMapper.selectOutTypeSummaryByRange(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final DateTimeFormatter DF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
||||||
@Override
|
|
||||||
public RkMonthInOutSummaryVO getThisMonthInOutSummary() {
|
|
||||||
// 本月起止: [YYYY-MM-01 00:00:00, 下月01 00:00:00)
|
|
||||||
LocalDate firstDay = LocalDate.now().withDayOfMonth(1);
|
|
||||||
LocalDate nextMonthFirst = firstDay.plusMonths(1);
|
|
||||||
|
|
||||||
String start = firstDay.atStartOfDay().format(DF);
|
|
||||||
String end = nextMonthFirst.atStartOfDay().format(DF);
|
|
||||||
|
|
||||||
RkMonthSummaryVO inSummary = rkStatisticsMapper.selectMonthlyInSummary(start, end);
|
|
||||||
RkMonthSummaryVO outSummary = rkStatisticsMapper.selectMonthlyOutSummary(start, end);
|
|
||||||
|
|
||||||
// null 兜底
|
|
||||||
if (inSummary == null) {
|
|
||||||
inSummary = new RkMonthSummaryVO();
|
|
||||||
}
|
|
||||||
if (outSummary == null) {
|
|
||||||
outSummary = new RkMonthSummaryVO();
|
|
||||||
}
|
|
||||||
|
|
||||||
RkMonthInOutSummaryVO vo = new RkMonthInOutSummaryVO();
|
|
||||||
vo.setInSummary(inSummary);
|
|
||||||
vo.setOutSummary(outSummary);
|
|
||||||
return vo;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GysJhUndeliveredVO getUndeliveredSummary() {
|
|
||||||
// 分别查询:未到(status=0)、部分未到(status=2)
|
|
||||||
GysJhUndeliveredSummaryVO undelivered = rkStatisticsMapper.selectUndelivered();
|
|
||||||
GysJhUndeliveredSummaryVO partial = rkStatisticsMapper.selectPartialUndelivered();
|
|
||||||
|
|
||||||
// 对象兜底
|
|
||||||
if (undelivered == null) undelivered = new GysJhUndeliveredSummaryVO();
|
|
||||||
if (partial == null) partial = new GysJhUndeliveredSummaryVO();
|
|
||||||
|
|
||||||
// 字段兜底(防止仍有 null 透出)
|
|
||||||
if (undelivered.getProjectCount() == null) undelivered.setProjectCount(0);
|
|
||||||
if (undelivered.getItemCount() == null) undelivered.setItemCount(0);
|
|
||||||
if (undelivered.getTotalQty() == null) undelivered.setTotalQty(0L);
|
|
||||||
if (undelivered.getAmountPlan() == null) undelivered.setAmountPlan(BigDecimal.ZERO);
|
|
||||||
|
|
||||||
if (partial.getProjectCount() == null) partial.setProjectCount(0);
|
|
||||||
if (partial.getItemCount() == null) partial.setItemCount(0);
|
|
||||||
if (partial.getTotalQty() == null) partial.setTotalQty(0L);
|
|
||||||
if (partial.getAmountPlan() == null) partial.setAmountPlan(BigDecimal.ZERO);
|
|
||||||
|
|
||||||
// 返回
|
|
||||||
GysJhUndeliveredVO vo = new GysJhUndeliveredVO();
|
|
||||||
vo.setUndelivered(undelivered);
|
|
||||||
vo.setPartialUndelivered(partial);
|
|
||||||
return vo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<WlTypeStockStatVO> getCurrentStockByWlType() {
|
|
||||||
List<WlTypeStockStatVO> list = rkStatisticsMapper.selectCurrentStockByWlType();
|
|
||||||
return list == null ? Collections.emptyList() : list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RkTypePieVO getAgeGt30Summary() {
|
|
||||||
RkTypePieVO vo = rkStatisticsMapper.selectAgeGt30Summary();
|
|
||||||
if (vo == null) vo = new RkTypePieVO();
|
|
||||||
|
|
||||||
// 兜底,避免前端拿到 null
|
|
||||||
if (vo.getProjectCount() == null) vo.setProjectCount(0);
|
|
||||||
if (vo.getGoodsCountTotal() == null) vo.setGoodsCountTotal(0);
|
|
||||||
if (vo.getSumQty() == null) vo.setSumQty(BigDecimal.ZERO);
|
|
||||||
if (vo.getSumAmount() == null) vo.setSumAmount(BigDecimal.ZERO);
|
|
||||||
|
|
||||||
// 本接口不设置 rkTypeCode / rkTypeName
|
|
||||||
vo.setRkTypeCode(null);
|
|
||||||
vo.setRkTypeName(null);
|
|
||||||
return vo;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static final DateTimeFormatter TS_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
||||||
private static final DateTimeFormatter DAY_FMT = DateTimeFormatter.ofPattern("MM-dd");
|
|
||||||
private static final DateTimeFormatter MON_FMT = DateTimeFormatter.ofPattern("yyyy-MM");
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<IOBucketVO> getIOBuckets(Integer range) {
|
|
||||||
if (range == null || (range != 0 && range != 2)) {
|
|
||||||
throw new IllegalArgumentException("range 仅支持 0(最近一周) 或 2(最近半年)");
|
|
||||||
}
|
|
||||||
|
|
||||||
Date now = DateUtils.getNowDate();
|
|
||||||
LocalDateTime nowLdt = LocalDateTime.ofInstant(now.toInstant(), ZoneId.systemDefault());
|
|
||||||
|
|
||||||
if (range == 0) {
|
|
||||||
// ===== 最近一周(按日),输出 MM-dd =====
|
|
||||||
LocalDate endDay = nowLdt.toLocalDate();
|
|
||||||
LocalDate startDay = endDay.minusDays(6);
|
|
||||||
LocalDateTime startTs = startDay.atStartOfDay();
|
|
||||||
LocalDateTime endTs = endDay.plusDays(1).atStartOfDay();
|
|
||||||
|
|
||||||
List<RkInVO> inRows = rkStatisticsMapper.selectInRange(startTs.format(TS_FMT), endTs.format(TS_FMT));
|
|
||||||
List<RkOutVO> outRows = rkStatisticsMapper.selectOutRange(startTs.format(TS_FMT), endTs.format(TS_FMT));
|
|
||||||
|
|
||||||
// 改为以 LocalDate 作为桶键,防止键格式与输出格式不一致导致匹配失败
|
|
||||||
LinkedHashMap<LocalDate, BucketAcc> acc = new LinkedHashMap<>();
|
|
||||||
for (int i = 0; i < 7; i++) {
|
|
||||||
LocalDate d = startDay.plusDays(i);
|
|
||||||
acc.put(d, new BucketAcc());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 入库聚合(按 LocalDate)
|
|
||||||
for (RkInVO r : inRows) {
|
|
||||||
if (r.getRkTime() == null) continue;
|
|
||||||
LocalDate d = r.getRkTime().toLocalDate();
|
|
||||||
BucketAcc b = acc.get(d);
|
|
||||||
if (b == null) continue;
|
|
||||||
b.inItemCount++;
|
|
||||||
if (StringUtils.isNotBlank(r.getXmNo())) {
|
|
||||||
b.inProjects.add(r.getXmNo().trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 出库聚合(按 LocalDate;ly_time 优先,否则 update_time)
|
|
||||||
for (RkOutVO r : outRows) {
|
|
||||||
LocalDateTime t = (r.getLyTime() != null) ? r.getLyTime() : r.getUpdateTime();
|
|
||||||
if (t == null) continue;
|
|
||||||
LocalDate d = t.toLocalDate();
|
|
||||||
BucketAcc b = acc.get(d);
|
|
||||||
if (b == null) continue;
|
|
||||||
b.outItemCount++;
|
|
||||||
String proj = StringUtils.isNotBlank(r.getXmNoCk()) ? r.getXmNoCk().trim() : r.getXmNo();
|
|
||||||
if (StringUtils.isNotBlank(proj)) b.outProjects.add(proj);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<IOBucketVO> out = new ArrayList<>(7);
|
|
||||||
for (Map.Entry<LocalDate, BucketAcc> e : acc.entrySet()) {
|
|
||||||
IOBucketVO row = new IOBucketVO();
|
|
||||||
row.setBucket(e.getKey().format(DAY_FMT)); // 仅返回 MM-dd
|
|
||||||
row.setInProjectCount(e.getValue().inProjects.size());
|
|
||||||
row.setInItemCount(e.getValue().inItemCount);
|
|
||||||
row.setOutProjectCount(e.getValue().outProjects.size());
|
|
||||||
row.setOutItemCount(e.getValue().outItemCount);
|
|
||||||
out.add(row);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// ===== 最近半年(按月),输出 yyyy-MM =====
|
|
||||||
YearMonth endYm = YearMonth.from(nowLdt.toLocalDate());
|
|
||||||
YearMonth startYm = endYm.minusMonths(5);
|
|
||||||
LocalDateTime startTs = startYm.atDay(1).atStartOfDay();
|
|
||||||
LocalDateTime endTs = endYm.plusMonths(1).atDay(1).atStartOfDay();
|
|
||||||
|
|
||||||
List<RkInVO> inRows = rkStatisticsMapper.selectInRange(startTs.format(TS_FMT), endTs.format(TS_FMT));
|
|
||||||
List<RkOutVO> outRows = rkStatisticsMapper.selectOutRange(startTs.format(TS_FMT), endTs.format(TS_FMT));
|
|
||||||
|
|
||||||
LinkedHashMap<YearMonth, BucketAcc> acc = new LinkedHashMap<>();
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
YearMonth ym = startYm.plusMonths(i);
|
|
||||||
acc.put(ym, new BucketAcc());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 入库按月
|
|
||||||
for (RkInVO r : inRows) {
|
|
||||||
if (r.getRkTime() == null) continue;
|
|
||||||
YearMonth ym = YearMonth.from(r.getRkTime().toLocalDate());
|
|
||||||
BucketAcc b = acc.get(ym);
|
|
||||||
if (b == null) continue;
|
|
||||||
b.inItemCount++;
|
|
||||||
if (StringUtils.isNotBlank(r.getXmNo())) {
|
|
||||||
b.inProjects.add(r.getXmNo().trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 出库按月
|
|
||||||
for (RkOutVO r : outRows) {
|
|
||||||
LocalDateTime t = (r.getLyTime() != null) ? r.getLyTime() : r.getUpdateTime();
|
|
||||||
if (t == null) continue;
|
|
||||||
YearMonth ym = YearMonth.from(t.toLocalDate());
|
|
||||||
BucketAcc b = acc.get(ym);
|
|
||||||
if (b == null) continue;
|
|
||||||
b.outItemCount++;
|
|
||||||
String proj = StringUtils.isNotBlank(r.getXmNoCk()) ? r.getXmNoCk().trim() : r.getXmNo();
|
|
||||||
if (StringUtils.isNotBlank(proj)) b.outProjects.add(proj);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<IOBucketVO> out = new ArrayList<>(6);
|
|
||||||
for (Map.Entry<YearMonth, BucketAcc> e : acc.entrySet()) {
|
|
||||||
IOBucketVO row = new IOBucketVO();
|
|
||||||
row.setBucket(e.getKey().format(MON_FMT)); // yyyy-MM
|
|
||||||
row.setInProjectCount(e.getValue().inProjects.size());
|
|
||||||
row.setInItemCount(e.getValue().inItemCount);
|
|
||||||
row.setOutProjectCount(e.getValue().outProjects.size());
|
|
||||||
row.setOutItemCount(e.getValue().outItemCount);
|
|
||||||
out.add(row);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 桶内累加器 */
|
|
||||||
private static class BucketAcc {
|
|
||||||
int inItemCount = 0;
|
|
||||||
int outItemCount = 0;
|
|
||||||
Set<String> inProjects = new HashSet<>();
|
|
||||||
Set<String> outProjects = new HashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<SceneAvailableVO> listAvailableByWarehouse(String warehouseCode) {
|
|
||||||
List<SceneAvailableVO> list = rkStatisticsMapper.selectAvailableByWarehouse(warehouseCode);
|
|
||||||
|
|
||||||
if (list == null || list.isEmpty()) {
|
|
||||||
// 没有查到任何数据时,返回一个默认对象
|
|
||||||
SceneAvailableVO vo = new SceneAvailableVO();
|
|
||||||
// vo.setSceneCode("N/A"); // 默认场景编码
|
|
||||||
// vo.setSceneName("无可用场景"); // 默认场景名称
|
|
||||||
vo.setAvailableCount(0); // 可用数量为0
|
|
||||||
vo.setPositions(new ArrayList<>()); // 空数组
|
|
||||||
|
|
||||||
list = new ArrayList<>();
|
|
||||||
list.add(vo);
|
|
||||||
} else {
|
|
||||||
// 保证 positions 不为 null
|
|
||||||
for (SceneAvailableVO vo : list) {
|
|
||||||
if (vo.getPositions() == null) {
|
|
||||||
vo.setPositions(new ArrayList<>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public Map<String, Object> selectStockStatistics(RkInfoQueryDTO query) {
|
|
||||||
//
|
|
||||||
// if (query.getIsChuku() == null) {
|
|
||||||
// query.setIsChuku("0"); // 默认只查在库
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Map<String, Object> result = rkInfoMapper.selectStockStatistics(query);
|
|
||||||
//
|
|
||||||
// // 处理空值情况,防止前端拿到 null 报错
|
|
||||||
// if (result == null) {
|
|
||||||
// result = new HashMap<>();
|
|
||||||
// }
|
|
||||||
// result.putIfAbsent("sumMoney", 0);
|
|
||||||
// result.putIfAbsent("sumQty", 0);
|
|
||||||
// result.putIfAbsent("pcdeCount", 0);
|
|
||||||
//
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,541 +2,115 @@
|
|||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="com.zg.project.wisdom.mapper.RkStatisticsMapper">
|
<mapper namespace="com.zg.project.wisdom.mapper.RkStatisticsMapper">
|
||||||
|
<!-- 当前入库类型统计 -->
|
||||||
<!-- 库龄统计(未出库;按项目数统计:COUNT DISTINCT xm_no) -->
|
<select id="statCurrentInByOperationType"
|
||||||
<select id="selectAgeStats" resultType="com.zg.project.wisdom.domain.vo.RkAgeStatVO">
|
resultType="com.zg.project.wisdom.domain.vo.StockStatisticGroupVO">
|
||||||
SELECT
|
SELECT
|
||||||
/* >10 天的项目数(至少一条记录满足 >10 天的 xm_no 个数) */
|
ri.operation_type AS groupValue,
|
||||||
COUNT(DISTINCT CASE
|
IFNULL(SUM(ri.real_qty * ri.ht_dj), 0) AS totalAmount,
|
||||||
WHEN ri.rk_time IS NOT NULL
|
COUNT(DISTINCT ri.pcode) AS locationCount,
|
||||||
AND DATEDIFF(CURDATE(), DATE(ri.rk_time)) > 10
|
IFNULL(SUM(ri.real_qty), 0) AS totalQuantity,
|
||||||
THEN ri.xm_no END) AS gt10,
|
COUNT(DISTINCT ri.xm_no) AS projectCount
|
||||||
|
|
||||||
/* >20 天的项目数 */
|
|
||||||
COUNT(DISTINCT CASE
|
|
||||||
WHEN ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), DATE(ri.rk_time)) > 20
|
|
||||||
THEN ri.xm_no END) AS gt20,
|
|
||||||
|
|
||||||
/* >30 天的项目数 */
|
|
||||||
COUNT(DISTINCT CASE
|
|
||||||
WHEN ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), DATE(ri.rk_time)) > 30
|
|
||||||
THEN ri.xm_no END) AS gt30
|
|
||||||
FROM rk_info ri
|
FROM rk_info ri
|
||||||
WHERE ri.is_delete = 0
|
WHERE ri.exec_status = 1
|
||||||
AND (ri.is_chuku = 0 OR ri.is_chuku IS NULL)
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
入库类型汇总SQL
|
|
||||||
统计每种入库类型(rk_type)下:
|
|
||||||
- 项目数量(去重xm_no)
|
|
||||||
- 合同单价合计(sumHtDj)
|
|
||||||
- 实际入库数量合计(sumRealQty)
|
|
||||||
- 金额合计(sumAmount = ht_dj * real_qty)
|
|
||||||
条件:
|
|
||||||
- 未删除(is_delete = 0)
|
|
||||||
- 未出库(is_chuku = 0)
|
|
||||||
-->
|
|
||||||
<select id="selectRkTypeSummary" resultType="com.zg.project.wisdom.domain.vo.RkTypeSummaryVO">
|
|
||||||
SELECT
|
|
||||||
ri.rk_type AS rkType,
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
|
||||||
SUM(IFNULL(ri.ht_dj, 0)) AS sumHtDj,
|
|
||||||
SUM(IFNULL(ri.real_qty, 0)) AS sumRealQty,
|
|
||||||
SUM(IFNULL(ri.ht_dj, 0) * IFNULL(ri.real_qty, 0)) AS sumAmount
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
AND ri.is_chuku = 0
|
||||||
GROUP BY ri.rk_type
|
AND ri.is_delete = 0
|
||||||
ORDER BY rkType
|
GROUP BY ri.operation_type
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!--
|
<!-- 当前物资类型统计 -->
|
||||||
2) 入库类型 × 项目:统计每个项目的“条目数”
|
<select id="statCurrentByMaterialType"
|
||||||
字段:
|
resultType="com.zg.project.wisdom.domain.vo.StockStatisticGroupVO">
|
||||||
- rkType:入库类型
|
|
||||||
- projectNo:xm_no
|
|
||||||
- projectName:MAX(xm_ms)
|
|
||||||
- goodsCount:COUNT(*)
|
|
||||||
过滤:is_delete=0 AND is_chuku=0
|
|
||||||
-->
|
|
||||||
<select id="selectProjectGoodsCountByType"
|
|
||||||
resultType="com.zg.project.wisdom.domain.vo.RkTypeProjectGoodsCountVO">
|
|
||||||
SELECT
|
SELECT
|
||||||
ri.rk_type AS rkType,
|
ri.wl_type AS groupValue,
|
||||||
ri.xm_no AS projectNo,
|
IFNULL(SUM(ri.real_qty * ri.ht_dj), 0) AS totalAmount,
|
||||||
MAX(ri.xm_ms) AS projectName,
|
COUNT(DISTINCT ri.pcode) AS locationCount,
|
||||||
COUNT(*) AS goodsCount
|
IFNULL(SUM(ri.real_qty), 0) AS totalQuantity,
|
||||||
|
COUNT(DISTINCT ri.xm_no) AS projectCount
|
||||||
FROM rk_info ri
|
FROM rk_info ri
|
||||||
WHERE ri.is_delete = 0
|
WHERE ri.exec_status = 1
|
||||||
AND ri.is_chuku = 0
|
AND ri.is_chuku = 0
|
||||||
GROUP BY ri.rk_type, ri.xm_no
|
AND ri.is_delete = 0
|
||||||
ORDER BY rkType, projectNo
|
GROUP BY ri.wl_type
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 入库类型汇总(未出库 & 过滤 NULL/空串/“无”) -->
|
<!-- 入库类型统计(时间) -->
|
||||||
<select id="selectTypeSummary" resultType="com.zg.project.wisdom.domain.vo.RkSummaryVO">
|
<select id="statInByOperationType"
|
||||||
|
resultType="com.zg.project.wisdom.domain.vo.StockStatisticGroupVO">
|
||||||
SELECT
|
SELECT
|
||||||
sit.type_name AS groupName,
|
ri.operation_type AS groupValue,
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
IFNULL(SUM(ri.real_qty * ri.ht_dj), 0) AS totalAmount,
|
||||||
COUNT(*) AS goodsCountTotal,
|
COUNT(DISTINCT ri.pcode) AS locationCount,
|
||||||
COALESCE(SUM(COALESCE(ri.real_qty, 0)), 0) AS sumQty,
|
IFNULL(SUM(ri.real_qty), 0) AS totalQuantity,
|
||||||
COALESCE(SUM(COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0)), 0) AS sumAmount
|
COUNT(DISTINCT ri.xm_no) AS projectCount
|
||||||
FROM rk_info ri
|
FROM rk_info ri
|
||||||
LEFT JOIN stock_in_type sit
|
WHERE ri.exec_status = 1
|
||||||
ON ri.rk_type = sit.type_code
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
-- 入库类型过滤:剔除 NULL / 空串 / '无'
|
|
||||||
AND ri.rk_type IS NOT NULL
|
|
||||||
AND TRIM(ri.rk_type) <> ''
|
|
||||||
AND ri.rk_type <> '无'
|
|
||||||
-- 名称做一层过滤,避免出现“无”或空的分组
|
|
||||||
AND sit.type_name IS NOT NULL
|
|
||||||
AND TRIM(sit.type_name) <> ''
|
|
||||||
AND sit.type_name <> '无'
|
|
||||||
GROUP BY sit.type_name
|
|
||||||
ORDER BY groupName
|
|
||||||
</select>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 县局汇总(未出库 & county 非空) -->
|
|
||||||
<select id="selectCountySummary" resultType="com.zg.project.wisdom.domain.vo.RkSummaryVO">
|
|
||||||
SELECT
|
|
||||||
ri.xj AS groupName, -- 县局
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount, -- 项目数
|
|
||||||
COUNT(*) AS goodsCountTotal, -- 条目总数
|
|
||||||
SUM(IFNULL(ri.ht_dj, 0) * IFNULL(ri.real_qty, 0)) AS sumAmount -- 总金额
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
AND ri.xj IS NOT NULL
|
|
||||||
AND TRIM(ri.xj) <> ''
|
|
||||||
GROUP BY ri.xj
|
|
||||||
ORDER BY groupName
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 入库(整段时间 + 县局):rk_time 在区间内;xj 为空归类为“未知县局” -->
|
|
||||||
<select id="selectWeekDailyIn" resultType="com.zg.project.wisdom.domain.vo.DayCountyStatVO">
|
|
||||||
SELECT
|
|
||||||
COALESCE(NULLIF(TRIM(ri.xj), ''), '未知县局') AS xj,
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
|
||||||
COUNT(*) AS itemCount,
|
|
||||||
SUM(COALESCE(ri.real_qty, 0)) AS totalQty,
|
|
||||||
SUM(COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0)) AS amountHt,
|
|
||||||
SUM(COALESCE(ri.jh_amt, 0)) AS amountPlan
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.rk_time BETWEEN #{startDate} AND #{endDate}
|
|
||||||
GROUP BY COALESCE(NULLIF(TRIM(ri.xj), ''), '未知县局')
|
|
||||||
ORDER BY xj
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 出库(整段时间 + 县局):ly_time 在区间内;只统计已出库 is_chuku=1;xj 为空归类为“未知县局” -->
|
|
||||||
<select id="selectWeekDailyOut" resultType="com.zg.project.wisdom.domain.vo.DayCountyStatVO">
|
|
||||||
SELECT
|
|
||||||
COALESCE(NULLIF(TRIM(ri.xj), ''), '未知县局') AS xj,
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
|
||||||
COUNT(*) AS itemCount,
|
|
||||||
SUM(COALESCE(ri.real_qty, 0)) AS totalQty,
|
|
||||||
SUM(COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0)) AS amountHt,
|
|
||||||
0 AS amountPlan
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 1
|
|
||||||
AND ri.ly_time BETWEEN #{startDate} AND #{endDate}
|
|
||||||
GROUP BY COALESCE(NULLIF(TRIM(ri.xj), ''), '未知县局')
|
|
||||||
ORDER BY xj
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- ======================
|
|
||||||
结果映射:汇总 AgeSummaryVO
|
|
||||||
====================== -->
|
|
||||||
<resultMap id="AgeSummaryMap" type="com.zg.project.wisdom.domain.vo.AgeSummaryVO">
|
|
||||||
<!-- 通过两个 association 绑定到内部 Slot 对象 -->
|
|
||||||
<association property="gt30" javaType="com.zg.project.wisdom.domain.vo.AgeSummaryVO$Slot">
|
|
||||||
<id property="dummyId" column="gt30_dummy_id"/>
|
|
||||||
<result property="projectCount" column="gt30ProjectCount"/>
|
|
||||||
<result property="goodsCount" column="gt30GoodsCount"/>
|
|
||||||
<result property="sumAmount" column="gt30Amount"/>
|
|
||||||
</association>
|
|
||||||
<association property="gt60" javaType="com.zg.project.wisdom.domain.vo.AgeSummaryVO$Slot">
|
|
||||||
<id property="dummyId" column="gt60_dummy_id"/>
|
|
||||||
<result property="projectCount" column="gt60ProjectCount"/>
|
|
||||||
<result property="goodsCount" column="gt60GoodsCount"/>
|
|
||||||
<result property="sumAmount" column="gt60Amount"/>
|
|
||||||
</association>
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
<!-- 汇总查询:>30 / >60 的项目数、条目数、总金额 -->
|
|
||||||
<select id="selectAge3060Summary" resultMap="AgeSummaryMap">
|
|
||||||
SELECT
|
|
||||||
1 AS gt30_dummy_id,
|
|
||||||
(SELECT COUNT(DISTINCT ri.xm_no)
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), ri.rk_time) > 30) AS gt30ProjectCount,
|
|
||||||
(SELECT COUNT(*)
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), ri.rk_time) > 30) AS gt30GoodsCount,
|
|
||||||
(SELECT SUM(IFNULL(ri.ht_dj, 0) * IFNULL(ri.real_qty, 0))
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), ri.rk_time) > 30) AS gt30Amount,
|
|
||||||
|
|
||||||
1 AS gt60_dummy_id,
|
|
||||||
(SELECT COUNT(DISTINCT ri.xm_no)
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), ri.rk_time) > 60) AS gt60ProjectCount,
|
|
||||||
(SELECT COUNT(*)
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), ri.rk_time) > 60) AS gt60GoodsCount,
|
|
||||||
(SELECT SUM(IFNULL(ri.ht_dj, 0) * IFNULL(ri.real_qty, 0))
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), ri.rk_time) > 60) AS gt60Amount
|
|
||||||
FROM dual
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- ======================
|
|
||||||
结果映射:明细 RkAgeDetailVO
|
|
||||||
====================== -->
|
|
||||||
<resultMap id="RkAgeDetailMap" type="com.zg.project.wisdom.domain.vo.RkAgeDetailVO">
|
|
||||||
<id property="id" column="id"/>
|
|
||||||
<result property="xmNo" column="xmNo"/>
|
|
||||||
<result property="xmMs" column="xmMs"/>
|
|
||||||
<result property="rkTime" column="rkTime"/>
|
|
||||||
<result property="kuLingDays" column="kuLingDays"/>
|
|
||||||
<result property="htDj" column="htDj"/>
|
|
||||||
<result property="realQty" column="realQty"/>
|
|
||||||
<result property="amount" column="amount"/>
|
|
||||||
<result property="pcode" column="pcode"/>
|
|
||||||
<result property="trayCode" column="trayCode"/>
|
|
||||||
<result property="billNo" column="billNo"/>
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
<!-- 明细查询:超过 minDays 天的所有未出库记录 -->
|
|
||||||
<select id="selectAgeDetails" parameterType="int" resultMap="RkAgeDetailMap">
|
|
||||||
SELECT
|
|
||||||
ri.id,
|
|
||||||
ri.xm_no AS xmNo,
|
|
||||||
ri.xm_ms AS xmMs,
|
|
||||||
ri.rk_time AS rkTime,
|
|
||||||
DATEDIFF(CURDATE(), ri.rk_time) AS kuLingDays,
|
|
||||||
ri.ht_dj AS htDj,
|
|
||||||
ri.real_qty AS realQty,
|
|
||||||
IFNULL(ri.ht_dj, 0) * IFNULL(ri.real_qty, 0) AS amount,
|
|
||||||
ri.pcode AS pcode,
|
|
||||||
ri.tray_code AS trayCode,
|
|
||||||
ri.bill_no AS billNo
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), ri.rk_time) > #{minDays}
|
|
||||||
ORDER BY ri.rk_time ASC
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<resultMap id="RkTypePieMap" type="com.zg.project.wisdom.domain.vo.RkTypePieVO">
|
|
||||||
<result property="rkTypeCode" column="rkTypeCode"/> <!-- 类型编码 -->
|
|
||||||
<result property="rkTypeName" column="rkTypeName"/> <!-- 类型名称 -->
|
|
||||||
<result property="projectCount" column="projectCount"/> <!-- 项目数 -->
|
|
||||||
<result property="goodsCountTotal" column="goodsCountTotal"/> <!-- 条目总数 -->
|
|
||||||
<result property="sumQty" column="sumQty"/> <!-- 总数量 -->
|
|
||||||
<result property="sumAmount" column="sumAmount"/> <!-- 总金额 -->
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
<!-- 入库类型饼图统计(联查 stock_in_type;未删除 + 未出库;rk_type 非空) -->
|
|
||||||
<select id="selectTypePie" resultMap="RkTypePieMap">
|
|
||||||
SELECT
|
|
||||||
|
|
||||||
COALESCE(sit.type_code, ri.rk_type) AS rkTypeCode,
|
|
||||||
COALESCE(sit.type_name, ri.rk_type) AS rkTypeName,
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
|
||||||
COUNT(*) AS goodsCountTotal,
|
|
||||||
SUM(IFNULL(ri.real_qty, 0)) AS sumQty,
|
|
||||||
SUM(IFNULL(ri.ht_dj, 0) * IFNULL(ri.real_qty, 0)) AS sumAmount
|
|
||||||
FROM rk_info ri
|
|
||||||
LEFT JOIN stock_in_type sit
|
|
||||||
ON ri.rk_type = sit.type_code
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 0
|
AND ri.is_chuku = 0
|
||||||
AND ri.rk_type IS NOT NULL
|
AND ri.is_delete = 0
|
||||||
AND TRIM(ri.rk_type) != ''
|
<if test="startDate != null">
|
||||||
GROUP BY COALESCE(sit.type_code, ri.rk_type),
|
AND ri.operation_time <![CDATA[>=]]> #{startDate}
|
||||||
COALESCE(sit.type_name, ri.rk_type)
|
</if>
|
||||||
ORDER BY sumAmount DESC
|
<if test="endDate != null">
|
||||||
|
AND ri.operation_time <![CDATA[<=]]> #{endDate}
|
||||||
|
</if>
|
||||||
|
GROUP BY ri.operation_type
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 按入库类型统计(时间范围;只统计类型有效,过滤 NULL/空/“无”) -->
|
<!-- 出库类型统计(时间) -->
|
||||||
<select id="selectTypeSummaryByRange" resultMap="RkTypePieMap">
|
<select id="statOutByOperationType"
|
||||||
<![CDATA[
|
resultType="com.zg.project.wisdom.domain.vo.StockStatisticGroupVO">
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(sit.type_code, ri.rk_type) AS rkTypeCode,
|
ri.operation_type AS groupValue,
|
||||||
COALESCE(sit.type_name, ri.rk_type) AS rkTypeName,
|
IFNULL(SUM(ri.real_qty * ri.ht_dj), 0) AS totalAmount,
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
COUNT(DISTINCT ri.pcode) AS locationCount,
|
||||||
COUNT(*) AS goodsCountTotal,
|
IFNULL(SUM(ri.real_qty), 0) AS totalQuantity,
|
||||||
COALESCE(SUM(COALESCE(ri.real_qty, 0)), 0) AS sumQty,
|
COUNT(DISTINCT ri.xm_no) AS projectCount
|
||||||
COALESCE(SUM(COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0)), 0) AS sumAmount
|
|
||||||
FROM rk_info ri
|
FROM rk_info ri
|
||||||
LEFT JOIN stock_in_type sit
|
WHERE ri.exec_status = 1
|
||||||
ON ri.rk_type = sit.type_code
|
AND ri.is_chuku = 1
|
||||||
WHERE ri.is_delete = 0
|
AND ri.is_delete = 0
|
||||||
AND (ri.is_chuku = 0 OR ri.is_chuku IS NULL) -- 当前库存口径(保持你原条件)
|
<if test="startDate != null">
|
||||||
-- 入库类型过滤:剔除 NULL / 空串 / '无'
|
AND ri.operation_time <![CDATA[>=]]> #{startDate}
|
||||||
AND ri.rk_type IS NOT NULL
|
</if>
|
||||||
AND TRIM(ri.rk_type) <> ''
|
<if test="endDate != null">
|
||||||
AND ri.rk_type <> '无'
|
AND ri.operation_time <![CDATA[<=]]> #{endDate}
|
||||||
-- 若字典表匹配到了名称且名称为“无”,也剔除;未匹配(NULL)则保留
|
</if>
|
||||||
AND (sit.type_name IS NULL OR (TRIM(sit.type_name) <> '' AND sit.type_name <> '无'))
|
GROUP BY ri.operation_type
|
||||||
-- 时间范围:闭区间 [start, end]
|
</select>
|
||||||
AND ri.rk_time >= #{start}
|
|
||||||
AND ri.rk_time < DATE_ADD(#{end}, INTERVAL 1 DAY)
|
<select id="statHomeKpi"
|
||||||
GROUP BY COALESCE(sit.type_code, ri.rk_type), COALESCE(sit.type_name, ri.rk_type)
|
resultType="com.zg.project.wisdom.domain.vo.HomeKpiVO">
|
||||||
ORDER BY sumAmount DESC
|
|
||||||
]]>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select id="selectOutTypeSummaryByRange"
|
|
||||||
resultType="com.zg.project.wisdom.domain.vo.RkTypePieVO">
|
|
||||||
<![CDATA[
|
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(sot.type_code, ri.ck_type) AS rkTypeCode,
|
/* 月入库 */
|
||||||
COALESCE(sot.type_name, ri.ck_type) AS rkTypeName,
|
COUNT(CASE WHEN ri.is_chuku = 0
|
||||||
COUNT(DISTINCT COALESCE(NULLIF(TRIM(ri.xm_no_ck), ''), ri.xm_no)) AS projectCount,
|
AND DATE_FORMAT(ri.operation_time,'%Y-%m') = DATE_FORMAT(CURDATE(),'%Y-%m')
|
||||||
COUNT(*) AS goodsCountTotal,
|
THEN 1 END) AS monthInCount,
|
||||||
SUM(IFNULL(ri.real_qty, 0)) AS sumQty,
|
|
||||||
SUM(IFNULL(ri.ht_dj, 0) * IFNULL(ri.real_qty, 0)) AS sumAmount
|
COUNT(DISTINCT CASE WHEN ri.is_chuku = 0
|
||||||
|
AND DATE_FORMAT(ri.operation_time,'%Y-%m') = DATE_FORMAT(CURDATE(),'%Y-%m')
|
||||||
|
THEN ri.xm_no END) AS monthInProjectCount,
|
||||||
|
|
||||||
|
IFNULL(SUM(CASE WHEN ri.is_chuku = 0
|
||||||
|
AND DATE_FORMAT(ri.operation_time,'%Y-%m') = DATE_FORMAT(CURDATE(),'%Y-%m')
|
||||||
|
THEN ri.real_qty * ri.ht_dj END),0) AS monthInAmount,
|
||||||
|
|
||||||
|
/* 月出库 */
|
||||||
|
COUNT(CASE WHEN ri.is_chuku = 1
|
||||||
|
AND DATE_FORMAT(ri.operation_time,'%Y-%m') = DATE_FORMAT(CURDATE(),'%Y-%m')
|
||||||
|
THEN 1 END) AS monthOutCount,
|
||||||
|
|
||||||
|
COUNT(DISTINCT CASE WHEN ri.is_chuku = 1
|
||||||
|
AND DATE_FORMAT(ri.operation_time,'%Y-%m') = DATE_FORMAT(CURDATE(),'%Y-%m')
|
||||||
|
THEN ri.xm_no END) AS monthOutProjectCount,
|
||||||
|
|
||||||
|
IFNULL(SUM(CASE WHEN ri.is_chuku = 1
|
||||||
|
AND DATE_FORMAT(ri.operation_time,'%Y-%m') = DATE_FORMAT(CURDATE(),'%Y-%m')
|
||||||
|
THEN ri.real_qty * ri.ht_dj END),0) AS monthOutAmount
|
||||||
FROM rk_info ri
|
FROM rk_info ri
|
||||||
LEFT JOIN stock_out_type sot ON ri.ck_type = sot.type_code
|
WHERE ri.exec_status = 1
|
||||||
WHERE ri.is_delete = 0
|
AND ri.is_delete = 0
|
||||||
AND ri.is_chuku = 1
|
|
||||||
-- 过滤出库类型为 NULL / 空串 / '无'
|
|
||||||
AND ri.ck_type IS NOT NULL
|
|
||||||
AND TRIM(ri.ck_type) <> ''
|
|
||||||
AND ri.ck_type <> '无'
|
|
||||||
AND (sot.type_name IS NULL OR TRIM(sot.type_name) <> '无')
|
|
||||||
-- 时间范围:闭区间 [start, end]
|
|
||||||
AND ri.ly_time >= #{start}
|
|
||||||
AND ri.ly_time < DATE_ADD(#{end}, INTERVAL 1 DAY)
|
|
||||||
GROUP BY COALESCE(sot.type_code, ri.ck_type), COALESCE(sot.type_name, ri.ck_type)
|
|
||||||
ORDER BY sumAmount DESC
|
|
||||||
]]>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 入库:rk_time 在区间内(不限制是否已出库,统计本月入库流水) -->
|
|
||||||
<select id="selectMonthlyInSummary" resultType="com.zg.project.wisdom.domain.vo.RkMonthSummaryVO">
|
|
||||||
SELECT
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
|
||||||
COUNT(*) AS itemCount,
|
|
||||||
SUM(COALESCE(ri.real_qty, 0)) AS totalQty,
|
|
||||||
SUM(COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0)) AS amountHt
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.rk_time >= #{start}
|
|
||||||
AND ri.rk_time < #{end}
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<!-- 出库:is_chuku=1,ly_time 在区间内 -->
|
|
||||||
<select id="selectMonthlyOutSummary" resultType="com.zg.project.wisdom.domain.vo.RkMonthSummaryVO">
|
|
||||||
SELECT
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
|
||||||
COUNT(*) AS itemCount,
|
|
||||||
SUM(COALESCE(ri.real_qty, 0)) AS totalQty,
|
|
||||||
SUM(COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0)) AS amountHt
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 1
|
|
||||||
AND ri.ly_time IS NOT NULL
|
|
||||||
AND ri.ly_time >= #{start}
|
|
||||||
AND ri.ly_time < #{end}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 未到货:status='0' -->
|
|
||||||
<select id="selectUndelivered" resultType="com.zg.project.wisdom.domain.vo.GysJhUndeliveredSummaryVO">
|
|
||||||
SELECT
|
|
||||||
COUNT(DISTINCT jh.xm_no) AS projectCount,
|
|
||||||
COUNT(*) AS itemCount,
|
|
||||||
SUM(COALESCE(jh.jh_qty, 0)) AS totalQty,
|
|
||||||
/* 金额 = 有效单价 × 剩余未到数量(jh_qty) */
|
|
||||||
SUM(
|
|
||||||
COALESCE(
|
|
||||||
NULLIF(jh.ht_dj, 0),
|
|
||||||
CASE WHEN COALESCE(jh.ht_qty, 0) > 0
|
|
||||||
THEN jh.jh_amt / jh.ht_qty
|
|
||||||
ELSE 0
|
|
||||||
END
|
|
||||||
) * COALESCE(jh.jh_qty, 0)
|
|
||||||
) AS amountPlan
|
|
||||||
FROM gys_jh jh
|
|
||||||
WHERE jh.is_delete = '0'
|
|
||||||
AND jh.status = '0'
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 部分未到:status='2' -->
|
|
||||||
<select id="selectPartialUndelivered" resultType="com.zg.project.wisdom.domain.vo.GysJhUndeliveredSummaryVO">
|
|
||||||
SELECT
|
|
||||||
COUNT(DISTINCT jh.xm_no) AS projectCount,
|
|
||||||
COUNT(*) AS itemCount,
|
|
||||||
SUM(COALESCE(jh.jh_qty, 0)) AS totalQty,
|
|
||||||
SUM(
|
|
||||||
COALESCE(
|
|
||||||
NULLIF(jh.ht_dj, 0),
|
|
||||||
CASE WHEN COALESCE(jh.ht_qty, 0) > 0
|
|
||||||
THEN jh.jh_amt / jh.ht_qty
|
|
||||||
ELSE 0
|
|
||||||
END
|
|
||||||
) * COALESCE(jh.jh_qty, 0)
|
|
||||||
) AS amountPlan
|
|
||||||
FROM gys_jh jh
|
|
||||||
WHERE jh.is_delete = '0'
|
|
||||||
AND jh.status = '2'
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 当前库存:按物资类型统计
|
|
||||||
- 仅统计未出库:is_chuku = 0 或 NULL
|
|
||||||
- 仅统计未删除:is_delete = 0
|
|
||||||
- 过滤 wl_type 为空/空白/'无'
|
|
||||||
-->
|
|
||||||
<select id="selectCurrentStockByWlType"
|
|
||||||
resultType="com.zg.project.wisdom.domain.vo.WlTypeStockStatVO">
|
|
||||||
SELECT
|
|
||||||
mt.type_name AS typeName,
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount,
|
|
||||||
COUNT(*) AS itemCount,
|
|
||||||
COALESCE(SUM(COALESCE(ri.real_qty, 0)), 0) AS totalQty,
|
|
||||||
COALESCE(SUM(COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0)), 0) AS amountHt
|
|
||||||
FROM rk_info ri
|
|
||||||
JOIN material_type mt
|
|
||||||
ON mt.type_code = ri.wl_type
|
|
||||||
AND mt.status = 1
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND (ri.is_chuku = 0 OR ri.is_chuku IS NULL)
|
|
||||||
AND ri.wl_type IS NOT NULL
|
|
||||||
AND TRIM(ri.wl_type) != ''
|
|
||||||
AND ri.wl_type != '无'
|
|
||||||
AND mt.type_name != '无'
|
|
||||||
GROUP BY mt.type_code, mt.type_name
|
|
||||||
ORDER BY amountHt DESC
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 当前库存:入库时间 > 30 天(仅未出库 & 未删除 & rk_time 非空) -->
|
|
||||||
<select id="selectAgeGt30Summary"
|
|
||||||
resultType="com.zg.project.wisdom.domain.vo.RkTypePieVO">
|
|
||||||
SELECT
|
|
||||||
COUNT(DISTINCT ri.xm_no) AS projectCount, -- 去重项目数
|
|
||||||
COUNT(*) AS goodsCountTotal, -- 条目数
|
|
||||||
COALESCE(SUM(COALESCE(ri.real_qty, 0)), 0) AS sumQty, -- 数量合计
|
|
||||||
COALESCE(SUM(COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0)), 0) AS sumAmount -- 金额合计
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND (ri.is_chuku = 0 OR ri.is_chuku IS NULL)
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND DATEDIFF(CURDATE(), DATE(ri.rk_time)) > 30
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 入库原始行 -->
|
|
||||||
<select id="selectInRange" resultType="com.zg.project.wisdom.domain.vo.RkInVO">
|
|
||||||
SELECT
|
|
||||||
ri.xm_no AS xmNo,
|
|
||||||
ri.rk_time AS rkTime
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.rk_time IS NOT NULL
|
|
||||||
AND ri.rk_time <![CDATA[>=]]> #{startTs}
|
|
||||||
AND ri.rk_time <![CDATA[<]]> #{endTs}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 出库原始行(有效时间=ly_time 优先,否则 update_time;项目号=xm_no_ck 优先,否则 xm_no) -->
|
|
||||||
<select id="selectOutRange" resultType="com.zg.project.wisdom.domain.vo.RkOutVO">
|
|
||||||
SELECT
|
|
||||||
ri.xm_no_ck AS xmNoCk,
|
|
||||||
ri.xm_no AS xmNo,
|
|
||||||
ri.ly_time AS lyTime,
|
|
||||||
ri.update_time AS updateTime
|
|
||||||
FROM rk_info ri
|
|
||||||
WHERE ri.is_delete = 0
|
|
||||||
AND ri.is_chuku = 1
|
|
||||||
AND (
|
|
||||||
(ri.ly_time IS NOT NULL
|
|
||||||
AND ri.ly_time <![CDATA[>=]]> #{startTs}
|
|
||||||
AND ri.ly_time <![CDATA[<]]> #{endTs})
|
|
||||||
OR (ri.ly_time IS NULL AND ri.update_time IS NOT NULL
|
|
||||||
AND ri.update_time <![CDATA[>=]]> #{startTs}
|
|
||||||
AND ri.update_time <![CDATA[<]]> #{endTs})
|
|
||||||
)
|
|
||||||
</select>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 外层聚合到 SceneAvailableVO,并级联 positions(PcdeDetailSimpleVO 列表) -->
|
|
||||||
<resultMap id="SceneAvailableMap"
|
|
||||||
type="com.zg.project.wisdom.domain.vo.SceneAvailableVO">
|
|
||||||
<result property="sceneCode" column="sceneCode"/>
|
|
||||||
<result property="sceneName" column="sceneName"/>
|
|
||||||
<result property="availableCount" column="availableCount"/>
|
|
||||||
<!-- 把外层 select 的 warehouseCode、sceneCode 作为参数传给内层查询 -->
|
|
||||||
<collection property="positions"
|
|
||||||
ofType="com.zg.project.wisdom.domain.vo.PcdeDetailSimpleVO"
|
|
||||||
select="selectAvailablePositionsByWarehouseAndScene"
|
|
||||||
column="{warehouseCode=warehouseCode,sceneCode=sceneCode}"/>
|
|
||||||
</resultMap>
|
|
||||||
|
|
||||||
<!-- 外层:按场景统计可用数量(并输出 warehouseCode、sceneCode 提供给内层) -->
|
|
||||||
<select id="selectAvailableByWarehouse" parameterType="string"
|
|
||||||
resultMap="SceneAvailableMap">
|
|
||||||
SELECT
|
|
||||||
#{warehouseCode} AS warehouseCode, -- 传给内层用
|
|
||||||
p.scene AS sceneCode,
|
|
||||||
sm.scene_name AS sceneName,
|
|
||||||
COUNT(*) AS availableCount
|
|
||||||
FROM pcde_detail p
|
|
||||||
LEFT JOIN scene_mapping sm
|
|
||||||
ON sm.scene_code = p.scene
|
|
||||||
LEFT JOIN rk_info ri
|
|
||||||
ON ri.pcode = p.pcode
|
|
||||||
AND ri.is_delete = 0
|
|
||||||
AND (ri.is_chuku = 0 OR ri.is_chuku IS NULL) -- 未出库 => 占用
|
|
||||||
WHERE p.is_delete = '0'
|
|
||||||
AND p.warehouse = #{warehouseCode}
|
|
||||||
AND ri.id IS NULL -- 无占用 => 可用
|
|
||||||
GROUP BY p.scene, sm.scene_name
|
|
||||||
ORDER BY p.scene
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 内层:指定仓库 + 场景,查询该场景的可用库位明细 -->
|
|
||||||
<select id="selectAvailablePositionsByWarehouseAndScene"
|
|
||||||
resultType="com.zg.project.wisdom.domain.vo.PcdeDetailSimpleVO">
|
|
||||||
SELECT
|
|
||||||
p.pcode,
|
|
||||||
p.tag,
|
|
||||||
p.encoded_id AS encodedId
|
|
||||||
FROM pcde_detail p
|
|
||||||
LEFT JOIN rk_info ri
|
|
||||||
ON ri.pcode = p.pcode
|
|
||||||
AND ri.is_delete = 0
|
|
||||||
AND (ri.is_chuku = 0 OR ri.is_chuku IS NULL)
|
|
||||||
WHERE p.is_delete = '0'
|
|
||||||
AND p.warehouse = #{warehouseCode}
|
|
||||||
AND p.scene = #{sceneCode}
|
|
||||||
AND ri.id IS NULL
|
|
||||||
ORDER BY p.pcode
|
|
||||||
</select>
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
Reference in New Issue
Block a user