菜谱排餐

This commit is contained in:
zjf committed 2026-07-03 10:19:57 +08:00
1 parent 245efd3936
commit 91a2facb83
24 files changed
+1294

No files matched your search

@@ -0,0 +1,23 @@
package com.bsd.pjcloud.canteen.dto.mealplan;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
@Data
@Schema(description = "排餐计划明细项")
public class CanteenMealPlanItemDTO {
private Long id;
private LocalDate planDate;
private Integer mealSegment;
private Long recipeId;
private String recipeName;
private Integer sortOrder;
}
@@ -0,0 +1,42 @@
package com.bsd.pjcloud.canteen.dto.mealplan;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
@Data
@Schema(description = "保存排餐计划")
public class CanteenMealPlanSaveDTO {
private Long id;
@NotBlank(message = "请选择商户")
private String merchantId;
@NotBlank(message = "请输入计划名称")
private String planName;
@NotNull(message = "请选择开始日期")
private LocalDate startDate;
@NotNull(message = "请填写排餐天数")
private Integer dayCount;
@NotEmpty(message = "请勾选餐次")
private List<Integer> mealSegments;
private List<Long> selectedMaterialIds;
private Integer matchMode;
private Integer status;
private String remark;
private List<CanteenMealPlanItemDTO> items;
}
@@ -0,0 +1,17 @@
package com.bsd.pjcloud.canteen.dto.menurecipe;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
@Schema(description = "按选用食材匹配菜谱")
public class CanteenMenuRecipeMatchDTO {
@Schema(description = "已选食材ID")
private List<Long> materialIds;
@Schema(description = "可选:限定商户")
private String merchantId;
}
@@ -113,4 +113,12 @@ public class CanteenErpMaterialEntity extends Model<CanteenErpMaterialEntity> {
@TableField(typeHandler = JacksonTypeHandler.class)
private List<CanteenMaterialNutritionTagDTO> nutritionTags;
@TableField(exist = false)
@Schema(description = "筛选:营养元素名称")
private String nutritionName;
@TableField(exist = false)
@Schema(description = "筛选:营养功效")
private String nutritionEffect;
}
@@ -0,0 +1,74 @@
package com.bsd.pjcloud.canteen.entity;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.bsd.pjcloud.common.core.util.TenantTable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Data
@TenantTable
@TableName(value = "canteen_meal_plan", autoResultMap = true)
@EqualsAndHashCode(callSuper = true)
@Schema(description = "排餐计划")
public class CanteenMealPlanEntity extends Model<CanteenMealPlanEntity> {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private Long tenantId;
private Long deptId;
private String merchantId;
private String planName;
private LocalDate startDate;
private Integer dayCount;
@TableField(value = "meal_segments_json", typeHandler = JacksonTypeHandler.class)
private List<Integer> mealSegments;
@TableField(value = "selected_material_ids_json", typeHandler = JacksonTypeHandler.class)
private List<Long> selectedMaterialIds;
private Integer matchMode;
@Schema(description = "0草稿 1已定稿")
private Integer status;
private String remark;
@TableField(fill = FieldFill.INSERT)
private String createBy;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic
@TableField(fill = FieldFill.INSERT)
private String delFlag;
@ExcelIgnore
@TableField(exist = false)
private String merchantName;
@ExcelIgnore
@TableField(exist = false)
private List<CanteenMealPlanItemEntity> itemList;
}
@@ -0,0 +1,37 @@
package com.bsd.pjcloud.canteen.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@TableName("canteen_meal_plan_item")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "排餐计划明细")
public class CanteenMealPlanItemEntity extends Model<CanteenMealPlanItemEntity> {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private Long planId;
private LocalDate planDate;
@Schema(description = "1早2午3晚4夜")
private Integer mealSegment;
private Long recipeId;
private String recipeName;
private Integer sortOrder;
private LocalDateTime createTime;
}
@@ -0,0 +1,76 @@
package com.bsd.pjcloud.canteen.entity;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.bsd.pjcloud.common.core.util.TenantTable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
import java.util.List;
@Data
@TenantTable
@TableName("canteen_menu_recipe")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "排菜菜谱")
public class CanteenMenuRecipeEntity extends Model<CanteenMenuRecipeEntity> {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private Long tenantId;
@Schema(description = "所属部门")
private Long deptId;
@Schema(description = "关联商户")
private String merchantId;
@Schema(description = "菜名")
private String name;
@Schema(description = "图片")
private String picUrl;
@Schema(description = "备注")
private String remark;
@Schema(description = "可选关联线上商品")
private Long onlineSpuId;
@Schema(description = "0正常 1停用")
private Integer status;
@TableField(fill = FieldFill.INSERT)
private String createBy;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic
@TableField(fill = FieldFill.INSERT)
private String delFlag;
@ExcelIgnore
@TableField(exist = false)
private List<CanteenMenuRecipeMaterialEntity> materialList;
@ExcelIgnore
@TableField(exist = false)
@Schema(description = "食材摘要(列表展示)")
private String materialSummary;
@ExcelIgnore
@TableField(exist = false)
@Schema(description = "关联线上商品名称")
private String onlineSpuName;
}
@@ -0,0 +1,40 @@
package com.bsd.pjcloud.canteen.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("canteen_menu_recipe_material")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "排菜菜谱-食材明细")
public class CanteenMenuRecipeMaterialEntity extends Model<CanteenMenuRecipeMaterialEntity> {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private Long recipeId;
private Long materialId;
@Schema(description = "参考用量")
private BigDecimal quantity;
private Integer sortOrder;
private LocalDateTime createTime;
@TableField(exist = false)
private String materialName;
@TableField(exist = false)
private String unit;
}
@@ -0,0 +1,17 @@
package com.bsd.pjcloud.canteen.vo.mealplan;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class CanteenMealPlanExportRow {
@ExcelProperty("日期")
private String planDate;
@ExcelProperty("餐次")
private String mealSegmentName;
@ExcelProperty("菜名")
private String recipeName;
}
@@ -0,0 +1,15 @@
package com.bsd.pjcloud.canteen.vo.mealplan;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "排餐选用食材摘要")
public class CanteenMealPlanMaterialBriefVO {
private Long id;
private String name;
private String unit;
}
@@ -0,0 +1,47 @@
package com.bsd.pjcloud.canteen.vo.mealplan;
import com.bsd.pjcloud.canteen.dto.mealplan.CanteenMealPlanItemDTO;
import com.bsd.pjcloud.canteen.vo.menurecipe.CanteenMenuRecipeVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Data
@Schema(description = "排餐计划详情")
public class CanteenMealPlanVO {
private Long id;
private String merchantId;
private String merchantName;
private String planName;
private LocalDate startDate;
private Integer dayCount;
private List<Integer> mealSegments;
private List<Long> selectedMaterialIds;
private Integer matchMode;
private Integer status;
private String remark;
private LocalDateTime createTime;
private List<LocalDate> planDates;
private List<CanteenMealPlanItemDTO> items;
private List<CanteenMealPlanMaterialBriefVO> selectedMaterials;
private List<CanteenMenuRecipeVO> matchedRecipes;
}
@@ -0,0 +1,23 @@
package com.bsd.pjcloud.canteen.vo.menurecipe;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Data
@Schema(description = "排菜菜谱食材明细")
public class CanteenMenuRecipeMaterialVO {
private Long id;
private Long materialId;
private String materialName;
private String unit;
private BigDecimal quantity;
private Integer sortOrder;
}
@@ -0,0 +1,36 @@
package com.bsd.pjcloud.canteen.vo.menurecipe;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
@Schema(description = "排菜菜谱详情")
public class CanteenMenuRecipeVO {
private Long id;
private Long deptId;
private String merchantId;
private String name;
private String picUrl;
private String remark;
private Long onlineSpuId;
private String onlineSpuName;
private Integer status;
private LocalDateTime createTime;
private String materialSummary;
private List<CanteenMenuRecipeMaterialVO> materialList;
}
@@ -0,0 +1,94 @@
package com.bsd.pjcloud.canteen.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.canteen.dto.mealplan.CanteenMealPlanSaveDTO;
import com.bsd.pjcloud.canteen.entity.CanteenMealPlanEntity;
import com.bsd.pjcloud.canteen.service.CanteenMealPlanService;
import com.bsd.pjcloud.canteen.vo.mealplan.CanteenMealPlanExportRow;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequiredArgsConstructor
@RequestMapping("/canteenMealPlan")
@Tag(name = "一键排餐")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class CanteenMealPlanController {
private final CanteenMealPlanService canteenMealPlanService;
@Operation(summary = "分页查询")
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('canteen_canteenMealPlan_view')")
public R<Page<CanteenMealPlanEntity>> page(@ParameterObject Page<CanteenMealPlanEntity> page,
@ParameterObject CanteenMealPlanEntity query) {
var wrapper = Wrappers.<CanteenMealPlanEntity>lambdaQuery()
.like(StrUtil.isNotBlank(query.getPlanName()), CanteenMealPlanEntity::getPlanName, query.getPlanName())
.eq(StrUtil.isNotBlank(query.getMerchantId()), CanteenMealPlanEntity::getMerchantId,
query.getMerchantId())
.eq(query.getStatus() != null, CanteenMealPlanEntity::getStatus, query.getStatus())
.orderByDesc(CanteenMealPlanEntity::getCreateTime);
return R.ok(canteenMealPlanService.pageScope(page, wrapper));
}
@Operation(summary = "详情")
@GetMapping("/{id}")
@PreAuthorize("@pms.hasPermission('canteen_canteenMealPlan_view')")
public R getById(@PathVariable Long id) {
return R.ok(canteenMealPlanService.getDetail(id));
}
@SysLog("新增排餐计划")
@Operation(summary = "新增")
@PostMapping
@PreAuthorize("@pms.hasPermission('canteen_canteenMealPlan_add')")
public R<Long> save(@Valid @RequestBody CanteenMealPlanSaveDTO dto) {
return R.ok(canteenMealPlanService.savePlan(dto));
}
@SysLog("修改排餐计划")
@Operation(summary = "修改")
@PutMapping
@PreAuthorize("@pms.hasPermission('canteen_canteenMealPlan_edit')")
public R update(@Valid @RequestBody CanteenMealPlanSaveDTO dto) {
return R.ok(canteenMealPlanService.updatePlan(dto));
}
@SysLog("删除排餐计划")
@Operation(summary = "删除")
@DeleteMapping
@PreAuthorize("@pms.hasPermission('canteen_canteenMealPlan_del')")
public R remove(@RequestBody Long[] ids) {
return R.ok(canteenMealPlanService.removePlans(ids));
}
@ResponseExcel(name = "排餐明细")
@Operation(summary = "导出明细(日期+餐次+菜名)")
@GetMapping("/export/{id}")
@PreAuthorize("@pms.hasPermission('canteen_canteenMealPlan_export')")
public List<CanteenMealPlanExportRow> exportDetail(@PathVariable Long id) {
return canteenMealPlanService.exportRows(id);
}
@Operation(summary = "导出餐表(横轴日期、纵轴餐次)")
@GetMapping("/export-grid/{id}")
@PreAuthorize("@pms.hasPermission('canteen_canteenMealPlan_export')")
public void exportGrid(@PathVariable Long id, HttpServletResponse response) {
canteenMealPlanService.exportGridExcel(id, response);
}
}
@@ -0,0 +1,84 @@
package com.bsd.pjcloud.canteen.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.canteen.dto.menurecipe.CanteenMenuRecipeMatchDTO;
import com.bsd.pjcloud.canteen.entity.CanteenMenuRecipeEntity;
import com.bsd.pjcloud.canteen.service.CanteenMenuRecipeService;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequiredArgsConstructor
@RequestMapping("/canteenMenuRecipe")
@Tag(name = "排菜菜谱")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class CanteenMenuRecipeController {
private final CanteenMenuRecipeService canteenMenuRecipeService;
@Operation(summary = "分页查询")
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('canteen_canteenMenuRecipe_view')")
public R<Page<CanteenMenuRecipeEntity>> page(@ParameterObject Page<CanteenMenuRecipeEntity> page,
@ParameterObject CanteenMenuRecipeEntity query) {
var wrapper = Wrappers.<CanteenMenuRecipeEntity>lambdaQuery()
.like(StrUtil.isNotBlank(query.getName()), CanteenMenuRecipeEntity::getName, query.getName())
.eq(StrUtil.isNotBlank(query.getMerchantId()), CanteenMenuRecipeEntity::getMerchantId,
query.getMerchantId())
.eq(query.getStatus() != null, CanteenMenuRecipeEntity::getStatus, query.getStatus())
.orderByDesc(CanteenMenuRecipeEntity::getCreateTime);
return R.ok(canteenMenuRecipeService.pageScope(page, wrapper));
}
@Operation(summary = "详情")
@GetMapping("/{id}")
@PreAuthorize("@pms.hasPermission('canteen_canteenMenuRecipe_view')")
public R getById(@PathVariable Long id) {
return R.ok(canteenMenuRecipeService.getDetail(id));
}
@SysLog("新增排菜菜谱")
@Operation(summary = "新增")
@PostMapping
@PreAuthorize("@pms.hasPermission('canteen_canteenMenuRecipe_add')")
public R save(@RequestBody CanteenMenuRecipeEntity entity) {
entity.setDeptId(SecurityUtils.getUser().getDeptId());
return R.ok(canteenMenuRecipeService.saveDeep(entity));
}
@SysLog("修改排菜菜谱")
@Operation(summary = "修改")
@PutMapping
@PreAuthorize("@pms.hasPermission('canteen_canteenMenuRecipe_edit')")
public R update(@RequestBody CanteenMenuRecipeEntity entity) {
return R.ok(canteenMenuRecipeService.updateDeep(entity));
}
@SysLog("删除排菜菜谱")
@Operation(summary = "删除")
@DeleteMapping
@PreAuthorize("@pms.hasPermission('canteen_canteenMenuRecipe_del')")
public R remove(@RequestBody Long[] ids) {
return R.ok(canteenMenuRecipeService.removeDeep(ids));
}
@Operation(summary = "按选用食材匹配可做菜谱", description = "所选食材须覆盖菜谱全部食材")
@PostMapping("/match-by-materials")
@PreAuthorize("@pms.hasPermission('canteen_canteenMenuRecipe_view')")
public R<List<?>> matchByMaterials(@RequestBody CanteenMenuRecipeMatchDTO dto) {
return R.ok(canteenMenuRecipeService.matchByMaterials(dto));
}
}
@@ -0,0 +1,9 @@
package com.bsd.pjcloud.canteen.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bsd.pjcloud.canteen.entity.CanteenMealPlanItemEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CanteenMealPlanItemMapper extends BaseMapper<CanteenMealPlanItemEntity> {
}
@@ -0,0 +1,9 @@
package com.bsd.pjcloud.canteen.mapper;
import com.bsd.pjcloud.canteen.entity.CanteenMealPlanEntity;
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CanteenMealPlanMapper extends PjcloudBaseMapper<CanteenMealPlanEntity> {
}
@@ -0,0 +1,9 @@
package com.bsd.pjcloud.canteen.mapper;
import com.bsd.pjcloud.canteen.entity.CanteenMenuRecipeEntity;
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CanteenMenuRecipeMapper extends PjcloudBaseMapper<CanteenMenuRecipeEntity> {
}
@@ -0,0 +1,9 @@
package com.bsd.pjcloud.canteen.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bsd.pjcloud.canteen.entity.CanteenMenuRecipeMaterialEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CanteenMenuRecipeMaterialMapper extends BaseMapper<CanteenMenuRecipeMaterialEntity> {
}
@@ -0,0 +1,29 @@
package com.bsd.pjcloud.canteen.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.canteen.dto.mealplan.CanteenMealPlanSaveDTO;
import com.bsd.pjcloud.canteen.entity.CanteenMealPlanEntity;
import com.bsd.pjcloud.canteen.vo.mealplan.CanteenMealPlanExportRow;
import com.bsd.pjcloud.canteen.vo.mealplan.CanteenMealPlanVO;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
public interface CanteenMealPlanService extends IService<CanteenMealPlanEntity> {
Page<CanteenMealPlanEntity> pageScope(Page<CanteenMealPlanEntity> page, LambdaQueryWrapper<CanteenMealPlanEntity> wrapper);
Long savePlan(CanteenMealPlanSaveDTO dto);
Boolean updatePlan(CanteenMealPlanSaveDTO dto);
Boolean removePlans(Long[] ids);
CanteenMealPlanVO getDetail(Long id);
List<CanteenMealPlanExportRow> exportRows(Long id);
void exportGridExcel(Long id, HttpServletResponse response);
}
@@ -0,0 +1,25 @@
package com.bsd.pjcloud.canteen.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.canteen.dto.menurecipe.CanteenMenuRecipeMatchDTO;
import com.bsd.pjcloud.canteen.entity.CanteenMenuRecipeEntity;
import com.bsd.pjcloud.canteen.vo.menurecipe.CanteenMenuRecipeVO;
import java.util.List;
public interface CanteenMenuRecipeService extends IService<CanteenMenuRecipeEntity> {
Page<CanteenMenuRecipeEntity> pageScope(Page<CanteenMenuRecipeEntity> page, LambdaQueryWrapper<CanteenMenuRecipeEntity> wrapper);
Boolean saveDeep(CanteenMenuRecipeEntity entity);
Boolean updateDeep(CanteenMenuRecipeEntity entity);
Boolean removeDeep(Long[] ids);
CanteenMenuRecipeVO getDetail(Long id);
List<CanteenMenuRecipeVO> matchByMaterials(CanteenMenuRecipeMatchDTO dto);
}
@@ -0,0 +1,346 @@
package com.bsd.pjcloud.canteen.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.canteen.dto.mealplan.CanteenMealPlanItemDTO;
import com.bsd.pjcloud.canteen.dto.mealplan.CanteenMealPlanSaveDTO;
import com.bsd.pjcloud.canteen.dto.menurecipe.CanteenMenuRecipeMatchDTO;
import com.bsd.pjcloud.canteen.entity.CanteenErpMaterialEntity;
import com.bsd.pjcloud.canteen.entity.CanteenMealPlanEntity;
import com.bsd.pjcloud.canteen.entity.CanteenMealPlanItemEntity;
import com.bsd.pjcloud.canteen.entity.CanteenMenuRecipeEntity;
import com.bsd.pjcloud.canteen.mapper.CanteenErpMaterialMapper;
import com.bsd.pjcloud.canteen.mapper.CanteenMealPlanItemMapper;
import com.bsd.pjcloud.canteen.mapper.CanteenMealPlanMapper;
import com.bsd.pjcloud.canteen.mapper.CanteenMenuRecipeMapper;
import com.bsd.pjcloud.canteen.service.CanteenMealPlanService;
import com.bsd.pjcloud.canteen.service.CanteenMenuRecipeService;
import com.bsd.pjcloud.canteen.vo.mealplan.CanteenMealPlanExportRow;
import com.bsd.pjcloud.canteen.vo.mealplan.CanteenMealPlanMaterialBriefVO;
import com.bsd.pjcloud.canteen.vo.mealplan.CanteenMealPlanVO;
import com.bsd.pjcloud.canteen.vo.menurecipe.CanteenMenuRecipeVO;
import com.bsd.pjcloud.common.core.util.BeanUtils;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Service
@RequiredArgsConstructor
public class CanteenMealPlanServiceImpl extends ServiceImpl<CanteenMealPlanMapper, CanteenMealPlanEntity>
implements CanteenMealPlanService {
private static final Map<Integer, String> SEGMENT_NAMES = Map.of(
1, "早餐",
2, "午餐",
3, "晚餐",
4, "夜宵");
private static final String[] WEEKDAY_LABELS = { "日", "一", "二", "三", "四", "五", "六" };
private final CanteenMealPlanItemMapper itemMapper;
private final CanteenErpMaterialMapper erpMaterialMapper;
private final CanteenMenuRecipeService menuRecipeService;
private final CanteenMenuRecipeMapper menuRecipeMapper;
private final RemoteMchService remoteMchService;
@Override
public Page<CanteenMealPlanEntity> pageScope(Page<CanteenMealPlanEntity> page,
LambdaQueryWrapper<CanteenMealPlanEntity> wrapper) {
Page<CanteenMealPlanEntity> result = baseMapper.selectPageByScope(page, wrapper, DataScope.of());
fillMerchantNames(result.getRecords());
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long savePlan(CanteenMealPlanSaveDTO dto) {
CanteenMealPlanEntity entity = toEntity(dto);
entity.setDeptId(SecurityUtils.getUser().getDeptId());
if (entity.getMatchMode() == null) {
entity.setMatchMode(1);
}
if (entity.getStatus() == null) {
entity.setStatus(0);
}
baseMapper.insert(entity);
saveItems(entity.getId(), dto.getItems());
return entity.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updatePlan(CanteenMealPlanSaveDTO dto) {
CanteenMealPlanEntity entity = toEntity(dto);
baseMapper.updateById(entity);
itemMapper.delete(Wrappers.<CanteenMealPlanItemEntity>lambdaQuery()
.eq(CanteenMealPlanItemEntity::getPlanId, dto.getId()));
saveItems(dto.getId(), dto.getItems());
return Boolean.TRUE;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean removePlans(Long[] ids) {
if (ids == null || ids.length == 0) {
return Boolean.TRUE;
}
baseMapper.deleteBatchIds(CollUtil.toList(ids));
itemMapper.delete(Wrappers.<CanteenMealPlanItemEntity>lambdaQuery()
.in(CanteenMealPlanItemEntity::getPlanId, CollUtil.toList(ids)));
return Boolean.TRUE;
}
@Override
public CanteenMealPlanVO getDetail(Long id) {
CanteenMealPlanEntity entity = baseMapper.selectById(id);
if (entity == null) {
return null;
}
CanteenMealPlanVO vo = BeanUtils.toBean(entity, CanteenMealPlanVO.class);
vo.setMerchantName(resolveMerchantName(entity.getMerchantId()));
vo.setPlanDates(buildPlanDates(entity.getStartDate(), entity.getDayCount()));
List<CanteenMealPlanItemEntity> items = itemMapper.selectList(
Wrappers.<CanteenMealPlanItemEntity>lambdaQuery()
.eq(CanteenMealPlanItemEntity::getPlanId, id)
.orderByAsc(CanteenMealPlanItemEntity::getPlanDate)
.orderByAsc(CanteenMealPlanItemEntity::getMealSegment)
.orderByAsc(CanteenMealPlanItemEntity::getSortOrder));
vo.setItems(BeanUtils.toBean(items, CanteenMealPlanItemDTO.class));
vo.setSelectedMaterials(loadMaterialBriefs(entity.getSelectedMaterialIds()));
if (CollUtil.isNotEmpty(entity.getSelectedMaterialIds())) {
CanteenMenuRecipeMatchDTO matchDTO = new CanteenMenuRecipeMatchDTO();
matchDTO.setMaterialIds(entity.getSelectedMaterialIds());
matchDTO.setMerchantId(entity.getMerchantId());
vo.setMatchedRecipes(menuRecipeService.matchByMaterials(matchDTO));
} else {
vo.setMatchedRecipes(Collections.emptyList());
}
return vo;
}
@Override
public List<CanteenMealPlanExportRow> exportRows(Long id) {
CanteenMealPlanVO detail = getDetail(id);
if (detail == null || CollUtil.isEmpty(detail.getItems())) {
return Collections.emptyList();
}
List<CanteenMealPlanExportRow> rows = new ArrayList<>();
for (CanteenMealPlanItemDTO item : detail.getItems()) {
CanteenMealPlanExportRow row = new CanteenMealPlanExportRow();
row.setPlanDate(item.getPlanDate() != null ? item.getPlanDate().toString() : "");
row.setMealSegmentName(SEGMENT_NAMES.getOrDefault(item.getMealSegment(), String.valueOf(item.getMealSegment())));
row.setRecipeName(item.getRecipeName());
rows.add(row);
}
return rows;
}
@Override
public void exportGridExcel(Long id, HttpServletResponse response) {
CanteenMealPlanVO detail = getDetail(id);
if (detail == null) {
throw new IllegalArgumentException("排餐计划不存在");
}
List<LocalDate> dates = detail.getPlanDates();
List<Integer> segments = detail.getMealSegments() != null ? detail.getMealSegments() : Collections.emptyList();
Map<String, List<String>> cellMap = new LinkedHashMap<>();
if (CollUtil.isNotEmpty(detail.getItems())) {
for (CanteenMealPlanItemDTO item : detail.getItems()) {
if (item.getPlanDate() == null || item.getMealSegment() == null) {
continue;
}
String name = item.getRecipeName() != null ? item.getRecipeName().trim() : "";
if (name.isEmpty()) {
continue;
}
String key = buildCellKey(item.getPlanDate(), item.getMealSegment());
cellMap.computeIfAbsent(key, k -> new ArrayList<>()).add(name);
}
}
List<List<String>> rows = new ArrayList<>();
List<String> header = new ArrayList<>();
header.add("餐次");
for (LocalDate d : dates) {
header.add(formatDateHeader(d));
}
rows.add(header);
for (Integer seg : segments) {
List<String> line = new ArrayList<>();
line.add(SEGMENT_NAMES.getOrDefault(seg, String.valueOf(seg)));
for (LocalDate d : dates) {
line.add(formatCellRecipes(cellMap.get(buildCellKey(d, seg))));
}
rows.add(line);
}
try {
String fileName = URLEncoder.encode(
(detail.getPlanName() != null ? detail.getPlanName() : "排餐计划") + "-餐表.xlsx",
StandardCharsets.UTF_8).replace("+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
EasyExcel.write(response.getOutputStream()).sheet("排餐餐表").doWrite(rows);
} catch (IOException e) {
throw new RuntimeException("导出失败", e);
}
}
private CanteenMealPlanEntity toEntity(CanteenMealPlanSaveDTO dto) {
CanteenMealPlanEntity entity = BeanUtils.toBean(dto, CanteenMealPlanEntity.class);
if (entity.getDayCount() == null || entity.getDayCount() < 1) {
entity.setDayCount(1);
}
return entity;
}
private void saveItems(Long planId, List<CanteenMealPlanItemDTO> items) {
if (CollUtil.isEmpty(items)) {
return;
}
Map<Long, String> recipeNameMap = loadRecipeNames(items);
int sort = 0;
for (CanteenMealPlanItemDTO dto : items) {
if (dto.getPlanDate() == null || dto.getMealSegment() == null || dto.getRecipeId() == null) {
continue;
}
CanteenMealPlanItemEntity item = new CanteenMealPlanItemEntity();
item.setPlanId(planId);
item.setPlanDate(dto.getPlanDate());
item.setMealSegment(dto.getMealSegment());
item.setRecipeId(dto.getRecipeId());
String name = dto.getRecipeName();
if (name == null || name.isBlank()) {
name = recipeNameMap.get(dto.getRecipeId());
}
item.setRecipeName(name);
item.setSortOrder(dto.getSortOrder() != null ? dto.getSortOrder() : sort++);
itemMapper.insert(item);
}
}
private Map<Long, String> loadRecipeNames(List<CanteenMealPlanItemDTO> items) {
Set<Long> ids = items.stream().map(CanteenMealPlanItemDTO::getRecipeId).filter(Objects::nonNull)
.collect(Collectors.toSet());
if (ids.isEmpty()) {
return Collections.emptyMap();
}
return menuRecipeMapper.selectBatchIds(ids).stream()
.collect(Collectors.toMap(CanteenMenuRecipeEntity::getId, CanteenMenuRecipeEntity::getName, (a, b) -> a));
}
private List<CanteenMealPlanMaterialBriefVO> loadMaterialBriefs(List<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
}
return erpMaterialMapper.selectBatchIds(ids).stream().map(m -> {
CanteenMealPlanMaterialBriefVO vo = new CanteenMealPlanMaterialBriefVO();
vo.setId(m.getId());
vo.setName(m.getName());
vo.setUnit(m.getUnit());
return vo;
}).toList();
}
private List<LocalDate> buildPlanDates(LocalDate startDate, Integer dayCount) {
if (startDate == null || dayCount == null || dayCount < 1) {
return Collections.emptyList();
}
List<LocalDate> list = new ArrayList<>();
for (int i = 0; i < dayCount; i++) {
list.add(startDate.plusDays(i));
}
return list;
}
private void fillMerchantNames(List<CanteenMealPlanEntity> records) {
if (CollUtil.isEmpty(records)) {
return;
}
Map<String, String> nameMap = loadMerchantNameMap(records.stream()
.map(CanteenMealPlanEntity::getMerchantId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList()));
for (CanteenMealPlanEntity record : records) {
if (StrUtil.isBlank(record.getMerchantId())) {
continue;
}
record.setMerchantName(nameMap.getOrDefault(record.getMerchantId().trim(), record.getMerchantId()));
}
}
private String resolveMerchantName(String merchantId) {
if (StrUtil.isBlank(merchantId)) {
return null;
}
return loadMerchantNameMap(Collections.singletonList(merchantId))
.getOrDefault(merchantId.trim(), merchantId);
}
private Map<String, String> loadMerchantNameMap(List<String> merchantIds) {
if (CollUtil.isEmpty(merchantIds)) {
return Collections.emptyMap();
}
List<Long> ids = merchantIds.stream()
.filter(StrUtil::isNotBlank)
.map(String::trim)
.distinct()
.map(id -> {
try {
return Long.parseLong(id);
}
catch (NumberFormatException ex) {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (ids.isEmpty()) {
return Collections.emptyMap();
}
R<List<MchManageVo>> resp = remoteMchService.getByIds(ids);
if (resp == null || !resp.isOk() || CollUtil.isEmpty(resp.getData())) {
return Collections.emptyMap();
}
return resp.getData().stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(m -> String.valueOf(m.getId()), MchManageVo::getName, (a, b) -> a));
}
private String buildCellKey(LocalDate planDate, Integer mealSegment) {
return planDate + "_" + mealSegment;
}
private String formatDateHeader(LocalDate date) {
int weekday = date.getDayOfWeek().getValue() % 7;
return date.format(DateTimeFormatter.ofPattern("M月d日")) + " 周" + WEEKDAY_LABELS[weekday];
}
private String formatCellRecipes(List<String> recipeNames) {
if (CollUtil.isEmpty(recipeNames)) {
return "";
}
return IntStream.range(0, recipeNames.size())
.mapToObj(i -> (i + 1) + ". " + recipeNames.get(i))
.collect(Collectors.joining("\n"));
}
}
@@ -0,0 +1,219 @@
package com.bsd.pjcloud.canteen.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.canteen.dto.menurecipe.CanteenMenuRecipeMatchDTO;
import com.bsd.pjcloud.canteen.entity.CanteenErpMaterialEntity;
import com.bsd.pjcloud.canteen.entity.CanteenMenuRecipeEntity;
import com.bsd.pjcloud.canteen.entity.CanteenMenuRecipeMaterialEntity;
import com.bsd.pjcloud.canteen.entity.CanteenOnlineSpuEntity;
import com.bsd.pjcloud.canteen.mapper.CanteenErpMaterialMapper;
import com.bsd.pjcloud.canteen.mapper.CanteenMenuRecipeMapper;
import com.bsd.pjcloud.canteen.mapper.CanteenMenuRecipeMaterialMapper;
import com.bsd.pjcloud.canteen.mapper.CanteenOnlineSpuMapper;
import com.bsd.pjcloud.canteen.service.CanteenMenuRecipeService;
import com.bsd.pjcloud.canteen.vo.menurecipe.CanteenMenuRecipeMaterialVO;
import com.bsd.pjcloud.canteen.vo.menurecipe.CanteenMenuRecipeVO;
import com.bsd.pjcloud.common.core.util.BeanUtils;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class CanteenMenuRecipeServiceImpl extends ServiceImpl<CanteenMenuRecipeMapper, CanteenMenuRecipeEntity>
implements CanteenMenuRecipeService {
private final CanteenMenuRecipeMaterialMapper materialMapper;
private final CanteenErpMaterialMapper erpMaterialMapper;
private final CanteenOnlineSpuMapper onlineSpuMapper;
@Override
public Page<CanteenMenuRecipeEntity> pageScope(Page<CanteenMenuRecipeEntity> page,
LambdaQueryWrapper<CanteenMenuRecipeEntity> wrapper) {
Page<CanteenMenuRecipeEntity> pageData = baseMapper.selectPageByScope(page, wrapper, DataScope.of());
fillListExtras(pageData.getRecords());
return pageData;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean saveDeep(CanteenMenuRecipeEntity entity) {
if (entity.getStatus() == null) {
entity.setStatus(0);
}
baseMapper.insert(entity);
saveMaterials(entity.getId(), entity.getMaterialList());
return Boolean.TRUE;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateDeep(CanteenMenuRecipeEntity entity) {
baseMapper.updateById(entity);
materialMapper.delete(Wrappers.<CanteenMenuRecipeMaterialEntity>lambdaQuery()
.eq(CanteenMenuRecipeMaterialEntity::getRecipeId, entity.getId()));
saveMaterials(entity.getId(), entity.getMaterialList());
return Boolean.TRUE;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean removeDeep(Long[] ids) {
if (ids == null || ids.length == 0) {
return Boolean.TRUE;
}
baseMapper.deleteBatchIds(CollUtil.toList(ids));
materialMapper.delete(Wrappers.<CanteenMenuRecipeMaterialEntity>lambdaQuery()
.in(CanteenMenuRecipeMaterialEntity::getRecipeId, CollUtil.toList(ids)));
return Boolean.TRUE;
}
@Override
public CanteenMenuRecipeVO getDetail(Long id) {
CanteenMenuRecipeEntity entity = baseMapper.selectById(id);
if (entity == null) {
return null;
}
CanteenMenuRecipeVO vo = BeanUtils.toBean(entity, CanteenMenuRecipeVO.class);
vo.setMaterialList(loadMaterialVos(id));
vo.setMaterialSummary(buildMaterialSummary(vo.getMaterialList()));
if (entity.getOnlineSpuId() != null) {
CanteenOnlineSpuEntity spu = onlineSpuMapper.selectById(entity.getOnlineSpuId());
if (spu != null) {
vo.setOnlineSpuName(spu.getName());
}
}
return vo;
}
@Override
public List<CanteenMenuRecipeVO> matchByMaterials(CanteenMenuRecipeMatchDTO dto) {
if (dto == null || CollUtil.isEmpty(dto.getMaterialIds())) {
return Collections.emptyList();
}
Set<Long> selected = new HashSet<>(dto.getMaterialIds());
LambdaQueryWrapper<CanteenMenuRecipeEntity> wrapper = Wrappers.<CanteenMenuRecipeEntity>lambdaQuery()
.eq(CanteenMenuRecipeEntity::getStatus, 0);
if (StringUtils.isNotBlank(dto.getMerchantId())) {
wrapper.and(w -> w.eq(CanteenMenuRecipeEntity::getMerchantId, dto.getMerchantId())
.or().isNull(CanteenMenuRecipeEntity::getMerchantId)
.or().eq(CanteenMenuRecipeEntity::getMerchantId, ""));
}
List<CanteenMenuRecipeEntity> recipes = baseMapper.selectListByScope(wrapper, DataScope.of());
if (CollUtil.isEmpty(recipes)) {
return Collections.emptyList();
}
List<Long> recipeIds = recipes.stream().map(CanteenMenuRecipeEntity::getId).toList();
List<CanteenMenuRecipeMaterialEntity> allLines = materialMapper.selectList(
Wrappers.<CanteenMenuRecipeMaterialEntity>lambdaQuery()
.in(CanteenMenuRecipeMaterialEntity::getRecipeId, recipeIds)
.orderByAsc(CanteenMenuRecipeMaterialEntity::getSortOrder));
Map<Long, List<Long>> recipeMaterialMap = allLines.stream()
.collect(Collectors.groupingBy(CanteenMenuRecipeMaterialEntity::getRecipeId,
Collectors.mapping(CanteenMenuRecipeMaterialEntity::getMaterialId, Collectors.toList())));
List<CanteenMenuRecipeVO> matched = new ArrayList<>();
for (CanteenMenuRecipeEntity recipe : recipes) {
List<Long> needIds = recipeMaterialMap.getOrDefault(recipe.getId(), Collections.emptyList());
if (CollUtil.isEmpty(needIds)) {
continue;
}
if (selected.containsAll(needIds)) {
matched.add(getDetail(recipe.getId()));
}
}
return matched;
}
private void saveMaterials(Long recipeId, List<CanteenMenuRecipeMaterialEntity> list) {
if (CollUtil.isEmpty(list)) {
return;
}
int sort = 0;
for (CanteenMenuRecipeMaterialEntity line : list) {
if (line.getMaterialId() == null) {
continue;
}
line.setId(null);
line.setRecipeId(recipeId);
if (line.getSortOrder() == null) {
line.setSortOrder(sort++);
}
materialMapper.insert(line);
}
}
private List<CanteenMenuRecipeMaterialVO> loadMaterialVos(Long recipeId) {
List<CanteenMenuRecipeMaterialEntity> lines = materialMapper.selectList(
Wrappers.<CanteenMenuRecipeMaterialEntity>lambdaQuery()
.eq(CanteenMenuRecipeMaterialEntity::getRecipeId, recipeId)
.orderByAsc(CanteenMenuRecipeMaterialEntity::getSortOrder));
if (CollUtil.isEmpty(lines)) {
return Collections.emptyList();
}
List<CanteenMenuRecipeMaterialVO> vos = BeanUtils.toBean(lines, CanteenMenuRecipeMaterialVO.class);
for (CanteenMenuRecipeMaterialVO vo : vos) {
CanteenErpMaterialEntity material = erpMaterialMapper.selectById(vo.getMaterialId());
if (material != null) {
vo.setMaterialName(material.getName());
vo.setUnit(material.getUnit());
}
}
return vos;
}
private void fillListExtras(List<CanteenMenuRecipeEntity> records) {
if (CollUtil.isEmpty(records)) {
return;
}
List<Long> recipeIds = records.stream().map(CanteenMenuRecipeEntity::getId).toList();
List<CanteenMenuRecipeMaterialEntity> allLines = materialMapper.selectList(
Wrappers.<CanteenMenuRecipeMaterialEntity>lambdaQuery()
.in(CanteenMenuRecipeMaterialEntity::getRecipeId, recipeIds)
.orderByAsc(CanteenMenuRecipeMaterialEntity::getSortOrder));
Set<Long> materialIds = allLines.stream().map(CanteenMenuRecipeMaterialEntity::getMaterialId)
.filter(Objects::nonNull).collect(Collectors.toSet());
Map<Long, CanteenErpMaterialEntity> materialMap = materialIds.isEmpty() ? Collections.emptyMap()
: erpMaterialMapper.selectBatchIds(materialIds).stream()
.collect(Collectors.toMap(CanteenErpMaterialEntity::getId, m -> m, (a, b) -> a));
Map<Long, List<CanteenMenuRecipeMaterialEntity>> grouped = allLines.stream()
.collect(Collectors.groupingBy(CanteenMenuRecipeMaterialEntity::getRecipeId));
Set<Long> spuIds = records.stream().map(CanteenMenuRecipeEntity::getOnlineSpuId).filter(Objects::nonNull)
.collect(Collectors.toSet());
Map<Long, String> spuNameMap = spuIds.isEmpty() ? Collections.emptyMap()
: onlineSpuMapper.selectBatchIds(spuIds).stream()
.collect(Collectors.toMap(CanteenOnlineSpuEntity::getId, CanteenOnlineSpuEntity::getName, (a, b) -> a));
for (CanteenMenuRecipeEntity record : records) {
List<CanteenMenuRecipeMaterialEntity> lines = grouped.getOrDefault(record.getId(), Collections.emptyList());
String summary = lines.stream().map(line -> {
CanteenErpMaterialEntity m = materialMap.get(line.getMaterialId());
return m != null ? m.getName() : String.valueOf(line.getMaterialId());
}).collect(Collectors.joining("、"));
record.setMaterialSummary(summary);
if (record.getOnlineSpuId() != null) {
record.setOnlineSpuName(spuNameMap.get(record.getOnlineSpuId()));
}
}
}
private String buildMaterialSummary(List<CanteenMenuRecipeMaterialVO> list) {
if (CollUtil.isEmpty(list)) {
return "";
}
return list.stream()
.map(vo -> vo.getMaterialName() != null ? vo.getMaterialName() : String.valueOf(vo.getMaterialId()))
.collect(Collectors.joining("、"));
}
}
@@ -61,6 +61,12 @@
<if test="canteenErpMaterial.materialType != null">
and m.material_type = #{canteenErpMaterial.materialType}
</if>
<if test="canteenErpMaterial.nutritionName != null and canteenErpMaterial.nutritionName != ''">
and m.nutrition_tags like concat('%"name":"%', #{canteenErpMaterial.nutritionName}, '%')
</if>
<if test="canteenErpMaterial.nutritionEffect != null and canteenErpMaterial.nutritionEffect != ''">
and m.nutrition_tags like concat('%"effect":"%', #{canteenErpMaterial.nutritionEffect}, '%')
</if>
</where>
</select>
</mapper>