feat(wms): 优化钢卷库区操作记录吞吐报表统计功能
- 后端新增 statistics 接口聚合图表数据,避免前端遍历计算 - 新增 WmsCoilWarehouseOperationLogStatisticsVo 数据传输对象 - 实现按操作人汇总、按日趋势、汇总指标三个维度的数据查询 - 前端 record 页面集成统计卡片、趋势图、饼图、柱状图展示 - 优化分页逻辑,移除前端全量数据存储和分页计算 - 添加完整的 SQL 统计查询语句支持多维度数据聚合
This commit is contained in:
@@ -71,4 +71,13 @@ export function getCoilWarehouseOperationLogByCoilId(params) {
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 吞吐报表统计(后端聚合图表数据)
|
||||
export function getStatistics(params) {
|
||||
return request({
|
||||
url: '/wms/coilWarehouseOperationLog/statistics',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
@@ -177,14 +177,14 @@
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
|
||||
@pagination="setPageData" />
|
||||
@pagination="getList" />
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCoilWarehouseOperationLog, delCoilWarehouseOperationLog } from "@/api/wms/coilWarehouseOperationLog";
|
||||
import { listCoilWarehouseOperationLog, delCoilWarehouseOperationLog, getStatistics } from "@/api/wms/coilWarehouseOperationLog";
|
||||
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo";
|
||||
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
|
||||
import dayjs from "dayjs";
|
||||
@@ -219,8 +219,6 @@ export default {
|
||||
total: 0,
|
||||
// 钢卷库区操作记录表格数据
|
||||
coilWarehouseOperationLogList: [],
|
||||
// 原始数据(用于前端分页)
|
||||
allData: [],
|
||||
// 统计指标
|
||||
stats: {
|
||||
totalCount: 0,
|
||||
@@ -248,6 +246,7 @@ export default {
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.getStats();
|
||||
},
|
||||
mounted() {
|
||||
// 初始化图表
|
||||
@@ -266,7 +265,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 查询钢卷库区操作记录列表 */
|
||||
/** 查询钢卷库区操作记录列表(仅表格分页数据) */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 处理时间范围
|
||||
@@ -274,67 +273,50 @@ export default {
|
||||
this.queryParams.createStartTime = this.queryParams.createTimeRange[0];
|
||||
this.queryParams.createEndTime = this.queryParams.createTimeRange[1];
|
||||
}
|
||||
// 移除分页参数,获取全部数据
|
||||
const params = { ...this.queryParams, pageNum: 1, pageSize: 10000 };
|
||||
const params = {
|
||||
...this.queryParams,
|
||||
pageNum: this.queryParams.pageNum,
|
||||
pageSize: this.queryParams.pageSize
|
||||
};
|
||||
|
||||
listCoilWarehouseOperationLog(params).then(response => {
|
||||
this.allData = response.rows;
|
||||
this.coilWarehouseOperationLogList = response.rows;
|
||||
this.total = response.total;
|
||||
this.calculateStats();
|
||||
this.setPageData();
|
||||
this.loading = false;
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 设置分页数据 */
|
||||
setPageData() {
|
||||
const start = (this.queryParams.pageNum - 1) * this.queryParams.pageSize;
|
||||
const end = start + parseInt(this.queryParams.pageSize);
|
||||
this.coilWarehouseOperationLogList = this.allData.slice(start, end);
|
||||
},
|
||||
/** 计算统计指标 */
|
||||
calculateStats() {
|
||||
// 计算操作记录总数
|
||||
this.stats.totalCount = this.allData.length;
|
||||
/** 查询吞吐报表统计(图表 + 卡片,后端聚合) */
|
||||
getStats() {
|
||||
const params = { ...this.queryParams };
|
||||
if (params.createTimeRange) {
|
||||
params.createStartTime = params.createTimeRange[0];
|
||||
params.createEndTime = params.createTimeRange[1];
|
||||
}
|
||||
delete params.pageNum;
|
||||
delete params.pageSize;
|
||||
|
||||
// 计算总重量
|
||||
this.stats.totalWeight = this.allData.reduce((sum, item) => {
|
||||
if (item.coil && item.coil.netWeight) {
|
||||
return sum + parseFloat(item.coil.netWeight);
|
||||
}
|
||||
return sum;
|
||||
}, 0).toFixed(2);
|
||||
|
||||
// 计算涉及的库位数量(去重)
|
||||
const warehouseIds = new Set();
|
||||
this.allData.forEach(item => {
|
||||
if (item.warehouse && item.warehouse.actualWarehouseId) {
|
||||
warehouseIds.add(item.warehouse.actualWarehouseId);
|
||||
}
|
||||
getStatistics(params).then(response => {
|
||||
const data = response.data;
|
||||
this.stats.totalCount = Number(data.totalCount) || 0;
|
||||
this.stats.totalWeight = Number(data.totalWeight || 0).toFixed(2);
|
||||
this.stats.warehouseCount = Number(data.warehouseCount) || 0;
|
||||
this.userSummaryData = (data.userSummary || []).map(item => ({
|
||||
createBy: item.createBy,
|
||||
coilCount: Number(item.coilCount) || 0,
|
||||
totalWeight: Number(item.totalWeight || 0)
|
||||
}));
|
||||
// 更新图表
|
||||
this.updateTrendChart((data.trendData || []).map(item => ({
|
||||
date: item.date,
|
||||
count: Number(item.count) || 0
|
||||
})));
|
||||
this.updatePieChart(this.userSummaryData);
|
||||
this.updateBarChart(this.userSummaryData);
|
||||
}).catch(err => {
|
||||
console.error('获取统计失败:', err);
|
||||
});
|
||||
this.stats.warehouseCount = warehouseIds.size;
|
||||
|
||||
// 按操作人汇总数据
|
||||
const userMap = {};
|
||||
this.allData.forEach(item => {
|
||||
const user = item.createBy || '未知';
|
||||
if (!userMap[user]) {
|
||||
userMap[user] = {
|
||||
createBy: user,
|
||||
coilCount: 0,
|
||||
totalWeight: 0
|
||||
};
|
||||
}
|
||||
userMap[user].coilCount++;
|
||||
if (item.coil && item.coil.netWeight) {
|
||||
userMap[user].totalWeight += parseFloat(item.coil.netWeight);
|
||||
}
|
||||
});
|
||||
|
||||
// 转换为数组并按操作卷数降序排序
|
||||
this.userSummaryData = Object.values(userMap).sort((a, b) => b.coilCount - a.coilCount);
|
||||
|
||||
// 更新图表数据
|
||||
this.updateCharts();
|
||||
},
|
||||
/** 初始化图表 */
|
||||
initCharts() {
|
||||
@@ -345,29 +327,12 @@ export default {
|
||||
// 柱状图
|
||||
this.barChart = echarts.init(document.getElementById('barChart'));
|
||||
},
|
||||
/** 更新图表数据 */
|
||||
updateCharts() {
|
||||
this.updateTrendChart();
|
||||
this.updatePieChart();
|
||||
this.updateBarChart();
|
||||
},
|
||||
/** 更新趋势图 */
|
||||
updateTrendChart() {
|
||||
updateTrendChart(trendData) {
|
||||
if (!this.trendChart) return;
|
||||
|
||||
// 按日期分组数据
|
||||
const dateMap = {};
|
||||
this.allData.forEach(item => {
|
||||
const date = item.createTime.substring(0, 10);
|
||||
if (!dateMap[date]) {
|
||||
dateMap[date] = 0;
|
||||
}
|
||||
dateMap[date]++;
|
||||
});
|
||||
|
||||
// 转换为数组并排序
|
||||
const dateArr = Object.keys(dateMap).sort();
|
||||
const dataArr = dateArr.map(date => dateMap[date]);
|
||||
const dateArr = (trendData || []).map(item => item.date);
|
||||
const dataArr = (trendData || []).map(item => item.count);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
@@ -390,26 +355,13 @@ export default {
|
||||
this.trendChart.setOption(option);
|
||||
},
|
||||
/** 更新饼图 */
|
||||
updatePieChart() {
|
||||
updatePieChart(userSummaryData) {
|
||||
if (!this.pieChart) return;
|
||||
|
||||
// 按操作人分组数据
|
||||
const userMap = {};
|
||||
this.allData.forEach(item => {
|
||||
const user = item.createBy || '未知';
|
||||
if (!userMap[user]) {
|
||||
userMap[user] = 0;
|
||||
}
|
||||
userMap[user]++;
|
||||
});
|
||||
|
||||
// 转换为数组并按操作次数从大到小排序
|
||||
const data = Object.entries(userMap)
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map(([user, value]) => ({
|
||||
name: user,
|
||||
value: value
|
||||
}));
|
||||
const data = (userSummaryData || []).map(item => ({
|
||||
name: item.createBy,
|
||||
value: item.coilCount
|
||||
}));
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
@@ -425,23 +377,11 @@ export default {
|
||||
this.pieChart.setOption(option);
|
||||
},
|
||||
/** 更新柱状图 */
|
||||
updateBarChart() {
|
||||
updateBarChart(userSummaryData) {
|
||||
if (!this.barChart) return;
|
||||
|
||||
// 按操作人分组数据
|
||||
const userMap = {};
|
||||
this.allData.forEach(item => {
|
||||
const user = item.createBy || '未知';
|
||||
if (!userMap[user]) {
|
||||
userMap[user] = 0;
|
||||
}
|
||||
userMap[user]++;
|
||||
});
|
||||
|
||||
// 转换为数组并按操作次数从大到小排序
|
||||
const sortedEntries = Object.entries(userMap).sort((a, b) => b[1] - a[1]);
|
||||
const users = sortedEntries.map(([user]) => user);
|
||||
const counts = sortedEntries.map(([, count]) => count);
|
||||
const users = (userSummaryData || []).map(item => item.createBy);
|
||||
const counts = (userSummaryData || []).map(item => item.coilCount);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
@@ -470,6 +410,7 @@ export default {
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
this.getStats();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogVo;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogExportVo;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogStatisticsVo;
|
||||
import com.klp.domain.bo.WmsCoilWarehouseOperationLogBo;
|
||||
import com.klp.service.IWmsCoilWarehouseOperationLogService;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
@@ -178,5 +179,13 @@ public class WmsCoilWarehouseOperationLogController extends BaseController {
|
||||
ExcelUtil.exportExcel(list, "钢卷库区操作记录导出", WmsCoilWarehouseOperationLogExportVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 吞吐报表统计 —— 后端聚合图表数据,前端仅负责渲染
|
||||
*/
|
||||
@GetMapping("/statistics")
|
||||
public R<WmsCoilWarehouseOperationLogStatisticsVo> statistics(WmsCoilWarehouseOperationLogBo bo) {
|
||||
return R.ok(iWmsCoilWarehouseOperationLogService.statistics(bo));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.klp.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 吞吐报表统计结果 VO —— 后端聚合所有图表数据,前端不再遍历全量 rows
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-06-22
|
||||
*/
|
||||
@Data
|
||||
public class WmsCoilWarehouseOperationLogStatisticsVo {
|
||||
|
||||
/** 操作记录总数 */
|
||||
private long totalCount;
|
||||
|
||||
/** 总重量(kg),所有关联钢卷净重之和 */
|
||||
private BigDecimal totalWeight;
|
||||
|
||||
/** 涉及库位数量(去重) */
|
||||
private long warehouseCount;
|
||||
|
||||
/** 操作人汇总(用于左侧表格 + 饼图 + 柱状图) */
|
||||
private List<UserSummary> userSummary;
|
||||
|
||||
/** 按日趋势数据(用于折线图) */
|
||||
private List<TrendItem> trendData;
|
||||
|
||||
// ---------- inner types ----------
|
||||
|
||||
@Data
|
||||
public static class UserSummary {
|
||||
/** 操作人 */
|
||||
private String createBy;
|
||||
/** 操作卷数 */
|
||||
private long coilCount;
|
||||
/** 总重量(kg) */
|
||||
private BigDecimal totalWeight;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class TrendItem {
|
||||
/** 日期,格式 yyyy-MM-dd */
|
||||
private String date;
|
||||
/** 当天操作笔数 */
|
||||
private long count;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.klp.mapper;
|
||||
|
||||
import com.klp.domain.WmsCoilWarehouseOperationLog;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogVo;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogStatisticsVo;
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@@ -21,4 +22,34 @@ public interface WmsCoilWarehouseOperationLogMapper extends BaseMapperPlus<WmsCo
|
||||
@Param("inOutType") Integer inOutType,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* 吞吐报表统计 —— 汇总指标(总数、总重量、涉及库位数)
|
||||
*/
|
||||
WmsCoilWarehouseOperationLogStatisticsVo selectStatisticsSummary(@Param("actualWarehouseId") Long actualWarehouseId,
|
||||
@Param("operationType") Integer operationType,
|
||||
@Param("inOutType") Integer inOutType,
|
||||
@Param("createBy") String createBy,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* 吞吐报表统计 —— 按操作人汇总
|
||||
*/
|
||||
List<WmsCoilWarehouseOperationLogStatisticsVo.UserSummary> selectUserSummary(@Param("actualWarehouseId") Long actualWarehouseId,
|
||||
@Param("operationType") Integer operationType,
|
||||
@Param("inOutType") Integer inOutType,
|
||||
@Param("createBy") String createBy,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* 吞吐报表统计 —— 按日趋势
|
||||
*/
|
||||
List<WmsCoilWarehouseOperationLogStatisticsVo.TrendItem> selectTrendData(@Param("actualWarehouseId") Long actualWarehouseId,
|
||||
@Param("operationType") Integer operationType,
|
||||
@Param("inOutType") Integer inOutType,
|
||||
@Param("createBy") String createBy,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.klp.common.core.domain.PageQuery;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Collection;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogExportVo;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogStatisticsVo;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@@ -85,4 +86,12 @@ public interface IWmsCoilWarehouseOperationLogService {
|
||||
* @return 导出数据列表
|
||||
*/
|
||||
List<WmsCoilWarehouseOperationLogExportVo> exportBySecondWarehouseIdAndTimeRange(Long secondWarehouseId, Integer operationType, Integer inOutType, Date startTime, Date endTime);
|
||||
|
||||
/**
|
||||
* 吞吐报表统计 —— 后端聚合,返回图表所需全部数据
|
||||
*
|
||||
* @param bo 查询条件(与 /list 共用同一套 BO)
|
||||
* @return 统计结果(汇总卡片 + 操作人排名 + 按日趋势)
|
||||
*/
|
||||
WmsCoilWarehouseOperationLogStatisticsVo statistics(WmsCoilWarehouseOperationLogBo bo);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.springframework.stereotype.Service;
|
||||
import com.klp.domain.bo.WmsCoilWarehouseOperationLogBo;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogVo;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogExportVo;
|
||||
import com.klp.domain.vo.WmsCoilWarehouseOperationLogStatisticsVo;
|
||||
import java.math.BigDecimal;
|
||||
import com.klp.domain.vo.WmsMaterialCoilVo;
|
||||
import com.klp.domain.WmsCoilWarehouseOperationLog;
|
||||
@@ -352,4 +353,34 @@ public class WmsCoilWarehouseOperationLogServiceImpl implements IWmsCoilWarehous
|
||||
default: return String.valueOf(inOutType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WmsCoilWarehouseOperationLogStatisticsVo statistics(WmsCoilWarehouseOperationLogBo bo) {
|
||||
Long actualWarehouseId = bo.getActualWarehouseId();
|
||||
Integer operationType = bo.getOperationType();
|
||||
Integer inOutType = bo.getInOutType();
|
||||
String createBy = bo.getCreateBy();
|
||||
Date startTime = bo.getCreateStartTime();
|
||||
Date endTime = bo.getCreateEndTime();
|
||||
|
||||
// 一次 RPC 内三次轻量 GROUP BY 查询,远比拉取全量 rows 再聚合快
|
||||
WmsCoilWarehouseOperationLogStatisticsVo summary =
|
||||
baseMapper.selectStatisticsSummary(actualWarehouseId, operationType, inOutType, createBy, startTime, endTime);
|
||||
|
||||
List<WmsCoilWarehouseOperationLogStatisticsVo.UserSummary> userSummary =
|
||||
baseMapper.selectUserSummary(actualWarehouseId, operationType, inOutType, createBy, startTime, endTime);
|
||||
|
||||
List<WmsCoilWarehouseOperationLogStatisticsVo.TrendItem> trendData =
|
||||
baseMapper.selectTrendData(actualWarehouseId, operationType, inOutType, createBy, startTime, endTime);
|
||||
|
||||
if (summary == null) {
|
||||
summary = new WmsCoilWarehouseOperationLogStatisticsVo();
|
||||
summary.setTotalCount(0);
|
||||
summary.setTotalWeight(BigDecimal.ZERO);
|
||||
summary.setWarehouseCount(0);
|
||||
}
|
||||
summary.setUserSummary(userSummary);
|
||||
summary.setTrendData(trendData);
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,4 +129,66 @@
|
||||
ORDER BY log.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- ==================== 吞吐报表统计 SQL ==================== -->
|
||||
|
||||
<!-- 公共过滤条件片段 -->
|
||||
<sql id="statisticsWhere">
|
||||
<where>
|
||||
log.del_flag = 0
|
||||
<if test="actualWarehouseId != null">
|
||||
AND log.actual_warehouse_id = #{actualWarehouseId}
|
||||
</if>
|
||||
<if test="operationType != null">
|
||||
AND log.operation_type = #{operationType}
|
||||
</if>
|
||||
<if test="inOutType != null">
|
||||
AND log.in_out_type = #{inOutType}
|
||||
</if>
|
||||
<if test="createBy != null and createBy != ''">
|
||||
AND log.create_by = #{createBy}
|
||||
</if>
|
||||
<if test="startTime != null">
|
||||
AND log.create_time >= #{startTime}
|
||||
</if>
|
||||
<if test="endTime != null">
|
||||
AND log.create_time <= #{endTime}
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 汇总指标:总数、总重量、涉及库位数 -->
|
||||
<select id="selectStatisticsSummary" resultType="com.klp.domain.vo.WmsCoilWarehouseOperationLogStatisticsVo">
|
||||
SELECT
|
||||
COUNT(*) AS totalCount,
|
||||
COALESCE(SUM(mc.net_weight), 0) AS totalWeight,
|
||||
COUNT(DISTINCT log.actual_warehouse_id) AS warehouseCount
|
||||
FROM wms_coil_warehouse_operation_log log
|
||||
LEFT JOIN wms_material_coil mc ON log.coil_id = mc.coil_id AND mc.del_flag = 0
|
||||
<include refid="statisticsWhere"/>
|
||||
</select>
|
||||
|
||||
<!-- 按操作人汇总 -->
|
||||
<select id="selectUserSummary" resultType="com.klp.domain.vo.WmsCoilWarehouseOperationLogStatisticsVo$UserSummary">
|
||||
SELECT
|
||||
log.create_by AS createBy,
|
||||
COUNT(*) AS coilCount,
|
||||
COALESCE(SUM(mc.net_weight), 0) AS totalWeight
|
||||
FROM wms_coil_warehouse_operation_log log
|
||||
LEFT JOIN wms_material_coil mc ON log.coil_id = mc.coil_id AND mc.del_flag = 0
|
||||
<include refid="statisticsWhere"/>
|
||||
GROUP BY log.create_by
|
||||
ORDER BY coilCount DESC
|
||||
</select>
|
||||
|
||||
<!-- 按日趋势 -->
|
||||
<select id="selectTrendData" resultType="com.klp.domain.vo.WmsCoilWarehouseOperationLogStatisticsVo$TrendItem">
|
||||
SELECT
|
||||
DATE_FORMAT(log.create_time, '%Y-%m-%d') AS date,
|
||||
COUNT(*) AS count
|
||||
FROM wms_coil_warehouse_operation_log log
|
||||
<include refid="statisticsWhere"/>
|
||||
GROUP BY DATE_FORMAT(log.create_time, '%Y-%m-%d')
|
||||
ORDER BY date ASC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user