From c9175b929fd9cd5ef55e26695679fef58ad5cde9 Mon Sep 17 00:00:00 2001 From: han0 Date: Wed, 20 Dec 2023 16:27:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(budget):=20=E6=96=B0=E5=A2=9E=E9=A2=84?= =?UTF-8?q?=E7=AE=97=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/constant/HttpErrorResponseEnum.java | 2 + .../main/controller/BudgetController.java | 142 ++++++++++++++++++ .../mjkf/xinke/main/dao/BudgetItemMapper.java | 16 ++ .../mjkf/xinke/main/dao/BudgetMapper.java | 16 ++ .../java/mjkf/xinke/main/model/db/Budget.java | 93 ++++++++++++ .../mjkf/xinke/main/model/db/BudgetItem.java | 84 +++++++++++ .../main/model/vo/BudgetCreateRequest.java | 50 ++++++ .../xinke/main/model/vo/BudgetDetail.java | 48 ++++++ .../xinke/main/service/BudgetItemService.java | 12 ++ .../xinke/main/service/BudgetService.java | 12 ++ .../main/service/PricePublishService.java | 24 +++ 11 files changed, 499 insertions(+) create mode 100644 src/main/java/mjkf/xinke/main/controller/BudgetController.java create mode 100644 src/main/java/mjkf/xinke/main/dao/BudgetItemMapper.java create mode 100644 src/main/java/mjkf/xinke/main/dao/BudgetMapper.java create mode 100644 src/main/java/mjkf/xinke/main/model/db/Budget.java create mode 100644 src/main/java/mjkf/xinke/main/model/db/BudgetItem.java create mode 100644 src/main/java/mjkf/xinke/main/model/vo/BudgetCreateRequest.java create mode 100644 src/main/java/mjkf/xinke/main/model/vo/BudgetDetail.java create mode 100644 src/main/java/mjkf/xinke/main/service/BudgetItemService.java create mode 100644 src/main/java/mjkf/xinke/main/service/BudgetService.java diff --git a/src/main/java/mjkf/xinke/main/constant/HttpErrorResponseEnum.java b/src/main/java/mjkf/xinke/main/constant/HttpErrorResponseEnum.java index fa81301..ad55b90 100644 --- a/src/main/java/mjkf/xinke/main/constant/HttpErrorResponseEnum.java +++ b/src/main/java/mjkf/xinke/main/constant/HttpErrorResponseEnum.java @@ -29,6 +29,8 @@ public enum HttpErrorResponseEnum implements NcHttpErrorResponseInterface { PRICE_PUBLISH_YEAR_MONTH_NEEDED("缺少年份或月份", 1201, HttpStatus.SC_NOT_FOUND), PRICE_PUBLISH_NOT_FOUND("未找到对应数据", 1202, HttpStatus.SC_NOT_FOUND), + + BUDGET_NOT_FOUND("未找到对应数据", 1301, HttpStatus.SC_NOT_FOUND), ; private String message; diff --git a/src/main/java/mjkf/xinke/main/controller/BudgetController.java b/src/main/java/mjkf/xinke/main/controller/BudgetController.java new file mode 100644 index 0000000..3b8c741 --- /dev/null +++ b/src/main/java/mjkf/xinke/main/controller/BudgetController.java @@ -0,0 +1,142 @@ +package mjkf.xinke.main.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jgy.xxs.core.http.exp.NcHttpException; +import com.jgy.xxs.core.http.resp.HttpResponse; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import mjkf.xinke.auth.core.util.StpLoginUserUtil; +import mjkf.xinke.main.common.http.FuHttpResponse; +import mjkf.xinke.main.constant.HttpErrorResponseEnum; +import mjkf.xinke.main.model.db.Budget; +import mjkf.xinke.main.model.db.BudgetItem; +import mjkf.xinke.main.model.db.PricePublish; +import mjkf.xinke.main.model.vo.BudgetCreateRequest; +import mjkf.xinke.main.model.vo.BudgetDetail; +import mjkf.xinke.main.service.BudgetItemService; +import mjkf.xinke.main.service.BudgetService; +import mjkf.xinke.main.service.PricePublishService; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + *

+ * 预算 前端控制器 + *

+ * + * @author han0 + * @since 2023-12-14 + */ +@RestController +@RequestMapping("/budget") +public class BudgetController { + + @Resource + BudgetService budgetService; + + @Resource + BudgetItemService budgetItemService; + + @Resource + PricePublishService pricePublishService; + + @ApiOperation("新增预算") + @PostMapping("/") + @Transactional + public HttpResponse create ( + @ApiParam("参数") @RequestBody BudgetCreateRequest params + ) throws Exception { + params.check(); + var user = StpLoginUserUtil.getLoginUser(); + + // 查询各月份材料价格 + LambdaQueryWrapper query = pricePublishService.getQuery(params); + // 转换查询结果为键值对 材料id,月份 => 价格 + var priceMap = pricePublishService.getPriceMapEntryByMaterialIdAndMonth(query); + // 各月份求和 + var totalMap = new HashMap(); + var budgetItemList = new ArrayList(); + for (var item: params.getItems()) { + var meta = new ArrayList>(); + for (var month: params.getMonths()) { + var key = item.getName() + month.toString(); + var price = priceMap.getOrDefault(key, 0); + meta.add(Map.of( + "month", month, + "total", price * item.getQuantity(), + "price", price + ) + ); + var total = totalMap.getOrDefault(month.toString(), 0); + totalMap.put(month.toString(), total + price * item.getQuantity()); + // 遍历月份 获取各材料各月份总数 + } + var budgetItem = new BudgetItem(item, meta); + budgetItemList.add(budgetItem); + } + // 入库 + var budget = new Budget(params, user, totalMap); + budgetService.save(budget); + for (var budgetItem: budgetItemList) { + budgetItem.setBudgetId(budget.getId()); + budgetItemService.save(budgetItem); + } + + return FuHttpResponse.Builder().dataResponse(budgetItemList).build(); + } + + @ApiOperation("查询预算") + @GetMapping("/") + public HttpResponse list ( + @ApiParam("每页数量") @RequestParam(name = "limit", defaultValue = "10") Integer limit, + @ApiParam("页码") @RequestParam(name = "page", defaultValue = "1") Integer page, + @ApiParam(value = "名称") @RequestParam(value="name") String name + ) throws Exception { + var query = new LambdaQueryWrapper(); + if (!ObjectUtils.isEmpty(name)) { + query.like(Budget::getName, name); + } + var result = budgetService.page(new Page<>(page, limit), query); + return FuHttpResponse.Builder().dataResponse(result).build(); + } + + @ApiOperation("删除预算") + @DeleteMapping("/") + public HttpResponse delete ( + @ApiParam(value = "id列表:1,2,3") @RequestParam(value="ids") String ids + ) throws Exception { + var idList = Arrays.asList(ids.split(",")); + var query = new LambdaQueryWrapper(); + query.in(Budget::getId, idList); + budgetService.remove(query); + return FuHttpResponse.Builder().dataResponse().build(); + } + + @ApiOperation("预算详情") + @GetMapping("/{id}") + public HttpResponse detail ( + @ApiParam(value = "id") @PathVariable("id") Integer id + ) throws Exception { + var budget = budgetService.getById(id); + if (budget == null) { + throw new NcHttpException(HttpErrorResponseEnum.BUDGET_NOT_FOUND); + } + + var query = new LambdaQueryWrapper(); + query.eq(BudgetItem::getBudgetId, id); + var list = budgetItemService.list(query); + + var result = new BudgetDetail(budget, list); + return FuHttpResponse.Builder().dataResponse(result).build(); + } + + // todo 在价格发布创建时补全材料id +} diff --git a/src/main/java/mjkf/xinke/main/dao/BudgetItemMapper.java b/src/main/java/mjkf/xinke/main/dao/BudgetItemMapper.java new file mode 100644 index 0000000..71d3649 --- /dev/null +++ b/src/main/java/mjkf/xinke/main/dao/BudgetItemMapper.java @@ -0,0 +1,16 @@ +package mjkf.xinke.main.dao; + +import mjkf.xinke.main.model.db.BudgetItem; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author han0 + * @since 2023-12-19 + */ +public interface BudgetItemMapper extends BaseMapper { + +} diff --git a/src/main/java/mjkf/xinke/main/dao/BudgetMapper.java b/src/main/java/mjkf/xinke/main/dao/BudgetMapper.java new file mode 100644 index 0000000..0d8a514 --- /dev/null +++ b/src/main/java/mjkf/xinke/main/dao/BudgetMapper.java @@ -0,0 +1,16 @@ +package mjkf.xinke.main.dao; + +import mjkf.xinke.main.model.db.Budget; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author han0 + * @since 2023-12-19 + */ +public interface BudgetMapper extends BaseMapper { + +} diff --git a/src/main/java/mjkf/xinke/main/model/db/Budget.java b/src/main/java/mjkf/xinke/main/model/db/Budget.java new file mode 100644 index 0000000..5ba938e --- /dev/null +++ b/src/main/java/mjkf/xinke/main/model/db/Budget.java @@ -0,0 +1,93 @@ +package mjkf.xinke.main.model.db; + +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 java.io.Serializable; +import java.time.LocalDate; +import java.util.*; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import mjkf.xinke.auth.core.pojo.SaBaseLoginUser; +import mjkf.xinke.main.common.serializer.FastjsonArrayHandler; +import mjkf.xinke.main.model.vo.BudgetCreateRequest; + +/** + *

+ * + *

+ * + * @author han0 + * @since 2023-12-19 + */ +@Getter +@Setter +@TableName(value="BUDGET", autoResultMap=true) +@ApiModel(value = "Budget对象", description = "") +public class Budget extends Model { + + private static final long serialVersionUID = 1L; + + @TableId(value = "ID", type = IdType.AUTO) + private Integer id; + + @ApiModelProperty("名称") + @TableField("`NAME`") + private String name; + + @ApiModelProperty("总数") + @TableField("AMOUNT") + private Integer amount; + + @ApiModelProperty("最小值") + @TableField("MIN_AMOUNT") + @JsonProperty(value = "min_amount") + private Integer minAmount; + + @ApiModelProperty("最大值") + @TableField("MAX_AMOUNT") + @JsonProperty(value = "max_amount") + private Integer maxAmount; + + @ApiModelProperty("日期") + @TableField("`DATE`") + private LocalDate date; + + @ApiModelProperty("年份") + @TableField("`YEAR`") + private Integer year; + + @ApiModelProperty("月份") + @TableField(value="`MONTHS`", typeHandler = FastjsonArrayHandler.class) + private List months; + + @Override + public Serializable pkVal() { + return this.id; + } + + public Budget() {} + + public Budget(BudgetCreateRequest params, SaBaseLoginUser user, HashMap totalMap) { + this.name = params.getName(); + this.amount = params.getItems().stream().mapToInt(item -> item.getTotalPrice()).sum(); + + List> list = new ArrayList(totalMap.entrySet()); + Collections.sort(list, (o1, o2) -> (o1.getValue() - o2.getValue())); + + this.minAmount = list.get(0).getValue(); + this.maxAmount = list.get(list.size() -1).getValue(); +// list.get(0).getKey(); +// list.get(list.size() -1 ).getKey(); + this.date = LocalDate.now(); + this.year = params.getYear(); + this.months = params.getMonths(); + } + +} diff --git a/src/main/java/mjkf/xinke/main/model/db/BudgetItem.java b/src/main/java/mjkf/xinke/main/model/db/BudgetItem.java new file mode 100644 index 0000000..73d3712 --- /dev/null +++ b/src/main/java/mjkf/xinke/main/model/db/BudgetItem.java @@ -0,0 +1,84 @@ +package mjkf.xinke.main.model.db; + +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 java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import mjkf.xinke.main.common.serializer.FastjsonArrayHandler; +import mjkf.xinke.main.model.vo.BudgetCreateRequest; + +/** + *

+ * + *

+ * + * @author han0 + * @since 2023-12-19 + */ +@Getter +@Setter +@TableName(value="BUDGET_ITEM", autoResultMap=true) +@ApiModel(value = "BudgetItem对象", description = "") +public class BudgetItem extends Model { + + private static final long serialVersionUID = 1L; + + @TableId(value = "ID", type = IdType.AUTO) + private Integer id; + + @ApiModelProperty("预算id") + @TableField("BUDGET_ID") + @JsonProperty(value = "budget_id") + private Integer budgetId; + + @ApiModelProperty("名称") + @TableField("`NAME`") + private String name; + + @ApiModelProperty("总数") + @TableField("QUANTITY") + private Integer quantity; + + @ApiModelProperty("数据") + @TableField(value="`META`", typeHandler = FastjsonArrayHandler.class) + private List> meta; + + @ApiModelProperty("单位") + @TableField("UNIT") + private String unit; + + @ApiModelProperty("单价") + @TableField("UNIT_PRICE") + private Integer unitPrice; + + @ApiModelProperty("总价") + @TableField("TOTAL_PRICE") + private Integer totalPrice; + + @Override + public Serializable pkVal() { + return this.id; + } + + public BudgetItem() {} + + public BudgetItem(BudgetCreateRequest.BudgetMaterial item, ArrayList> meta) { + this.meta = meta; + this.name = item.getName(); + this.quantity = item.getTotalPrice(); + this.unit = item.getUnit(); + this.unitPrice = item.getUnitPrice(); + this.totalPrice = item.getTotalPrice(); + } +} diff --git a/src/main/java/mjkf/xinke/main/model/vo/BudgetCreateRequest.java b/src/main/java/mjkf/xinke/main/model/vo/BudgetCreateRequest.java new file mode 100644 index 0000000..f5bca1f --- /dev/null +++ b/src/main/java/mjkf/xinke/main/model/vo/BudgetCreateRequest.java @@ -0,0 +1,50 @@ +package mjkf.xinke.main.model.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +public class BudgetCreateRequest { + + @ApiModelProperty("项目名称") + private String name; + + @ApiModelProperty("年份") + private Integer year; + + @ApiModelProperty("月份") + private List months; + + @ApiModelProperty("材料") + private List items; + + public void check() throws Exception{ + } + + @Data + static public class BudgetMaterial implements Serializable { + @ApiModelProperty("材料id") + private String id; + + @ApiModelProperty("材料名称") + private String name; + + @ApiModelProperty("单位") + private String unit; + + @ApiModelProperty("单价") + @JsonProperty(value = "unit_price") + private Integer unitPrice; + + @ApiModelProperty("数量") + private Integer quantity; + + @ApiModelProperty("总价") + @JsonProperty(value = "total_price") + private Integer totalPrice; + } +} diff --git a/src/main/java/mjkf/xinke/main/model/vo/BudgetDetail.java b/src/main/java/mjkf/xinke/main/model/vo/BudgetDetail.java new file mode 100644 index 0000000..a18af75 --- /dev/null +++ b/src/main/java/mjkf/xinke/main/model/vo/BudgetDetail.java @@ -0,0 +1,48 @@ +package mjkf.xinke.main.model.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import mjkf.xinke.main.model.db.Budget; +import mjkf.xinke.main.model.db.BudgetItem; +import mjkf.xinke.main.model.db.LocalMaterial; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +@Data +public class BudgetDetail{ + private Integer id; + + private String name; + + private Integer amount; + + @JsonProperty(value = "min_amount") + private Integer minAmount; + + @JsonProperty(value = "max_amount") + private Integer maxAmount; + + private LocalDate date; + + private Integer year; + + private List months; + + private List list; + + public BudgetDetail() {} + + public BudgetDetail(Budget data, List list) { + this.id = data.getId(); + this.name = data.getName(); + this.amount = data.getAmount(); + this.minAmount = data.getMinAmount(); + this.maxAmount = data.getMaxAmount(); + this.date = data.getDate(); + this.year = data.getYear(); + this.months = data.getMonths(); + this.list = list; + } +} diff --git a/src/main/java/mjkf/xinke/main/service/BudgetItemService.java b/src/main/java/mjkf/xinke/main/service/BudgetItemService.java new file mode 100644 index 0000000..3e2e9a0 --- /dev/null +++ b/src/main/java/mjkf/xinke/main/service/BudgetItemService.java @@ -0,0 +1,12 @@ +package mjkf.xinke.main.service; + +import mjkf.xinke.main.model.db.BudgetItem; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +@Service +public class BudgetItemService extends ServiceImpl, BudgetItem> { + +} + diff --git a/src/main/java/mjkf/xinke/main/service/BudgetService.java b/src/main/java/mjkf/xinke/main/service/BudgetService.java new file mode 100644 index 0000000..3f5613e --- /dev/null +++ b/src/main/java/mjkf/xinke/main/service/BudgetService.java @@ -0,0 +1,12 @@ +package mjkf.xinke.main.service; + +import mjkf.xinke.main.model.db.Budget; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +@Service +public class BudgetService extends ServiceImpl, Budget> { + +} + diff --git a/src/main/java/mjkf/xinke/main/service/PricePublishService.java b/src/main/java/mjkf/xinke/main/service/PricePublishService.java index d126dcd..ef2bfcf 100644 --- a/src/main/java/mjkf/xinke/main/service/PricePublishService.java +++ b/src/main/java/mjkf/xinke/main/service/PricePublishService.java @@ -4,8 +4,13 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import mjkf.xinke.main.model.db.PricePublish; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import mjkf.xinke.main.model.vo.BudgetCreateRequest; import org.springframework.stereotype.Service; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + @Service public class PricePublishService extends ServiceImpl, PricePublish> { @@ -28,5 +33,24 @@ public class PricePublishService extends ServiceImpl, P } return query; } + + public LambdaQueryWrapper getQuery(BudgetCreateRequest params) { + var query = new LambdaQueryWrapper(); + query.eq(PricePublish::getYear, params.getYear()); + query.in(PricePublish::getMonth, params.getMonths()); + query.in(PricePublish::getName, params.getItems().stream().map(item -> item.getName()).collect(Collectors.toList())); +// query.in(PricePublish::getMaterialId, params.getItems().stream().map(item -> item.getId()).collect(Collectors.toList())); + return query; + } + + public Map getPriceMapEntryByMaterialIdAndMonth(LambdaQueryWrapper query) { + var result = new HashMap(); + var items = this.list(query); + for (PricePublish item: items) { + var key = item.getName() + item.getMonth().toString(); + result.put(key, item.getPrice().intValue()); + } + return result; + } }