feat(module): 饲喂量统计

+ 添加量饲喂量统计功能
+ 解决了其他两个页面的若干逻辑错误
+ 优化了配料清单的缓存结构:
    + 将缓存和同步过程移动到Service层, 以便其他模块调用
This commit is contained in:
HashMap 2025-08-24 23:40:21 +08:00
parent 02634eb7b6
commit 02d95fc51f
14 changed files with 881 additions and 125 deletions

View File

@ -1,15 +1,10 @@
package com.zhyc.module.feed.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import com.zhyc.module.feed.domain.SgFeedPlan;
import com.zhyc.module.feed.domain.SgFormulaManagement;
import com.zhyc.module.feed.service.ISgFeedPlanService;
import com.zhyc.module.feed.service.ISgFormulaManagementService;
import com.zhyc.module.feed.service.impl.SgFeedListServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
@ -41,19 +36,12 @@ import com.zhyc.common.core.page.TableDataInfo;
public class SgFeedListController extends BaseController {
private final ISgFeedListService sgFeedListService;
private final ISgFormulaManagementService sgFormulaManagementService;
private final ISgFeedPlanService sgFeedPlanService;
private final Map<String, SgFeedList> sgFeedListMap = new HashMap<>();
public static boolean refresh = true;
@Autowired
public SgFeedListController(ISgFeedListService sgFeedListService, ISgFormulaManagementService sgFormulaManagementService, ISgFeedPlanService sgFeedPlanService) {
public SgFeedListController(ISgFeedListService sgFeedListService) {
this.sgFeedListService = sgFeedListService;
this.sgFormulaManagementService = sgFormulaManagementService;
this.sgFeedPlanService = sgFeedPlanService;
}
/**
@ -68,7 +56,7 @@ public class SgFeedListController extends BaseController {
当配方管理表出现更新 饲喂计划表出现增删改时会将refresh置为true 通知此处进行刷新
*/
if (refresh) {
SyncFeedList();
sgFeedListService.SyncFeedList();
refresh = false;
}
startPage();
@ -78,7 +66,7 @@ public class SgFeedListController extends BaseController {
for (SgFeedList item : list) {
String key = item.getFormulaId() + "_" + item.getFormulaBatchId();
// 从缓存中取出完整对象
SgFeedList itemInCache = sgFeedListMap.getOrDefault(key, item);
SgFeedList itemInCache = SgFeedListServiceImpl.getSgFeedListMap().getOrDefault(key, item);
// 将数据库查询的基本信息替换掉缓存中去除的内容 - 前端展示与修改需要
itemInCache.setId(item.getId());
itemInCache.setFormulaBatchId(item.getFormulaBatchId());
@ -143,94 +131,4 @@ public class SgFeedListController extends BaseController {
return toAjax(sgFeedListService.deleteSgFeedListByIds(ids));
}
public void SyncFeedList() {
// 清空旧缓存
sgFeedListMap.clear();
// 获取配方管理和现有配料清单内容
List<SgFormulaManagement> formulaManagementList = sgFormulaManagementService.selectSgFormulaManagementList(new SgFormulaManagement());
List<SgFeedList> feedLists = sgFeedListService.selectSgFeedListList(new SgFeedList());
// 将最新查询的配料清单加入缓存
for (SgFeedList sgFeedList : feedLists) {
sgFeedListMap.put(sgFeedList.getFormulaId() + "_" + sgFeedList.getFormulaBatchId(), sgFeedList);
}
// 与新的配方管理列表同步 - 如果配料清单没有对应数据则加入
for (SgFormulaManagement sgFormulaManagement : formulaManagementList) {
// 匹配 但忽略模板配方
if (sgFormulaManagement.getFormulaId() != null && sgFormulaManagement.getBatchId() != null && !sgFormulaManagement.getBatchId().equals("0")) {
// 查询当前配方管理项是否存在现有配料计划中 (不论是否存在都要设置,因为缓存被清空,存在则更新,不存在则插入)
boolean isExist = sgFeedListMap.containsKey(sgFormulaManagement.getFormulaId() + "_" + sgFormulaManagement.getBatchId());
// 标志位 : 如果当前配方不在饲喂计划中则不生成配量清单
boolean isPlan = true;
// 设置缓存对象具体值
SgFeedList sgFeedList = new SgFeedList();
sgFeedList.setFormulaId(sgFormulaManagement.getFormulaId());
sgFeedList.setFormulaBatchId(sgFormulaManagement.getBatchId());
sgFeedList.setFormulaList(sgFormulaManagement.getSgFormulaList());
sgFeedList.setRootFormula(sgFormulaManagement);
// 从饲喂计划列表中查出对应值(饲喂量需要计划中的比例计算)
SgFeedPlan rootPlanQuery = new SgFeedPlan();
rootPlanQuery.setFormulaId(sgFormulaManagement.getFormulaId());
rootPlanQuery.setBatchId(sgFormulaManagement.getBatchId());
List<SgFeedPlan> sgFeedPlans = sgFeedPlanService.selectSgFeedPlanList(rootPlanQuery);
// 为空则标识当前配方不在饲喂计划中 && 不在缓存中设置
if (sgFeedPlans.isEmpty()) {
isPlan = false;
} else {
// rootPlan中存储的是该配方批号的总量
SgFeedPlan rootPlan = computePlanTotal(sgFeedPlans);
// 将计划实体对象设置到配料清单中
sgFeedList.setRootPlan(rootPlan);
// 完整的配料清单对象加入缓存
sgFeedListMap.put(sgFormulaManagement.getFormulaId() + "_" + sgFormulaManagement.getBatchId(), sgFeedList);
}
// 不存在则插入
if (!isExist && isPlan) {
sgFeedListService.insertSgFeedList(sgFeedList);
}
}
}
}
/**
* 计算某个配方某个批次的总和值
*
* @param sgFeedPlans 配方计划列表
* @return 各个值总和
*/
private static SgFeedPlan computePlanTotal(List<SgFeedPlan> sgFeedPlans) {
SgFeedPlan rootPlan = new SgFeedPlan();
if (!sgFeedPlans.isEmpty()) {
int sheepCountTotal = 0;
double sheepDailySize = 0.0;
double planFeedMorningSize = 0.0;
double planFeedNoonSize = 0.0;
double planFeedAfternoonSize = 0.0;
double planFeedTotalSize = 0.0;
for (SgFeedPlan sgFeedPlan : sgFeedPlans) {
sheepCountTotal += sgFeedPlan.getSheepCount();
sheepDailySize += sgFeedPlan.getPlanDailySize();
planFeedMorningSize += sgFeedPlan.getPlanMorningSize();
planFeedNoonSize += sgFeedPlan.getPlanNoonSize();
planFeedAfternoonSize += sgFeedPlan.getPlanAfternoonSize();
planFeedTotalSize += sgFeedPlan.getPlanFeedTotal();
}
rootPlan.setSheepCount(sheepCountTotal);
rootPlan.setPlanDailySize(sheepDailySize);
rootPlan.setPlanMorningSize(planFeedMorningSize);
rootPlan.setPlanNoonSize(planFeedNoonSize);
rootPlan.setPlanAfternoonSize(planFeedAfternoonSize);
rootPlan.setPlanFeedTotal(planFeedTotalSize);
// 设置计划日期
rootPlan.setPlanDate(sgFeedPlans.get(0).getPlanDate());
}
return rootPlan;
}
}

View File

@ -0,0 +1,129 @@
package com.zhyc.module.feed.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.zhyc.common.utils.uuid.UUID;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.zhyc.common.annotation.Log;
import com.zhyc.common.core.controller.BaseController;
import com.zhyc.common.core.domain.AjaxResult;
import com.zhyc.common.enums.BusinessType;
import com.zhyc.module.feed.domain.SgFeedStatistic;
import com.zhyc.module.feed.service.ISgFeedStatisticService;
import com.zhyc.common.utils.poi.ExcelUtil;
import com.zhyc.common.core.page.TableDataInfo;
/**
* 饲喂量统计Controller
*
* @author HashMap
* @date 2025-08-23
*/
@RestController
@RequestMapping("/feed/FeedStatistic")
@Transactional(rollbackFor = Exception.class)
public class SgFeedStatisticController extends BaseController {
private final ISgFeedStatisticService sgFeedStatisticService;
public SgFeedStatisticController(ISgFeedStatisticService sgFeedStatisticService) {
this.sgFeedStatisticService = sgFeedStatisticService;
}
/**
* 查询饲喂量统计列表
*/
@PreAuthorize("@ss.hasPermi('feed:FeedStatistic:list')")
@GetMapping("/list")
public TableDataInfo list(SgFeedStatistic sgFeedStatistic) {
startPage();
List<SgFeedStatistic> list = sgFeedStatisticService.selectSgFeedStatisticList(sgFeedStatistic);
return getDataTable(list);
}
/**
* 导出饲喂量统计列表
*/
@PreAuthorize("@ss.hasPermi('feed:FeedStatistic:export')")
@Log(title = "饲喂量统计", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, SgFeedStatistic sgFeedStatistic) {
List<SgFeedStatistic> list = sgFeedStatisticService.selectSgFeedStatisticList(sgFeedStatistic);
ExcelUtil<SgFeedStatistic> util = new ExcelUtil<>(SgFeedStatistic.class);
util.exportExcel(response, list, "饲喂量统计数据");
}
/**
* 获取饲喂量统计详细信息
*/
@PreAuthorize("@ss.hasPermi('feed:FeedStatistic:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") String id) {
return success(sgFeedStatisticService.selectSgFeedStatisticById(id));
}
/**
* 新增饲喂量统计
*/
@PreAuthorize("@ss.hasPermi('feed:FeedStatistic:add')")
@Log(title = "饲喂量统计", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody SgFeedStatistic sgFeedStatistic) {
if (null == sgFeedStatistic.getFormulaId() && null == sgFeedStatistic.getFormulaBatchId()) {
throw new RuntimeException("ERROR: 数据为空");
}
List<SgFeedStatistic> isExist = sgFeedStatisticService.selectSgFeedStatisticList(sgFeedStatistic);
if (null != isExist && !isExist.isEmpty()) {
throw new RuntimeException("WARNING: 数据重复");
}
// 设定唯一标识符主键
sgFeedStatistic.setId(UUID.randomUUID().toString());
/*
* 初始化数据
* 弃用: 此处不再需要初始化前端选定批号后会触发预载, 此处再初始化会覆盖前端后续的自定义数据
*/
// sgFeedStatisticService.getInitSgFeedStatistic(sgFeedStatistic);
return toAjax(sgFeedStatisticService.insertSgFeedStatistic(sgFeedStatistic));
}
/**
* 修改饲喂量统计
*/
@PreAuthorize("@ss.hasPermi('feed:FeedStatistic:edit')")
@Log(title = "饲喂量统计", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody SgFeedStatistic sgFeedStatistic) {
return toAjax(sgFeedStatisticService.updateSgFeedStatistic(sgFeedStatistic));
}
/**
* 删除饲喂量统计
*/
@PreAuthorize("@ss.hasPermi('feed:FeedStatistic:remove')")
@Log(title = "饲喂量统计", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable String[] ids) {
return toAjax(sgFeedStatisticService.deleteSgFeedStatisticByIds(ids));
}
@GetMapping("/init")
public TableDataInfo getInitData(SgFeedStatistic sgFeedStatistic){
sgFeedStatisticService.getInitSgFeedStatistic(sgFeedStatistic);
// 兼容写法 - 实际只是为了返回一个 sgFeedStatistic
List<SgFeedStatistic> list = new ArrayList<>();
list.add(sgFeedStatistic);
return getDataTable(list);
}
}

View File

@ -0,0 +1,98 @@
package com.zhyc.module.feed.domain;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.zhyc.module.base.domain.DaSheepfold;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.zhyc.common.annotation.Excel;
import com.zhyc.common.core.domain.BaseEntity;
import java.util.Date;
import java.util.List;
/**
* 饲喂量统计对象 sg_feed_statistic
*
* @author HashMap
* @date 2025-08-23
*/
@Setter
@Getter
public class SgFeedStatistic extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* UUID
*/
private String id;
/**
* 配方编号
*/
@Excel(name = "配方编号")
private String formulaId;
/**
* 配方批号
*/
@Excel(name = "配方批号")
private String formulaBatchId;
/**
* 羊只数量
*/
@Excel(name = "羊只数量")
private Long sheepFoldCount;
/**
* 青贮损耗比例
*/
@Excel(name = "青贮损耗比例")
private String silageLossRate;
/**
* 总饲喂量
*/
@Excel(name = "总饲喂量")
private Double feedTotalSize;
/**
* 日均饲喂量
*/
@Excel(name = "日均饲喂量")
private Double feedDailySize;
/**
* 配方列表
*/
@Excel(name = "配方列表")
private List<SgFormulaList> materialList;
/**
* 羊舍列表
*/
@Excel(name = "羊舍列表")
private List<DaSheepfold> sheepFoldList;
@Excel(name = "日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date feedDate;
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("formulaId", getFormulaId())
.append("formulaBatchId", getFormulaBatchId())
.append("sheepFoldCount", getSheepFoldCount())
.append("silageLossRate", getSilageLossRate())
.append("feedTotalSize", getFeedTotalSize())
.append("feedDailySize", getFeedDailySize())
.append("materialList", getMaterialList())
.append("sheepFoldList", getSheepFoldList())
.toString();
}
}

View File

@ -39,14 +39,25 @@ public class SgFormulaList extends BaseEntity
@Excel(name = "比例")
private Long ratio;
/** 颗粒原料 */
/**
* 颗粒原料
* 当前不局限于 "是否颗粒原料" 而且多种类型的标识符
*/
@Excel(name = "颗粒原料")
private String isGranular;
/** 补饲 */
/**
* 补饲
* 当前用作饲喂类型标识
*/
@Excel(name = "补饲")
private String isSupplement;
/**
* 添加量 - 供其他一些统计模块使用
*/
private Double feedSize;
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

View File

@ -0,0 +1,63 @@
package com.zhyc.module.feed.mapper;
import java.util.List;
import com.zhyc.module.feed.domain.SgFeedStatistic;
import org.apache.ibatis.annotations.Mapper;
/**
* 饲喂量统计Mapper接口
*
* @author HashMap
* @date 2025-08-23
*/
@Mapper
public interface SgFeedStatisticMapper
{
/**
* 查询饲喂量统计
*
* @param id 饲喂量统计主键
* @return 饲喂量统计
*/
SgFeedStatistic selectSgFeedStatisticById(String id);
/**
* 查询饲喂量统计列表
*
* @param sgFeedStatistic 饲喂量统计
* @return 饲喂量统计集合
*/
List<SgFeedStatistic> selectSgFeedStatisticList(SgFeedStatistic sgFeedStatistic);
/**
* 新增饲喂量统计
*
* @param sgFeedStatistic 饲喂量统计
* @return 结果
*/
int insertSgFeedStatistic(SgFeedStatistic sgFeedStatistic);
/**
* 修改饲喂量统计
*
* @param sgFeedStatistic 饲喂量统计
* @return 结果
*/
int updateSgFeedStatistic(SgFeedStatistic sgFeedStatistic);
/**
* 删除饲喂量统计
*
* @param id 饲喂量统计主键
* @return 结果
*/
int deleteSgFeedStatisticById(String id);
/**
* 批量删除饲喂量统计
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
int deleteSgFeedStatisticByIds(String[] ids);
}

View File

@ -0,0 +1,38 @@
package com.zhyc.module.feed.mapper.TypeHandler;
import com.alibaba.fastjson2.JSON;
import com.zhyc.module.base.domain.DaSheepfold;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@MappedTypes(List.class)
public class DaSheepfoldHandler extends BaseTypeHandler<List<DaSheepfold>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
List<DaSheepfold> parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public List<DaSheepfold> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return JSON.parseArray(rs.getString(columnName), DaSheepfold.class);
}
@Override
public List<DaSheepfold> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return JSON.parseArray(rs.getString(columnIndex), DaSheepfold.class);
}
@Override
public List<DaSheepfold> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return JSON.parseArray(cs.getString(columnIndex), DaSheepfold.class);
}
}

View File

@ -0,0 +1,42 @@
package com.zhyc.module.feed.mapper.TypeHandler;
import com.alibaba.fastjson2.JSON;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JsonTypeHandler<T> extends BaseTypeHandler<T> {
private final Class<T> type;
public JsonTypeHandler(Class<T> type) {
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return JSON.parseObject(json, type);
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
return JSON.parseObject(json, type);
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
return JSON.parseObject(json, type);
}
}

View File

@ -0,0 +1,37 @@
package com.zhyc.module.feed.mapper.TypeHandler;
import com.alibaba.fastjson2.JSON;
import com.zhyc.module.feed.domain.SgFormulaList;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@MappedTypes(List.class)
public class SgFormulaListHandler extends BaseTypeHandler<List<SgFormulaList>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
List<SgFormulaList> parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public List<SgFormulaList> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return JSON.parseArray(rs.getString(columnName), SgFormulaList.class);
}
@Override
public List<SgFormulaList> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return JSON.parseArray(rs.getString(columnIndex), SgFormulaList.class);
}
@Override
public List<SgFormulaList> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return JSON.parseArray(cs.getString(columnIndex), SgFormulaList.class);
}
}

View File

@ -1,6 +1,7 @@
package com.zhyc.module.feed.service;
import java.util.List;
import com.zhyc.module.feed.domain.SgFeedList;
/**
@ -9,8 +10,7 @@ import com.zhyc.module.feed.domain.SgFeedList;
* @author HashMap
* @date 2025-08-19
*/
public interface ISgFeedListService
{
public interface ISgFeedListService {
/**
* 查询配料清单
*
@ -58,4 +58,6 @@ public interface ISgFeedListService
* @return 结果
*/
int deleteSgFeedListById(Long id);
void SyncFeedList();
}

View File

@ -0,0 +1,65 @@
package com.zhyc.module.feed.service;
import java.util.List;
import com.zhyc.module.feed.domain.SgFeedStatistic;
/**
* 饲喂量统计Service接口
*
* @author HashMap
* @date 2025-08-23
*/
public interface ISgFeedStatisticService
{
/**
* 查询饲喂量统计
*
* @param id 饲喂量统计主键
* @return 饲喂量统计
*/
SgFeedStatistic selectSgFeedStatisticById(String id);
/**
* 查询饲喂量统计列表
*
* @param sgFeedStatistic 饲喂量统计
* @return 饲喂量统计集合
*/
List<SgFeedStatistic> selectSgFeedStatisticList(SgFeedStatistic sgFeedStatistic);
/**
* 新增饲喂量统计
*
* @param sgFeedStatistic 饲喂量统计
* @return 结果
*/
int insertSgFeedStatistic(SgFeedStatistic sgFeedStatistic);
/**
* 修改饲喂量统计
*
* @param sgFeedStatistic 饲喂量统计
* @return 结果
*/
int updateSgFeedStatistic(SgFeedStatistic sgFeedStatistic);
/**
* 批量删除饲喂量统计
*
* @param ids 需要删除的饲喂量统计主键集合
* @return 结果
*/
int deleteSgFeedStatisticByIds(String[] ids);
/**
* 删除饲喂量统计信息
*
* @param id 饲喂量统计主键
* @return 结果
*/
int deleteSgFeedStatisticById(String id);
void getInitSgFeedStatistic(SgFeedStatistic sgFeedStatistic);
}

View File

@ -1,7 +1,14 @@
package com.zhyc.module.feed.service.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.zhyc.module.feed.domain.SgFeedPlan;
import com.zhyc.module.feed.domain.SgFormulaManagement;
import com.zhyc.module.feed.service.ISgFeedPlanService;
import com.zhyc.module.feed.service.ISgFormulaManagementService;
import lombok.Getter;
import org.springframework.stereotype.Service;
import com.zhyc.module.feed.mapper.SgFeedListMapper;
import com.zhyc.module.feed.domain.SgFeedList;
@ -14,12 +21,17 @@ import com.zhyc.module.feed.service.ISgFeedListService;
* @date 2025-08-19
*/
@Service
public class SgFeedListServiceImpl implements ISgFeedListService
{
public class SgFeedListServiceImpl implements ISgFeedListService {
private final SgFeedListMapper sgFeedListMapper;
private final ISgFormulaManagementService sgFormulaManagementService;
private final ISgFeedPlanService sgFeedPlanService;
@Getter
private final static Map<String, SgFeedList> sgFeedListMap = new HashMap<>();
public SgFeedListServiceImpl(SgFeedListMapper sgFeedListMapper) {
public SgFeedListServiceImpl(SgFeedListMapper sgFeedListMapper, ISgFormulaManagementService sgFormulaManagementService, ISgFeedPlanService sgFeedPlanService) {
this.sgFeedListMapper = sgFeedListMapper;
this.sgFormulaManagementService = sgFormulaManagementService;
this.sgFeedPlanService = sgFeedPlanService;
}
/**
@ -29,8 +41,7 @@ public class SgFeedListServiceImpl implements ISgFeedListService
* @return 配料清单
*/
@Override
public SgFeedList selectSgFeedListById(Long id)
{
public SgFeedList selectSgFeedListById(Long id) {
return sgFeedListMapper.selectSgFeedListById(id);
}
@ -41,8 +52,7 @@ public class SgFeedListServiceImpl implements ISgFeedListService
* @return 配料清单
*/
@Override
public List<SgFeedList> selectSgFeedListList(SgFeedList sgFeedList)
{
public List<SgFeedList> selectSgFeedListList(SgFeedList sgFeedList) {
return sgFeedListMapper.selectSgFeedListList(sgFeedList);
}
@ -53,8 +63,7 @@ public class SgFeedListServiceImpl implements ISgFeedListService
* @return 结果
*/
@Override
public int insertSgFeedList(SgFeedList sgFeedList)
{
public int insertSgFeedList(SgFeedList sgFeedList) {
return sgFeedListMapper.insertSgFeedList(sgFeedList);
}
@ -65,8 +74,7 @@ public class SgFeedListServiceImpl implements ISgFeedListService
* @return 结果
*/
@Override
public int updateSgFeedList(SgFeedList sgFeedList)
{
public int updateSgFeedList(SgFeedList sgFeedList) {
return sgFeedListMapper.updateSgFeedList(sgFeedList);
}
@ -77,8 +85,7 @@ public class SgFeedListServiceImpl implements ISgFeedListService
* @return 结果
*/
@Override
public int deleteSgFeedListByIds(Long[] ids)
{
public int deleteSgFeedListByIds(Long[] ids) {
return sgFeedListMapper.deleteSgFeedListByIds(ids);
}
@ -89,8 +96,97 @@ public class SgFeedListServiceImpl implements ISgFeedListService
* @return 结果
*/
@Override
public int deleteSgFeedListById(Long id)
{
public int deleteSgFeedListById(Long id) {
return sgFeedListMapper.deleteSgFeedListById(id);
}
public void SyncFeedList() {
// 清空旧缓存
sgFeedListMap.clear();
// 获取配方管理和现有配料清单内容
List<SgFormulaManagement> formulaManagementList = sgFormulaManagementService.selectSgFormulaManagementList(new SgFormulaManagement());
List<SgFeedList> feedLists = this.selectSgFeedListList(new SgFeedList());
// 将最新查询的配料清单加入缓存
for (SgFeedList sgFeedList : feedLists) {
sgFeedListMap.put(sgFeedList.getFormulaId() + "_" + sgFeedList.getFormulaBatchId(), sgFeedList);
}
// 与新的配方管理列表同步 - 如果配料清单没有对应数据则加入
for (SgFormulaManagement sgFormulaManagement : formulaManagementList) {
// 匹配 但忽略模板配方
if (sgFormulaManagement.getFormulaId() != null && sgFormulaManagement.getBatchId() != null && !sgFormulaManagement.getBatchId().equals("0")) {
// 查询当前配方管理项是否存在现有配料计划中 (不论是否存在都要设置,因为缓存被清空,存在则更新,不存在则插入)
boolean isExist = sgFeedListMap.containsKey(sgFormulaManagement.getFormulaId() + "_" + sgFormulaManagement.getBatchId());
// 标志位 : 如果当前配方不在饲喂计划中则不生成配量清单
boolean isPlan = true;
// 设置缓存对象具体值
SgFeedList sgFeedList = new SgFeedList();
sgFeedList.setFormulaId(sgFormulaManagement.getFormulaId());
sgFeedList.setFormulaBatchId(sgFormulaManagement.getBatchId());
sgFeedList.setFormulaList(sgFormulaManagement.getSgFormulaList());
sgFeedList.setRootFormula(sgFormulaManagement);
// 从饲喂计划列表中查出对应值(饲喂量需要计划中的比例计算)
SgFeedPlan rootPlanQuery = new SgFeedPlan();
rootPlanQuery.setFormulaId(sgFormulaManagement.getFormulaId());
rootPlanQuery.setBatchId(sgFormulaManagement.getBatchId());
List<SgFeedPlan> sgFeedPlans = sgFeedPlanService.selectSgFeedPlanList(rootPlanQuery);
// 为空则标识当前配方不在饲喂计划中 && 不在缓存中设置
if (sgFeedPlans.isEmpty()) {
isPlan = false;
} else {
// rootPlan中存储的是该配方批号的总量
SgFeedPlan rootPlan = computePlanTotal(sgFeedPlans);
// 将计划实体对象设置到配料清单中
sgFeedList.setRootPlan(rootPlan);
// 完整的配料清单对象加入缓存
sgFeedListMap.put(sgFormulaManagement.getFormulaId() + "_" + sgFormulaManagement.getBatchId(), sgFeedList);
}
// 不存在则插入
if (!isExist && isPlan) {
this.insertSgFeedList(sgFeedList);
}
}
}
}
/**
* 计算某个配方某个批次的总和值
*
* @param sgFeedPlans 配方计划列表
* @return 各个值总和
*/
private static SgFeedPlan computePlanTotal(List<SgFeedPlan> sgFeedPlans) {
SgFeedPlan rootPlan = new SgFeedPlan();
if (!sgFeedPlans.isEmpty()) {
int sheepCountTotal = 0;
double sheepDailySize = 0.0;
double planFeedMorningSize = 0.0;
double planFeedNoonSize = 0.0;
double planFeedAfternoonSize = 0.0;
double planFeedTotalSize = 0.0;
for (SgFeedPlan sgFeedPlan : sgFeedPlans) {
sheepCountTotal += sgFeedPlan.getSheepCount();
sheepDailySize += sgFeedPlan.getPlanDailySize();
planFeedMorningSize += sgFeedPlan.getPlanMorningSize();
planFeedNoonSize += sgFeedPlan.getPlanNoonSize();
planFeedAfternoonSize += sgFeedPlan.getPlanAfternoonSize();
planFeedTotalSize += sgFeedPlan.getPlanFeedTotal();
}
rootPlan.setSheepCount(sheepCountTotal);
rootPlan.setPlanDailySize(sheepDailySize);
rootPlan.setPlanMorningSize(planFeedMorningSize);
rootPlan.setPlanNoonSize(planFeedNoonSize);
rootPlan.setPlanAfternoonSize(planFeedAfternoonSize);
rootPlan.setPlanFeedTotal(planFeedTotalSize);
// 设置计划日期
rootPlan.setPlanDate(sgFeedPlans.get(0).getPlanDate());
}
return rootPlan;
}
}

View File

@ -0,0 +1,176 @@
package com.zhyc.module.feed.service.impl;
import java.util.List;
import java.util.stream.Collectors;
import com.zhyc.module.base.domain.DaSheepfold;
import com.zhyc.module.feed.domain.SgFeedList;
import com.zhyc.module.feed.domain.SgFeedPlan;
import com.zhyc.module.feed.domain.SgFormulaList;
import com.zhyc.module.feed.service.ISgFeedListService;
import com.zhyc.module.feed.service.ISgFeedPlanService;
import org.springframework.stereotype.Service;
import com.zhyc.module.feed.mapper.SgFeedStatisticMapper;
import com.zhyc.module.feed.domain.SgFeedStatistic;
import com.zhyc.module.feed.service.ISgFeedStatisticService;
/**
* 饲喂量统计Service业务层处理
*
* @author HashMap
* @date 2025-08-23
*/
@Service
public class SgFeedStatisticServiceImpl implements ISgFeedStatisticService {
private final SgFeedStatisticMapper sgFeedStatisticMapper;
private final ISgFeedListService sgFeedListService;
private final ISgFeedPlanService sgFeedPlanService;
public SgFeedStatisticServiceImpl(SgFeedStatisticMapper sgFeedStatisticMapper, ISgFeedListService sgFeedListService, ISgFeedPlanService sgFeedPlanService) {
this.sgFeedStatisticMapper = sgFeedStatisticMapper;
this.sgFeedListService = sgFeedListService;
this.sgFeedPlanService = sgFeedPlanService;
}
/**
* 查询饲喂量统计
*
* @param id 饲喂量统计主键
* @return 饲喂量统计
*/
@Override
public SgFeedStatistic selectSgFeedStatisticById(String id) {
return sgFeedStatisticMapper.selectSgFeedStatisticById(id);
}
/**
* 查询饲喂量统计列表
*
* @param sgFeedStatistic 饲喂量统计
* @return 饲喂量统计
*/
@Override
public List<SgFeedStatistic> selectSgFeedStatisticList(SgFeedStatistic sgFeedStatistic) {
return sgFeedStatisticMapper.selectSgFeedStatisticList(sgFeedStatistic);
}
/**
* 新增饲喂量统计
*
* @param sgFeedStatistic 饲喂量统计
* @return 结果
*/
@Override
public int insertSgFeedStatistic(SgFeedStatistic sgFeedStatistic) {
return sgFeedStatisticMapper.insertSgFeedStatistic(sgFeedStatistic);
}
/**
* 修改饲喂量统计
*
* @param sgFeedStatistic 饲喂量统计
* @return 结果
*/
@Override
public int updateSgFeedStatistic(SgFeedStatistic sgFeedStatistic) {
return sgFeedStatisticMapper.updateSgFeedStatistic(sgFeedStatistic);
}
/**
* 批量删除饲喂量统计
*
* @param ids 需要删除的饲喂量统计主键
* @return 结果
*/
@Override
public int deleteSgFeedStatisticByIds(String[] ids) {
return sgFeedStatisticMapper.deleteSgFeedStatisticByIds(ids);
}
/**
* 删除饲喂量统计信息
*
* @param id 饲喂量统计主键
* @return 结果
*/
@Override
public int deleteSgFeedStatisticById(String id) {
return sgFeedStatisticMapper.deleteSgFeedStatisticById(id);
}
/**
* 向待插入数据表单提供数据预载服务
*
* @param sgFeedStatistic 待填充的初始化数据
* @author ShiHan Wang
*/
@Override
public void getInitSgFeedStatistic(SgFeedStatistic sgFeedStatistic) {
// 1. 查找饲料清单
SgFeedList sgFeedListQuery = new SgFeedList();
sgFeedListQuery.setFormulaId(sgFeedStatistic.getFormulaId());
sgFeedListQuery.setFormulaBatchId(sgFeedStatistic.getFormulaBatchId());
List<SgFeedList> feedLists = sgFeedListService.selectSgFeedListList(sgFeedListQuery);
if (!feedLists.isEmpty()) {
// 刷新缓存
sgFeedListService.SyncFeedList();
// 从缓存获取完整配方清单
String cacheKey = sgFeedStatistic.getFormulaId() + "_" + sgFeedStatistic.getFormulaBatchId();
SgFeedList sgFeedList = SgFeedListServiceImpl.getSgFeedListMap().get(cacheKey);
if (sgFeedList != null && sgFeedList.getFormulaList() != null) {
// 并行流式计算 提高性能
sgFeedList.getFormulaList().parallelStream().forEach(item -> {
double ratio = item.getRatio() / 100.0;
double feedSize = sgFeedList.getRootPlan().getPlanMorningSize() * ratio
+ sgFeedList.getRootPlan().getPlanNoonSize() * ratio
+ sgFeedList.getRootPlan().getPlanAfternoonSize() * ratio;
item.setFeedSize(feedSize);
});
// 统计总和
double totalFeedSize = sgFeedList.getFormulaList()
.parallelStream()
.mapToDouble(SgFormulaList::getFeedSize)
.sum();
sgFeedStatistic.setMaterialList(sgFeedList.getFormulaList());
sgFeedStatistic.setFeedTotalSize(totalFeedSize);
} else {
throw new RuntimeException("WARNING: 原料数据为空");
}
}
// 2. 查找饲喂计划并填充羊舍信息
SgFeedPlan sgFeedPlanQuery = new SgFeedPlan();
sgFeedPlanQuery.setFormulaId(sgFeedStatistic.getFormulaId());
sgFeedPlanQuery.setBatchId(sgFeedStatistic.getFormulaBatchId());
List<SgFeedPlan> sgFeedPlans = sgFeedPlanService.selectSgFeedPlanList(sgFeedPlanQuery);
if (!sgFeedPlans.isEmpty()) {
// 并行计算提高查询性能
List<DaSheepfold> sheepfolds = sgFeedPlans.parallelStream()
.map(plan -> {
DaSheepfold sheepfold = new DaSheepfold();
sheepfold.setId((long) plan.getSheepHouseId());
return sheepfold;
})
.collect(Collectors.toList());
long sheepCount = sgFeedPlans.parallelStream()
.mapToLong(SgFeedPlan::getSheepCount)
.sum();
sgFeedStatistic.setSheepFoldList(sheepfolds);
sgFeedStatistic.setSheepFoldCount(sheepCount);
// 计算日均饲喂量
sgFeedStatistic.setFeedDailySize(sgFeedStatistic.getFeedTotalSize() / sgFeedStatistic.getSheepFoldCount());
} else {
throw new RuntimeException("WARNING: 不存在该计划");
}
}
}

View File

@ -20,6 +20,7 @@
<include refid="selectSgFeedListVo"/>
<where>
<if test="formulaId != null and formulaId != ''"> and formula_id = #{formulaId}</if>
<if test="formulaBatchId != null and formulaBatchId != ''"> and formula_batch_id = #{formulaBatchId}</if>
<if test="zookeeper != null and zookeeper != ''"> and zookeeper = #{zookeeper}</if>
<if test="deployDate != null "> and deploy_date = #{deployDate}</if>
</where>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhyc.module.feed.mapper.SgFeedStatisticMapper">
<resultMap type="SgFeedStatistic" id="SgFeedStatisticResult">
<result property="id" column="id" />
<result property="formulaId" column="formula_id" />
<result property="formulaBatchId" column="formula_batch_id" />
<result property="sheepFoldCount" column="sheep_fold_count" />
<result property="silageLossRate" column="silage_loss_rate" />
<result property="feedTotalSize" column="feed_total_size" />
<result property="feedDailySize" column="feed_daily_size" />
<!--
适配泛型TypeHandler
弃用: XML中无法使用"<>"
-->
<!-- <result property="materialList" column="material_list"-->
<!-- typeHandler="com.zhyc.module.feed.mapper.TypeHandler.JsonTypeHandler<java.util.List<com.zhyc.module.feed.domain.SgFormulaList>>" />-->
<!-- 分别使用两个TypeHandler完成实体类List<T> 到 数据库 JSON串的映射转换 -->
<result property="materialList" column="material_list" typeHandler="com.zhyc.module.feed.mapper.TypeHandler.SgFormulaListHandler"/>
<result property="sheepFoldList" column="sheep_fold_list" typeHandler="com.zhyc.module.feed.mapper.TypeHandler.DaSheepfoldHandler"/>
<result property="feedDate" column="feed_date" />
</resultMap>
<sql id="selectSgFeedStatisticVo">
select id, formula_id, formula_batch_id, sheep_fold_count, silage_loss_rate, feed_total_size, feed_daily_size, material_list, sheep_fold_list,feed_date from sg_feed_statistic
</sql>
<select id="selectSgFeedStatisticList" parameterType="SgFeedStatistic" resultMap="SgFeedStatisticResult">
<include refid="selectSgFeedStatisticVo"/>
<where>
<if test="formulaId != null and formulaId != ''"> and formula_id = #{formulaId}</if>
<if test="formulaBatchId != null and formulaBatchId != ''"> and formula_batch_id = #{formulaBatchId}</if>
<if test="silageLossRate != null and silageLossRate != ''"> and silage_loss_rate = #{silageLossRate}</if>
</where>
</select>
<select id="selectSgFeedStatisticById" parameterType="String" resultMap="SgFeedStatisticResult">
<include refid="selectSgFeedStatisticVo"/>
where id = #{id}
</select>
<insert id="insertSgFeedStatistic" parameterType="SgFeedStatistic">
insert into sg_feed_statistic
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="formulaId != null and formulaId != ''">formula_id,</if>
<if test="formulaBatchId != null and formulaBatchId != ''">formula_batch_id,</if>
<if test="sheepFoldCount != null">sheep_fold_count,</if>
<if test="silageLossRate != null">silage_loss_rate,</if>
<if test="feedTotalSize != null">feed_total_size,</if>
<if test="feedDailySize != null">feed_daily_size,</if>
<if test="materialList != null">material_list,</if>
<if test="sheepFoldList != null">sheep_fold_list,</if>
<if test="feedDate != null">feed_date,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="formulaId != null and formulaId != ''">#{formulaId},</if>
<if test="formulaBatchId != null and formulaBatchId != ''">#{formulaBatchId},</if>
<if test="sheepFoldCount != null">#{sheepFoldCount},</if>
<if test="silageLossRate != null">#{silageLossRate},</if>
<if test="feedTotalSize != null">#{feedTotalSize},</if>
<if test="feedDailySize != null">#{feedDailySize},</if>
# 写入操作需要手动指定 TypeHandler 参数
<if test="materialList != null">#{materialList, typeHandler=com.zhyc.module.feed.mapper.TypeHandler.SgFormulaListHandler},</if>
<if test="sheepFoldList != null">#{sheepFoldList, typeHandler=com.zhyc.module.feed.mapper.TypeHandler.DaSheepfoldHandler},</if>
<if test="feedDate != null">#{feedDate},</if>
</trim>
</insert>
<update id="updateSgFeedStatistic" parameterType="SgFeedStatistic">
update sg_feed_statistic
<trim prefix="SET" suffixOverrides=",">
<if test="formulaId != null and formulaId != ''">formula_id = #{formulaId},</if>
<if test="formulaBatchId != null and formulaBatchId != ''">formula_batch_id = #{formulaBatchId},</if>
<if test="sheepFoldCount != null">sheep_fold_count = #{sheepFoldCount},</if>
<if test="silageLossRate != null">silage_loss_rate = #{silageLossRate},</if>
<if test="feedTotalSize != null">feed_total_size = #{feedTotalSize},</if>
<if test="feedDailySize != null">feed_daily_size = #{feedDailySize},</if>
<if test="materialList != null">material_list = #{materialList, typeHandler=com.zhyc.module.feed.mapper.TypeHandler.SgFormulaListHandler},</if>
<if test="sheepFoldList != null">sheep_fold_list = #{sheepFoldList, typeHandler=com.zhyc.module.feed.mapper.TypeHandler.DaSheepfoldHandler},</if>
<if test="feedDate != null">feed_date = #{feedDate},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteSgFeedStatisticById" parameterType="String">
delete from sg_feed_statistic where id = #{id}
</delete>
<delete id="deleteSgFeedStatisticByIds" parameterType="String">
delete from sg_feed_statistic where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>