From 46b422214d5d422be5dfa0df57560cda678058c9 Mon Sep 17 00:00:00 2001
From: chen.llin <1442464845@qq.comm>
Date: 星期三, 24 十二月 2025 08:30:38 +0800
Subject: [PATCH] 月结功能-主体
---
src/main/java/com/zy/asrs/mapper/MonthlySettleDetailMapper.java | 20
src/main/resources/mapper/MonthlySettleDetailMapper.xml | 62 +
src/main/java/com/zy/asrs/entity/MonthlySettleDetail.java | 157 ++++
src/main/java/com/zy/asrs/entity/param/DateRangeParam.java | 29
src/main/webapp/static/js/monthlySettle/monthlySettle.js | 630 +++++++++++++++++
src/main/java/com/zy/asrs/entity/result/MonthlySettleResultVO.java | 44 +
src/main/java/com/zy/asrs/service/impl/MonthlySettleServiceImpl.java | 385 ++++++++++
src/main/webapp/views/monthlySettle/monthlySettle.html | 122 +++
src/main/java/com/zy/asrs/mapper/MonthlySettleMapper.java | 64 +
src/main/java/com/zy/asrs/service/MonthlySettleService.java | 54 +
src/main/java/com/zy/asrs/controller/MonthlySettleController.java | 135 +++
src/main/java/com/zy/asrs/entity/result/MaterialInOutStatDTO.java | 43 +
src/main/java/com/zy/asrs/entity/result/PreviousSettleEndingQtyDTO.java | 33
src/main/resources/mapper/MonthlySettleMapper.xml | 159 ++++
src/main/java/com/zy/asrs/entity/result/MonthlySettleStatisticsVO.java | 28
src/main/java/com/zy/asrs/entity/MonthlySettle.java | 188 +++++
src/main/java/com/zy/asrs/entity/param/MonthlySettleQueryParam.java | 48 +
17 files changed, 2,201 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/zy/asrs/controller/MonthlySettleController.java b/src/main/java/com/zy/asrs/controller/MonthlySettleController.java
new file mode 100644
index 0000000..a3c847a
--- /dev/null
+++ b/src/main/java/com/zy/asrs/controller/MonthlySettleController.java
@@ -0,0 +1,135 @@
+package com.zy.asrs.controller;
+
+import com.baomidou.mybatisplus.plugins.Page;
+import com.core.annotations.ManagerAuth;
+import com.core.common.R;
+import com.zy.asrs.entity.MonthlySettle;
+import com.zy.asrs.entity.param.DateRangeParam;
+import com.zy.asrs.entity.param.MonthlySettleQueryParam;
+import com.zy.asrs.service.MonthlySettleService;
+import com.zy.common.web.BaseController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@RestController
+public class MonthlySettleController extends BaseController {
+
+ @Autowired
+ private MonthlySettleService monthlySettleService;
+
+ /**
+ * 鑾峰彇鏈堢粨淇℃伅
+ */
+ @RequestMapping(value = "/monthlySettle/{id}/auth")
+ @ManagerAuth
+ public R get(@PathVariable("id") Long id) {
+ return R.ok(monthlySettleService.selectById(id));
+ }
+
+ /**
+ * 鍒嗛〉鏌ヨ鏈堢粨鍒楄〃
+ */
+ @RequestMapping(value = "/monthlySettle/list/auth")
+ @ManagerAuth
+ public R list(MonthlySettleQueryParam param) {
+ Page<MonthlySettle> page = new Page<>(param.getCurr(), param.getLimit());
+ java.util.Map<String, Object> condition = new java.util.HashMap<>();
+ if (param.getSettleNo() != null && !param.getSettleNo().trim().isEmpty()) {
+ condition.put("settleNo", param.getSettleNo());
+ }
+ if (param.getStatus() != null) {
+ condition.put("status", param.getStatus());
+ }
+ if (param.getStartDate() != null && !param.getStartDate().trim().isEmpty()
+ && param.getEndDate() != null && !param.getEndDate().trim().isEmpty()) {
+ condition.put("startDate", param.getStartDate());
+ condition.put("endDate", param.getEndDate());
+ }
+ page.setCondition(condition);
+ return R.ok(monthlySettleService.getPage(page));
+ }
+
+ /**
+ * 鑾峰彇鏈�杩戠殑鏈堢粨璁板綍
+ */
+ @RequestMapping(value = "/monthlySettle/latest/auth")
+ @ManagerAuth
+ public R getLatest() {
+ MonthlySettle latest = monthlySettleService.getLatestSettle();
+ return R.ok(latest);
+ }
+
+ /**
+ * 鑾峰彇涓嬩竴涓湀缁撶殑璧峰鏃ユ湡
+ */
+ @RequestMapping(value = "/monthlySettle/nextStartDate/auth")
+ @ManagerAuth
+ public R getNextStartDate() {
+ Date nextStartDate = monthlySettleService.getNextStartDate();
+ if (nextStartDate != null) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ return R.ok(sdf.format(nextStartDate));
+ }
+ return R.ok(null);
+ }
+
+ /**
+ * 鑾峰彇鏈�鏅氭湀缁撹褰曠殑缁撴潫鏃ユ湡
+ */
+ @RequestMapping(value = "/monthlySettle/latestEndDate/auth")
+ @ManagerAuth
+ public R getLatestEndDate() {
+ Date latestEndDate = monthlySettleService.getLatestEndDate();
+ if (latestEndDate != null) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ return R.ok(sdf.format(latestEndDate));
+ }
+ return R.ok(null);
+ }
+
+ /**
+ * 妫�鏌ユ湀缁撴椂闂磋寖鍥村唴鏄惁鏈夋湭瀹屾垚鐨勮鍗�
+ */
+ @RequestMapping(value = "/monthlySettle/checkUnfinished/auth")
+ @ManagerAuth
+ public R checkUnfinished(DateRangeParam param) {
+ boolean hasUnfinished = monthlySettleService.hasUnfinishedOrders(param.getStartDate(), param.getEndDate());
+ if (hasUnfinished) {
+ return R.error("鏈堢粨鏃堕棿鑼冨洿鍐呭瓨鍦ㄦ湭瀹屾垚鐨勮鍗曪紝鏃犳硶杩涜鏈堢粨");
+ }
+ return R.ok();
+ }
+
+ /**
+ * 鍙戣捣鏈堢粨
+ */
+ @RequestMapping(value = "/monthlySettle/start/auth")
+ @ManagerAuth
+ public R startSettle(DateRangeParam param) {
+ return R.ok(monthlySettleService.startSettle(param.getStartDate(), param.getEndDate(), getUserId()));
+ }
+
+ /**
+ * 鑾峰彇鏈堢粨缁熻淇℃伅
+ */
+ @RequestMapping(value = "/monthlySettle/statistics/{id}/auth")
+ @ManagerAuth
+ public R getStatistics(@PathVariable("id") Long id) {
+ return R.ok(monthlySettleService.getSettleStatistics(id));
+ }
+
+ /**
+ * 鍒犻櫎鏈堢粨璁板綍
+ */
+ @RequestMapping(value = "/monthlySettle/{id}/auth", method = RequestMethod.DELETE)
+ @ManagerAuth
+ public R delete(@PathVariable("id") Long id) {
+ monthlySettleService.deleteSettle(id);
+ return R.ok("鍒犻櫎鎴愬姛");
+ }
+
+}
+
diff --git a/src/main/java/com/zy/asrs/entity/MonthlySettle.java b/src/main/java/com/zy/asrs/entity/MonthlySettle.java
new file mode 100644
index 0000000..73df7e9
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/MonthlySettle.java
@@ -0,0 +1,188 @@
+package com.zy.asrs.entity;
+
+import com.baomidou.mybatisplus.annotations.TableField;
+import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.annotations.TableName;
+import com.baomidou.mybatisplus.enums.IdType;
+import com.core.common.Cools;
+import com.core.common.SpringUtils;
+import com.zy.system.entity.User;
+import com.zy.system.service.UserService;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@Data
+@TableName("man_monthly_settle")
+public class MonthlySettle implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * ID
+ */
+ @ApiModelProperty(value = "ID")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 鏈堢粨缂栧彿
+ */
+ @ApiModelProperty(value = "鏈堢粨缂栧彿")
+ @TableField("settle_no")
+ private String settleNo;
+
+ /**
+ * 璧峰鏃ユ湡
+ */
+ @ApiModelProperty(value = "璧峰鏃ユ湡")
+ @TableField("start_date")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date startDate;
+
+ /**
+ * 缁撴潫鏃ユ湡
+ */
+ @ApiModelProperty(value = "缁撴潫鏃ユ湡")
+ @TableField("end_date")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date endDate;
+
+ /**
+ * 鐘舵�� 0:寰呮湀缁� 1:宸叉湀缁�
+ */
+ @ApiModelProperty(value = "鐘舵�� 0:寰呮湀缁� 1:宸叉湀缁�")
+ private Integer status;
+
+ /**
+ * 鎬诲叆搴撴暟閲�
+ */
+ @ApiModelProperty(value = "鎬诲叆搴撴暟閲�")
+ @TableField("total_in_qty")
+ private BigDecimal totalInQty;
+
+ /**
+ * 鎬诲嚭搴撴暟閲�
+ */
+ @ApiModelProperty(value = "鎬诲嚭搴撴暟閲�")
+ @TableField("total_out_qty")
+ private BigDecimal totalOutQty;
+
+ /**
+ * 鐗╂枡绉嶇被鏁�
+ */
+ @ApiModelProperty(value = "鐗╂枡绉嶇被鏁�")
+ @TableField("total_materials")
+ private Integer totalMaterials;
+
+ /**
+ * 澶囨敞
+ */
+ @ApiModelProperty(value = "澶囨敞")
+ private String memo;
+
+ /**
+ * 鍒涘缓浜哄憳
+ */
+ @ApiModelProperty(value = "鍒涘缓浜哄憳")
+ @TableField("create_by")
+ private Long createBy;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+ @TableField("create_time")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+
+ /**
+ * 淇敼浜哄憳
+ */
+ @ApiModelProperty(value = "淇敼浜哄憳")
+ @TableField("update_by")
+ private Long updateBy;
+
+ /**
+ * 淇敼鏃堕棿
+ */
+ @ApiModelProperty(value = "淇敼鏃堕棿")
+ @TableField("update_time")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+
+ /**
+ * 鍒犻櫎鏍囪 0:鏈垹闄� 1:宸插垹闄�
+ */
+ @ApiModelProperty(value = "鍒犻櫎鏍囪 0:鏈垹闄� 1:宸插垹闄�")
+ @TableField("is_deleted")
+ private Integer isDeleted;
+
+ public String getStatus$() {
+ if (null == this.status) {
+ return null;
+ }
+ switch (this.status) {
+ case 0:
+ return "寰呮湀缁�";
+ case 1:
+ return "宸叉湀缁�";
+ default:
+ return String.valueOf(this.status);
+ }
+ }
+
+
+ public String getStartDate$() {
+ if (Cools.isEmpty(this.startDate)) {
+ return "";
+ }
+ return new SimpleDateFormat("yyyy-MM-dd").format(this.startDate);
+ }
+
+ public String getEndDate$() {
+ if (Cools.isEmpty(this.endDate)) {
+ return "";
+ }
+ return new SimpleDateFormat("yyyy-MM-dd").format(this.endDate);
+ }
+
+ public String getCreateBy$() {
+ UserService service = SpringUtils.getBean(UserService.class);
+ User user = service.selectById(this.createBy);
+ if (!Cools.isEmpty(user)) {
+ return String.valueOf(user.getUsername());
+ }
+ return null;
+ }
+
+ public String getCreateTime$() {
+ if (Cools.isEmpty(this.createTime)) {
+ return "";
+ }
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime);
+ }
+
+ public String getUpdateBy$() {
+ UserService service = SpringUtils.getBean(UserService.class);
+ User user = service.selectById(this.updateBy);
+ if (!Cools.isEmpty(user)) {
+ return String.valueOf(user.getUsername());
+ }
+ return null;
+ }
+
+ public String getUpdateTime$() {
+ if (Cools.isEmpty(this.updateTime)) {
+ return "";
+ }
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime);
+ }
+}
+
+
diff --git a/src/main/java/com/zy/asrs/entity/MonthlySettleDetail.java b/src/main/java/com/zy/asrs/entity/MonthlySettleDetail.java
new file mode 100644
index 0000000..01db1d5
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/MonthlySettleDetail.java
@@ -0,0 +1,157 @@
+package com.zy.asrs.entity;
+
+import com.baomidou.mybatisplus.annotations.TableField;
+import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.annotations.TableName;
+import com.baomidou.mybatisplus.enums.IdType;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@TableName("man_monthly_settle_detail")
+public class MonthlySettleDetail implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * ID
+ */
+ @ApiModelProperty(value = "ID")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 鏈堢粨涓昏〃ID
+ */
+ @ApiModelProperty(value = "鏈堢粨涓昏〃ID")
+ @TableField("settle_id")
+ private Long settleId;
+
+ /**
+ * 鏈堢粨缂栧彿
+ */
+ @ApiModelProperty(value = "鏈堢粨缂栧彿")
+ @TableField("settle_no")
+ private String settleNo;
+
+ // ========== 鍩烘湰淇℃伅 ==========
+ /**
+ * 鐗╂枡缂栫爜
+ */
+ @ApiModelProperty(value = "鐗╂枡缂栫爜")
+ private String matnr;
+
+ /**
+ * 鎵规锛堣鍗曟槑缁嗘壒娆★級
+ */
+ @ApiModelProperty(value = "鎵规")
+ private String batch;
+
+ /**
+ * 鐗╂枡鍚嶇О锛堟湀缁撴椂浠庤鍗曟槑缁嗚〃鑾峰彇锛�
+ */
+ @ApiModelProperty(value = "鐗╂枡鍚嶇О")
+ private String maktx;
+
+ /**
+ * 鍝佺墝锛堟湀缁撴椂浠庤鍗曟槑缁嗚〃鑾峰彇锛�
+ */
+ @ApiModelProperty(value = "鍝佺墝")
+ private String brand;
+
+ // ========== 鏁伴噺淇℃伅 ==========
+ /**
+ * 鏈熷垵搴撳瓨锛堜笂鏈熺粨浣欙級
+ */
+ @ApiModelProperty(value = "鏈熷垵搴撳瓨锛堜笂鏈熺粨浣欙級")
+ @TableField("beginning_qty")
+ private BigDecimal beginningQty;
+
+ /**
+ * 鏈湡鍏ュ簱鏁伴噺
+ */
+ @ApiModelProperty(value = "鏈湡鍏ュ簱鏁伴噺")
+ @TableField("in_qty")
+ private BigDecimal inQty;
+
+ /**
+ * 鏈湡鍑哄簱鏁伴噺
+ */
+ @ApiModelProperty(value = "鏈湡鍑哄簱鏁伴噺")
+ @TableField("out_qty")
+ private BigDecimal outQty;
+
+ /**
+ * 鏈熸湯搴撳瓨锛堟湡鍒�+鍏ュ簱-鍑哄簱锛�
+ */
+ @ApiModelProperty(value = "鏈熸湯搴撳瓨锛堟湡鍒�+鍏ュ簱-鍑哄簱锛�")
+ @TableField("ending_qty")
+ private BigDecimal endingQty;
+
+ /**
+ * 褰撳墠瀹為檯搴撳瓨鏁伴噺
+ */
+ @ApiModelProperty(value = "褰撳墠瀹為檯搴撳瓨鏁伴噺")
+ @TableField("stock_qty")
+ private BigDecimal stockQty;
+
+ /**
+ * 宸紓鏁伴噺锛堝疄闄呭簱瀛�-鏈熸湯搴撳瓨锛�
+ */
+ @ApiModelProperty(value = "宸紓鏁伴噺锛堝疄闄呭簱瀛�-鏈熸湯搴撳瓨锛�")
+ @TableField("diff_qty")
+ private BigDecimal diffQty;
+
+ // ========== 鍏宠仈瀛楁锛堥�氳繃鍏宠仈鏌ヨ鑾峰彇锛屼笉瀛樺偍鍦ㄦ槑缁嗚〃涓級==========
+
+ /**
+ * 瑙勬牸锛堜紭鍏堜粠鍑哄叆搴撹鍗曟槑缁嗚〃鑾峰彇锛屽鏋滀负绌哄垯浠庣墿鏂欒〃鑾峰彇锛�
+ */
+ @ApiModelProperty(value = "瑙勬牸")
+ @TableField(exist = false)
+ private String specs;
+
+ /**
+ * 鍨嬪彿锛堜紭鍏堜粠鍑哄叆搴撹鍗曟槑缁嗚〃鑾峰彇锛屽鏋滀负绌哄垯浠庣墿鏂欒〃鑾峰彇锛�
+ */
+ @ApiModelProperty(value = "鍨嬪彿")
+ @TableField(exist = false)
+ private String model;
+
+ /**
+ * 棰滆壊锛堜紭鍏堜粠鍑哄叆搴撹鍗曟槑缁嗚〃鑾峰彇锛屽鏋滀负绌哄垯浠庣墿鏂欒〃鑾峰彇锛�
+ */
+ @ApiModelProperty(value = "棰滆壊")
+ @TableField(exist = false)
+ private String color;
+
+ /**
+ * 鍗曚綅锛堜粠鐗╂枡琛ㄨ幏鍙栵級
+ */
+ @ApiModelProperty(value = "鍗曚綅")
+ @TableField(exist = false)
+ private String unit;
+
+ // ========== 鏃堕棿淇℃伅 ==========
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+ @TableField("create_time")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+
+ /**
+ * 鍒犻櫎鏍囪 0:鏈垹闄� 1:宸插垹闄�
+ */
+ @ApiModelProperty(value = "鍒犻櫎鏍囪 0:鏈垹闄� 1:宸插垹闄�")
+ @TableField("is_deleted")
+ private Integer isDeleted;
+}
+
+
diff --git a/src/main/java/com/zy/asrs/entity/param/DateRangeParam.java b/src/main/java/com/zy/asrs/entity/param/DateRangeParam.java
new file mode 100644
index 0000000..cb59c60
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/param/DateRangeParam.java
@@ -0,0 +1,29 @@
+package com.zy.asrs.entity.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * 鏃ユ湡鑼冨洿鍙傛暟
+ */
+@Data
+public class DateRangeParam {
+
+ /**
+ * 璧峰鏃ユ湡
+ */
+ @ApiModelProperty(value = "璧峰鏃ユ湡", required = true)
+ @DateTimeFormat(pattern = "yyyy-MM-dd")
+ private Date startDate;
+
+ /**
+ * 缁撴潫鏃ユ湡锛堝彲浠ユ帴鍙� yyyy-MM-dd 鎴� yyyy-MM-dd HH:mm:ss 鏍煎紡锛�
+ */
+ @ApiModelProperty(value = "缁撴潫鏃ユ湡", required = true)
+ @DateTimeFormat(pattern = "yyyy-MM-dd")
+ private Date endDate;
+}
+
diff --git a/src/main/java/com/zy/asrs/entity/param/MonthlySettleQueryParam.java b/src/main/java/com/zy/asrs/entity/param/MonthlySettleQueryParam.java
new file mode 100644
index 0000000..e6b0a20
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/param/MonthlySettleQueryParam.java
@@ -0,0 +1,48 @@
+package com.zy.asrs.entity.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 鏈堢粨鏌ヨ鍙傛暟
+ */
+@Data
+public class MonthlySettleQueryParam {
+
+ /**
+ * 褰撳墠椤�
+ */
+ @ApiModelProperty(value = "褰撳墠椤�")
+ private Integer curr = 1;
+
+ /**
+ * 姣忛〉鏁伴噺
+ */
+ @ApiModelProperty(value = "姣忛〉鏁伴噺")
+ private Integer limit = 10;
+
+ /**
+ * 鏈堢粨缂栧彿
+ */
+ @ApiModelProperty(value = "鏈堢粨缂栧彿")
+ private String settleNo;
+
+ /**
+ * 鐘舵��
+ */
+ @ApiModelProperty(value = "鐘舵��")
+ private Integer status;
+
+ /**
+ * 璧峰鏃ユ湡
+ */
+ @ApiModelProperty(value = "璧峰鏃ユ湡")
+ private String startDate;
+
+ /**
+ * 缁撴潫鏃ユ湡
+ */
+ @ApiModelProperty(value = "缁撴潫鏃ユ湡")
+ private String endDate;
+}
+
diff --git a/src/main/java/com/zy/asrs/entity/result/MaterialInOutStatDTO.java b/src/main/java/com/zy/asrs/entity/result/MaterialInOutStatDTO.java
new file mode 100644
index 0000000..ddb57a0
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/result/MaterialInOutStatDTO.java
@@ -0,0 +1,43 @@
+package com.zy.asrs.entity.result;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 鐗╂枡鍑哄叆搴撶粺璁�
+ */
+@Data
+public class MaterialInOutStatDTO {
+
+ /**
+ * 鐗╂枡缂栫爜
+ */
+ private String matnr;
+
+ /**
+ * 鐗╂枡鍚嶇О
+ */
+ private String maktx;
+
+ /**
+ * 鎵规
+ */
+ private String batch;
+
+ /**
+ * 鍝佺墝
+ */
+ private String brand;
+
+ /**
+ * 鍏ュ簱鏁伴噺
+ */
+ private BigDecimal inQty;
+
+ /**
+ * 鍑哄簱鏁伴噺
+ */
+ private BigDecimal outQty;
+}
+
diff --git a/src/main/java/com/zy/asrs/entity/result/MonthlySettleResultVO.java b/src/main/java/com/zy/asrs/entity/result/MonthlySettleResultVO.java
new file mode 100644
index 0000000..77ec981
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/result/MonthlySettleResultVO.java
@@ -0,0 +1,44 @@
+package com.zy.asrs.entity.result;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 鏈堢粨缁撴灉
+ */
+@Data
+public class MonthlySettleResultVO {
+
+ /**
+ * 鏈堢粨ID
+ */
+ @ApiModelProperty(value = "鏈堢粨ID")
+ private Long settleId;
+
+ /**
+ * 鏈堢粨缂栧彿
+ */
+ @ApiModelProperty(value = "鏈堢粨缂栧彿")
+ private String settleNo;
+
+ /**
+ * 鎬诲叆搴撴暟閲�
+ */
+ @ApiModelProperty(value = "鎬诲叆搴撴暟閲�")
+ private BigDecimal totalInQty;
+
+ /**
+ * 鎬诲嚭搴撴暟閲�
+ */
+ @ApiModelProperty(value = "鎬诲嚭搴撴暟閲�")
+ private BigDecimal totalOutQty;
+
+ /**
+ * 鐗╂枡绉嶇被鏁�
+ */
+ @ApiModelProperty(value = "鐗╂枡绉嶇被鏁�")
+ private Integer totalMaterials;
+}
+
diff --git a/src/main/java/com/zy/asrs/entity/result/MonthlySettleStatisticsVO.java b/src/main/java/com/zy/asrs/entity/result/MonthlySettleStatisticsVO.java
new file mode 100644
index 0000000..c4b7a6a
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/result/MonthlySettleStatisticsVO.java
@@ -0,0 +1,28 @@
+package com.zy.asrs.entity.result;
+
+import com.zy.asrs.entity.MonthlySettle;
+import com.zy.asrs.entity.MonthlySettleDetail;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 鏈堢粨缁熻淇℃伅
+ */
+@Data
+public class MonthlySettleStatisticsVO {
+
+ /**
+ * 鏈堢粨涓昏褰�
+ */
+ @ApiModelProperty(value = "鏈堢粨涓昏褰�")
+ private MonthlySettle settle;
+
+ /**
+ * 鏈堢粨鏄庣粏鍒楄〃
+ */
+ @ApiModelProperty(value = "鏈堢粨鏄庣粏鍒楄〃")
+ private List<MonthlySettleDetail> details;
+}
+
diff --git a/src/main/java/com/zy/asrs/entity/result/PreviousSettleEndingQtyDTO.java b/src/main/java/com/zy/asrs/entity/result/PreviousSettleEndingQtyDTO.java
new file mode 100644
index 0000000..5b9a727
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/result/PreviousSettleEndingQtyDTO.java
@@ -0,0 +1,33 @@
+package com.zy.asrs.entity.result;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 涓婃湡鏈堢粨鏈熸湯搴撳瓨
+ */
+@Data
+public class PreviousSettleEndingQtyDTO {
+
+ /**
+ * 鐗╂枡缂栫爜
+ */
+ private String matnr;
+
+ /**
+ * 鎵规
+ */
+ private String batch;
+
+ /**
+ * 鍝佺墝
+ */
+ private String brand;
+
+ /**
+ * 鏈熸湯搴撳瓨
+ */
+ private BigDecimal endingQty;
+}
+
diff --git a/src/main/java/com/zy/asrs/mapper/MonthlySettleDetailMapper.java b/src/main/java/com/zy/asrs/mapper/MonthlySettleDetailMapper.java
new file mode 100644
index 0000000..9af3484
--- /dev/null
+++ b/src/main/java/com/zy/asrs/mapper/MonthlySettleDetailMapper.java
@@ -0,0 +1,20 @@
+package com.zy.asrs.mapper;
+
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.zy.asrs.entity.MonthlySettleDetail;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Mapper
+@Repository
+public interface MonthlySettleDetailMapper extends BaseMapper<MonthlySettleDetail> {
+
+ /**
+ * 鏌ヨ鏈堢粨鏄庣粏锛堝叧鑱旂墿鏂欒〃锛�
+ */
+ List<MonthlySettleDetail> selectDetailWithMat(@Param("settleId") Long settleId);
+}
+
diff --git a/src/main/java/com/zy/asrs/mapper/MonthlySettleMapper.java b/src/main/java/com/zy/asrs/mapper/MonthlySettleMapper.java
new file mode 100644
index 0000000..1710a27
--- /dev/null
+++ b/src/main/java/com/zy/asrs/mapper/MonthlySettleMapper.java
@@ -0,0 +1,64 @@
+package com.zy.asrs.mapper;
+
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.zy.asrs.entity.MonthlySettle;
+import com.zy.asrs.entity.result.MaterialInOutStatDTO;
+import com.zy.asrs.entity.result.PreviousSettleEndingQtyDTO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Mapper
+@Repository
+public interface MonthlySettleMapper extends BaseMapper<MonthlySettle> {
+
+ /**
+ * 鑾峰彇鏈�杩戠殑鏈堢粨璁板綍
+ */
+ MonthlySettle selectLatestSettle();
+
+ /**
+ * 缁熻鏈堢粨鏃堕棿鑼冨洿鍐呯殑璁㈠崟鏁伴噺
+ */
+ int countOrdersInRange(@Param("startDate") String startDate, @Param("endDate") String endDate);
+
+ /**
+ * 缁熻鏈堢粨鏃堕棿鑼冨洿鍐呮湭瀹屾垚鐨勮鍗曟暟閲忥紙鍏ュ簱鍜屽嚭搴擄級
+ */
+ int countUnfinishedOrdersInRange(@Param("startDate") String startDate, @Param("endDate") String endDate);
+
+ /**
+ * 缁熻鏈堢粨鏃堕棿鑼冨洿鍐呯殑鐗╂枡鍑哄叆搴撴暟閲忥紙鍚堝苟鍏ュ簱鍜屽嚭搴擄級
+ */
+ List<MaterialInOutStatDTO> statisticsMaterialInOut(@Param("startDate") String startDate, @Param("endDate") String endDate);
+
+ /**
+ * 鑾峰彇涓婁竴涓湀缁撶殑鐗╂枡鏈熸湯搴撳瓨
+ */
+ List<PreviousSettleEndingQtyDTO> getPreviousSettleEndingQty(@Param("previousSettleId") Long previousSettleId);
+
+ /**
+ * 鏇存柊鍏ュ簱璁㈠崟鐨勬湀缁撲俊鎭�
+ */
+ int updateOrderSettleInfo(@Param("settleId") Long settleId, @Param("settleNo") String settleNo,
+ @Param("startDate") String startDate, @Param("endDate") String endDate);
+
+ /**
+ * 鏇存柊鍑哄簱璁㈠崟鐨勬湀缁撲俊鎭�
+ */
+ int updateOrderSettleInfoPakout(@Param("settleId") Long settleId, @Param("settleNo") String settleNo,
+ @Param("startDate") String startDate, @Param("endDate") String endDate);
+
+ /**
+ * 娓呴櫎鍏ュ簱璁㈠崟鐨勬湀缁撲俊鎭�
+ */
+ int clearOrderSettleInfo(@Param("settleId") Long settleId);
+
+ /**
+ * 娓呴櫎鍑哄簱璁㈠崟鐨勬湀缁撲俊鎭�
+ */
+ int clearOrderSettleInfoPakout(@Param("settleId") Long settleId);
+}
+
diff --git a/src/main/java/com/zy/asrs/service/MonthlySettleService.java b/src/main/java/com/zy/asrs/service/MonthlySettleService.java
new file mode 100644
index 0000000..599215d
--- /dev/null
+++ b/src/main/java/com/zy/asrs/service/MonthlySettleService.java
@@ -0,0 +1,54 @@
+package com.zy.asrs.service;
+
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.service.IService;
+import com.zy.asrs.entity.MonthlySettle;
+import com.zy.asrs.entity.result.MonthlySettleResultVO;
+import com.zy.asrs.entity.result.MonthlySettleStatisticsVO;
+
+import java.util.Date;
+
+public interface MonthlySettleService extends IService<MonthlySettle> {
+
+ /**
+ * 鑾峰彇鏈�杩戠殑鏈堢粨璁板綍
+ */
+ MonthlySettle getLatestSettle();
+
+ /**
+ * 鑾峰彇涓嬩竴涓湀缁撶殑璧峰鏃ユ湡
+ */
+ Date getNextStartDate();
+
+ /**
+ * 鑾峰彇鏈�鏅氭湀缁撹褰曠殑缁撴潫鏃ユ湡
+ */
+ Date getLatestEndDate();
+
+ /**
+ * 妫�鏌ユ湀缁撴椂闂磋寖鍥村唴鏄惁鏈夋湭瀹屾垚鐨勮鍗�
+ */
+ boolean hasUnfinishedOrders(Date startDate, Date endDate);
+
+ /**
+ * 鍙戣捣鏈堢粨
+ */
+ MonthlySettleResultVO startSettle(Date startDate, Date endDate, Long userId);
+
+ /**
+ * 鑾峰彇鏈堢粨缁熻淇℃伅
+ */
+ MonthlySettleStatisticsVO getSettleStatistics(Long settleId);
+
+ /**
+ * 鍒嗛〉鏌ヨ鏈堢粨鍒楄〃
+ */
+ Page<MonthlySettle> getPage(Page<MonthlySettle> page);
+
+ /**
+ * 鍒犻櫎鏈堢粨璁板綍
+ */
+ void deleteSettle(Long settleId);
+}
+
+
diff --git a/src/main/java/com/zy/asrs/service/impl/MonthlySettleServiceImpl.java b/src/main/java/com/zy/asrs/service/impl/MonthlySettleServiceImpl.java
new file mode 100644
index 0000000..4dd63c1
--- /dev/null
+++ b/src/main/java/com/zy/asrs/service/impl/MonthlySettleServiceImpl.java
@@ -0,0 +1,385 @@
+package com.zy.asrs.service.impl;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import com.core.common.SnowflakeIdWorker;
+import com.core.exception.CoolException;
+import com.zy.asrs.entity.MonthlySettle;
+import com.zy.asrs.entity.MonthlySettleDetail;
+import com.zy.asrs.entity.result.MaterialInOutStatDTO;
+import com.zy.asrs.entity.result.MonthlySettleResultVO;
+import com.zy.asrs.entity.result.MonthlySettleStatisticsVO;
+import com.zy.asrs.entity.result.PreviousSettleEndingQtyDTO;
+import com.zy.asrs.mapper.MonthlySettleDetailMapper;
+import com.zy.asrs.mapper.MonthlySettleMapper;
+import com.zy.asrs.service.ManLocDetlService;
+import com.zy.asrs.service.MonthlySettleService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service("monthlySettleService")
+public class MonthlySettleServiceImpl extends ServiceImpl<MonthlySettleMapper, MonthlySettle> implements MonthlySettleService {
+
+ @Autowired
+ private MonthlySettleDetailMapper monthlySettleDetailMapper;
+ @Autowired
+ private ManLocDetlService manLocDetlService;
+ @Autowired
+ private SnowflakeIdWorker snowflakeIdWorker;
+
+ @Override
+ public MonthlySettle getLatestSettle() {
+ return this.baseMapper.selectLatestSettle();
+ }
+
+ @Override
+ public Date getNextStartDate() {
+ MonthlySettle latestSettle = getLatestSettle();
+ if (latestSettle == null) {
+ // 濡傛灉娌℃湁鏈堢粨璁板綍锛岃繑鍥瀗ull锛岀敱鍓嶇閫夋嫨璧峰鏃ユ湡
+ return null;
+ }
+ // 杩斿洖鏈�鏅氭湀缁撹褰曠粨鏉熸棩鏈熺殑涓嬩竴澶╋紙璧峰鏃ユ湡搴旇鏄粨鏉熸棩鏈�+1澶╃殑00:00:00锛�
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(latestSettle.getEndDate());
+ // 鍏堣缃负褰撳ぉ鐨�00:00:00锛岀劧鍚庡姞1澶╋紝纭繚杩斿洖鐨勬槸涓嬩竴澶╃殑00:00:00
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ cal.add(Calendar.DAY_OF_MONTH, 1);
+ return cal.getTime();
+ }
+
+ @Override
+ public Date getLatestEndDate() {
+ MonthlySettle latestSettle = getLatestSettle();
+ if (latestSettle == null) {
+ return null;
+ }
+ // 杩斿洖鏈�鏅氭湀缁撹褰曠殑缁撴潫鏃ユ湡锛堟牸寮忓寲涓哄綋澶╃殑00:00:00锛岀敤浜庢樉绀猴級
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(latestSettle.getEndDate());
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ return cal.getTime();
+ }
+
+ @Override
+ public boolean hasUnfinishedOrders(Date startDate, Date endDate) {
+ // 缁撴潫鏃ユ湡+23:59:59
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(endDate);
+ cal.set(Calendar.HOUR_OF_DAY, 23);
+ cal.set(Calendar.MINUTE, 59);
+ cal.set(Calendar.SECOND, 59);
+ cal.set(Calendar.MILLISECOND, 999);
+ endDate = cal.getTime();
+
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String startDateStr = dateFormat.format(startDate);
+ String endDateStr = dateTimeFormat.format(endDate);
+ int count = this.baseMapper.countUnfinishedOrdersInRange(startDateStr, endDateStr);
+ return count > 0;
+ }
+
+ @Override
+ @Transactional
+ public MonthlySettleResultVO startSettle(Date startDate, Date endDate, Long userId) {
+ // 缁撴潫鏃ユ湡+23:59:59
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(endDate);
+ cal.set(Calendar.HOUR_OF_DAY, 23);
+ cal.set(Calendar.MINUTE, 59);
+ cal.set(Calendar.SECOND, 59);
+ cal.set(Calendar.MILLISECOND, 999);
+ endDate = cal.getTime();
+
+ // 妫�鏌ヨ捣濮嬫棩鏈熷繀椤诲ぇ浜庢渶鏅氭湀缁撹褰曠殑缁撴潫鏃ユ湡
+ MonthlySettle latestSettle = getLatestSettle();
+ if (latestSettle != null) {
+ Calendar startCal = Calendar.getInstance();
+ startCal.setTime(startDate);
+ startCal.set(Calendar.HOUR_OF_DAY, 0);
+ startCal.set(Calendar.MINUTE, 0);
+ startCal.set(Calendar.SECOND, 0);
+ startCal.set(Calendar.MILLISECOND, 0);
+
+ Calendar latestEndCal = Calendar.getInstance();
+ latestEndCal.setTime(latestSettle.getEndDate());
+ latestEndCal.set(Calendar.HOUR_OF_DAY, 0);
+ latestEndCal.set(Calendar.MINUTE, 0);
+ latestEndCal.set(Calendar.SECOND, 0);
+ latestEndCal.set(Calendar.MILLISECOND, 0);
+
+ // 璧峰鏃ユ湡蹇呴』澶т簬鏈�鏅氱粨鏉熸棩鏈燂紝涓嶈兘绛変簬鎴栧皬浜�
+ if (!startCal.getTime().after(latestEndCal.getTime())) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ throw new CoolException("璧峰鏃ユ湡蹇呴』澶т簬鏈�鏅氭湀缁撹褰曠殑缁撴潫鏃ユ湡锛�" + sdf.format(latestSettle.getEndDate()));
+ }
+ }
+
+ // 妫�鏌ユ槸鍚︽湁鏈畬鎴愮殑璁㈠崟
+ if (hasUnfinishedOrders(startDate, endDate)) {
+ throw new CoolException("鏈堢粨鏃堕棿鑼冨洿鍐呭瓨鍦ㄦ湭瀹屾垚鐨勮鍗曪紝鏃犳硶杩涜鏈堢粨");
+ }
+
+ // 缁熻鐗╂枡鍑哄叆搴撴暟閲忥紙鍚堝苟鍏ュ簱鍜屽嚭搴擄級
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String startDateStr = dateFormat.format(startDate);
+ String endDateStr = dateTimeFormat.format(endDate);
+ List<MaterialInOutStatDTO> materialStats = this.baseMapper.statisticsMaterialInOut(startDateStr, endDateStr);
+
+ // 妫�鏌ユ槸鍚︽湁鍑哄叆搴撳巻鍙茶鍗�
+ if (materialStats == null || materialStats.isEmpty()) {
+ throw new CoolException("鏈堢粨鏃堕棿鑼冨洿鍐呮病鏈夊嚭鍏ュ簱鍘嗗彶璁㈠崟锛屾棤娉曡繘琛屾湀缁�");
+ }
+
+ // 鑾峰彇涓婁竴涓湀缁撹褰曪紙鐢ㄤ簬璁$畻鏈熷垵搴撳瓨锛�
+ MonthlySettle previousSettle = getLatestSettle();
+ Map<String, BigDecimal> previousEndingQtyMap = new HashMap<>();
+ if (previousSettle != null) {
+ List<PreviousSettleEndingQtyDTO> previousDetails = this.baseMapper.getPreviousSettleEndingQty(previousSettle.getId());
+ for (PreviousSettleEndingQtyDTO detail : previousDetails) {
+ String key = detail.getMatnr() + "_" +
+ (detail.getBatch() != null ? detail.getBatch() : "") + "_" +
+ (detail.getBrand() != null ? detail.getBrand() : "");
+ BigDecimal endingQty = detail.getEndingQty() != null ? detail.getEndingQty() : BigDecimal.ZERO;
+ previousEndingQtyMap.put(key, endingQty);
+ }
+ }
+
+ // 鐢熸垚鏈堢粨缂栧彿
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+ String settleNo = "MS" + sdf.format(new Date()) + String.format("%04d", snowflakeIdWorker.nextId() % 10000);
+
+ // 鍒涘缓鏈堢粨涓昏褰�
+ MonthlySettle monthlySettle = new MonthlySettle();
+ monthlySettle.setSettleNo(settleNo);
+ monthlySettle.setStartDate(startDate);
+ monthlySettle.setEndDate(endDate);
+ monthlySettle.setStatus(1); // 宸叉湀缁�
+ monthlySettle.setIsDeleted(0); // 鏈垹闄�
+ monthlySettle.setCreateBy(userId);
+ monthlySettle.setCreateTime(new Date());
+ this.insert(monthlySettle);
+
+ BigDecimal totalInQty = BigDecimal.ZERO;
+ BigDecimal totalOutQty = BigDecimal.ZERO;
+ int materialCount = 0;
+
+ // 鍒涘缓鏈堢粨鏄庣粏
+ for (MaterialInOutStatDTO stat : materialStats) {
+ // 1. 鎻愬彇鍩虹淇℃伅
+ String matnr = stat.getMatnr();
+ String batch = stat.getBatch() != null ? stat.getBatch() : "";
+ String brand = stat.getBrand() != null ? stat.getBrand() : "";
+ String maktx = stat.getMaktx();
+
+ // 2. 鎻愬彇鏁伴噺淇℃伅
+ BigDecimal inQty = stat.getInQty() != null ? stat.getInQty() : BigDecimal.ZERO;
+ BigDecimal outQty = stat.getOutQty() != null ? stat.getOutQty() : BigDecimal.ZERO;
+
+ // 3. 璁$畻搴撳瓨鐩稿叧鏁伴噺
+ BigDecimal beginningQty = getBeginningQty(matnr, batch, brand, previousEndingQtyMap);
+ BigDecimal endingQty = calculateEndingQty(beginningQty, inQty, outQty);
+ BigDecimal stockQtyDecimal = getCurrentStockQty(matnr, batch);
+ BigDecimal diffQty = calculateDiffQty(stockQtyDecimal, endingQty);
+
+ // 4. 鍒涘缓骞朵繚瀛樻槑缁嗚褰�
+ MonthlySettleDetail detail = buildMonthlySettleDetail(
+ monthlySettle.getId(), settleNo, matnr, batch, maktx, brand,
+ beginningQty, inQty, outQty, endingQty, stockQtyDecimal, diffQty
+ );
+ detail.setIsDeleted(0); // 鏈垹闄�
+ monthlySettleDetailMapper.insert(detail);
+
+ // 5. 绱缁熻
+ totalInQty = totalInQty.add(inQty);
+ totalOutQty = totalOutQty.add(outQty);
+ materialCount++;
+ }
+
+ // 鏇存柊鏈堢粨涓昏褰�
+ monthlySettle.setTotalInQty(totalInQty);
+ monthlySettle.setTotalOutQty(totalOutQty);
+ monthlySettle.setTotalMaterials(materialCount);
+ monthlySettle.setStatus(1); // 宸叉湀缁�
+ monthlySettle.setUpdateBy(userId);
+ monthlySettle.setUpdateTime(new Date());
+ this.updateById(monthlySettle);
+
+ // 鏇存柊璁㈠崟鐨勬湀缁撲俊鎭紙鍏ュ簱鍜屽嚭搴撻兘瑕佹洿鏂帮級
+ this.baseMapper.updateOrderSettleInfo(monthlySettle.getId(), settleNo, startDateStr, endDateStr);
+ this.baseMapper.updateOrderSettleInfoPakout(monthlySettle.getId(), settleNo, startDateStr, endDateStr);
+
+ MonthlySettleResultVO result = new MonthlySettleResultVO();
+ result.setSettleId(monthlySettle.getId());
+ result.setSettleNo(settleNo);
+ result.setTotalInQty(totalInQty);
+ result.setTotalOutQty(totalOutQty);
+ result.setTotalMaterials(materialCount);
+ return result;
+ }
+
+ @Override
+ public MonthlySettleStatisticsVO getSettleStatistics(Long settleId) {
+ MonthlySettle settle = this.selectById(settleId);
+ if (settle == null || (settle.getIsDeleted() != null && settle.getIsDeleted() == 1)) {
+ throw new CoolException("鏈堢粨璁板綍涓嶅瓨鍦�");
+ }
+
+ // 鍏宠仈鐗╂枡琛ㄦ煡璇㈡槑缁�
+ List<MonthlySettleDetail> details = monthlySettleDetailMapper.selectDetailWithMat(settleId);
+
+ MonthlySettleStatisticsVO result = new MonthlySettleStatisticsVO();
+ result.setSettle(settle);
+ result.setDetails(details);
+ return result;
+ }
+
+ @Override
+ public Page<MonthlySettle> getPage(Page<MonthlySettle> page) {
+ Map<String, Object> condition = page.getCondition();
+ EntityWrapper<MonthlySettle> wrapper = new EntityWrapper<>();
+ wrapper.eq("is_deleted", 0);
+
+ if (condition != null) {
+ if (condition.get("settleNo") != null) {
+ wrapper.like("settle_no", condition.get("settleNo").toString());
+ }
+ if (condition.get("status") != null) {
+ wrapper.eq("status", condition.get("status"));
+ }
+ if (condition.get("startDate") != null && condition.get("endDate") != null) {
+ wrapper.ge("start_date", condition.get("startDate"));
+ wrapper.le("end_date", condition.get("endDate"));
+ }
+ }
+
+ wrapper.orderBy("create_time", false);
+ List<MonthlySettle> list = this.selectList(wrapper);
+
+ EntityWrapper<MonthlySettle> countWrapper = new EntityWrapper<>();
+ countWrapper.eq("is_deleted", 0);
+ if (condition != null) {
+ if (condition.get("settleNo") != null) {
+ countWrapper.like("settle_no", condition.get("settleNo").toString());
+ }
+ if (condition.get("status") != null) {
+ countWrapper.eq("status", condition.get("status"));
+ }
+ if (condition.get("startDate") != null && condition.get("endDate") != null) {
+ countWrapper.ge("start_date", condition.get("startDate"));
+ countWrapper.le("end_date", condition.get("endDate"));
+ }
+ }
+ page.setRecords(list);
+ page.setTotal(this.selectCount(countWrapper));
+ return page;
+ }
+
+ /**
+ * 鑾峰彇鏈熷垵搴撳瓨锛堜笂鏈熺粨浣欙級
+ */
+ private BigDecimal getBeginningQty(String matnr, String batch, String brand, Map<String, BigDecimal> previousEndingQtyMap) {
+ String key = matnr + "_" + batch + "_" + brand;
+ return previousEndingQtyMap.getOrDefault(key, BigDecimal.ZERO);
+ }
+
+ /**
+ * 璁$畻鏈熸湯搴撳瓨锛堟湡鍒�+鍏ュ簱-鍑哄簱锛�
+ */
+ private BigDecimal calculateEndingQty(BigDecimal beginningQty, BigDecimal inQty, BigDecimal outQty) {
+ return beginningQty.add(inQty).subtract(outQty);
+ }
+
+ /**
+ * 鑾峰彇褰撳墠瀹為檯搴撳瓨鏁伴噺
+ */
+ private BigDecimal getCurrentStockQty(String matnr, String batch) {
+ Double stockQty = manLocDetlService.queryStockAnfme(matnr, batch);
+ return stockQty != null ? BigDecimal.valueOf(stockQty) : BigDecimal.ZERO;
+ }
+
+ /**
+ * 璁$畻宸紓鏁伴噺锛堝疄闄呭簱瀛�-鏈熸湯搴撳瓨锛�
+ */
+ private BigDecimal calculateDiffQty(BigDecimal stockQty, BigDecimal endingQty) {
+ return stockQty.subtract(endingQty);
+ }
+
+ /**
+ * 鏋勫缓鏈堢粨鏄庣粏瀵硅薄
+ */
+ private MonthlySettleDetail buildMonthlySettleDetail(
+ Long settleId, String settleNo, String matnr, String batch, String maktx, String brand,
+ BigDecimal beginningQty, BigDecimal inQty, BigDecimal outQty, BigDecimal endingQty,
+ BigDecimal stockQty, BigDecimal diffQty) {
+ MonthlySettleDetail detail = new MonthlySettleDetail();
+ // 鍩烘湰淇℃伅
+ detail.setSettleId(settleId);
+ detail.setSettleNo(settleNo);
+ detail.setMatnr(matnr);
+ detail.setBatch(batch);
+ detail.setMaktx(maktx);
+ detail.setBrand(brand);
+ // 鏁伴噺淇℃伅
+ detail.setBeginningQty(beginningQty);
+ detail.setInQty(inQty);
+ detail.setOutQty(outQty);
+ detail.setEndingQty(endingQty);
+ detail.setStockQty(stockQty);
+ detail.setDiffQty(diffQty);
+ // 鏃堕棿淇℃伅
+ detail.setCreateTime(new Date());
+ return detail;
+ }
+
+ @Override
+ @Transactional
+ public void deleteSettle(Long settleId) {
+ MonthlySettle settle = this.selectById(settleId);
+ if (settle == null || (settle.getIsDeleted() != null && settle.getIsDeleted() == 1)) {
+ throw new CoolException("鏈堢粨璁板綍涓嶅瓨鍦�");
+ }
+
+ // 娓呴櫎鍑哄叆搴撹鍗曠殑鏈堢粨淇℃伅
+ this.baseMapper.clearOrderSettleInfo(settleId);
+ this.baseMapper.clearOrderSettleInfoPakout(settleId);
+
+ // 閫昏緫鍒犻櫎鏈堢粨鏄庣粏
+ EntityWrapper<MonthlySettleDetail> detailWrapper = new EntityWrapper<>();
+ detailWrapper.eq("settle_id", settleId);
+ detailWrapper.eq("is_deleted", 0);
+ List<MonthlySettleDetail> details = monthlySettleDetailMapper.selectList(detailWrapper);
+ if (details != null && !details.isEmpty()) {
+ for (MonthlySettleDetail detail : details) {
+ detail.setIsDeleted(1);
+ monthlySettleDetailMapper.updateById(detail);
+ }
+ }
+
+ // 閫昏緫鍒犻櫎鏈堢粨涓昏褰�
+ settle.setIsDeleted(1);
+ settle.setUpdateTime(new Date());
+ this.updateById(settle);
+ }
+}
+
diff --git a/src/main/resources/mapper/MonthlySettleDetailMapper.xml b/src/main/resources/mapper/MonthlySettleDetailMapper.xml
new file mode 100644
index 0000000..21cb23a
--- /dev/null
+++ b/src/main/resources/mapper/MonthlySettleDetailMapper.xml
@@ -0,0 +1,62 @@
+<?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.zy.asrs.mapper.MonthlySettleDetailMapper">
+
+ <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+ <resultMap id="BaseResultMap" type="com.zy.asrs.entity.MonthlySettleDetail">
+ <id column="id" property="id" />
+ <result column="settle_id" property="settleId" />
+ <result column="settle_no" property="settleNo" />
+ <result column="matnr" property="matnr" />
+ <result column="batch" property="batch" />
+ <result column="maktx" property="maktx" />
+ <result column="brand" property="brand" />
+ <result column="beginning_qty" property="beginningQty" />
+ <result column="in_qty" property="inQty" />
+ <result column="out_qty" property="outQty" />
+ <result column="ending_qty" property="endingQty" />
+ <result column="stock_qty" property="stockQty" />
+ <result column="diff_qty" property="diffQty" />
+ <result column="create_time" property="createTime" />
+ <result column="is_deleted" property="isDeleted" />
+ </resultMap>
+
+ <!-- 鍏宠仈鐗╂枡琛ㄧ殑鏌ヨ鏄犲皠缁撴灉锛堣幏鍙栧叾浠栫墿鏂欎俊鎭級 -->
+ <resultMap id="DetailWithMatResultMap" type="com.zy.asrs.entity.MonthlySettleDetail" extends="BaseResultMap">
+ <result column="specs" property="specs" />
+ <result column="model" property="model" />
+ <result column="color" property="color" />
+ <result column="unit" property="unit" />
+ </resultMap>
+
+ <!-- 鏌ヨ鏈堢粨鏄庣粏锛堜粠鏄庣粏琛ㄦ煡璇紝鍏宠仈鐗╂枡琛ㄨ幏鍙栬ˉ鍏呬俊鎭級 -->
+ <select id="selectDetailWithMat" resultMap="DetailWithMatResultMap">
+ SELECT
+ d.id,
+ d.settle_id,
+ d.settle_no,
+ d.matnr,
+ d.batch,
+ d.maktx,
+ d.brand,
+ d.beginning_qty,
+ d.in_qty,
+ d.out_qty,
+ d.ending_qty,
+ d.stock_qty,
+ d.diff_qty,
+ d.create_time,
+ m.specs,
+ m.model,
+ m.color,
+ m.unit
+ FROM man_monthly_settle_detail d
+ LEFT JOIN man_mat m ON d.matnr = m.matnr
+ WHERE d.settle_id = #{settleId}
+ AND d.is_deleted = 0
+ ORDER BY d.matnr, d.batch
+ </select>
+
+</mapper>
+
+
diff --git a/src/main/resources/mapper/MonthlySettleMapper.xml b/src/main/resources/mapper/MonthlySettleMapper.xml
new file mode 100644
index 0000000..78cc204
--- /dev/null
+++ b/src/main/resources/mapper/MonthlySettleMapper.xml
@@ -0,0 +1,159 @@
+<?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.zy.asrs.mapper.MonthlySettleMapper">
+
+ <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+ <resultMap id="BaseResultMap" type="com.zy.asrs.entity.MonthlySettle">
+ <id column="id" property="id" />
+ <result column="settle_no" property="settleNo" />
+ <result column="start_date" property="startDate" />
+ <result column="end_date" property="endDate" />
+ <result column="status" property="status" />
+ <result column="total_in_qty" property="totalInQty" />
+ <result column="total_out_qty" property="totalOutQty" />
+ <result column="total_materials" property="totalMaterials" />
+ <result column="memo" property="memo" />
+ <result column="create_by" property="createBy" />
+ <result column="create_time" property="createTime" />
+ <result column="update_by" property="updateBy" />
+ <result column="update_time" property="updateTime" />
+ <result column="is_deleted" property="isDeleted" />
+ </resultMap>
+
+ <!-- 鑾峰彇鏈�杩戠殑鏈堢粨璁板綍 -->
+ <select id="selectLatestSettle" resultMap="BaseResultMap">
+ SELECT TOP 1 * FROM man_monthly_settle
+ WHERE is_deleted = 0
+ ORDER BY end_date DESC
+ </select>
+
+ <!-- 缁熻鏈堢粨鏃堕棿鑼冨洿鍐呯殑璁㈠崟鏁伴噺 -->
+ <select id="countOrdersInRange" resultType="int">
+ SELECT COUNT(*) FROM man_order
+ WHERE status = 1
+ AND order_time >= #{startDate}
+ AND order_time <= #{endDate}
+ </select>
+
+ <!-- 缁熻鏈堢粨鏃堕棿鑼冨洿鍐呮湭瀹屾垚鐨勮鍗曟暟閲忥紙鍏ュ簱鍜屽嚭搴擄級 -->
+ <select id="countUnfinishedOrdersInRange" resultType="int">
+ SELECT COUNT(*) FROM (
+ SELECT DISTINCT o.id FROM man_order_log_pakin o
+ INNER JOIN man_order_detl_log_pakin od ON o.id = od.order_id
+ WHERE o.status = 1
+ AND CONVERT(date, o.order_time) >= #{startDate}
+ AND o.order_time <= #{endDate}
+ AND o.move_status != 2
+ AND (od.anfme > od.qty OR od.qty IS NULL)
+ AND (o.monthly_settle_id IS NULL OR o.monthly_settle_id = 0)
+ UNION
+ SELECT DISTINCT o.id FROM man_order_log_pakout o
+ INNER JOIN man_order_detl_log_pakout od ON o.id = od.order_id
+ WHERE o.status = 1
+ AND CONVERT(date, o.order_time) >= #{startDate}
+ AND o.order_time <= #{endDate}
+ AND o.move_status != 2
+ AND (od.anfme > od.qty OR od.qty IS NULL)
+ AND (o.monthly_settle_id IS NULL OR o.monthly_settle_id = 0)
+ ) t
+ </select>
+
+ <!-- 缁熻鏈堢粨鏃堕棿鑼冨洿鍐呯殑鐗╂枡鍑哄叆搴撴暟閲忥紙鍚堝苟鍏ュ簱鍑哄簱锛� -->
+ <select id="statisticsMaterialInOut" resultType="com.zy.asrs.entity.result.MaterialInOutStatDTO">
+ SELECT
+ matnr,
+ MAX(maktx) as maktx,
+ batch,
+ brand,
+ SUM(in_qty) as inQty,
+ SUM(out_qty) as outQty
+ FROM (
+ SELECT
+ od.matnr,
+ MAX(od.maktx) as maktx,
+ ISNULL(od.batch, '') as batch,
+ ISNULL(od.brand, '') as brand,
+ SUM(od.qty) as in_qty,
+ 0 as out_qty
+ FROM man_order_log_pakin o
+ INNER JOIN man_order_detl_log_pakin od ON o.id = od.order_id
+ WHERE o.status = 1
+ AND CONVERT(date, o.order_time) >= #{startDate}
+ AND o.order_time <= #{endDate}
+ AND o.move_status = 2
+ AND (o.monthly_settle_id IS NULL OR o.monthly_settle_id = 0)
+ GROUP BY od.matnr, od.batch, od.brand
+ UNION ALL
+ SELECT
+ od.matnr,
+ MAX(od.maktx) as maktx,
+ ISNULL(od.batch, '') as batch,
+ ISNULL(od.brand, '') as brand,
+ 0 as in_qty,
+ SUM(od.qty) as out_qty
+ FROM man_order_log_pakout o
+ INNER JOIN man_order_detl_log_pakout od ON o.id = od.order_id
+ WHERE o.status = 1
+ AND CONVERT(date, o.order_time) >= #{startDate}
+ AND o.order_time <= #{endDate}
+ AND o.move_status = 2
+ AND (o.monthly_settle_id IS NULL OR o.monthly_settle_id = 0)
+ GROUP BY od.matnr, od.batch, od.brand
+ ) t
+ GROUP BY matnr, batch, brand
+ </select>
+
+ <!-- 鑾峰彇涓婁竴涓湀缁撶殑鐗╂枡鏈熸湯搴撳瓨 -->
+ <select id="getPreviousSettleEndingQty" resultType="com.zy.asrs.entity.result.PreviousSettleEndingQtyDTO">
+ SELECT
+ matnr,
+ batch,
+ brand,
+ ending_qty as endingQty
+ FROM man_monthly_settle_detail
+ WHERE settle_id = #{previousSettleId}
+ </select>
+
+ <!-- 鏇存柊鍏ュ簱璁㈠崟鐨勬湀缁撲俊鎭� -->
+ <update id="updateOrderSettleInfo">
+ UPDATE man_order_log_pakin
+ SET monthly_settle_id = #{settleId},
+ monthly_settle_no = #{settleNo}
+ WHERE status = 1
+ AND CONVERT(date, order_time) >= #{startDate}
+ AND order_time <= #{endDate}
+ AND move_status = 2
+ AND (monthly_settle_id IS NULL OR monthly_settle_id = 0)
+ </update>
+
+ <!-- 鏇存柊鍑哄簱璁㈠崟鐨勬湀缁撲俊鎭� -->
+ <update id="updateOrderSettleInfoPakout">
+ UPDATE man_order_log_pakout
+ SET monthly_settle_id = #{settleId},
+ monthly_settle_no = #{settleNo}
+ WHERE status = 1
+ AND CONVERT(date, order_time) >= #{startDate}
+ AND order_time <= #{endDate}
+ AND move_status = 2
+ AND (monthly_settle_id IS NULL OR monthly_settle_id = 0)
+ </update>
+
+ <!-- 娓呴櫎鍏ュ簱璁㈠崟鐨勬湀缁撲俊鎭� -->
+ <update id="clearOrderSettleInfo">
+ UPDATE man_order_log_pakin
+ SET monthly_settle_id = NULL,
+ monthly_settle_no = NULL
+ WHERE monthly_settle_id = #{settleId}
+ </update>
+
+ <!-- 娓呴櫎鍑哄簱璁㈠崟鐨勬湀缁撲俊鎭� -->
+ <update id="clearOrderSettleInfoPakout">
+ UPDATE man_order_log_pakout
+ SET monthly_settle_id = NULL,
+ monthly_settle_no = NULL
+ WHERE monthly_settle_id = #{settleId}
+ </update>
+
+</mapper>
+
+
diff --git a/src/main/webapp/static/js/monthlySettle/monthlySettle.js b/src/main/webapp/static/js/monthlySettle/monthlySettle.js
new file mode 100644
index 0000000..dc9df4f
--- /dev/null
+++ b/src/main/webapp/static/js/monthlySettle/monthlySettle.js
@@ -0,0 +1,630 @@
+var pageCurr;
+layui.config({
+ base: baseUrl + "/static/layui/lay/modules/"
+}).use(['layer', 'form', 'table', 'util', 'admin', 'laydate', 'laytpl'], function () {
+ var $ = layui.jquery;
+ var layer = layui.layer;
+ var form = layui.form;
+ var table = layui.table;
+ var util = layui.util;
+ var admin = layui.admin;
+ var layDate = layui.laydate;
+ var laytpl = layui.laytpl;
+
+ // 娓叉煋琛ㄦ牸
+ tableIns = table.render({
+ elem: '#monthlySettle',
+ url: baseUrl + '/monthlySettle/list/auth',
+ headers: {token: localStorage.getItem('token')},
+ method: 'POST',
+ page: true,
+ cellMinWidth: 100,
+ where: {},
+ cols: [[
+ {type: 'numbers'},
+ {field: 'settleNo', title: '鏈堢粨缂栧彿', width: 180},
+ {field: 'startDate$', align: 'center', title: '璧峰鏃ユ湡', width: 120},
+ {field: 'endDate$', align: 'center', title: '缁撴潫鏃ユ湡', width: 120},
+ {field: 'totalInQty', align: 'center', title: '鎬诲叆搴撴暟閲�', width: 120},
+ {field: 'totalOutQty', align: 'center', title: '鎬诲嚭搴撴暟閲�', width: 120},
+ {field: 'totalMaterials', align: 'center', title: '鐗╂枡绉嶇被鏁�', width: 120},
+ {field: 'createTime$', title: '鍒涘缓鏃堕棿', minWidth: 180, width: 180},
+ {align: 'center', title: '鎿嶄綔', toolbar: '#operate', width: 180}
+ ]],
+ request: {
+ pageName: 'curr',
+ pageSize: 'limit'
+ },
+ parseData: function (res) {
+ return {
+ 'code': res.code,
+ 'msg': res.msg,
+ 'count': res.data.total,
+ 'data': res.data.records
+ }
+ },
+ response: {
+ statusCode: 200
+ },
+ done: function (res, curr, count) {
+ if (res.code === 403) {
+ top.location.href = baseUrl + "/";
+ }
+ pageCurr = curr;
+ }
+ });
+
+ // 鎼滅储
+ form.on('submit(search)', function (data) {
+ pageCurr = 1;
+ tableReload(false);
+ });
+
+ // 閲嶇疆
+ form.on('submit(reset)', function (data) {
+ pageCurr = 1;
+ clearFormVal($('#search-box'));
+ // 鎵嬪姩娓呯┖鏃ユ湡鑼冨洿閫夋嫨鍣�
+ $('input[name="date_range"]').val('');
+ // 鏄惧紡娓呯┖琛ㄦ牸閰嶇疆涓殑 where 鍙傛暟
+ if (tableIns && tableIns.config) {
+ tableIns.config.where = {};
+ }
+ // 浣跨敤 setTimeout 纭繚琛ㄥ崟鍊艰瀹屽叏娓呯┖鍚庡啀閲嶆柊鍔犺浇琛ㄦ牸
+ setTimeout(function() {
+ tableReload(false);
+ }, 0);
+ });
+
+ // 鏃ユ湡鑼冨洿閫夋嫨鍣�
+ layDate.render({
+ elem: '.layui-laydate-range',
+ type: 'date',
+ range: true
+ });
+
+ // 鍙戣捣鏈堢粨
+ $('#startSettleBtn').click(function () {
+ showStartSettleDialog();
+ });
+
+ // 鏄剧ず鍙戣捣鏈堢粨寮圭獥
+ function showStartSettleDialog() {
+ admin.open({
+ type: 1,
+ title: '鍙戣捣鏈堢粨',
+ content: $('#startSettleDialog').html(),
+ area: '500px',
+ success: function (layero, dIndex) {
+ var startDateIns = null;
+ var endDateIns = null;
+
+ // 鍒濆鍖栫粨鏉熸棩鏈熼�夋嫨鍣紙鍏堝垵濮嬪寲锛屽悗缁啀璁剧疆min锛�
+ // 浣跨敤 setTimeout 纭繚 DOM 宸插畬鍏ㄦ覆鏌�
+ setTimeout(function() {
+ var $endDate = layero.find('#endDate');
+ if ($endDate.length > 0) {
+ endDateIns = layDate.render({
+ elem: $endDate[0],
+ type: 'date',
+ done: function(value, date, endDate){
+ var startDate = layero.find('#startDate').val();
+ if (startDate && value < startDate) {
+ layer.msg('缁撴潫鏃ユ湡涓嶈兘鏃╀簬璧峰鏃ユ湡', {icon: 2});
+ layero.find('#endDate').val('');
+ checkUnfinishedOrders(startDate, '');
+ return;
+ }
+ checkUnfinishedOrders(startDate, value);
+ }
+ });
+ }
+ }, 50);
+
+ // 鑾峰彇涓嬩竴涓湀缁撶殑璧峰鏃ユ湡锛堟渶鏅氭湀缁撹褰曠粨鏉熸棩鏈熺殑涓嬩竴澶╋級
+ $.ajax({
+ url: baseUrl + '/monthlySettle/nextStartDate/auth',
+ headers: {'token': localStorage.getItem('token')},
+ method: 'POST',
+ success: function (res) {
+ if (res.code === 200) {
+ // 鏁版嵁鍦� msg 瀛楁涓�
+ var nextStartDate = res.msg;
+ // 纭繚 nextStartDate 鏄瓧绗︿覆鏍煎紡
+ if (nextStartDate != null && nextStartDate !== '') {
+ // 杞崲涓哄瓧绗︿覆锛屽鐞嗗彲鑳界殑鏁板瓧鎴栧叾浠栫被鍨�
+ nextStartDate = String(nextStartDate).trim();
+ if (nextStartDate !== '' && nextStartDate !== 'null') {
+ // 浣跨敤 setTimeout 纭繚 DOM 宸插畬鍏ㄦ覆鏌�
+ setTimeout(function() {
+ // 浣跨敤 layero.find 鏌ユ壘寮圭獥鍐呯殑鍏冪礌
+ var $startDate = layero.find('#startDate');
+ if ($startDate.length > 0) {
+ $startDate.val(nextStartDate);
+ $startDate.attr('readonly', true);
+ $startDate.css('background-color', '#f5f5f5');
+ $startDate.css('cursor', 'not-allowed');
+ console.log('宸茶缃捣濮嬫棩鏈�:', $startDate.val());
+ } else {
+ console.error('鏈壘鍒� #startDate 鍏冪礌');
+ }
+ }, 50);
+
+ // 鑾峰彇鏈�鏅氱粨鏉熸棩鏈熺敤浜庢彁绀�
+ $.ajax({
+ url: baseUrl + '/monthlySettle/latestEndDate/auth',
+ headers: {'token': localStorage.getItem('token')},
+ method: 'POST',
+ success: function (latestRes) {
+ var latestEndDate = (latestRes.code === 200 && latestRes.msg) ? String(latestRes.msg) : '';
+ var tipMsg = latestEndDate
+ ? '鎻愮ず锛氭渶鏅氭湀缁撹褰曠粨鏉熸棩鏈熶负 ' + latestEndDate + '锛屾湰娆℃湀缁撹捣濮嬫棩鏈熷凡鑷姩璁剧疆涓� ' + nextStartDate + '锛屼笉鍙慨鏀�'
+ : '鎻愮ず锛氭湰娆℃湀缁撹捣濮嬫棩鏈熷凡鑷姩璁剧疆涓� ' + nextStartDate + '锛屼笉鍙慨鏀�';
+ layero.find('#settleTip').html(tipMsg);
+ },
+ error: function() {
+ layero.find('#settleTip').html('鎻愮ず锛氭湰娆℃湀缁撹捣濮嬫棩鏈熷凡鑷姩璁剧疆涓� ' + nextStartDate + '锛屼笉鍙慨鏀�');
+ }
+ });
+
+ // 閲嶆柊娓叉煋缁撴潫鏃ユ湡閫夋嫨鍣紝璁剧疆鏈�灏忔棩鏈熶负璧峰鏃ユ湡
+ setTimeout(function() {
+ endDateIns = layDate.render({
+ elem: layero.find('#endDate')[0],
+ type: 'date',
+ min: nextStartDate,
+ done: function(value, date, endDate){
+ var startDate = layero.find('#startDate').val();
+ if (startDate && value < startDate) {
+ layer.msg('缁撴潫鏃ユ湡涓嶈兘鏃╀簬璧峰鏃ユ湡', {icon: 2});
+ layero.find('#endDate').val('');
+ checkUnfinishedOrders(startDate, '');
+ return;
+ }
+ checkUnfinishedOrders(startDate, value);
+ }
+ });
+ }, 100);
+ }
+ } else {
+ // 娌℃湁鏈堢粨璁板綍锛屽厑璁歌嚜鐢遍�夋嫨璧峰鏃ユ湡
+ setTimeout(function() {
+ var $startDate = layero.find('#startDate');
+ if ($startDate.length > 0) {
+ startDateIns = layDate.render({
+ elem: $startDate[0],
+ type: 'date',
+ done: function(value, date, endDate){
+ // 褰撹捣濮嬫棩鏈熸敼鍙樻椂锛岄噸鏂版覆鏌撶粨鏉熸棩鏈熼�夋嫨鍣紝璁剧疆鏈�灏忔棩鏈�
+ var currentEndDate = layero.find('#endDate').val();
+ if (currentEndDate && currentEndDate < value) {
+ layero.find('#endDate').val('');
+ layero.find('#settleTip').html('<span style="color: #ff5722;">璀﹀憡锛氱粨鏉熸棩鏈熶笉鑳芥棭浜庤捣濮嬫棩鏈燂紝璇烽噸鏂伴�夋嫨缁撴潫鏃ユ湡</span>');
+ }
+
+ // 閲嶆柊娓叉煋缁撴潫鏃ユ湡閫夋嫨鍣�
+ endDateIns = layDate.render({
+ elem: layero.find('#endDate')[0],
+ type: 'date',
+ min: value,
+ done: function(endValue, endDate, endEndDate){
+ if (value && endValue < value) {
+ layer.msg('缁撴潫鏃ユ湡涓嶈兘鏃╀簬璧峰鏃ユ湡', {icon: 2});
+ layero.find('#endDate').val('');
+ checkUnfinishedOrders(value, '');
+ return;
+ }
+ checkUnfinishedOrders(value, endValue);
+ }
+ });
+
+ checkUnfinishedOrders(value, layero.find('#endDate').val());
+ }
+ });
+ layero.find('#settleTip').html('鎻愮ず锛氶娆℃湀缁擄紝璇烽�夋嫨璧峰鏃ユ湡');
+ }
+ }, 50);
+ }
+ } else if (res.code === 403) {
+ top.location.href = baseUrl + "/";
+ }
+ },
+ error: function() {
+ // 濡傛灉鑾峰彇澶辫触锛屽厑璁歌嚜鐢遍�夋嫨璧峰鏃ユ湡
+ setTimeout(function() {
+ var $startDate = layero.find('#startDate');
+ if ($startDate.length > 0) {
+ startDateIns = layDate.render({
+ elem: $startDate[0],
+ type: 'date',
+ done: function(value, date, endDate){
+ var currentEndDate = layero.find('#endDate').val();
+ if (currentEndDate && currentEndDate < value) {
+ layero.find('#endDate').val('');
+ layero.find('#settleTip').html('<span style="color: #ff5722;">璀﹀憡锛氱粨鏉熸棩鏈熶笉鑳芥棭浜庤捣濮嬫棩鏈燂紝璇烽噸鏂伴�夋嫨缁撴潫鏃ユ湡</span>');
+ }
+
+ endDateIns = layDate.render({
+ elem: layero.find('#endDate')[0],
+ type: 'date',
+ min: value,
+ done: function(endValue, endDate, endEndDate){
+ if (value && endValue < value) {
+ layer.msg('缁撴潫鏃ユ湡涓嶈兘鏃╀簬璧峰鏃ユ湡', {icon: 2});
+ layero.find('#endDate').val('');
+ checkUnfinishedOrders(value, '');
+ return;
+ }
+ checkUnfinishedOrders(value, endValue);
+ }
+ });
+
+ checkUnfinishedOrders(value, layero.find('#endDate').val());
+ }
+ });
+ layero.find('#settleTip').html('鎻愮ず锛氳閫夋嫨璧峰鏃ユ湡');
+ }
+ }, 50);
+ }
+ });
+
+ // 琛ㄥ崟鎻愪氦浜嬩欢
+ form.on('submit(startSettleSubmit)', function (data) {
+ var startDate = layero.find('#startDate').val();
+ var endDate = layero.find('#endDate').val();
+
+ if (!startDate || !endDate) {
+ layer.msg('璇烽�夋嫨璧峰鏃ユ湡鍜岀粨鏉熸棩鏈�', {icon: 2});
+ return false;
+ }
+
+ if (startDate > endDate) {
+ layer.msg('缁撴潫鏃ユ湡涓嶈兘鏃╀簬璧峰鏃ユ湡锛岃閲嶆柊閫夋嫨', {icon: 2});
+ return false;
+ }
+
+ // 灏嗙粨鏉熸棩鏈熻缃负褰撳ぉ鐨� 23:59:59
+ var endDateTime = endDate + ' 23:59:59';
+
+ layer.load(2);
+ $.ajax({
+ url: baseUrl + '/monthlySettle/start/auth',
+ headers: {'token': localStorage.getItem('token')},
+ data: {
+ startDate: startDate,
+ endDate: endDateTime
+ },
+ method: 'POST',
+ success: function (res) {
+ layer.closeAll('loading');
+ if (res.code === 200) {
+ layer.close(dIndex);
+ tableIns.reload({page: {curr: 1}});
+ layer.msg(res.msg || '鏈堢粨鎴愬姛', {icon: 1});
+ } else if (res.code === 403) {
+ top.location.href = baseUrl + "/";
+ } else {
+ layer.msg(res.msg || '鏈堢粨澶辫触', {icon: 2});
+ }
+ },
+ error: function() {
+ layer.closeAll('loading');
+ layer.msg('鏈堢粨璇锋眰澶辫触', {icon: 2});
+ }
+ });
+ return false;
+ });
+ }
+ });
+ }
+
+ // 妫�鏌ユ湭瀹屾垚鐨勮鍗�
+ function checkUnfinishedOrders(startDate, endDate) {
+ if (!startDate && !endDate) {
+ $('#settleTip').html('<span style="color: #999;">璇烽�夋嫨璧峰鏃ユ湡鍜岀粨鏉熸棩鏈�</span>');
+ return;
+ }
+
+ if (!startDate) {
+ $('#settleTip').html('<span style="color: #999;">璇烽�夋嫨璧峰鏃ユ湡</span>');
+ return;
+ }
+
+ if (!endDate) {
+ $('#settleTip').html('<span style="color: #999;">璇烽�夋嫨缁撴潫鏃ユ湡</span>');
+ return;
+ }
+
+ // 楠岃瘉鏃ユ湡鑼冨洿
+ if (startDate > endDate) {
+ $('#settleTip').html('<span style="color: #ff5722;">璀﹀憡锛氱粨鏉熸棩鏈熶笉鑳芥棭浜庤捣濮嬫棩鏈燂紝璇烽噸鏂伴�夋嫨</span>');
+ return;
+ }
+
+ $.ajax({
+ url: baseUrl + '/monthlySettle/checkUnfinished/auth',
+ headers: {'token': localStorage.getItem('token')},
+ data: {
+ startDate: startDate,
+ endDate: endDate
+ },
+ method: 'POST',
+ success: function (res) {
+ if (res.code === 200) {
+ $('#settleTip').html('<span style="color: #5FB878;">鉁� 鏃ユ湡鑼冨洿鏈夋晥锛屽彲浠ユ甯歌繘琛屾湀缁�</span>');
+ } else {
+ $('#settleTip').html('<span style="color: #ff5722;">璀﹀憡锛�' + (res.msg || '鏈堢粨鏃堕棿鑼冨洿鍐呭瓨鍦ㄦ湭瀹屾垚鐨勮鍗曪紝鏃犳硶杩涜鏈堢粨') + '</span>');
+ }
+ },
+ error: function() {
+ $('#settleTip').html('<span style="color: #ff5722;">妫�鏌ュけ璐ワ紝璇烽噸璇�</span>');
+ }
+ });
+ }
+
+ // 宸ュ叿鏉$偣鍑讳簨浠�
+ table.on('tool(monthlySettle)', function (obj) {
+ var data = obj.data;
+ var layEvent = obj.event;
+ if (layEvent === 'detail') {
+ showDetailDialog(data);
+ } else if (layEvent === 'delete') {
+ deleteSettle(data);
+ }
+ });
+
+ // 鏄剧ず鏄庣粏寮圭獥
+ function showDetailDialog(data) {
+ layer.load(2);
+ $.ajax({
+ url: baseUrl + '/monthlySettle/statistics/' + data.id + '/auth',
+ headers: {'token': localStorage.getItem('token')},
+ method: 'POST',
+ success: function (res) {
+ layer.closeAll('loading');
+ if (res.code === 200) {
+ var settle = res.data.settle;
+ var details = res.data.details;
+
+ // 鍏堟覆鏌撴ā鏉�
+ var template = $('#detailDialog').html();
+ var html = laytpl(template).render(settle);
+
+ admin.open({
+ type: 1,
+ title: '鏈堢粨鏄庣粏 - ' + settle.settleNo,
+ content: html,
+ area: ['90%', '80%'],
+ success: function (layero, dIndex) {
+ // 娓叉煋鏄庣粏琛ㄦ牸锛堝璐﹀崟鏍煎紡锛�
+ table.render({
+ elem: '#detailTable',
+ data: details,
+ page: true,
+ cellMinWidth: 100,
+ cols: [[
+ {type: 'numbers', title: '搴忓彿', width: 60, align: 'center'},
+ {field: 'matnr', title: '鐗╂枡缂栫爜', width: 150},
+ {field: 'maktx', title: '鐗╂枡鍚嶇О', width: 200},
+ {field: 'batch', title: '鎵规', width: 120},
+ {field: 'brand', title: '鍝佺墝', width: 120},
+ {
+ field: 'beginningQty',
+ align: 'right',
+ title: '鏈熷垵搴撳瓨',
+ width: 120,
+ templet: function (d) {
+ var qty = parseFloat(d.beginningQty || 0);
+ return qty.toFixed(2);
+ }
+ },
+ {
+ field: 'inQty',
+ align: 'right',
+ title: '鏈湡鍏ュ簱',
+ width: 120,
+ templet: function (d) {
+ var qty = parseFloat(d.inQty || 0);
+ return qty.toFixed(2);
+ }
+ },
+ {
+ field: 'outQty',
+ align: 'right',
+ title: '鏈湡鍑哄簱',
+ width: 120,
+ templet: function (d) {
+ var qty = parseFloat(d.outQty || 0);
+ return qty.toFixed(2);
+ }
+ },
+ {
+ field: 'endingQty',
+ align: 'right',
+ title: '鏈熸湯搴撳瓨',
+ width: 120,
+ templet: function (d) {
+ var qty = parseFloat(d.endingQty || 0);
+ return qty.toFixed(2);
+ }
+ },
+ {
+ field: 'stockQty',
+ align: 'right',
+ title: '瀹為檯搴撳瓨',
+ width: 120,
+ templet: function (d) {
+ var qty = parseFloat(d.stockQty || 0);
+ return qty.toFixed(2);
+ }
+ },
+ {
+ field: 'diffQty',
+ align: 'right',
+ title: '宸紓鏁伴噺',
+ width: 120,
+ templet: function (d) {
+ var diff = parseFloat(d.diffQty || 0);
+ if (diff > 0) {
+ return '<span style="color: #5FB878;">+' + diff.toFixed(2) + '</span>';
+ } else if (diff < 0) {
+ return '<span style="color: #ff5722;">' + diff.toFixed(2) + '</span>';
+ } else {
+ return diff.toFixed(2);
+ }
+ }
+ }
+ ]]
+ });
+ }
+ });
+ } else if (res.code === 403) {
+ top.location.href = baseUrl + "/";
+ } else {
+ layer.msg(res.msg || '鑾峰彇鏄庣粏澶辫触', {icon: 2});
+ }
+ }
+ });
+ }
+
+ // 鍒犻櫎鏈堢粨璁板綍
+ function deleteSettle(data) {
+ layer.confirm('纭瑕佸垹闄ゆ湀缁撹褰� "' + data.settleNo + '" 鍚楋紵鍒犻櫎鍚庡皢娓呴櫎鍏宠仈鐨勫嚭鍏ュ簱璁㈠崟鏈堢粨淇℃伅锛屽彲浠ラ噸鏂拌繘琛屾湀缁撱��', {
+ shade: .1,
+ skin: 'layui-layer-admin'
+ }, function (i) {
+ layer.close(i);
+ layer.load(2);
+ $.ajax({
+ url: baseUrl + '/monthlySettle/' + data.id + '/auth',
+ headers: {'token': localStorage.getItem('token')},
+ method: 'DELETE',
+ success: function (res) {
+ layer.closeAll('loading');
+ if (res.code === 200) {
+ tableIns.reload({page: {curr: 1}});
+ layer.msg(res.msg || '鍒犻櫎鎴愬姛', {icon: 1});
+ } else if (res.code === 403) {
+ top.location.href = baseUrl + "/";
+ } else {
+ layer.msg(res.msg || '鍒犻櫎澶辫触', {icon: 2});
+ }
+ },
+ error: function() {
+ layer.closeAll('loading');
+ layer.msg('鍒犻櫎澶辫触', {icon: 2});
+ }
+ });
+ });
+ }
+});
+
+function tableReload(child) {
+ var searchData = {};
+ $.each($('#search-box [name]').serializeArray(), function() {
+ var value = this.value;
+ // 澶勭悊鏃ユ湡鑼冨洿瀛楁
+ if (this.name === 'date_range') {
+ // 鍙鐞嗛潪绌哄��
+ if (value && value.trim() !== '') {
+ var dates = value.split(' - ');
+ if (dates.length === 2) {
+ var startDate = dates[0].trim();
+ var endDate = dates[1].trim();
+ if (startDate !== '' && endDate !== '') {
+ searchData.startDate = startDate;
+ searchData.endDate = endDate;
+ }
+ }
+ }
+ } else if (this.name === 'settle_no') {
+ // 鍙鐞嗛潪绌哄��
+ var trimmedValue = value ? value.trim() : '';
+ if (trimmedValue !== '') {
+ searchData.settleNo = trimmedValue;
+ }
+ }
+ });
+ debugger; // 璋冭瘯鐢細妫�鏌� searchData 鐨勫��
+
+ // 鑾峰彇 table 瀹炰緥
+ var tableInstance = child ? parent.tableIns : tableIns;
+
+ // 濡傛灉 searchData 涓虹┖瀵硅薄锛岄渶瑕佹樉寮忎紶鍏ヨ鐩栨墍鏈夊彲鑳藉弬鏁扮殑瀵硅薄
+ // 鍥犱负 layui table 鍙兘浼氬悎骞舵棫鐨勫弬鏁帮紝鍗充娇浼犲叆绌哄璞′篃鍙兘淇濈暀鏃у��
+ if (Object.keys(searchData).length === 0) {
+ if (tableInstance && tableInstance.config) {
+ // 鍏堜繚瀛樻棫鐨� where 涓彲鑳藉瓨鍦ㄧ殑鎵�鏈夐敭
+ var oldWhereKeys = [];
+ if (tableInstance.config.where) {
+ for (var key in tableInstance.config.where) {
+ if (tableInstance.config.where.hasOwnProperty(key)) {
+ oldWhereKeys.push(key);
+ }
+ }
+ }
+
+ // 瀹屽叏鏇挎崲 where 瀵硅薄
+ tableInstance.config.where = {};
+
+ // 濡傛灉涔嬪墠鏈夊弬鏁帮紝鍒涘缓涓�涓槑纭鐩栫殑瀵硅薄锛屽皢鎵�鏈夋棫鍙傛暟璁剧疆涓虹┖瀛楃涓�
+ // 浣跨敤绌哄瓧绗︿覆鑰屼笉鏄� null锛屽洜涓� layui 鍙兘浼氳繃婊� null 鍊�
+ if (oldWhereKeys.length > 0) {
+ var overrideWhere = {};
+ oldWhereKeys.forEach(function(key) {
+ overrideWhere[key] = ''; // 璁剧疆涓虹┖瀛楃涓叉潵瑕嗙洊鏃у��
+ });
+ searchData = overrideWhere;
+ console.log('鍒涘缓瑕嗙洊瀵硅薄锛屾棫鍙傛暟閿�:', oldWhereKeys, '瑕嗙洊瀵硅薄:', JSON.stringify(overrideWhere));
+ } else {
+ // 鍗充娇娌℃湁鏃у弬鏁帮紝涔熷垱寤轰竴涓寘鍚墍鏈夊彲鑳藉弬鏁扮殑绌哄璞�
+ // 杩欐牱鍙互纭繚瑕嗙洊浠讳綍鍙兘鐨勬棫鍙傛暟
+ searchData = {
+ settleNo: '',
+ startDate: '',
+ endDate: ''
+ };
+ console.log('鍒涘缓榛樿瑕嗙洊瀵硅薄:', JSON.stringify(searchData));
+ }
+ }
+ }
+
+ // 鏋勫缓 reload 鍙傛暟
+ var reloadOptions = {
+ where: searchData,
+ page: {
+ curr: pageCurr
+ },
+ done: function (res, curr, count) {
+ if (res.code === 403) {
+ top.location.href = baseUrl+"/";
+ }
+ pageCurr=curr;
+ if (res.data.length === 0 && count !== 0) {
+ var reloadTableInstance = child ? parent.tableIns : tableIns;
+ // 濡傛灉 searchData 涓虹┖锛屼篃瀹屽叏鏇挎崲 where 瀵硅薄
+ if (Object.keys(searchData).length === 0 && reloadTableInstance && reloadTableInstance.config) {
+ reloadTableInstance.config.where = {};
+ }
+ reloadTableInstance.reload({
+ where: searchData,
+ page: {
+ curr: pageCurr-1
+ }
+ });
+ pageCurr -= 1;
+ }
+ }
+ };
+
+ // 璋冭瘯锛氭墦鍗� reload 鍓嶇殑閰嶇疆
+ console.log('reload 鍓嶇殑 config.where:', JSON.stringify(tableInstance.config ? tableInstance.config.where : 'no config'));
+ console.log('reload 鏃剁殑 where 鍙傛暟:', JSON.stringify(reloadOptions.where));
+
+ tableInstance.reload(reloadOptions);
+
+ // 璋冭瘯锛氭墦鍗� reload 鍚庣殑閰嶇疆
+ setTimeout(function() {
+ console.log('reload 鍚庣殑 config.where:', JSON.stringify(tableInstance.config ? tableInstance.config.where : 'no config'));
+ }, 100);
+}
diff --git a/src/main/webapp/views/monthlySettle/monthlySettle.html b/src/main/webapp/views/monthlySettle/monthlySettle.html
new file mode 100644
index 0000000..c0ba70c
--- /dev/null
+++ b/src/main/webapp/views/monthlySettle/monthlySettle.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>鏈堢粨绠$悊</title>
+ <meta name="renderer" content="webkit">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+ <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all">
+ <link rel="stylesheet" href="../../static/css/admin.css?v=318" media="all">
+ <link rel="stylesheet" href="../../static/css/cool.css" media="all">
+</head>
+<body>
+
+<div class="layui-fluid">
+ <div class="layui-card">
+ <div class="layui-card-body">
+ <div class="layui-form toolbar" id="search-box">
+ <div class="layui-form-item">
+ <div class="layui-inline">
+ <div class="layui-input-inline mr0">
+ <input name="settle_no" class="layui-input" type="text" placeholder="杈撳叆鏈堢粨缂栧彿"/>
+ </div>
+ </div>
+ <div class="layui-inline" style="width: 300px">
+ <div class="layui-input-inline">
+ <input class="layui-input layui-laydate-range" name="date_range" type="text" placeholder="璧峰鏃ユ湡 - 缁撴潫鏃ユ湡" autocomplete="off" style="width: 300px">
+ </div>
+ </div>
+ <div class="layui-inline">
+ <button class="layui-btn icon-btn" lay-filter="search" lay-submit>
+ <i class="layui-icon"></i>鎼滅储
+ </button>
+ <button id="startSettleBtn" class="layui-btn icon-btn layui-btn-normal">
+ <i class="layui-icon"></i>鍙戣捣鏈堢粨
+ </button>
+ <button type="button" class="layui-btn icon-btn layui-btn-primary" lay-filter="reset" lay-submit>
+ <i class="layui-icon"></i>閲嶇疆
+ </button>
+ </div>
+ </div>
+ </div>
+ <table class="layui-hide" id="monthlySettle" lay-filter="monthlySettle" ></table>
+ </div>
+ </div>
+</div>
+
+<!-- 琛ㄦ牸鎿嶄綔鍒� -->
+<script type="text/html" id="operate">
+ <a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">鏌ョ湅鏄庣粏</a>
+ <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete">鍒犻櫎</a>
+</script>
+
+<!-- 鍙戣捣鏈堢粨寮圭獥 -->
+<script type="text/html" id="startSettleDialog">
+ <form id="startSettleForm" lay-filter="startSettleForm" class="layui-form model-form">
+ <div class="layui-form-item">
+ <label class="layui-form-label">璧峰鏃ユ湡锛�</label>
+ <div class="layui-input-block">
+ <input id="startDate" name="startDate" placeholder="閫夋嫨璧峰鏃ユ湡" type="text" class="layui-input" autocomplete="off" lay-verType="tips" lay-verify="required">
+ </div>
+ </div>
+ <div class="layui-form-item">
+ <label class="layui-form-label">缁撴潫鏃ユ湡锛�</label>
+ <div class="layui-input-block">
+ <input id="endDate" name="endDate" placeholder="閫夋嫨缁撴潫鏃ユ湡" type="text" class="layui-input" autocomplete="off" lay-verType="tips" lay-verify="required">
+ </div>
+ </div>
+ <div class="layui-form-item">
+ <label class="layui-form-label">鎻愮ず锛�</label>
+ <div class="layui-input-block">
+ <div id="settleTip" style="color: #ff5722;"></div>
+ </div>
+ </div>
+ <div class="layui-form-item text-right">
+ <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">鍙栨秷</button>
+ <button class="layui-btn" lay-filter="startSettleSubmit" lay-submit>纭鏈堢粨</button>
+ </div>
+ </form>
+</script>
+
+<!-- 鏈堢粨鏄庣粏寮圭獥 -->
+<script type="text/html" id="detailDialog">
+ <div style="padding: 20px;">
+ <div class="layui-row">
+ <div class="layui-col-md6">
+ {{# if(d.settleNo) { }}
+ <p><strong>鏈堢粨缂栧彿锛�</strong>{{ d.settleNo }}</p>
+ {{# } }}
+ {{# if(d.startDate$) { }}
+ <p><strong>璧峰鏃ユ湡锛�</strong>{{ d.startDate$ }}</p>
+ {{# } }}
+ {{# if(d.endDate$) { }}
+ <p><strong>缁撴潫鏃ユ湡锛�</strong>{{ d.endDate$ }}</p>
+ {{# } }}
+ </div>
+ <div class="layui-col-md6">
+ {{# if(d.totalInQty !== null && d.totalInQty !== undefined) { }}
+ <p><strong>鎬诲叆搴撴暟閲忥細</strong>{{ d.totalInQty }}</p>
+ {{# } }}
+ {{# if(d.totalOutQty !== null && d.totalOutQty !== undefined) { }}
+ <p><strong>鎬诲嚭搴撴暟閲忥細</strong>{{ d.totalOutQty }}</p>
+ {{# } }}
+ {{# if(d.totalMaterials !== null && d.totalMaterials !== undefined) { }}
+ <p><strong>鐗╂枡绉嶇被鏁帮細</strong>{{ d.totalMaterials }}</p>
+ {{# } }}
+ </div>
+ </div>
+ <hr class="layui-bg-gray">
+ <table id="detailTable" lay-filter="detailTable"></table>
+ </div>
+</script>
+
+<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
+<script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/cool.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/monthlySettle/monthlySettle.js" charset="utf-8"></script>
+</body>
+</html>
+
+
--
Gitblit v1.9.1