From 1a3f5db043fd381b60a0a5f40687136274a2cbd1 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期五, 27 二月 2026 09:57:41 +0800
Subject: [PATCH] Merge branch 'refs/heads/dev_New' into dev_New_kthg

---
 src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java                          |    6 
 src/main/java/com/ruoyi/project/system/service/SysUserClientService.java                             |   19 
 src/main/java/com/ruoyi/account/pojo/AccountIncome.java                                              |    2 
 src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceRecords.java                                    |   98 +
 src/main/resources/mapper/production/ProductProcessMapper.xml                                        |    7 
 src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java                                |    2 
 src/main/resources/mapper/system/SysNoticeMapper.xml                                                 |    3 
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java                         |   18 
 src/main/java/com/ruoyi/quality/mapper/QualityUnqualifiedMapper.java                                 |    5 
 src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml                                          |   50 
 src/main/java/com/ruoyi/compensationperformance/pojo/CompensationPerformance.java                    |  207 +--
 src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java                                       |  193 +-
 src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java                              |    1 
 src/main/resources/mapper/sales/SalesLedgerProductMapper.xml                                         |   18 
 src/main/java/com/ruoyi/project/system/domain/GetuiConfig.java                                       |   46 
 src/main/resources/mapper/staff/StaffOnJobMapper.xml                                                 |   25 
 src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceLocationConfigServiceImpl.java          |   25 
 src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java                                          |    3 
 src/main/resources/mapper/system/SysMenuMapper.xml                                                   |   11 
 src/main/resources/application-dev.yml                                                               |   10 
 src/main/java/com/ruoyi/project/system/service/impl/SysUserClientServiceImpl.java                    |   43 
 src/main/java/com/ruoyi/staff/task/PersonalAttendanceRecordsTask.java                                |   76 +
 src/main/java/com/ruoyi/project/system/mapper/SysUserClientMapper.java                               |   18 
 src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java                                |    7 
 src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java                          |   46 
 src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java                       |   24 
 src/main/java/com/ruoyi/basic/controller/ProductController.java                                      |   22 
 src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java                         |  104 -
 src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java                                       |   14 
 src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java                                         |    5 
 src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java                                           |   12 
 src/main/java/com/ruoyi/CodeGenerator.java                                                           |    6 
 src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java                          |    3 
 src/main/java/com/ruoyi/sales/dto/StatisticsTableDto.java                                            |    4 
 src/main/resources/mapper/account/AccountIncomeMapper.xml                                            |    2 
 src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java                        |   40 
 src/main/java/com/ruoyi/staff/controller/PersonalAttendanceLocationConfigController.java             |   53 
 src/main/java/com/ruoyi/customervisits/service/impl/CustomerVisitsServiceImpl.java                   |   16 
 src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceLocationConfig.java                             |   60 +
 src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java                              |   87 +
 src/main/java/com/ruoyi/inspectiontask/controller/InspectionTaskController.java                      |    2 
 src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java                         |    2 
 src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java                      |   27 
 src/main/java/com/ruoyi/production/controller/ProductOrderController.java                            |   23 
 src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java                                       |    5 
 src/main/java/com/ruoyi/project/system/service/impl/UnipushService.java                              |  208 +++
 src/main/resources/application-new.yml                                                               |   10 
 src/main/java/com/ruoyi/compensationperformance/mapper/CompensationPerformanceMapper.java            |   18 
 src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java                                   |    9 
 src/main/java/com/ruoyi/compensationperformance/controller/CompensationPerformanceController.java    |   32 
 src/main/java/com/ruoyi/project/system/domain/SysUserClient.java                                     |   47 
 src/main/java/com/ruoyi/staff/dto/PersonalAttendanceRecordsDto.java                                  |   43 
 src/main/resources/mapper/staff/PersonalAttendanceRecordsMapper.xml                                  |   71 +
 src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java                          |   78 +
 src/main/java/com/ruoyi/project/system/domain/SysNotice.java                                         |    8 
 src/main/resources/mapper/production/ProductionProductInputMapper.xml                                |   41 
 src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceRecordsMapper.java                            |   25 
 src/main/java/com/ruoyi/compensationperformance/service/impl/CompensationPerformanceServiceImpl.java |   11 
 src/main/java/com/ruoyi/quality/service/IQualityUnqualifiedService.java                              |    1 
 src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java                 |  248 ++++
 src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml                                       |   61 
 src/main/java/com/ruoyi/account/pojo/AccountExpense.java                                             |    4 
 src/main/java/com/ruoyi/sales/pojo/SalesLedger.java                                                  |    4 
 src/main/resources/mapper/staff/PersonalAttendanceLocationConfigMapper.xml                           |   17 
 pom.xml                                                                                              |   83 
 src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java                   |    2 
 src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java                              |    2 
 src/main/java/com/ruoyi/project/system/controller/SysUserClientController.java                       |   44 
 src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java                    |    2 
 src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java                                  |  139 +-
 src/main/resources/application-khl.yml                                                               |  245 ++++
 src/main/resources/application-newTest.yml                                                           |  245 ++++
 src/main/resources/mapper/production/ProductionProductOutputMapper.xml                               |    2 
 src/main/java/com/ruoyi/basic/dto/ProductModelExportDto.java                                         |   24 
 src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java                           |   23 
 src/main/java/com/ruoyi/basic/service/IProductModelService.java                                      |    3 
 src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java                          |   58 
 src/main/java/com/ruoyi/staff/controller/HolidayApplicationController.java                           |    1 
 src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceLocationConfigMapper.java                     |   18 
 src/main/java/com/ruoyi/staff/utils/LocationUtils.java                                               |   37 
 src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java                |   18 
 src/main/resources/mapper/compensationperformance/CompensationPerformanceMapper.xml                  |   31 
 src/main/resources/mapper/stock/StockInventoryMapper.xml                                             |   14 
 src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java                                 |    2 
 src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java                           |   17 
 src/main/java/com/ruoyi/staff/pojo/StaffOnJob.java                                                   |    2 
 src/main/java/com/ruoyi/staff/service/PersonalAttendanceRecordsService.java                          |   23 
 src/main/java/com/ruoyi/quality/controller/QualityInspectController.java                             |   11 
 doc/20260209_create_personal_attendance_records.sql                                                  |   18 
 src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java                                     |    8 
 src/main/resources/mapper/production/ProductionProductMainMapper.xml                                 |    3 
 src/main/java/com/ruoyi/inspectiontask/controller/TimingTaskController.java                          |    2 
 src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java                            |    4 
 src/main/java/com/ruoyi/staff/service/PersonalAttendanceLocationConfigService.java                   |   16 
 src/main/java/com/ruoyi/compensationperformance/service/CompensationPerformanceService.java          |   16 
 src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java                    |   67 
 96 files changed, 2,805 insertions(+), 761 deletions(-)

diff --git a/doc/20260209_create_personal_attendance_records.sql b/doc/20260209_create_personal_attendance_records.sql
new file mode 100644
index 0000000..0a25e18
--- /dev/null
+++ b/doc/20260209_create_personal_attendance_records.sql
@@ -0,0 +1,18 @@
+#鍛樺伐鑰冨嫟琛�
+drop table if exists personal_attendance_records;
+create table personal_attendance_records
+(
+    id              bigint auto_increment primary key,
+    staff_on_job_id bigint not null default 0 comment '鍛樺伐鍦ㄨ亴id',
+    date            date not null comment '鏃ユ湡',
+    work_start_at   datetime null comment '宸ヤ綔寮�濮嬫椂闂�',
+    work_end_at     datetime null comment '宸ヤ綔缁撴潫鏃堕棿',
+    work_hours      decimal(5,2) null comment '宸ヤ綔鏃堕暱',
+    status          tinyint not null default 0 comment '鐘舵�� 0姝e父 1杩熷埌 2鏃╅��',
+    remark          text null comment '澶囨敞',
+    tenant_id       bigint not null comment '绉熸埛id',
+    create_time     datetime null comment '褰曞叆鏃堕棿',
+    update_time     datetime null comment '鏇存柊鏃堕棿',
+    index idx_staff_on_job_id (staff_on_job_id),
+    unique idx_staff_on_job_id_date (staff_on_job_id, date)
+);
diff --git a/pom.xml b/pom.xml
index 790a3e7..25bd9fe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.5.15</version>
-        <relativePath />
+        <relativePath/>
     </parent>
 
     <properties>
@@ -43,6 +43,7 @@
         <spring-security.version>5.7.12</spring-security.version>
         <spring-framework.version>5.3.39</spring-framework.version>
         <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
+        <getui-sdk.version>1.0.7.0</getui-sdk.version>
     </properties>
 
     <dependencies>
@@ -269,7 +270,6 @@
         </dependency>
 
 
-
         <!-- minio -->
         <dependency>
             <groupId>io.minio</groupId>
@@ -301,51 +301,58 @@
             <artifactId>easyexcel</artifactId>
             <version>4.0.3</version>
         </dependency>
-        
-         <dependency>
+
+        <dependency>
             <groupId>com.google.zxing</groupId>
             <artifactId>core</artifactId>
             <version>3.3.3</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.getui.push</groupId>
+            <artifactId>restful-sdk</artifactId>
+            <version>${getui-sdk.version}</version>
+            <scope>compile</scope>
+        </dependency>
+
     </dependencies>
 
-	<build>
-	    <finalName>${project.artifactId}</finalName>
-	    <plugins>
-	        <plugin>
-	            <groupId>org.springframework.boot</groupId>
-	            <artifactId>spring-boot-maven-plugin</artifactId>
-	            <configuration>
-	                <fork>true</fork> <!-- 濡傛灉娌℃湁璇ラ厤缃紝devtools涓嶄細鐢熸晥 -->
-	            </configuration>
-	        </plugin>
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <fork>true</fork> <!-- 濡傛灉娌℃湁璇ラ厤缃紝devtools涓嶄細鐢熸晥 -->
+                </configuration>
+            </plugin>
         </plugins>
-	</build>
+    </build>
 
-	<repositories>
-	    <repository>
-	        <id>public</id>
-	        <name>aliyun nexus</name>
-	        <url>https://maven.aliyun.com/repository/public</url>
-	        <releases>
-	            <enabled>true</enabled>
-	        </releases>
-	    </repository>
-	</repositories>
+    <repositories>
+        <repository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+        </repository>
+    </repositories>
 
-	<pluginRepositories>
-	    <pluginRepository>
-	        <id>public</id>
-	        <name>aliyun nexus</name>
-	        <url>https://maven.aliyun.com/repository/public</url>
-	        <releases>
-	            <enabled>true</enabled>
-	        </releases>
-	        <snapshots>
-	            <enabled>false</enabled>
-	        </snapshots>
-	    </pluginRepository>
-	</pluginRepositories>
+    <pluginRepositories>
+        <pluginRepository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
 
 </project>
diff --git a/src/main/java/com/ruoyi/CodeGenerator.java b/src/main/java/com/ruoyi/CodeGenerator.java
index e670dbb..6356273 100644
--- a/src/main/java/com/ruoyi/CodeGenerator.java
+++ b/src/main/java/com/ruoyi/CodeGenerator.java
@@ -19,11 +19,11 @@
 // 婕旂ず渚嬪瓙锛屾墽琛� main 鏂规硶鎺у埗鍙拌緭鍏ユā鍧楄〃鍚嶅洖杞﹁嚜鍔ㄧ敓鎴愬搴旈」鐩洰褰曚腑
 public class CodeGenerator {
 
-    public static String database_url = "jdbc:mysql://localhost:3306/product-inventory-management-new";
+    public static String database_url = "jdbc:mysql://1.15.17.182:9999/product-inventory-management-new";
     public static String database_username = "root";
-    public static String database_password= "123456";
+    public static String database_password= "xd@123456..";
     public static String author = "鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃";
-    public static String model = "purchase"; // 妯″潡
+    public static String model = "staff"; // 妯″潡
     public static String setParent = "com.ruoyi."+ model; // 鍖呰矾寰�
     public static String tablePrefix = ""; // 璁剧疆杩囨护琛ㄥ墠缂�
     public static void main(String[] args) {
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountExpense.java b/src/main/java/com/ruoyi/account/pojo/AccountExpense.java
index c87f423..1ad0463 100644
--- a/src/main/java/com/ruoyi/account/pojo/AccountExpense.java
+++ b/src/main/java/com/ruoyi/account/pojo/AccountExpense.java
@@ -48,9 +48,9 @@
     private Date expenseDate;
 
     /**
-     * 鏀嚭绫诲瀷(鍔炲叕鐢ㄥ搧锛屽憳宸ュ伐璧勶紝宸梾璐癸紝璁惧璐圭敤锛屽叾浠�)
+     * 鏀嚭绫诲瀷(鍔炲叕鐢ㄥ搧锛屽憳宸ュ伐璧勶紝宸梾璐癸紝璁惧璐圭敤锛屾潵绁ㄤ粯娆撅紝鍏朵粬)
      */
-    @Excel(name = "鏀嚭绫诲瀷",readConverterExp = "0=鍔炲叕鐢ㄥ搧,1=鍛樺伐宸ヨ祫,2=宸梾璐�,3=璁惧璐圭敤,4=鍏朵粬")
+    @Excel(name = "鏀嚭绫诲瀷",readConverterExp = "0=鍔炲叕鐢ㄥ搧,1=鍛樺伐宸ヨ祫,2=宸梾璐�,3=璁惧璐圭敤,4=鏉ョエ浠樻,5=鍏朵粬")
     @NotBlank(message = "鏀嚭绫诲瀷涓嶈兘涓虹┖!!")
     private String expenseType;
 
diff --git a/src/main/java/com/ruoyi/account/pojo/AccountIncome.java b/src/main/java/com/ruoyi/account/pojo/AccountIncome.java
index ff89f7b..fee01ad 100644
--- a/src/main/java/com/ruoyi/account/pojo/AccountIncome.java
+++ b/src/main/java/com/ruoyi/account/pojo/AccountIncome.java
@@ -50,7 +50,7 @@
     /**
      * 鏀跺叆绫诲瀷(閿�鍞敹鍏ワ紝鏈嶅姟鏀跺叆锛屽叾浠栨敹鍏�)
      */
-    @Excel(name = "鏀跺叆绫诲瀷",readConverterExp = "0=閿�鍞敹鍏�,1=鏈嶅姟鏀跺叆,2=鍏朵粬鏀跺叆")
+    @Excel(name = "鏀跺叆绫诲瀷",readConverterExp = "0=閿�鍞敹鍏�,1=鏈嶅姟鏀跺叆,2=鍏朵粬鏀跺叆,3=鍥炴鏀跺叆")
     @NotBlank(message = "鏀跺叆绫诲瀷涓嶈兘涓虹┖!!")
     private String incomeType;
 
diff --git a/src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java
index ee69c6f..74692c4 100644
--- a/src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java
@@ -100,7 +100,7 @@
                 accountExpense.setBusinessId(borrowInfo.getId());
                 accountExpense.setBusinessType(2);
                 accountExpense.setExpenseDate(DateUtils.toDate(borrowInfo.getRepayDate()));
-                accountExpense.setExpenseType("4");
+                accountExpense.setExpenseType("5");
                 accountExpense.setExpenseMoney(borrowInfo.getBorrowAmount());
                 accountExpense.setExpenseDescribed("杩樻");
                 accountExpense.setExpenseMethod("3");
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
index 14fe835..a624661 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -25,8 +25,12 @@
 import com.ruoyi.project.system.mapper.SysDeptMapper;
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.project.system.service.ISysNoticeService;
+import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
+import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.sales.mapper.CommonFileMapper;
+import com.ruoyi.sales.mapper.ShippingInfoMapper;
 import com.ruoyi.sales.pojo.CommonFile;
+import com.ruoyi.sales.pojo.ShippingInfo;
 import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
 import lombok.AllArgsConstructor;
 import lombok.RequiredArgsConstructor;
@@ -157,15 +161,61 @@
         return sysDeptList;
     }
 
+    @Autowired
+    private PurchaseLedgerMapper purchaseLedgerMapper;
+
+    @Autowired
+    private ShippingInfoMapper shippingInfoMapper;
+
     @Override
     public IPage<ApproveProcess> listAll(Page page, ApproveProcess approveProcess) {
         IPage<ApproveProcess> approveProcessIPage = approveProcessMapper.listPage(page, approveProcess);
         List<ApproveProcess> records = approveProcessIPage.getRecords();
+
         for (ApproveProcess record : records) {
-            List<CommonFile> commonFiles = commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
-                    .eq(CommonFile::getCommonId, record.getId())
-                    .eq(CommonFile::getType, FileNameType.ApproveProcess.getValue()));
-            record.setCommonFileList(commonFiles);
+            List<CommonFile> allFiles = new ArrayList<>();
+
+            //  閲囪喘瀹℃壒鏌ヨ
+            if (record.getApproveType() == 5) {
+                String contractNo = record.getApproveReason();
+                PurchaseLedger ledger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
+                        .eq(PurchaseLedger::getPurchaseContractNumber, contractNo)
+                        .last("limit 1"));
+
+                if (ledger != null) {
+                    allFiles = commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
+                            .eq(CommonFile::getCommonId, ledger.getId())
+                            .eq(CommonFile::getType, FileNameType.PURCHASE.getValue()));
+                }
+            }
+
+            //  鍙戣揣瀹℃壒鏌ヨ
+            else if (record.getApproveType() == 7) {
+                String reason = record.getApproveReason(); // 鏍煎紡涓� "xx:...-..."
+                if (StringUtils.hasText(reason) && reason.contains(":")) {
+                    // 鎻愬彇鍐掑彿鍚庨潰鐨勫彂璐у崟鍙�
+                    String shippingNo = reason.split(":")[1];
+                    // 鏍规嵁鍙戣揣鍗曞彿鏌ヨ鍙戣揣鍙拌处璁板綍
+                    ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
+                            .eq(ShippingInfo::getShippingNo, shippingNo)
+                            .last("limit 1"));
+                    if (shippingInfo != null) {
+                        // 浣跨敤鍙戣揣鍙拌处鐨� 閿�鍞彴璐D 鍘绘煡闄勪欢
+                        allFiles = commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
+                                .eq(CommonFile::getCommonId, shippingInfo.getSalesLedgerId())
+                                .eq(CommonFile::getType, FileNameType.SALE.getValue()));
+                    }
+                }
+            }
+
+            //  鏌ヨ瀹℃壒鍗曡嚜韬殑闄勪欢
+            else {
+                allFiles = commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
+                        .eq(CommonFile::getCommonId, record.getId())
+                        .eq(CommonFile::getType, FileNameType.ApproveProcess.getValue()));
+            }
+
+            record.setCommonFileList(allFiles);
         }
         return approveProcessIPage;
     }
diff --git a/src/main/java/com/ruoyi/basic/controller/ProductController.java b/src/main/java/com/ruoyi/basic/controller/ProductController.java
index a97bd7b..252ab4d 100644
--- a/src/main/java/com/ruoyi/basic/controller/ProductController.java
+++ b/src/main/java/com/ruoyi/basic/controller/ProductController.java
@@ -5,10 +5,12 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.basic.dto.ProductDto;
 import com.ruoyi.basic.dto.ProductModelDto;
+import com.ruoyi.basic.dto.ProductModelExportDto;
 import com.ruoyi.basic.dto.ProductTreeDto;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.service.IProductModelService;
 import com.ruoyi.basic.service.IProductService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
@@ -23,6 +25,7 @@
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 @RestController
@@ -124,9 +127,20 @@
     /**
      * 瀵煎叆浜у搧
      */
-    @Log(title = "瀵煎叆浜у搧",businessType = BusinessType.IMPORT)
-    @PostMapping("import")
-    public AjaxResult importProduct(MultipartFile file) {
-        return AjaxResult.success(productModelService.importProduct(file));
+    @PostMapping("/import")
+    @Log(title = "瀵煎叆浜у搧", businessType = BusinessType.IMPORT)
+    public AjaxResult importProductModel(@RequestParam("file") MultipartFile file, Integer productId) {
+        return productModelService.importProductModel(file, productId);
+    }
+
+    /**
+     * 浜у搧瀵煎叆妯℃澘
+     */
+    @GetMapping("/export")
+    @ApiOperation("浜у搧瀵煎叆妯℃澘")
+    @Log(title = "浜у搧瀵煎叆妯℃澘", businessType = BusinessType.EXPORT)
+    public void importProduct(HttpServletResponse response) {
+        ExcelUtil<ProductModelExportDto> excelUtil = new ExcelUtil<>(ProductModelExportDto.class);
+        excelUtil.importTemplateExcel(response, "浜у搧瑙勬牸瀵煎叆妯℃澘");
     }
 }
diff --git a/src/main/java/com/ruoyi/basic/dto/ProductModelExportDto.java b/src/main/java/com/ruoyi/basic/dto/ProductModelExportDto.java
new file mode 100644
index 0000000..c8c838a
--- /dev/null
+++ b/src/main/java/com/ruoyi/basic/dto/ProductModelExportDto.java
@@ -0,0 +1,24 @@
+package com.ruoyi.basic.dto;
+
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import lombok.Data;
+
+/**
+ * <br>
+ * 浜у搧瀵煎嚭妯℃澘
+ * </br>
+ *
+ * @author deslrey
+ * @version 1.0
+ * @since 2026/02/10 14:39
+ */
+@Data
+public class ProductModelExportDto {
+
+    @Excel(name = "瑙勬牸鍨嬪彿")
+    private String model;
+
+    @Excel(name = "鍗曚綅")
+    private String unit;
+
+}
diff --git a/src/main/java/com/ruoyi/basic/service/IProductModelService.java b/src/main/java/com/ruoyi/basic/service/IProductModelService.java
index f254612..dd268d6 100644
--- a/src/main/java/com/ruoyi/basic/service/IProductModelService.java
+++ b/src/main/java/com/ruoyi/basic/service/IProductModelService.java
@@ -6,6 +6,7 @@
 import com.ruoyi.basic.dto.ProductDto;
 import com.ruoyi.basic.dto.ProductModelDto;
 import com.ruoyi.basic.pojo.ProductModel;
+import com.ruoyi.framework.web.domain.AjaxResult;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
@@ -33,5 +34,5 @@
      */
     IPage<ProductModel> modelListPage(Page page , ProductDto productDto);
 
-    Boolean importProduct(MultipartFile file);
+    AjaxResult importProductModel(MultipartFile file, Integer productId);
 }
diff --git a/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java b/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
index cf9ef84..9382134 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -3,6 +3,7 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.basic.dto.ProductDto;
@@ -12,20 +13,19 @@
 import com.ruoyi.basic.pojo.Product;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.service.IProductModelService;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.common.utils.uuid.IdUtils;
+import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -47,13 +47,12 @@
 
         if (productModelDto.getId() == null) {
             ProductModel productModel = new ProductModel();
-            BeanUtils.copyProperties(productModelDto,productModel);
+            BeanUtils.copyProperties(productModelDto, productModel);
             return productModelMapper.insert(productModel);
         } else {
             return productModelMapper.updateById(productModelDto);
         }
     }
-
 
 
     @Override
@@ -76,6 +75,7 @@
 
     /**
      * 鏍规嵁id鏌ヨ浜у搧瑙勬牸鍒嗛〉鏌ヨ
+     *
      * @param page
      * @param productDto
      * @return
@@ -88,24 +88,67 @@
     }
 
     @Override
-    public Boolean importProduct(MultipartFile file) {
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult importProductModel(MultipartFile file, Integer productId) {
+        if (productId == null) {
+            return AjaxResult.error("璇峰厛閫夋嫨浜у搧鍐嶅鍏ヨ鏍煎瀷鍙�");
+        }
+
+        Product product = productMapper.selectById(productId);
+        if (product == null) {
+            return AjaxResult.error("閫夋嫨鐨勪骇鍝佷笉瀛樺湪");
+        }
+
         try {
             ExcelUtil<ProductModel> productModelExcelUtil = new ExcelUtil<>(ProductModel.class);
             List<ProductModel> productModelList = productModelExcelUtil.importExcel(file.getInputStream());
-            Map<String, List<ProductModel>> collect = productModelList.stream().collect(Collectors.groupingBy(ProductModel::getProductName));
-            collect.forEach((k,v)->{
-                Product product = productMapper.selectOne(new LambdaQueryWrapper<Product>().eq(Product::getProductName, k).last("LIMIT 1"));
-                if (product != null) {
-                    v.forEach(productModel -> {
-                        productModel.setProductId(product.getId());
-                    });
-                    this.saveOrUpdateBatch(v);
+
+            if (CollectionUtils.isEmpty(productModelList)) {
+                return AjaxResult.error("瀵煎叆鏁版嵁涓嶈兘涓虹┖");
+            }
+
+            //  鑾峰彇褰撳墠浜у搧涓嬫墍鏈夌殑瑙勬牸鍨嬪彿鍚�
+            List<ProductModel> existingModels = list(new LambdaQueryWrapper<ProductModel>().eq(ProductModel::getProductId, productId));
+            Set<String> existingModelNames = existingModels.stream().map(ProductModel::getModel).collect(Collectors.toSet());
+
+            List<ProductModel> waitToSaveList = new ArrayList<>();
+            int skipCount = 0;
+
+            for (int i = 0; i < productModelList.size(); i++) {
+                ProductModel item = productModelList.get(i);
+                int rowNum = i + 2;
+
+                if (StringUtils.isEmpty(item.getModel())) {
+                    return AjaxResult.error("绗� " + rowNum + " 琛屽鍏ュけ璐�: [瑙勬牸鍨嬪彿] 涓嶈兘涓虹┖");
                 }
-            });
-            return true;
-        }catch (Exception e) {
-            e.printStackTrace();
+                if (StringUtils.isEmpty(item.getUnit())) {
+                    return AjaxResult.error("绗� " + rowNum + " 琛屽鍏ュけ璐�: [鍗曚綅] 涓嶈兘涓虹┖");
+                }
+
+                //  鍘婚噸,濡傛灉宸插寘鍚鍨嬪彿,鍒欒烦杩�
+                if (existingModelNames.contains(item.getModel())) {
+                    skipCount++;
+                    continue;
+                }
+
+                item.setProductId(product.getId());
+                waitToSaveList.add(item);
+
+                existingModelNames.add(item.getModel());
+            }
+
+            if (!waitToSaveList.isEmpty()) {
+                saveBatch(waitToSaveList);
+            }
+
+            if (skipCount == 0) {
+                return AjaxResult.success(String.format("鎴愬姛瀵煎叆 %d 鏉℃暟鎹�", waitToSaveList.size()));
+            } else {
+                return AjaxResult.success(String.format("鎴愬姛瀵煎叆 %d 鏉★紝璺宠繃宸插瓨鍦ㄦ暟鎹� %d 鏉�", waitToSaveList.size(), skipCount));
+            }
+        } catch (Exception e) {
+            log.error("瀵煎叆浜у搧瑙勬牸寮傚父", e);
+            throw new ServiceException("瀵煎叆澶辫触");
         }
-        return false;
     }
 }
diff --git a/src/main/java/com/ruoyi/compensationperformance/controller/CompensationPerformanceController.java b/src/main/java/com/ruoyi/compensationperformance/controller/CompensationPerformanceController.java
index e1faffb..f6eee0f 100644
--- a/src/main/java/com/ruoyi/compensationperformance/controller/CompensationPerformanceController.java
+++ b/src/main/java/com/ruoyi/compensationperformance/controller/CompensationPerformanceController.java
@@ -40,11 +40,14 @@
     @Autowired
     private CompensationPerformanceService compensationPerformanceService;
 
+    @Autowired
+    private StaffOnJobMapper staffOnJobMapper;
+
     @GetMapping("/listPage")
     @Log(title = "钖叕缁╂晥-鍒嗛〉鏌ヨ", businessType = BusinessType.OTHER)
     @ApiOperation("钖叕缁╂晥-鍒嗛〉鏌ヨ")
-    public AjaxResult listPage(Page page, CompensationPerformance compensationPerformance){
-        IPage<CompensationPerformance> listPage = compensationPerformanceService.listPage(page, compensationPerformance);
+    public AjaxResult listPage(Page page, String staffName, String payDateStr) {
+        IPage<CompensationPerformance> listPage = compensationPerformanceService.listPage(page, staffName, payDateStr);
         return AjaxResult.success(listPage);
     }
 
@@ -52,7 +55,7 @@
     @Log(title = "钖叕缁╂晥-娣诲姞", businessType = BusinessType.INSERT)
     @ApiOperation("钖叕缁╂晥-娣诲姞")
     @Transactional(rollbackFor = Exception.class)
-    public AjaxResult add(@RequestBody CompensationPerformance compensationPerformance){
+    public AjaxResult add(@RequestBody CompensationPerformance compensationPerformance) {
         boolean save = compensationPerformanceService.save(compensationPerformance);
         return save ? AjaxResult.success("娣诲姞鎴愬姛") : AjaxResult.error("娣诲姞澶辫触");
     }
@@ -61,7 +64,7 @@
     @Log(title = "钖叕缁╂晥-淇敼", businessType = BusinessType.UPDATE)
     @ApiOperation("钖叕缁╂晥-淇敼")
     @Transactional(rollbackFor = Exception.class)
-    public AjaxResult update(@RequestBody CompensationPerformance compensationPerformance){
+    public AjaxResult update(@RequestBody CompensationPerformance compensationPerformance) {
         boolean update = compensationPerformanceService.updateById(compensationPerformance);
         return update ? AjaxResult.success("淇敼鎴愬姛") : AjaxResult.error("淇敼澶辫触");
     }
@@ -70,17 +73,17 @@
     @Log(title = "钖叕缁╂晥-鍒犻櫎", businessType = BusinessType.DELETE)
     @ApiOperation("钖叕缁╂晥-鍒犻櫎")
     @Transactional(rollbackFor = Exception.class)
-    public AjaxResult delete(@RequestBody List<Long> ids){
-        if(CollectionUtils.isEmpty(ids)) return AjaxResult.error("璇蜂紶鍏ヨ鍒犻櫎鐨処D");
+    public AjaxResult delete(@RequestBody List<Long> ids) {
+        if (CollectionUtils.isEmpty(ids)) return AjaxResult.error("璇蜂紶鍏ヨ鍒犻櫎鐨処D");
         boolean delete = compensationPerformanceService.removeBatchByIds(ids);
         return delete ? AjaxResult.success("鍒犻櫎鎴愬姛") : AjaxResult.error("鍒犻櫎澶辫触");
     }
 
     @Log(title = "瀵煎嚭钖祫绠$悊鍒楄〃", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
-    public void export(HttpServletResponse response ) {
-        List<CompensationPerformance> list = compensationPerformanceService.list();
-        ExcelUtil<CompensationPerformance> util = new ExcelUtil<CompensationPerformance>(CompensationPerformance.class);
+    public void export(HttpServletResponse response) {
+        List<CompensationPerformance> list = compensationPerformanceService.exportList();
+        ExcelUtil<CompensationPerformance> util = new ExcelUtil<>(CompensationPerformance.class);
         util.exportExcel(response, list, "瀵煎嚭钖祫绠$悊鍒楄〃");
     }
 
@@ -92,18 +95,15 @@
         util.exportExcel(response, list, "涓嬭浇钖祫绠$悊鍒楄〃妯℃澘");
     }
 
-    @Autowired
-    private SysUserMapper sysUserMapper;
-
     @Log(title = "瀵煎叆钖祫绠$悊鍒楄〃", businessType = BusinessType.IMPORT)
     @PostMapping("/importData")
     public AjaxResult importData(MultipartFile file) throws Exception {
         ExcelUtil<CompensationPerformance> util = new ExcelUtil<>(CompensationPerformance.class);
         List<CompensationPerformance> list = util.importExcel(file.getInputStream());
-        list.forEach(item->{
-            SysUser staffOnJob = sysUserMapper.selectUserByNickName(item.getName());
-            if(staffOnJob!=null){
-                item.setStaffId(staffOnJob.getUserId());
+        list.forEach(item -> {
+            StaffOnJob staffOnJob = staffOnJobMapper.selectStaffByNickName(item.getStaffName());
+            if (staffOnJob != null) {
+                item.setStaffId(staffOnJob.getId());
             }
         });
         boolean b = compensationPerformanceService.saveBatch(list);
diff --git a/src/main/java/com/ruoyi/compensationperformance/mapper/CompensationPerformanceMapper.java b/src/main/java/com/ruoyi/compensationperformance/mapper/CompensationPerformanceMapper.java
index 2526df0..394ab03 100644
--- a/src/main/java/com/ruoyi/compensationperformance/mapper/CompensationPerformanceMapper.java
+++ b/src/main/java/com/ruoyi/compensationperformance/mapper/CompensationPerformanceMapper.java
@@ -6,6 +6,8 @@
 import com.ruoyi.compensationperformance.pojo.CompensationPerformance;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * @author :yys
  * @date : 2025/8/8 9:54
@@ -15,9 +17,17 @@
     /**
      * 鍒嗛〉鏌ヨ
      *
-     * @param page
-     * @param compensationPerformance
-     * @return
+     * @param page       鍒嗛〉
+     * @param staffName  鍛樺伐濮撳悕
+     * @param payDateStr 钖祫鏃ユ湡
+     * @return 鏌ヨ鐨勪汉鍛樿柂璧勪俊鎭�
      */
-    IPage<CompensationPerformance> listPage(Page page,@Param("req") CompensationPerformance compensationPerformance);
+    IPage<CompensationPerformance> listPage(Page page, @Param("staffName") String staffName, @Param("payDateStr") String payDateStr);
+
+    /**
+     * 瀵煎嚭浜哄憳钖祫
+     *
+     * @return 浜哄憳钖祫淇℃伅
+     */
+    List<CompensationPerformance> exportList();
 }
diff --git a/src/main/java/com/ruoyi/compensationperformance/pojo/CompensationPerformance.java b/src/main/java/com/ruoyi/compensationperformance/pojo/CompensationPerformance.java
index 84d6138..686b975 100644
--- a/src/main/java/com/ruoyi/compensationperformance/pojo/CompensationPerformance.java
+++ b/src/main/java/com/ruoyi/compensationperformance/pojo/CompensationPerformance.java
@@ -8,193 +8,156 @@
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.Date;
 
 /**
+ * 钖叕缁╂晥鏄庣粏
+ *
  * @author :yys
- * @date : 2025/8/8 9:40
+ * @date : 2025/8/8
  */
 @Data
 @TableName("compensation_performance")
-@ApiModel
-public class CompensationPerformance {
-
+@ApiModel("钖叕缁╂晥鏄庣粏")
+public class CompensationPerformance implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
     @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty("涓婚敭")
     private Long id;
 
     /**
-     * 鐢ㄦ埛id
+     * 鍛樺伐id
      */
-    @ApiModelProperty("鐢ㄦ埛id")
+    @ApiModelProperty("鍛樺伐id")
     private Long staffId;
 
     /**
-     * 濮撳悕
+     * 鍛樺伐濮撳悕
      */
-    @ApiModelProperty("濮撳悕")
-    @Excel(name = "濮撳悕")
-    private String name;
+    @ApiModelProperty("鍛樺伐濮撳悕")
+    @Excel(name = "鍛樺伐濮撳悕")
+    @TableField(exist = false)
+    private String staffName;
 
     /**
-     * 钖祫鏈堜唤(鏌ヨ)
+     * 宀椾綅鍚嶇О
      */
-    @ApiModelProperty("钖祫鏈堜唤(鏌ヨ)")
+    @ApiModelProperty("宀椾綅鍚嶇О")
+    @Excel(name = "宀椾綅鍚嶇О")
     @TableField(exist = false)
-    private String payDateStr;
+    private String postName;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    @ApiModelProperty("閮ㄩ棬鍚嶇О")
+    @Excel(name = "閮ㄩ棬鍚嶇О")
+    @TableField(exist = false)
+    private String deptName;
 
     /**
      * 钖祫鏈堜唤
      */
     @ApiModelProperty("钖祫鏈堜唤")
-    @Excel(name = "钖祫鏈堜唤", dateFormat = "yyyy-MM", width = 30)
+    @Excel(name = "鏈堜唤", dateFormat = "yyyy-MM", width = 20)
     @JsonFormat(pattern = "yyyy-MM", timezone = "GMT+8")
     @DateTimeFormat(pattern = "yyyy-MM")
     private Date payDate;
-
-
-    /**
-     * 搴斿嚭鍕ゅぉ鏁�
-     */
-    @ApiModelProperty("搴斿嚭鍕ゅぉ鏁�")
-//    @Excel(name = "搴斿嚭鍕ゅぉ鏁�")
-    private BigDecimal shouldAttendedNum;
-
-    /**
-     * 瀹為檯鍑哄嫟澶╂暟
-     */
-    @ApiModelProperty("瀹為檯鍑哄嫟澶╂暟")
-//    @Excel(name = "瀹為檯鍑哄嫟澶╂暟")
-    private BigDecimal actualAttendedNum;
-
 
     /**
      * 鍩烘湰宸ヨ祫
      */
     @ApiModelProperty("鍩烘湰宸ヨ祫")
-//    @Excel(name = "鍩烘湰宸ヨ祫")
+    @Excel(name = "鍩烘湰宸ヨ祫")
     private BigDecimal basicSalary;
 
     /**
-     * 宀椾綅宸ヨ祫
+     * 璁′欢宸ヨ祫
      */
-    @ApiModelProperty("宀椾綅宸ヨ祫")
-//    @Excel(name = "宀椾綅宸ヨ祫")
-    private BigDecimal postSalary;
+    @ApiModelProperty("璁′欢宸ヨ祫")
+    @Excel(name = "璁′欢宸ヨ祫")
+    private BigDecimal pieceworkSalary;
 
     /**
-     * 鍏ョ鑱岀己鍕ゆ墸娆�
+     * 璁℃椂宸ヨ祫
      */
-    @ApiModelProperty("鍏ョ鑱岀己鍕ゆ墸娆�")
-//    @Excel(name = "鍏ョ鑱岀己鍕ゆ墸娆�")
-    private BigDecimal deductionAbsenteeism;
-
+    @ApiModelProperty("璁℃椂宸ヨ祫")
+    @Excel(name = "璁℃椂宸ヨ祫")
+    private BigDecimal hourlySalary;
 
     /**
-     * 鐥呭亣鎵f
+     * 鍏朵粬鏀跺叆
      */
-    @ApiModelProperty("鐥呭亣鎵f")
-//    @Excel(name = "鐥呭亣鎵f")
-    private BigDecimal sickLeaveDeductions;
-
-    /**
-     * 浜嬪亣鎵f
-     */
-    @ApiModelProperty("浜嬪亣鎵f")
-//    @Excel(name = "浜嬪亣鎵f")
-    private BigDecimal deductionPersonalLeave;
-    /**
-     * 蹇樿鎵撳崱鎵f
-     */
-    @ApiModelProperty("蹇樿鎵撳崱鎵f")
-//    @Excel(name = "蹇樿鎵撳崱鎵f")
-    private BigDecimal forgetClockDeduct;
-
-    /**
-     * 缁╂晥寰楀垎
-     */
-    @ApiModelProperty("缁╂晥寰楀垎")
-//    @Excel(name = "缁╂晥寰楀垎")
-    private BigDecimal performanceScore;
-
-    /**
-     * 缁╂晥宸ヨ祫
-     */
-    @ApiModelProperty("缁╂晥宸ヨ祫")
-//    @Excel(name = "缁╂晥宸ヨ祫")
-    private BigDecimal performancePay;
-
-
-    /**
-     * 搴斿彂鍚堣
-     */
-    @ApiModelProperty("搴斿彂鍚堣")
-//    @Excel(name = "搴斿彂鍚堣")
-    private BigDecimal payableWages;
+    @ApiModelProperty("鍏朵粬鏀跺叆")
+    @Excel(name = "鍏朵粬鏀跺叆")
+    private BigDecimal otherIncome;
 
     /**
      * 绀句繚涓汉
      */
     @ApiModelProperty("绀句繚涓汉")
-//    @Excel(name = "绀句繚涓汉")
+    @Excel(name = "绀句繚涓汉")
     private BigDecimal socialSecurityIndividuals;
-    /**
-     * 绀句繚鍏徃
-     */
-    @ApiModelProperty("绀句繚鍏徃")
-//    @Excel(name = "绀句繚鍏徃")
-    private BigDecimal socialSecurityCompanies;
-
-    /**
-     * 绀句繚鍚堣
-     */
-    @ApiModelProperty("绀句繚鍚堣")
-//    @Excel(name = "绀句繚鍚堣")
-    private BigDecimal socialSecurityTotal;
-
-    /**
-     * 鍏Н閲戝悎璁�
-     */
-    @ApiModelProperty("鍏Н閲戝悎璁�")
-//    @Excel(name = "鍏Н閲戝悎璁�")
-    private BigDecimal providentFundTotal;
-    /**
-     * 鍏Н閲戝叕鍙�
-     */
-    @ApiModelProperty("鍏Н閲戝叕鍙�")
-//    @Excel(name = "鍏Н閲戝叕鍙�")
-    private BigDecimal providentFundCompany;
 
     /**
      * 鍏Н閲戜釜浜�
      */
     @ApiModelProperty("鍏Н閲戜釜浜�")
-//    @Excel(name = "鍏Н閲戜釜浜�")
+    @Excel(name = "鍏Н閲戜釜浜�")
     private BigDecimal providentFundIndividuals;
 
     /**
-     * 搴旂◣宸ヨ祫
+     * 宸ヨ祫涓◣
      */
-    @ApiModelProperty("搴旂◣宸ヨ祫")
-//    @Excel(name = "搴旂◣宸ヨ祫")
-    private BigDecimal taxableWaget;
-    /**
-     * 涓汉鎵�寰楃◣
-     */
-    @ApiModelProperty("涓汉鎵�寰楃◣")
-//    @Excel(name = "涓汉鎵�寰楃◣")
+    @ApiModelProperty("宸ヨ祫涓◣")
+    @Excel(name = "宸ヨ祫涓◣")
     private BigDecimal personalIncomeTax;
+
+    /**
+     * 鍏朵粬鏀嚭
+     */
+    @ApiModelProperty("鍏朵粬鏀嚭")
+    @Excel(name = "鍏朵粬鏀嚭")
+    private BigDecimal otherDeductions;
+
+    /**
+     * 搴斿彂宸ヨ祫
+     */
+    @ApiModelProperty("搴斿彂宸ヨ祫")
+    @Excel(name = "搴斿彂宸ヨ祫")
+    private BigDecimal payableWages;
+
+    /**
+     * 搴旀墸宸ヨ祫
+     */
+    @ApiModelProperty("搴旀墸宸ヨ祫")
+    @Excel(name = "搴旀墸宸ヨ祫")
+    private BigDecimal deductibleWages;
 
     /**
      * 瀹炲彂宸ヨ祫
      */
     @ApiModelProperty("瀹炲彂宸ヨ祫")
-    @Excel(name = "瀹炲彂宸ヨ祫", width = 30)
+    @Excel(name = "瀹炲彂宸ヨ祫")
     private BigDecimal actualWages;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty("澶囨敞")
+    @Excel(name = "澶囨敞")
+    private String remark;
+
+    /**
+     * 绉熸埛ID
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long tenantId;
 
     /**
      * 鍒涘缓鑰�
@@ -206,6 +169,7 @@
      * 鍒涘缓鏃堕棿
      */
     @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime createTime;
 
     /**
@@ -218,12 +182,7 @@
      * 淇敼鏃堕棿
      */
     @TableField(fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime updateTime;
 
-    /**
-     * 绉熸埛ID
-     */
-    @TableField(fill = FieldFill.INSERT)
-    private Long tenantId;
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/compensationperformance/service/CompensationPerformanceService.java b/src/main/java/com/ruoyi/compensationperformance/service/CompensationPerformanceService.java
index 547fbf8..a7af9a4 100644
--- a/src/main/java/com/ruoyi/compensationperformance/service/CompensationPerformanceService.java
+++ b/src/main/java/com/ruoyi/compensationperformance/service/CompensationPerformanceService.java
@@ -5,6 +5,8 @@
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.compensationperformance.pojo.CompensationPerformance;
 
+import java.util.List;
+
 /**
  * @author :yys
  * @date : 2025/8/8 9:55
@@ -14,9 +16,17 @@
     /**
      * 鍒嗛〉鏌ヨ
      *
-     * @param page
-     * @param compensationPerformance
+     * @param page       鍒嗛〉鎻掍欢
+     * @param staffName  鍛樺伐濮撳悕
+     * @param payDateStr 钖祫鏃ユ湡
      * @return
      */
-    IPage<CompensationPerformance> listPage(Page page, CompensationPerformance compensationPerformance);
+    IPage<CompensationPerformance> listPage(Page page, String staffName, String payDateStr);
+
+    /**
+     * 瀵煎嚭浜哄憳鏂板
+     *
+     * @return 浜哄憳钖祫
+     */
+    List<CompensationPerformance> exportList();
 }
diff --git a/src/main/java/com/ruoyi/compensationperformance/service/impl/CompensationPerformanceServiceImpl.java b/src/main/java/com/ruoyi/compensationperformance/service/impl/CompensationPerformanceServiceImpl.java
index 04a3c48..b3b3aa7 100644
--- a/src/main/java/com/ruoyi/compensationperformance/service/impl/CompensationPerformanceServiceImpl.java
+++ b/src/main/java/com/ruoyi/compensationperformance/service/impl/CompensationPerformanceServiceImpl.java
@@ -10,6 +10,8 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 /**
  * @author :yys
  * @date : 2025/8/8 9:55
@@ -23,7 +25,12 @@
 
 
     @Override
-    public IPage<CompensationPerformance> listPage(Page page, CompensationPerformance compensationPerformance) {
-        return compensationPerformanceMapper.listPage(page, compensationPerformance);
+    public IPage<CompensationPerformance> listPage(Page page, String staffName, String payDateStr) {
+        return compensationPerformanceMapper.listPage(page, staffName, payDateStr);
+    }
+
+    @Override
+    public List<CompensationPerformance> exportList() {
+        return compensationPerformanceMapper.exportList();
     }
 }
diff --git a/src/main/java/com/ruoyi/customervisits/service/impl/CustomerVisitsServiceImpl.java b/src/main/java/com/ruoyi/customervisits/service/impl/CustomerVisitsServiceImpl.java
index d63fcb8..c36cf70 100644
--- a/src/main/java/com/ruoyi/customervisits/service/impl/CustomerVisitsServiceImpl.java
+++ b/src/main/java/com/ruoyi/customervisits/service/impl/CustomerVisitsServiceImpl.java
@@ -26,11 +26,19 @@
 
     @Override
     public IPage<CustomerVisits> listPage(Page page, CustomerVisits customerVisits) {
-        LambdaQueryWrapper<CustomerVisits> customerVisitsLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        if (customerVisits != null && !StringUtils.isEmpty(customerVisits.getCustomerName())) {
-            customerVisitsLambdaQueryWrapper.like(CustomerVisits::getCustomerName, customerVisits.getCustomerName());
+        LambdaQueryWrapper<CustomerVisits> wrapper = new LambdaQueryWrapper<>();
+
+        if (customerVisits != null) {
+            if (StringUtils.hasText(customerVisits.getCustomerName())) {
+                wrapper.like(CustomerVisits::getCustomerName, customerVisits.getCustomerName());
+            }
+
+            if (StringUtils.hasText(customerVisits.getVisitingPeople())) {
+                wrapper.like(CustomerVisits::getVisitingPeople, customerVisits.getVisitingPeople());
+            }
         }
-        return customerVisitsMapper.selectPage(page, customerVisitsLambdaQueryWrapper);
+
+        return customerVisitsMapper.selectPage(page, wrapper);
     }
 
     @Override
diff --git a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
index 76e948d..2d3e608 100644
--- a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
+++ b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.account.mapper.AccountIncomeMapper;
 import com.ruoyi.account.pojo.AccountExpense;
@@ -144,6 +145,12 @@
 
     @Autowired
     private ProductProcessMapper productProcessMapper;
+    
+    @Autowired
+    private AccountExpenseMapper accountExpenseMapper;
+
+    @Autowired
+    private AccountIncomeMapper accountIncomeMapper;
 
     @Override
     public HomeBusinessDto business() {
@@ -178,28 +185,31 @@
         LambdaQueryWrapper<PurchaseLedger> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.ge(PurchaseLedger::getEntryDate, currentMonth.atDay(1).atStartOfDay()) // 澶т簬绛変簬鏈湀绗竴澶�
                 .lt(PurchaseLedger::getEntryDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // 灏忎簬涓嬫湀绗竴澶�
-        // 鎵ц鏌ヨ骞惰绠楁�诲拰
+
         List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(queryWrapper);
         if (!CollectionUtils.isEmpty(purchaseLedgers)) {
-            LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductMapperLambdaQueryWrapperCopy = new LambdaQueryWrapper<SalesLedgerProduct>();
-            salesLedgerProductMapperLambdaQueryWrapperCopy.eq(SalesLedgerProduct::getType, 2)
+            LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductMapperLambdaQueryWrapperCopy = new LambdaQueryWrapper<>();
+            salesLedgerProductMapperLambdaQueryWrapperCopy.eq(SalesLedgerProduct::getType, 2) // 閲囪喘绫诲瀷
                     .in(SalesLedgerProduct::getSalesLedgerId,
                             purchaseLedgers.stream().map(PurchaseLedger::getId).collect(Collectors.toList()));
+
             List<SalesLedgerProduct> salesLedgerProductsCopy = salesLedgerProductMapper
                     .selectList(salesLedgerProductMapperLambdaQueryWrapperCopy);
-            // 鍚堣鍚堝悓閲戦
+
+            // 鍚堣鍚堝悓鎬婚噾棰�
             BigDecimal receiveAmount = purchaseLedgers.stream()
                     .map(PurchaseLedger::getContractAmount)
                     .filter(Objects::nonNull)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
-            // 鏈紑绁ㄩ噾棰�
+
+            //  寰呬粯娆炬�婚噾棰�
             BigDecimal unReceiptPaymentAmount = salesLedgerProductsCopy.stream()
-                    .map(SalesLedgerProduct::getNoInvoiceAmount)
+                    .map(SalesLedgerProduct::getPendingTicketsTotal)
                     .filter(Objects::nonNull)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
+
             homeBusinessDto.setMonthPurchaseMoney(receiveAmount.setScale(2, RoundingMode.HALF_UP).toString());
-            homeBusinessDto
-                    .setMonthPurchaseHaveMoney(unReceiptPaymentAmount.setScale(2, RoundingMode.HALF_UP).toString());
+            homeBusinessDto.setMonthPurchaseHaveMoney(unReceiptPaymentAmount.setScale(2, RoundingMode.HALF_UP).toString());
         }
         // 缁熻搴撳瓨
         BigDecimal stockQuantityTotal = stockInventoryMapper.selectTotal();
@@ -330,10 +340,10 @@
             // 褰撴湀鐨勭粨鏉熸棩鏈燂紙姣忔湀鏈�鍚庝竴澶╋級
             LocalDate monthEnd = currentMonth.withDayOfMonth(currentMonth.lengthOfMonth());
 
-            // 鏋勫缓褰撴湀鐨勬煡璇㈡潯浠讹紙濡傛灉鎯充竴娆℃�ф煡鍏�4涓湀鏁版嵁鍐嶅唴瀛樼瓫閫夛紝鍙紭鍖栦负鍏堟煡鍏ㄥ啀寰幆绛涢�夛級
+            // 鏋勫缓褰撴湀鐨勬煡璇㈡潯浠�
             LambdaQueryWrapper<QualityInspect> queryWrapper = new LambdaQueryWrapper<>();
-            queryWrapper.ge(QualityInspect::getCheckTime, monthStart)
-                    .le(QualityInspect::getCheckTime, monthEnd); // 绛涢�夊綋鏈堟暟鎹�
+            queryWrapper.ge(QualityInspect::getCheckTime, monthStart.toString())
+                    .le(QualityInspect::getCheckTime, monthEnd.toString());
             List<QualityInspect> monthInspects = qualityStatisticsMapper.selectList(queryWrapper);
             BigDecimal reduce = monthInspects.stream()
                     .filter(inspect -> inspect.getInspectType().equals(0))
@@ -464,8 +474,8 @@
         }
         // 搴旀敹
         List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
-        // .ge(SalesLedger::getEntryDate, startDate)
-        // .lt(SalesLedger::getEntryDate, endDate)
+                // .ge(SalesLedger::getEntryDate, startDate)
+                // .lt(SalesLedger::getEntryDate, endDate)
         );
         // BigDecimal receivableMoney =
         // salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO,
@@ -474,8 +484,8 @@
         // 搴斾粯
         List<PurchaseLedger> procurementRecords = purchaseLedgerMapper
                 .selectList(new LambdaQueryWrapper<PurchaseLedger>()
-                // .ge(PurchaseLedger::getEntryDate, startDate)
-                // .lt(PurchaseLedger::getEntryDate, endDate)
+                        // .ge(PurchaseLedger::getEntryDate, startDate)
+                        // .lt(PurchaseLedger::getEntryDate, endDate)
                 );
         // BigDecimal payableMoney =
         // procurementRecords.stream().map(PurchaseLedger::getContractAmount).reduce(BigDecimal.ZERO,
@@ -483,8 +493,8 @@
         BigDecimal payableMoney = sumAmount(procurementRecords, PurchaseLedger::getContractAmount);
         // 棰勬敹
         List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
-        // .ge(ReceiptPayment::getReceiptPaymentDate, startDate)
-        // .lt(ReceiptPayment::getReceiptPaymentDate, endDate)
+                // .ge(ReceiptPayment::getReceiptPaymentDate, startDate)
+                // .lt(ReceiptPayment::getReceiptPaymentDate, endDate)
         );
         // BigDecimal advanceMoney =
         // receiptPayments.stream().map(ReceiptPayment::getReceiptPaymentAmount).reduce(BigDecimal.ZERO,
@@ -493,8 +503,8 @@
         // 棰勪粯
         List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper
                 .selectList(new LambdaQueryWrapper<PaymentRegistration>()
-                // .ge(PaymentRegistration::getPaymentDate, startDate)
-                // .lt(PaymentRegistration::getPaymentDate, endDate)
+                        // .ge(PaymentRegistration::getPaymentDate, startDate)
+                        // .lt(PaymentRegistration::getPaymentDate, endDate)
                 );
         // BigDecimal prepayMoney =
         // paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO,
@@ -558,7 +568,7 @@
         productionProgressDto.setCompletedOrderDetails(productOrderDtos);
         long totalCount = productOrderDtos.size();
         long count = productOrderDtos.stream().filter(
-                productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(productOrderDto.getQuantity()) >= 0)
+                        productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(productOrderDto.getQuantity()) >= 0)
                 .count();
         long count2 = productOrderDtos.stream()
                 .filter(productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(BigDecimal.ZERO) == 0)
@@ -1031,28 +1041,20 @@
 
     @Override
     public List<MapDto> salesPurchaseStorageProductCount() {
-        LocalDate now = LocalDate.now();
-        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        LocalDateTime now = LocalDateTime.now();
+        LocalDateTime currentMonthStart = now.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
+        LocalDateTime lastMonth = now.minusMonths(1);
+        LocalDateTime lastMonthStart = lastMonth.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
+        LocalDateTime lastMonthEnd = lastMonth.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
 
-        String currentMonthStart = now.with(TemporalAdjusters.firstDayOfMonth()).format(dtf);
-        String currentMonthNow = now.format(dtf);
-
-        LocalDate lastMonth = now.minusMonths(1);
-        String lastMonthStart = lastMonth.with(TemporalAdjusters.firstDayOfMonth()).format(dtf);
-        String lastMonthEnd = lastMonth.with(TemporalAdjusters.lastDayOfMonth()).format(dtf);
-
-        // 閿�鍞�
-        int currentSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, currentMonthStart,
-                currentMonthNow);
+        //  閿�鍞�
+        int currentSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, currentMonthStart, now);
         int lastSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, lastMonthStart, lastMonthEnd);
-
-        // 閲囪喘
-        int currentPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, currentMonthStart,
-                currentMonthNow);
+        //  閲囪喘
+        int currentPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, currentMonthStart, now);
         int lastPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, lastMonthStart, lastMonthEnd);
-
-        // 鍌ㄥ瓨
-        int currentStorage = stockInventoryMapper.selectStorageProductCountByDate(currentMonthStart, currentMonthNow);
+        //  鍌ㄥ瓨
+        int currentStorage = stockInventoryMapper.selectStorageProductCountByDate(currentMonthStart, now);
         int lastStorage = stockInventoryMapper.selectStorageProductCountByDate(lastMonthStart, lastMonthEnd);
 
         List<MapDto> list = new ArrayList<>();
@@ -1151,12 +1153,6 @@
     public List<MapDto> productTurnoverDays() {
         return homeMapper.productTurnoverDays();
     }
-
-    @Autowired
-    private AccountExpenseMapper accountExpenseMapper;
-
-    @Autowired
-    private AccountIncomeMapper accountIncomeMapper;
 
     public List<Map<String, Object>> incomeExpenseAnalysis(Integer type) {
 
@@ -1281,36 +1277,21 @@
         String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
         String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 
-        // List<IncomeExpenseAnalysisDto> incomeList =
-        // salesLedgerMapper.selectIncomeStats(startStr, endStr, dateFormat);
-        List<IncomeExpenseAnalysisDto> incomeList = new ArrayList<>();
-        List<IncomeExpenseAnalysisDto> purchaseList = purchaseLedgerMapper.selectPurchaseStats(startStr, endStr,
-                dateFormat);
-        List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr,
-                dateFormat);
+        List<IncomeExpenseAnalysisDto> incomeList = accountIncomeMapper.selectIncomeStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr, dateFormat);
 
         Map<String, BigDecimal> incomeMap = incomeList.stream().collect(Collectors
-                .toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
-        Map<String, BigDecimal> purchaseMap = purchaseList.stream().collect(Collectors
                 .toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
         Map<String, BigDecimal> expenseMap = expenseList.stream().collect(Collectors
                 .toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
 
         List<MapDto> result = new ArrayList<>();
-
         for (String month : months) {
             MapDto dto = new MapDto();
             dto.setName(month);
-
             BigDecimal income = incomeMap.getOrDefault(month, BigDecimal.ZERO);
-
-            BigDecimal purchase = purchaseMap.getOrDefault(month, BigDecimal.ZERO);
-            income = BigDecimal.ZERO;
             BigDecimal expense = expenseMap.getOrDefault(month, BigDecimal.ZERO);
-            BigDecimal totalExpense = purchase.add(expense);
-
-            BigDecimal profit = income.subtract(totalExpense);
-
+            BigDecimal profit = income.subtract(expense);
             dto.setValue(profit.setScale(2, RoundingMode.HALF_UP).toString());
             result.add(dto);
         }
@@ -1916,10 +1897,8 @@
         LocalDate startDate = range[0];
         LocalDate endDate = range[1];
 
-        String startStr = startDate.atStartOfDay()
-                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-        String endStr = endDate.atTime(LocalTime.MAX)
-                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        String startStr = startDate.toString();
+        String endStr = endDate.toString();
 
         List<QualityInspect> list = qualityInspectMapper.selectList(
                 new LambdaQueryWrapper<QualityInspect>()
@@ -1957,7 +1936,7 @@
                 endDate = today.with(DayOfWeek.SUNDAY);
         }
 
-        return new LocalDate[] { startDate, endDate };
+        return new LocalDate[]{startDate, endDate};
     }
 
     private QualityQualifiedAnalysisDto buildQualifiedAnalysis(List<QualityInspect> list) {
@@ -2009,20 +1988,14 @@
 
     @Override
     public QualityInspectionCountDto qualityInspectionCount() {
-        // 鑾峰彇浠婂ぉ鐨勫紑濮嬪拰缁撴潫鏃ユ湡,鍖呭惈鏃跺垎绉�
-        LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
-        LocalDateTime todayEnd = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(0);
-        // 鑾峰彇鍓嶄竴澶╃殑寮�濮嬪拰缁撴潫鏃ユ湡,鍖呭惈鏃跺垎绉�
-        LocalDateTime prevStart = todayStart.minusDays(1);
-        LocalDateTime prevEnd = todayEnd.minusDays(1);
+        String todayStr = LocalDate.now().toString();
+        String prevDayStr = LocalDate.now().minusDays(1).toString();
         // 鏌ヨ鍑烘埅姝粖鏃ョ殑鎬绘楠屾暟
         List<QualityInspect> todayList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
-                // .eq(QualityInspect::getInspectState, 1)
-                .le(QualityInspect::getCheckTime, todayEnd));
+                .le(QualityInspect::getCheckTime, todayStr));
         // 鏌ヨ鍑烘埅姝㈠墠涓�澶╃殑鎬绘楠屾暟
         List<QualityInspect> prevList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
-                // .eq(QualityInspect::getInspectState, 1)
-                .le(QualityInspect::getCheckTime, prevEnd));
+                .le(QualityInspect::getCheckTime, prevDayStr));
         // 璁$畻浠婃棩鐨勬�绘楠屾暟
         BigDecimal todayCount = todayList.stream()
                 .map(QualityInspect::getQuantity)
@@ -2038,14 +2011,12 @@
         // 璁$畻浠婂ぉ鐨勫緟瀹屾垚鏁伴噺
         List<QualityInspect> todayPendingList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                 .eq(QualityInspect::getInspectState, 0)
-                .ge(QualityInspect::getCheckTime, todayStart)
-                .le(QualityInspect::getCheckTime, todayEnd));
+                .eq(QualityInspect::getCheckTime, todayStr));
 
         // 璁$畻鍓嶄竴澶╃殑寰呭畬鎴愭暟閲�
         List<QualityInspect> prevPendingList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                 .eq(QualityInspect::getInspectState, 0)
-                .ge(QualityInspect::getCheckTime, prevStart)
-                .le(QualityInspect::getCheckTime, prevEnd));
+                .eq(QualityInspect::getCheckTime, prevDayStr));
         // 璁$畻浠婂ぉ鐨勫緟瀹屾垚鏁伴噺
         BigDecimal todayPendingCount = todayPendingList.stream()
                 .map(QualityInspect::getQuantity)
@@ -2061,14 +2032,12 @@
         List<QualityInspect> todayCompletedList = qualityInspectMapper
                 .selectList(new LambdaQueryWrapper<QualityInspect>()
                         .eq(QualityInspect::getInspectState, 1)
-                        .ge(QualityInspect::getCheckTime, todayStart)
-                        .le(QualityInspect::getCheckTime, todayEnd));
+                        .eq(QualityInspect::getCheckTime, todayStr));
         // 璁$畻鍓嶄竴澶╃殑宸插畬鎴愭暟閲�
         List<QualityInspect> prevCompletedList = qualityInspectMapper
                 .selectList(new LambdaQueryWrapper<QualityInspect>()
                         .eq(QualityInspect::getInspectState, 1)
-                        .ge(QualityInspect::getCheckTime, prevStart)
-                        .le(QualityInspect::getCheckTime, prevEnd));
+                        .eq(QualityInspect::getCheckTime, prevDayStr));
         // 璁$畻浠婂ぉ鐨勫凡瀹屾垚鏁伴噺
         BigDecimal todayCompletedCount = todayCompletedList.stream()
                 .map(QualityInspect::getQuantity)
@@ -2101,18 +2070,16 @@
 
     @Override
     public NonComplianceWarningDto nonComplianceWarning() {
-
-        // 杩戜竷澶╂椂闂村尯闂�
-        LocalDateTime[] range = lastSevenDaysRange();
-        LocalDateTime startTime = range[0];
-        LocalDateTime endTime = range[1];
+        String[] range = lastSevenDaysDateRange();
+        String startStr = range[0];
+        String endStr = range[1];
 
         // 鏌ヨ杩戜竷澶╁凡澶勭悊涓嶅悎鏍兼暟鎹�
         List<QualityUnqualified> list = qualityUnqualifiedMapper.selectList(
                 new LambdaQueryWrapper<QualityUnqualified>()
                         .eq(QualityUnqualified::getInspectState, 1)
-                        .ge(QualityUnqualified::getCheckTime, startTime)
-                        .le(QualityUnqualified::getCheckTime, endTime));
+                        .ge(QualityUnqualified::getCheckTime, startStr)
+                        .le(QualityUnqualified::getCheckTime, endStr));
 
         NonComplianceWarningDto dto = new NonComplianceWarningDto();
 
@@ -2211,29 +2178,24 @@
     }
 
     /**
-     * 鑾峰彇杩戜竷澶╃殑鏃堕棿鍖洪棿锛堝寘鍚粖澶╋級
+     * 鑾峰彇杩戜竷澶╃殑鏃ユ湡鍖洪棿锛堜粎鍚勾鏈堟棩锛�
      */
-    public static LocalDateTime[] lastSevenDaysRange() {
+    public static String[] lastSevenDaysDateRange() {
         LocalDate today = LocalDate.now();
-
-        LocalDateTime startTime = today.minusDays(6).atStartOfDay();
-        LocalDateTime endTime = today.atTime(23, 59, 59);
-
-        return new LocalDateTime[] { startTime, endTime };
+        return new String[]{today.minusDays(6).toString(), today.toString()};
     }
 
     @Override
     public List<CompletedInspectionCountDto> completedInspectionCount() {
-        // 杩戜竷澶╂椂闂村尯闂�
-        LocalDateTime[] range = lastSevenDaysRange();
-        LocalDateTime startTime = range[0];
-        LocalDateTime endTime = range[1];
+        String[] range = lastSevenDaysDateRange();
+        String startStr = range[0];
+        String endStr = range[1];
 
         // 鏌ヨ杩戜竷澶╁凡瀹屾垚鐨勬楠屾暟鎹�
         List<QualityInspect> list = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                 .eq(QualityInspect::getInspectState, 1)
-                .ge(QualityInspect::getCheckTime, startTime)
-                .le(QualityInspect::getCheckTime, endTime));
+                .ge(QualityInspect::getCheckTime, startStr)
+                .le(QualityInspect::getCheckTime, endStr));
 
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
 
@@ -2440,8 +2402,8 @@
 
         List<QualityInspect> qualityInspectList = qualityInspectMapper
                 .selectList(new LambdaQueryWrapper<QualityInspect>()
-                        .ge(QualityInspect::getCheckTime, startDate)
-                        .le(QualityInspect::getCheckTime, endDate)
+                        .ge(QualityInspect::getCheckTime, startDate.toString())
+                        .le(QualityInspect::getCheckTime, endDate.toString())
                         .eq(QualityInspect::getInspectState, 1));
 
         QualityStatisticsDto dto = new QualityStatisticsDto();
@@ -2449,6 +2411,13 @@
         dto.setProcessNum(sumQuantity(qualityInspectList, 1)); // 杩囩▼
         dto.setFactoryNum(sumQuantity(qualityInspectList, 2)); // 鍑哄巶
 
+        // 鍋囪 qualityInspectList 鏄竴涓� List<QualityInspect> 绫诲瀷鐨勯泦鍚�
+        Map<String, List<QualityInspect>> groupedByCheckResult = qualityInspectList.stream()
+                .collect(Collectors.groupingBy(QualityInspect::getCheckResult));
+        List<QualityInspect> qualityInspects = groupedByCheckResult.get("涓嶅悎鏍�");
+        if (ObjectUtils.isNull(qualityInspects) || qualityInspects.size() == 0) {
+            return null;
+        }
         // 4. 澶勭悊鍥捐〃椤� (Item)
         List<QualityStatisticsItem> itemList = new ArrayList<>();
 
@@ -2458,7 +2427,7 @@
                         i -> i.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()));
         if (type == 3) {
             // 瀛e害妯″紡锛氭寜鏈堝垎缁�
-            Map<String, List<QualityInspect>> groupByMonth = qualityInspectList.stream()
+            Map<String, List<QualityInspect>> groupByMonth = qualityInspects.stream()
                     .collect(Collectors.groupingBy(i -> {
                         LocalDate ld = dateMap.get(i);
                         return ld.format(DateTimeFormatter.ofPattern("yyyy-MM"));
@@ -2471,7 +2440,7 @@
             }
         } else {
             // 鍛ㄦ垨鏈堟ā寮忥細鎸夊ぉ鍒嗙粍
-            Map<String, List<QualityInspect>> groupByDay = qualityInspectList.stream()
+            Map<String, List<QualityInspect>> groupByDay = qualityInspects.stream()
                     .collect(Collectors.groupingBy(i -> {
                         LocalDate ld = dateMap.get(i);
                         return ld.format(DateTimeFormatter.ofPattern("MM/dd"));
@@ -2512,7 +2481,7 @@
 
     @Override
     public List<processDataProductionStatisticsDto> processDataProductionStatistics(Integer type,
-            List<Long> processIds) {
+                                                                                    List<Long> processIds) {
         LoginUser loginUser = SecurityUtils.getLoginUser();
         Long userId = SecurityUtils.isAdmin(loginUser.getUserId()) ? null : loginUser.getUserId();
 
@@ -2543,4 +2512,4 @@
 
         return productProcessMapper.calculateProductionStatistics(startDateTime, endDateTime, userId, processIds);
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/ruoyi/inspectiontask/controller/InspectionTaskController.java b/src/main/java/com/ruoyi/inspectiontask/controller/InspectionTaskController.java
index f08eb0e..40445d1 100644
--- a/src/main/java/com/ruoyi/inspectiontask/controller/InspectionTaskController.java
+++ b/src/main/java/com/ruoyi/inspectiontask/controller/InspectionTaskController.java
@@ -22,7 +22,7 @@
  * @date : 2025/9/19 10:52
  */
 @RestController
-@Api(tags = "宸℃浠诲姟绠$悊")
+@Api(tags = "宸℃浠诲姟璁板綍")
 @RequestMapping("/inspectionTask")
 public class InspectionTaskController extends BaseController {
 
diff --git a/src/main/java/com/ruoyi/inspectiontask/controller/TimingTaskController.java b/src/main/java/com/ruoyi/inspectiontask/controller/TimingTaskController.java
index ee13756..ccaf969 100644
--- a/src/main/java/com/ruoyi/inspectiontask/controller/TimingTaskController.java
+++ b/src/main/java/com/ruoyi/inspectiontask/controller/TimingTaskController.java
@@ -23,7 +23,7 @@
  * @date : 2025/9/19 10:53
  */
 @RestController
-@Api(tags = "瀹氭椂浠诲姟绠$悊")
+@Api(tags = "宸℃绠$悊")
 @RequestMapping("/timingTask")
 public class TimingTaskController extends BaseController {
 
diff --git a/src/main/java/com/ruoyi/production/controller/ProductOrderController.java b/src/main/java/com/ruoyi/production/controller/ProductOrderController.java
index fb8011a..09bd010 100644
--- a/src/main/java/com/ruoyi/production/controller/ProductOrderController.java
+++ b/src/main/java/com/ruoyi/production/controller/ProductOrderController.java
@@ -51,29 +51,6 @@
     @PostMapping("/export")
     public void export(HttpServletResponse response, ProductOrderDto productOrderDto) {
         List<ProductOrderDto> list = productOrderService.pageProductOrder(new Page<>(1, -1), productOrderDto).getRecords();
-
-        if (list != null && !list.isEmpty()) {
-            list.forEach(item -> {
-                // 鍒ょ┖
-                if (item.getQuantity() == null || item.getCompleteQuantity() == null) {
-                    item.setCompletionStatus(BigDecimal.ZERO);
-                    return;
-                }
-
-                // 鍒ら浂
-                if (item.getQuantity().compareTo(BigDecimal.ZERO) == 0) {
-                    item.setCompletionStatus(BigDecimal.ZERO);
-                    return;
-                }
-                BigDecimal progress = item.getCompleteQuantity()
-                        .divide(item.getQuantity(), 4, BigDecimal.ROUND_HALF_UP)
-                        .multiply(new BigDecimal(100))
-                        .setScale(2, BigDecimal.ROUND_HALF_UP);
-
-                item.setCompletionStatus(progress);
-            });
-        }
-
         ExcelUtil<ProductOrderDto> util = new ExcelUtil<>(ProductOrderDto.class);
         util.exportExcel(response, list, "鐢熶骇璁㈠崟鏁版嵁");
     }
diff --git a/src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java b/src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java
index 7f398b6..e8f8adf 100644
--- a/src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java
+++ b/src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java
@@ -45,9 +45,7 @@
 
     @ApiOperation("鍒犻櫎鎶ュ伐")
     @DeleteMapping("/delete")
-    @Transactional(rollbackFor = Exception.class)
     public R delete(@RequestBody ProductionProductMainDto productionProductMainDto) {
-
         return R.ok(productionProductMainService.removeProductMain(productionProductMainDto.getId()));
     }
 
diff --git a/src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java b/src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java
index 76723de..511d5f0 100644
--- a/src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java
+++ b/src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java
@@ -54,6 +54,8 @@
     private LocalDate schedulingDate;
     private String schedulingUserName;
     private String customerName;
+    //宸ュ簭
+    @Excel(name = "宸ュ簭")
     private String process;
     private BigDecimal workHours;
     private BigDecimal wages;
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
index 2ef08c1..8a1099c 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -4,6 +4,7 @@
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+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.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
@@ -145,92 +146,27 @@
 
     @Override
     public Boolean delete(Long[] ids) {
-
-        //鎵归噺鏌ヨproductOrder
-        List<ProductOrder> productOrders = productOrderMapper.selectList(
-                new LambdaQueryWrapper<ProductOrder>()
-                        .in(ProductOrder::getId, ids)
-        );
-        if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
-
-
-            // 鎵归噺鏌ヨprocessRouteItems
-            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
-                    new LambdaQueryWrapper<ProductProcessRouteItem>()
-                            .in(ProductProcessRouteItem::getProductOrderId, ids)
-            );
-
-            if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(allRouteItems)) {
-                // 鑾峰彇瑕佸垹闄ょ殑宸ュ簭椤笽D
-                List<Long> routeItemIds = allRouteItems.stream()
-                        .map(ProductProcessRouteItem::getId)
-                        .collect(Collectors.toList());
-
-                // 鏌ヨ鍏宠仈鐨勫伐鍗旾D
-                List<ProductWorkOrder> workOrders = productWorkOrderMapper.selectList(
-                        new LambdaQueryWrapper<ProductWorkOrder>()
-                                .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds)
-                );
-                if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(workOrders)) {
-                    List<Long> workOrderIds = workOrders.stream()
-                            .map(ProductWorkOrder::getId)
-                            .collect(Collectors.toList());
-
-                    // 鏌ヨ鍏宠仈鐨勭敓浜т富琛↖D
-                    List<ProductionProductMain> productMains = productionProductMainMapper.selectList(
-                            new LambdaQueryWrapper<ProductionProductMain>()
-                                    .in(ProductionProductMain::getWorkOrderId, workOrderIds)
-                    );
-                    List<Long> productMainIds = productMains.stream()
-                            .map(ProductionProductMain::getId)
-                            .collect(Collectors.toList());
-
-                    // 鍒犻櫎浜у嚭琛ㄣ�佹姇鍏ヨ〃鏁版嵁
-                    if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(productMainIds)) {
-                        productionProductOutputMapper.deleteByProductMainIds(productMainIds);
-                        productionProductInputMapper.deleteByProductMainIds(productMainIds);
-                        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
-                                new LambdaQueryWrapper<QualityInspect>()
-                                        .in(QualityInspect::getProductMainId, productMainIds)
-                        );
-                        //鍒犻櫎鍑哄簱璁板綍
-                        for (Long productMainId : productMainIds) {
-                            //鍒犻櫎鐢熶骇鍑哄簱璁板綍
-                            stockUtils.deleteStockOutRecord(productMainId, StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
-                            //鍒犻櫎鎶ュ簾鐨勫叆搴撹褰�
-                            stockUtils.deleteStockInRecord(productMainId, StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
-                        }
-                        qualityInspects.forEach(qualityInspect -> {
-                            //inspectState=1 宸叉彁浜� 涓嶈兘鍒犻櫎
-                            if (qualityInspect.getInspectState() == 1) {
-                                throw new RuntimeException("宸叉彁浜ょ殑妫�楠屽崟涓嶈兘鍒犻櫎");
-                            }
-                        });
-                        qualityInspectMapper.deleteByProductMainIds(productMainIds);
-                        salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
-                                .in(SalesLedgerProductionAccounting::getProductMainId, productMainIds));
-                    }
-
-                    // 鍒犻櫎鐢熶骇涓昏〃鏁版嵁
-                    productionProductMainMapper.deleteByWorkOrderIds(workOrderIds);
-
-                    // 鍒犻櫎宸ュ崟鏁版嵁
-                    productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
-                            .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds));
-                }
+        //濡傛灉宸茬粡寮�濮嬬敓浜�,涓嶈兘鍒犻櫎
+        //鏌ヨ鐢熶骇璁㈠崟涓嬬殑宸ュ崟
+        List<ProductWorkOrder> productWorkOrders = productWorkOrderMapper.selectList(Wrappers.<ProductWorkOrder>lambdaQuery().in(ProductWorkOrder::getProductOrderId, ids));
+        if (productWorkOrders.size()>0){
+            //鍒ゆ柇鏄惁鏈夋姤宸ユ暟鎹�
+            List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(Wrappers.<ProductionProductMain>lambdaQuery()
+                    .in(ProductionProductMain::getWorkOrderId, productWorkOrders.stream().map(ProductWorkOrder::getId).collect(Collectors.toList())));
+            if (productionProductMains.size()>0){
+                throw new RuntimeException("鐢熶骇璁㈠崟宸茬粡寮�濮嬬敓浜�,涓嶈兘鍒犻櫎");
             }
-            // 鎵归噺鍒犻櫎processRouteItem
-            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
-                    .in(ProductProcessRouteItem::getProductOrderId, ids));
-
-            // 鎵归噺鍒犻櫎productProcessRoute
-            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
-                    .in(ProductProcessRoute::getProductOrderId, ids));
-
-            // 鎵归噺鍒犻櫎productOrder
-            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
-                    .in(ProductOrder::getId, ids));
+            //鍒犻櫎宸ュ崟
+            productWorkOrderMapper.delete(Wrappers.<ProductWorkOrder>lambdaQuery().in(ProductWorkOrder::getProductOrderId, ids));
         }
+        //鍒犻櫎宸ヨ壓璺嚎
+        productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
+                .in(ProductProcessRouteItem::getProductOrderId, ids));
+        productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
+                .in(ProductProcessRoute::getProductOrderId, ids));
+        //鍒犻櫎鐢熶骇璁㈠崟
+        productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
+                .in(ProductOrder::getId, ids));
         return true;
     }
 
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
index 5079036..0759514 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -40,6 +40,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 @Service
 @AllArgsConstructor
@@ -61,6 +62,7 @@
     private ProductModelMapper productModelMapper;
 
     private QualityInspectMapper qualityInspectMapper;
+    private QualityUnqualifiedMapper qualityUnqualifiedMapper;
 
     private ProductProcessMapper productProcessMapper;
     private ProductProcessRouteMapper productProcessRouteMapper;
@@ -254,8 +256,16 @@
     }
 
     @Override
-    @Transactional(rollbackFor = Exception.class)
     public Boolean removeProductMain(Long id) {
+        //鍒ゆ柇璇ユ潯鎶ュ伐鏄惁涓嶅悎鏍煎鐞�,濡傛灉涓嶅悎鏍煎鐞嗕簡锛屽垯涓嶅厑璁稿垹闄�
+        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(Wrappers.<QualityInspect>lambdaQuery().eq(QualityInspect::getProductMainId, id));
+        if (qualityInspects.size() > 0){
+            List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(Wrappers.<QualityUnqualified>lambdaQuery()
+                    .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList())));
+            if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState()==1) {
+                throw new ServiceException("璇ユ潯鎶ュ伐宸茬粡涓嶅悎鏍煎鐞嗕簡锛屼笉鍏佽鍒犻櫎");
+            }
+        }
         ProductionProductMain productionProductMain = productionProductMainMapper.selectById(id);
         //璇ユ姤宸ュ搴旂殑宸ヨ壓璺嚎璇︽儏
         ProductProcessRouteItem productProcessRouteItem = productProcessRouteItemMapper.selectById(productionProductMain.getProductProcessRouteItemId());
@@ -280,7 +290,6 @@
         } else {
             throw new ServiceException("鎿嶄綔澶辫触锛氬伐鍗曚俊鎭垨浜у嚭璁板綍涓嶅瓨鍦�");
         }
-
         //鍒ゆ柇鏄惁鏄渶鍚庝竴閬撳伐搴�
         List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId()));
         if (productProcessRouteItem.getDragSort() != null && productProcessRouteItems != null && productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) {
@@ -289,15 +298,10 @@
                 BigDecimal orderCompleteQty = productOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : productOrder.getCompleteQuantity();
                 BigDecimal totalQty = productionProductOutput.getQuantity() != null ? productionProductOutput.getQuantity() : BigDecimal.ZERO;
                 BigDecimal scrapQty = productionProductOutput.getScrapQty() != null ? productionProductOutput.getScrapQty() : BigDecimal.ZERO;
-
                 BigDecimal actualQualifiedQty = totalQty.subtract(scrapQty);
-
                 BigDecimal newCompleteQty = orderCompleteQty.subtract(actualQualifiedQty);
-
                 productOrder.setCompleteQuantity(newCompleteQty.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newCompleteQty);
-
                 productOrder.setEndTime(null);
-
                 productOrderMapper.updateById(productOrder);
             } else {
                 throw new ServiceException("鍏宠仈鐨勭敓浜ц鍗曚笉瀛樺湪");
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java b/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
index 75176f0..5f856f1 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
@@ -5,17 +5,11 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.framework.web.domain.R;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
@@ -99,4 +93,11 @@
     {
         return toAjax(noticeService.readAll());
     }
+
+    @PostMapping("appReadNotice")
+    @ApiOperation("绉诲姩绔牴鎹秷鎭疘D杩涜宸茶")
+    public AjaxResult appReadNotice(@RequestParam("noticeId") Long noticeId) {
+        boolean result = noticeService.appReadNotice(noticeId);
+        return toAjax(result);
+    }
 }
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysUserClientController.java b/src/main/java/com/ruoyi/project/system/controller/SysUserClientController.java
new file mode 100644
index 0000000..c05fa73
--- /dev/null
+++ b/src/main/java/com/ruoyi/project/system/controller/SysUserClientController.java
@@ -0,0 +1,44 @@
+package com.ruoyi.project.system.controller;
+
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.domain.GetuiConfig;
+import com.ruoyi.project.system.domain.SysUserClient;
+import com.ruoyi.project.system.service.SysUserClientService;
+import com.ruoyi.common.utils.SecurityUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 鐢ㄦ埛瀹夊崜璁惧绠$悊鎺у埗灞�
+ *
+ * @author deslrey
+ * @version 1.0
+ * @since 2026/2/9
+ */
+@Api(tags = "鐢ㄦ埛璁惧缁戝畾")
+@RestController
+@RequestMapping("/system/client")
+public class SysUserClientController extends BaseController {
+
+    @Autowired
+    private SysUserClientService sysUserClientService;
+
+    /**
+     * 娣诲姞/鏇存柊鐢ㄦ埛cid
+     */
+    @PostMapping("/addOrUpdateClientId")
+    @ApiOperation("娣诲姞/鏇存柊鐢ㄦ埛cid")
+    public AjaxResult addOrUpdateClientId(@RequestBody SysUserClient sysUserClient) {
+        Long userId = SecurityUtils.getUserId();
+        sysUserClient.setUserId(userId);
+        boolean result = sysUserClientService.addOrUpdateClientId(sysUserClient);
+        return result ? success() : error("璁惧缁戝畾澶辫触");
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/project/system/domain/GetuiConfig.java b/src/main/java/com/ruoyi/project/system/domain/GetuiConfig.java
new file mode 100644
index 0000000..f5ba300
--- /dev/null
+++ b/src/main/java/com/ruoyi/project/system/domain/GetuiConfig.java
@@ -0,0 +1,46 @@
+package com.ruoyi.project.system.domain;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * <p>
+ * 涓帹 (Unipush v2) 娑堟伅鎺ㄩ�侀厤缃被
+ * </p>
+ *
+ * @author deslrey
+ * @version 1.0
+ * @since 2026/2/9
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "ruoyi.getui")
+public class GetuiConfig {
+
+    /**
+     * AppID
+     */
+    private String appId;
+
+    /**
+     * AppKey
+     */
+    private String appKey;
+
+    /**
+     * MasterSecret
+     */
+    private String masterSecret;
+
+    /**
+     * 涓帹 RESTful API 鍩熷悕鍦板潃
+     */
+    private String domain;
+
+    /**
+     * 绂荤嚎鎺ㄩ�� Intent 鐩爣缁勪欢鍚�
+     * 鏍煎紡: 鍖呭悕/鍏ュ彛Activity鍚�
+     */
+    private String intentComponent;
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/project/system/domain/SysNotice.java b/src/main/java/com/ruoyi/project/system/domain/SysNotice.java
index a7e696f..b88a57c 100644
--- a/src/main/java/com/ruoyi/project/system/domain/SysNotice.java
+++ b/src/main/java/com/ruoyi/project/system/domain/SysNotice.java
@@ -3,8 +3,7 @@
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.Size;
 
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import org.apache.commons.lang3.builder.ToStringBuilder;
@@ -20,11 +19,13 @@
  * @author ruoyi
  */
 @Data
+@TableName("sys_notice")
 public class SysNotice
 {
     private static final long serialVersionUID = 1L;
 
     /** 鍏憡ID */
+    @TableId(value = "notice_id", type = IdType.AUTO)
     private Long noticeId;
 
     /** 鍏憡鏍囬 */
@@ -48,6 +49,9 @@
     /** 璺宠浆璺緞 */
     private String jumpPath;
 
+    /** APP璺宠浆璺緞 */
+    private String appJumpPath;
+
     /** 鍒涘缓鑰� */
     @TableField(fill = FieldFill.INSERT)
     private String createBy;
diff --git a/src/main/java/com/ruoyi/project/system/domain/SysUserClient.java b/src/main/java/com/ruoyi/project/system/domain/SysUserClient.java
new file mode 100644
index 0000000..24dc336
--- /dev/null
+++ b/src/main/java/com/ruoyi/project/system/domain/SysUserClient.java
@@ -0,0 +1,47 @@
+package com.ruoyi.project.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <br>
+ * 鐢ㄦ埛瀹夊崜璁惧鍏宠仈瀵硅薄 sys_user_client
+ * </br>
+ *
+ * @author deslrey
+ * @version 1.0
+ * @since 2026/2/9
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("sys_user_client")
+public class SysUserClient implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    @TableId(type = IdType.INPUT)
+    private Long userId;
+
+    /**
+     * 涓帹璁惧鏍囪瘑 (CID)
+     */
+    private String cid;
+
+    /**
+     * 鏈�鍚庢椿璺冩椂闂�
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java b/src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java
index 00810db..9f6c989 100644
--- a/src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java
+++ b/src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java
@@ -36,6 +36,20 @@
      */
     private String component;
 
+
+    public String getAppComponent() {
+        return appComponent;
+    }
+
+    public void setAppComponent(String appComponent) {
+        this.appComponent = appComponent;
+    }
+
+    /**
+     * app缁勪欢鍦板潃
+     */
+    private String appComponent;
+
     /**
      * 璺敱鍙傛暟锛氬 {"id": 1, "name": "ry"}
      */
diff --git a/src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java b/src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java
index 3a0857d..a570593 100644
--- a/src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java
+++ b/src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java
@@ -122,4 +122,12 @@
      * @return 缁撴灉
      */
     public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
+
+    /**
+     * 鏍规嵁璺敱鍦板潃鏌ヨ鑿滃崟
+     *
+     * @param lastSegment 璺敱鍦板潃
+     * @return 鑿滃崟
+     */
+    SysMenu selectMenuByPath(String lastSegment);
 }
diff --git a/src/main/java/com/ruoyi/project/system/mapper/SysUserClientMapper.java b/src/main/java/com/ruoyi/project/system/mapper/SysUserClientMapper.java
new file mode 100644
index 0000000..b48e2e7
--- /dev/null
+++ b/src/main/java/com/ruoyi/project/system/mapper/SysUserClientMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.project.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.project.system.domain.SysUserClient;
+
+/**
+ * <br>
+ * 鐢ㄦ埛瀹夊崜璁惧鍏宠仈mapper
+ * </br>
+ *
+ * @author deslrey
+ * @version 1.0
+ * @since 2026/2/9
+ */
+
+public interface SysUserClientMapper extends BaseMapper<SysUserClient> {
+
+}
diff --git a/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java b/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java
index ab5d333..f371744 100644
--- a/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java
+++ b/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java
@@ -82,4 +82,11 @@
      */
     void simpleNoticeAll(final String title, final String message,final String jumpPath);
 
+    /**
+     * APP鐐瑰嚮鎺ㄩ�佹秷鎭洿鏀逛负宸茶鐘舵��
+     *
+     * @param noticeId 娑堟伅ID
+     * @return 澶辫触/鎴愬姛
+     */
+    boolean appReadNotice(Long noticeId);
 }
diff --git a/src/main/java/com/ruoyi/project/system/service/SysUserClientService.java b/src/main/java/com/ruoyi/project/system/service/SysUserClientService.java
new file mode 100644
index 0000000..0ff0009
--- /dev/null
+++ b/src/main/java/com/ruoyi/project/system/service/SysUserClientService.java
@@ -0,0 +1,19 @@
+package com.ruoyi.project.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.project.system.domain.SysUserClient;
+
+/**
+ * <br>
+ * 鐢ㄦ埛瀹夊崜璁惧鍏宠仈鎺ュ彛
+ * </br>
+ *
+ * @author deslrey
+ * @version 1.0
+ * @since 2026/2/9
+ */
+
+public interface SysUserClientService extends IService<SysUserClient> {
+
+    boolean addOrUpdateClientId(SysUserClient sysUserClient);
+}
diff --git a/src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java b/src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java
index fad86e5..db14845 100644
--- a/src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java
+++ b/src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java
@@ -172,6 +172,7 @@
             router.setName(getRouteName(menu));
             router.setPath(getRouterPath(menu));
             router.setComponent(getComponent(menu));
+            router.setAppComponent(menu.getAppComponent());
             router.setQuery(menu.getQuery());
             router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
             List<SysMenu> cMenus = menu.getChildren();
@@ -187,6 +188,7 @@
                 List<RouterVo> childrenList = new ArrayList<RouterVo>();
                 RouterVo children = new RouterVo();
                 children.setPath(menu.getPath());
+                children.setAppComponent(menu.getAppComponent());
                 children.setComponent(menu.getComponent());
                 children.setName(getRouteName(menu.getRouteName(), menu.getPath()));
                 children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
@@ -202,6 +204,7 @@
                 RouterVo children = new RouterVo();
                 String routerPath = innerLinkReplaceEach(menu.getPath());
                 children.setPath(routerPath);
+                children.setAppComponent(menu.getAppComponent());
                 children.setComponent(UserConstants.INNER_LINK);
                 children.setName(getRouteName(menu.getRouteName(), routerPath));
                 children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
diff --git a/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java b/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java
index 679514d..28ec77c 100644
--- a/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java
+++ b/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java
@@ -28,6 +28,7 @@
 import com.ruoyi.project.system.domain.SysNotice;
 import com.ruoyi.project.system.mapper.SysNoticeMapper;
 import com.ruoyi.project.system.service.ISysNoticeService;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 鍏憡 鏈嶅姟灞傚疄鐜�
@@ -52,6 +53,9 @@
     @Autowired
     @Lazy
     private ISysNoticeService sysNoticeService;
+
+    @Autowired
+    private UnipushService unipushService;
 
     /**
      * 鏌ヨ鍏憡淇℃伅
@@ -141,11 +145,18 @@
     }
 
     @Override
-    public void simpleNoticeByUser(String title, String message,  List<Long> consigneeId, String jumpPath) {
+    public void simpleNoticeByUser(String title, String message, List<Long> consigneeId, String jumpPath) {
         Long userId = SecurityUtils.getLoginUser().getUserId();
         Long tenantId = SecurityUtils.getLoginUser().getTenantId();
-        List<SysNotice> sysNotices = consigneeId.stream().map(it -> convertSysNotice(title, message, it,tenantId, jumpPath, userId)).collect(Collectors.toList());
+        List<SysNotice> sysNotices = consigneeId.stream()
+                .map(it -> convertSysNotice(title, message, it, tenantId, jumpPath, unipushService.convertWebPathToAppPath(jumpPath), userId))
+                .collect(Collectors.toList());
         sysNoticeService.saveBatch(sysNotices);
+        try {
+            unipushService.sendClientMessage(sysNotices);
+        } catch (Exception e) {
+            log.error("APP鎺ㄩ�侀�氱煡澶辫触锛屽師鍥�: {}", e);
+        }
     }
 
     @Override
@@ -192,15 +203,21 @@
                         it.getUserId(),
                         it.getTenantId(),
                         jumpPath,
+                        unipushService.convertWebPathToAppPath(jumpPath),
                         userId
                 ))
                 .collect(Collectors.toList());
 
         sysNoticeService.saveBatch(collect);
+        try {
+            unipushService.sendClientMessage(collect);
+        } catch (Exception e) {
+            log.error("APP鎺ㄩ�侀�氱煡澶辫触锛屽師鍥�: {}", e);
+        }
     }
 
 
-    private SysNotice convertSysNotice(String title,String message,Long consigneeId, Long tenantId,String jumpPath,Long currentUserId) {
+    private SysNotice convertSysNotice(String title,String message,Long consigneeId, Long tenantId,String jumpPath,String appJumpPath,Long currentUserId) {
         SysNotice sysNotice = new SysNotice();
         sysNotice.setNoticeType("1");
         sysNotice.setNoticeTitle(title);//鏍囬
@@ -209,8 +226,25 @@
         sysNotice.setConsigneeId(consigneeId);
         sysNotice.setSenderId(currentUserId);
         sysNotice.setJumpPath(jumpPath);
+        sysNotice.setAppJumpPath(appJumpPath);
         sysNotice.setTenantId(tenantId);
         return sysNotice;
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean appReadNotice(Long noticeId) {
+        if (noticeId == null) {
+            return false;
+        }
+        SysNotice sysNotice = noticeMapper.selectNoticeById(noticeId);
+        if (sysNotice == null) {
+            return false;
+        }
+        sysNotice.setStatus("1");
+        return noticeMapper.update(null, Wrappers.<SysNotice>lambdaUpdate()
+                .eq(SysNotice::getNoticeId, noticeId)
+                .eq(SysNotice::getStatus, "0")
+                .set(SysNotice::getStatus, "1")) > 0;
+    }
 }
diff --git a/src/main/java/com/ruoyi/project/system/service/impl/SysUserClientServiceImpl.java b/src/main/java/com/ruoyi/project/system/service/impl/SysUserClientServiceImpl.java
new file mode 100644
index 0000000..7130bf4
--- /dev/null
+++ b/src/main/java/com/ruoyi/project/system/service/impl/SysUserClientServiceImpl.java
@@ -0,0 +1,43 @@
+package com.ruoyi.project.system.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.project.system.domain.SysUserClient;
+import com.ruoyi.project.system.mapper.SysUserClientMapper;
+import com.ruoyi.project.system.service.SysUserClientService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+
+/**
+ * 鐢ㄦ埛瀹夊崜璁惧鍏宠仈鎺ュ彛瀹炵幇绫�
+ *
+ * @author deslrey
+ * @version 1.0
+ * @since 2026/2/9
+ */
+@Service
+public class SysUserClientServiceImpl extends ServiceImpl<SysUserClientMapper, SysUserClient> implements SysUserClientService {
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean addOrUpdateClientId(SysUserClient sysUserClient) {
+        if (sysUserClient == null || sysUserClient.getUserId() == null || StringUtils.isEmpty(sysUserClient.getCid())) {
+            return false;
+        }
+
+        String cid = sysUserClient.getCid();
+        Long userId = sysUserClient.getUserId();
+
+        remove(new LambdaQueryWrapper<SysUserClient>().eq(SysUserClient::getCid, cid).ne(SysUserClient::getUserId, userId));
+
+        SysUserClient userClient = new SysUserClient();
+        userClient.setUserId(userId);
+        userClient.setCid(cid);
+        userClient.setUpdateTime(new Date());
+
+        return saveOrUpdate(userClient);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/project/system/service/impl/UnipushService.java b/src/main/java/com/ruoyi/project/system/service/impl/UnipushService.java
new file mode 100644
index 0000000..3de2b9e
--- /dev/null
+++ b/src/main/java/com/ruoyi/project/system/service/impl/UnipushService.java
@@ -0,0 +1,208 @@
+package com.ruoyi.project.system.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.getui.push.v2.sdk.ApiHelper;
+import com.getui.push.v2.sdk.GtApiConfiguration;
+import com.getui.push.v2.sdk.api.PushApi;
+import com.getui.push.v2.sdk.common.ApiResult;
+import com.getui.push.v2.sdk.dto.req.Audience;
+import com.getui.push.v2.sdk.dto.req.message.PushChannel;
+import com.getui.push.v2.sdk.dto.req.message.PushDTO;
+import com.getui.push.v2.sdk.dto.req.message.PushMessage;
+import com.getui.push.v2.sdk.dto.req.message.android.AndroidDTO;
+import com.getui.push.v2.sdk.dto.req.message.android.ThirdNotification;
+import com.getui.push.v2.sdk.dto.req.message.android.Ups;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.project.system.domain.GetuiConfig;
+import com.ruoyi.project.system.domain.SysMenu;
+import com.ruoyi.project.system.domain.SysNotice;
+import com.ruoyi.project.system.domain.SysUserClient;
+import com.ruoyi.project.system.mapper.SysMenuMapper;
+import com.ruoyi.project.system.service.SysUserClientService;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * APP娑堟伅鎺ㄩ�佹湇鍔�
+ *
+ * @author deslrey
+ * @version 1.4
+ * @since 2026/2/9
+ */
+@Slf4j
+@Component
+public class UnipushService {
+
+    @Autowired
+    private SysMenuMapper sysMenuMapper;
+
+    @Autowired
+    private GetuiConfig getuiConfig;
+
+    @Autowired
+    private SysUserClientService userClientService;
+
+    private PushApi pushApi;
+
+    private static final String DEFAULT_APP_PAGE = "pages/index";
+
+    @PostConstruct
+    public void init() {
+        GtApiConfiguration config = new GtApiConfiguration();
+        config.setAppId(getuiConfig.getAppId());
+        config.setAppKey(getuiConfig.getAppKey());
+        config.setMasterSecret(getuiConfig.getMasterSecret());
+        config.setDomain(getuiConfig.getDomain());
+        ApiHelper apiHelper = ApiHelper.build(config);
+        this.pushApi = apiHelper.creatApi(PushApi.class);
+    }
+
+    /**
+     * 鎵归噺鍙戦�侀�氱煡鍏憡鍒扮Щ鍔ㄧ
+     */
+    @Async
+    public void sendClientMessage(List<SysNotice> sysNoticeList) {
+        if (sysNoticeList == null || sysNoticeList.isEmpty()) {
+            return;
+        }
+
+        for (SysNotice sysNotice : sysNoticeList) {
+            SysUserClient client = userClientService.getById(sysNotice.getConsigneeId());
+            if (client == null || StringUtils.isEmpty(client.getCid())) {
+                log.warn("鐢ㄦ埛 {} 鏈粦瀹氱Щ鍔ㄧ CID,璺宠繃鎺ㄩ��", sysNotice.getConsigneeId());
+                continue;
+            }
+
+            // 杞崲璺緞
+            String appPath = convertWebPathToAppPath(sysNotice.getJumpPath());
+
+            // 鎺ㄩ��
+            sendRoutingPush(
+                    sysNotice.getNoticeId(),
+                    client.getCid(),
+                    sysNotice.getNoticeTitle(),
+                    sysNotice.getRemark() != null ? sysNotice.getRemark() : sysNotice.getNoticeContent(),
+                    appPath
+            );
+        }
+    }
+
+    /**
+     * 灏� Web 绔垎灞傚叏璺緞杞崲涓� App 绔粍浠惰矾鐢�
+     */
+    public String convertWebPathToAppPath(String webPath) {
+        if (StringUtils.isEmpty(webPath)) {
+            return DEFAULT_APP_PAGE;
+        }
+
+        String pathOnly = webPath;
+        String queryString = "";
+        if (webPath.contains("?")) {
+            int index = webPath.indexOf("?");
+            pathOnly = webPath.substring(0, index);
+            queryString = webPath.substring(index);
+        }
+
+        String lastSegment;
+        int lastSlashIndex = pathOnly.lastIndexOf("/");
+        if (lastSlashIndex != -1) {
+            lastSegment = pathOnly.substring(lastSlashIndex + 1);
+        } else {
+            lastSegment = pathOnly;
+        }
+
+        if (StringUtils.isEmpty(lastSegment)) {
+            return DEFAULT_APP_PAGE;
+        }
+
+        SysMenu menu = sysMenuMapper.selectMenuByPath(lastSegment);
+
+        if (menu != null && StringUtils.isNotEmpty(menu.getAppComponent())) {
+            String appPath = menu.getAppComponent();
+
+            if (appPath.startsWith("/")) {
+                appPath = appPath.substring(1);
+            }
+
+            //  鎷兼帴 Web 绔師濮嬪弬鏁板苟杩斿洖
+            return appPath + queryString;
+        }
+
+        return DEFAULT_APP_PAGE;
+    }
+
+    /**
+     * 鍙戦�佸崟浜鸿矾鐢辨帹閫�
+     */
+    private void sendRoutingPush(Long noticeId, String cid, String title, String content, String targetPath) {
+        log.info("鍑嗗鎺ㄩ�佹秷鎭�:NoticeId={}, CID={}, Title={}, TargetPath={}", noticeId, cid, title, targetPath);
+
+        PushDTO<Audience> pushDTO = new PushDTO<>();
+        pushDTO.setRequestId("REQ_" + System.currentTimeMillis());
+
+        // 鍦ㄧ嚎閫忎紶鍐呭
+        PushMessage pushMessage = new PushMessage();
+        Map<String, Object> pushMessageMap = new HashMap<>();
+        Map<String, Object> payloadMap = new HashMap<>();
+        pushMessageMap.put("title", title);
+        pushMessageMap.put("content", content);
+        payloadMap.put("url", targetPath);
+        payloadMap.put("noticeId", noticeId);
+        pushMessageMap.put("payload", JSON.toJSONString(payloadMap));
+
+        String transmissionContent = JSON.toJSONString(pushMessageMap);
+        pushMessage.setTransmission(transmissionContent);
+        pushDTO.setPushMessage(pushMessage);
+
+        // 鎺ユ敹浜�
+        Audience audience = new Audience();
+        audience.addCid(cid);
+        pushDTO.setAudience(audience);
+
+        // 绂荤嚎鎺ㄩ�侀�氶亾
+//        pushDTO.setPushChannel(getPushChannel(noticeId, title, content, targetPath));
+
+        try {
+            ApiResult<Map<String, Map<String, String>>> result = pushApi.pushToSingleByCid(pushDTO);
+            if (result.isSuccess()) {
+                log.info("Unipush 鎺ㄩ�佹垚鍔�: CID={}", cid);
+            } else {
+                log.error("Unipush 鎺ㄩ�佸け璐�: CID={}, Code={}, Msg={}", cid, result.getCode(), result.getMsg());
+            }
+        } catch (Exception e) {
+            log.error("Unipush 鎺ㄩ�佸紓甯�: ", e);
+        }
+    }
+
+    @NotNull
+    private PushChannel getPushChannel(Long noticeId, String title, String content, String targetPath) {
+        PushChannel pushChannel = new PushChannel();
+        AndroidDTO androidDTO = new AndroidDTO();
+        Ups ups = new Ups();
+        ThirdNotification thirdNotification = new ThirdNotification();
+        thirdNotification.setTitle(title);
+        thirdNotification.setBody(content);
+        thirdNotification.setClickType("intent");
+
+        String intent = "intent:#Intent;launchFlags=0x04000000;"
+                + "component=" + getuiConfig.getIntentComponent() + ";"
+                + "S.UP-OL-P9=true;"
+                + "S.path=" + targetPath + ";"
+                + "S.payload=" + targetPath + ";"
+                + "end";
+        thirdNotification.setIntent(intent);
+
+        ups.setNotification(thirdNotification);
+        androidDTO.setUps(ups);
+        pushChannel.setAndroid(androidDTO);
+        return pushChannel;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java
index 7ab6c61..55aea8f 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java
@@ -127,7 +127,7 @@
             // 2. 澶勭悊璐︽埛鏀嚭
             AccountExpense accountExpense = new AccountExpense();
             accountExpense.setExpenseDate(purchaseLedger.getEntryDate());
-            accountExpense.setExpenseType("0");
+            accountExpense.setExpenseType("4");
             accountExpense.setSupplierName(purchaseLedger.getSupplierName());
             accountExpense.setExpenseMoney(paymentRegistration.getCurrentPaymentAmount());
             accountExpense.setExpenseDescribed("浠樻鏀嚭");
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java
index e6d8b7b..fda5910 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java
@@ -80,37 +80,55 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public AjaxResult updateRecord(ProductRecordDto productRecordDto) {
-        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(productRecordDto.getSaleLedgerProjectId());
         ProductRecord productRecord = productRecordMapper.selectById(productRecordDto.getId());
+        if (productRecord == null) return AjaxResult.error("璁板綍涓嶅瓨鍦�");
+
+        //  鏇存柊浜у搧鍙拌处
+        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(productRecord.getSaleLedgerProjectId());
         if (salesLedgerProduct != null) {
-            salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getFutureTicketsAmount().add(productRecord.getTicketsAmount()).subtract(productRecordDto.getTicketsAmount()));
-            salesLedgerProduct.setFutureTickets(salesLedgerProduct.getFutureTickets().add(productRecord.getTicketsNum().subtract(productRecordDto.getTicketsNum())));
+            // 鏈潵绁ㄩ噾棰� = 鍘熸湭鏉ョエ閲戦 + 鏃ц閲戦 - 鏂拌閲戦
+            BigDecimal futureTicketsAmount = salesLedgerProduct.getFutureTicketsAmount()
+                    .add(productRecord.getTicketsAmount())
+                    .subtract(productRecordDto.getTicketsAmount());
+            salesLedgerProduct.setFutureTicketsAmount(futureTicketsAmount);
+
+            // 鏈潵绁ㄦ暟 = 鍘熸湭鏉ョエ鏁� + 鏃ц鏁伴噺 - 鏂拌鏁伴噺
+            BigDecimal futureTickets = salesLedgerProduct.getFutureTickets()
+                    .add(productRecord.getTicketsNum())
+                    .subtract(productRecordDto.getTicketsNum());
+            salesLedgerProduct.setFutureTickets(futureTickets);
+
+            // 鏇存柊浜у搧琛ㄦ湰娆℃暟鍊�
             salesLedgerProduct.setTicketsAmount(productRecordDto.getTicketsAmount());
             salesLedgerProduct.setTicketsNum(productRecordDto.getTicketsNum());
             salesLedgerProductMapper.updateById(salesLedgerProduct);
         }
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(productRecord.getPurchaseLedgerId());
-        if (purchaseLedger != null) {
-            purchaseLedger.setReceiptPaymentAmount(purchaseLedger.getReceiptPaymentAmount());
-        }
-        // 淇敼鍙戠エ鍙�
+
+        //  鏇存柊鏉ョエ鐧昏
         TicketRegistration ticketRegistration = ticketRegistrationMapper.selectById(productRecord.getTicketRegistrationId());
-        if(ticketRegistration != null){
+        if (ticketRegistration != null) {
+            // 閲戦 = 鏂伴噾棰� - 鏃ч噾棰�
+            BigDecimal amountDiff = productRecordDto.getTicketsAmount().subtract(productRecord.getTicketsAmount());
+            // 鎬婚噾棰� = 鍘熸�婚噾棰� + 宸��
+            ticketRegistration.setInvoiceAmount(ticketRegistration.getInvoiceAmount().add(amountDiff));
+            // 鏇存柊鍙戠エ鍙�
             ticketRegistration.setInvoiceNumber(productRecordDto.getInvoiceNumber());
-            ticketRegistration.setInvoiceAmount(productRecordDto.getTicketsAmount());
+
             ticketRegistrationMapper.updateById(ticketRegistration);
         }
-        BeanUtils.copyProperties(productRecordDto,productRecord);
+
+        BeanUtils.copyProperties(productRecordDto, productRecord);
+        // 閲嶆柊璁$畻鏈潵绁ㄩ噾棰濓紙鏍规嵁鍓╀綑绁ㄦ暟 * 鍗曚环锛�
         productRecord.setFutureTicketsAmount(productRecord.getFutureTickets().multiply(productRecord.getTaxInclusiveUnitPrice()));
         productRecordMapper.updateById(productRecord);
 
         return AjaxResult.success("淇敼鎴愬姛");
     }
 
-     @Override
+    @Override
     public ProductRecordDto getProductRecordById(ProductRecordDto productRecordDto) {
         List<ProductRecordDto> productRecordDtoList = productRecordMapper.getProductRecordById(productRecordDto);
-        if(CollectionUtils.isNotEmpty(productRecordDtoList)){
+        if (CollectionUtils.isNotEmpty(productRecordDtoList)) {
             ProductRecordDto productRecordDto1 = productRecordDtoList.stream()
                     .filter(item -> item.getId().equals(productRecordDto.getId()))
                     .findFirst()
@@ -121,7 +139,7 @@
                     .filter(item -> item.getProductModelId().equals(productRecordDto.getProductModelId()))
                     .map(ProductRecordDto::getTicketsNum)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
-            if(productRecordDto1 != null){
+            if (productRecordDto1 != null) {
                 productRecordDto1.setFutureTickets(productRecordDto1.getQuantity().subtract(reduce));
                 productRecordDto1.setFutureTicketsAmount(productRecordDto1.getFutureTickets().multiply(productRecordDto1.getTaxInclusiveUnitPrice()));
             }
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
index 37ca018..d71b3bb 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -209,15 +209,15 @@
         if (productList != null && !productList.isEmpty()) {
             handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType());
         }
-        //鏂板鍘熸潗鏂欐楠�
-        if (productList != null) {
-            for (SalesLedgerProduct saleProduct : productList) {
-                //鏄惁鎺ㄩ�佽川妫�锛屽鏋渢rue灏辨坊鍔�
-                if (saleProduct.getIsChecked()) {
-                    addQualityInspect(purchaseLedger, saleProduct);
-                }
-            }
-        }
+        //鏂板鍘熸潗鏂欐楠�  瀹℃壒涔嬪悗鎵嶇敓鎴愭楠�
+//        if (productList != null) {
+//            for (SalesLedgerProduct saleProduct : productList) {
+//                //鏄惁鎺ㄩ�佽川妫�锛屽鏋渢rue灏辨坊鍔�
+//                if (saleProduct.getIsChecked()) {
+//                    addQualityInspect(purchaseLedger, saleProduct);
+//                }
+//            }
+//        }
         // 5. 杩佺Щ涓存椂鏂囦欢鍒版寮忕洰褰�
         if (purchaseLedgerDto.getTempFileIds() != null && !purchaseLedgerDto.getTempFileIds().isEmpty()) {
             migrateTempFilesToFormal(purchaseLedger.getId(), purchaseLedgerDto.getTempFileIds());
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
index 39f90eb..dec3d1c 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -63,16 +63,19 @@
         if(CollectionUtils.isEmpty(ids)){
             return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
         }
+        //濡傛灉宸茬粡鎻愪氦灏变笉鍏佽鍒犻櫎
+        List<QualityInspect> qualityInspects = qualityInspectService.listByIds(ids);
+        for (QualityInspect qualityInspect : qualityInspects) {
+            if(qualityInspect.getInspectState()==1){
+               throw new RuntimeException("宸叉彁浜ょ殑鏁版嵁涓嶅厑璁稿垹闄�");
+            }
+        }
         //鍒犻櫎妫�楠屽弬鏁�
         qualityInspectParamService.remove(Wrappers.<QualityInspectParam>lambdaQuery()
         .in(QualityInspectParam::getInspectId,ids));
         //鍒犻櫎妫�楠岄檮浠�
         qualityInspectFileService.remove(Wrappers.<QualityInspectFile>lambdaQuery()
         .in(QualityInspectFile::getInspectId,ids));
-        //鍒犻櫎鍏ュ簱璁板綍
-        for (Integer id : ids) {
-            stockUtils.deleteStockInRecord(Long.valueOf(id), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
-        }
         //鍒犻櫎妫�楠屽崟
         return AjaxResult.success(qualityInspectService.removeBatchByIds(ids));
     }
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java b/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
index 041d75c..e558c30 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
@@ -55,7 +55,7 @@
      */
     @GetMapping("/{id}")
     public AjaxResult QualityUnqualifiedDetail(@PathVariable("id") Integer id) {
-        return AjaxResult.success(qualityUnqualifiedService.getById(id));
+        return AjaxResult.success(qualityUnqualifiedService.getUnqualified(id));
     }
 
     /**
diff --git a/src/main/java/com/ruoyi/quality/mapper/QualityUnqualifiedMapper.java b/src/main/java/com/ruoyi/quality/mapper/QualityUnqualifiedMapper.java
index 82e2f6d..c3e75e6 100644
--- a/src/main/java/com/ruoyi/quality/mapper/QualityUnqualifiedMapper.java
+++ b/src/main/java/com/ruoyi/quality/mapper/QualityUnqualifiedMapper.java
@@ -17,4 +17,9 @@
     IPage<QualityUnqualified> qualityUnqualifiedListPage(Page page, @Param("qualityUnqualified") QualityUnqualified qualityUnqualified);
 
     List<QualityUnqualified> qualityUnqualifiedExport(@Param("qualityUnqualified") QualityUnqualified qualityUnqualified);
+
+    QualityUnqualified getUnqualified(@Param("id") Integer id);
+
+    //鎵嬪姩鏂板涓嶅悎鏍肩殑鏃跺��,鏍规嵁浜у搧鍚嶇О鍜岃鏍煎瀷鍙锋煡鍑哄搴旂殑瑙勬牸鍨嬪彿id
+    Long getModelId(@Param("productName") String productName, @Param("model") String model);
 }
diff --git a/src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java b/src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java
index eaebece..d2f8e88 100644
--- a/src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java
+++ b/src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java
@@ -135,4 +135,9 @@
 
     @ApiModelProperty("鍏宠仈妫�娴媔d")
     private Long inspectId;
+
+
+    @ApiModelProperty("鏄惁涓嶅悎鏍煎鐞嗚嚜宸辨柊澧�")
+    @TableField(exist = false)
+    private Boolean method;
 }
diff --git a/src/main/java/com/ruoyi/quality/service/IQualityUnqualifiedService.java b/src/main/java/com/ruoyi/quality/service/IQualityUnqualifiedService.java
index 7cd7f79..ceff474 100644
--- a/src/main/java/com/ruoyi/quality/service/IQualityUnqualifiedService.java
+++ b/src/main/java/com/ruoyi/quality/service/IQualityUnqualifiedService.java
@@ -17,4 +17,5 @@
 
     int deal(QualityUnqualified qualityUnqualified);
 
+    QualityUnqualified getUnqualified(Integer id);
 }
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
index 2111b99..8a1e066 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -82,8 +82,12 @@
     @Override
     public int submit(QualityInspect inspect) {
         QualityInspect qualityInspect = qualityInspectMapper.selectById(inspect.getId());
+        //鎻愪氦鍓嶅繀椤诲垽鏂槸鍚﹀悎鏍�
+        if (ObjectUtils.isNull(qualityInspect.getCheckResult())) {
+            throw new RuntimeException("璇峰厛鍒ゆ柇鏄惁鍚堟牸");
+        }
         /*鍒ゆ柇涓嶅悎鏍�*/
-        if (ObjectUtils.isNotNull(qualityInspect.getCheckResult()) && qualityInspect.getCheckResult().equals("涓嶅悎鏍�")) {
+        if (qualityInspect.getCheckResult().equals("涓嶅悎鏍�")) {
             QualityUnqualified qualityUnqualified = new QualityUnqualified();
             BeanUtils.copyProperties(qualityInspect, qualityUnqualified);
             qualityUnqualified.setInspectState(0);//寰呭鐞�
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
index 5e98fa8..1650690 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -64,7 +64,7 @@
     public int deal(QualityUnqualified qualityUnqualified) {
         QualityUnqualified unqualified = qualityUnqualifiedMapper.selectById(qualityUnqualified.getId());
         QualityInspect qualityInspect = qualityInspectService.getById(unqualified.getInspectId());
-        if (ObjectUtils.isNotNull(qualityInspect) && qualityInspect.getInspectType()!=0) {
+        if (ObjectUtils.isNotNull(qualityInspect) && qualityInspect.getInspectType() != 0) {
             switch (qualityUnqualified.getDealResult()) {
                 case "杩斾慨":
                 case "杩斿伐":
@@ -113,7 +113,7 @@
                                     }
                                 }
                                 // 鐢熸垚瀹屾暣鐨勫伐鍗曞彿
-                                String workOrderNoStr ="FG" +String.format("%s%03d", datePrefix, sequenceNumber);
+                                String workOrderNoStr = "FG" + String.format("%s%03d", datePrefix, sequenceNumber);
                                 ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                                 productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                                 productWorkOrder.setProductOrderId(order.getId());
@@ -132,14 +132,33 @@
                 case "璁╂鏀捐":
                     //璋冪敤鎻愪氦鍚堟牸鐨勬帴鍙�
                     stockUtils.addStock(qualityInspect.getProductModelId(), unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId());
-                    qualityInspect.setCheckResult("鍚堟牸");
-                    qualityInspectService.submit(qualityInspect);
                     break;
                 default:
                     break;
             }
+        } else {
+            //鏌ヨ瀵瑰簲鐨勮鏍煎瀷鍙穒d
+            Long modelId = qualityUnqualifiedMapper.getModelId(qualityUnqualified.getProductName(), qualityUnqualified.getModel());
+            switch (qualityUnqualified.getDealResult()) {
+                case "鎶ュ簾":
+                    //璋冪敤涓嶅悎鏍煎簱瀛樻帴鍙� 鍏ヤ笉鍚堟牸搴�
+                    stockUtils.addUnStock(modelId, unqualified.getQuantity(), StockInUnQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId());
+                    break;
+                case "璁╂鏀捐":
+                    //璋冪敤鎻愪氦鍚堟牸鐨勬帴鍙�
+                    stockUtils.addStock(modelId, unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId());
+                    break;
+                default:
+                    break;
+            }
+
         }
         qualityUnqualified.setInspectState(1);//宸插鐞�
         return qualityUnqualifiedMapper.updateById(qualityUnqualified);
     }
+
+    @Override
+    public QualityUnqualified getUnqualified(Integer id) {
+        return qualityUnqualifiedMapper.getUnqualified(id);
+    }
 }
diff --git a/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java b/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
index f006c5b..cbef46f 100644
--- a/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
+++ b/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -14,10 +14,7 @@
 import com.ruoyi.sales.dto.InvoiceLedgerDto;
 import com.ruoyi.sales.dto.SalesLedgerDto;
 import com.ruoyi.sales.mapper.InvoiceLedgerMapper;
-import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
 import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
-import com.ruoyi.sales.pojo.InvoiceLedger;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
 import com.ruoyi.sales.pojo.ReceiptPayment;
 import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.service.ICommonFileService;
@@ -39,10 +36,7 @@
 import java.io.OutputStream;
 import java.math.BigDecimal;
 import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -64,9 +58,6 @@
 
     @Autowired
     private InvoiceLedgerMapper invoiceLedgerMapper;
-
-    @Autowired
-    private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
 
     @Autowired
     private ReceiptPaymentMapper receiptPaymentMapper;
@@ -267,69 +258,85 @@
      */
     @GetMapping("/listPage")
     public IPage<SalesLedger> listPage(Page page, SalesLedgerDto salesLedgerDto) {
-        IPage<SalesLedger> iPage = salesLedgerService.selectSalesLedgerListPage(page,salesLedgerDto);
-        // 璁$畻宸插紑绁ㄩ噾棰�/鏈紑绁ㄩ噾棰�(宸插~鍐欏彂绁ㄩ噾棰濅负鍑�)
-        if(CollectionUtils.isEmpty(iPage.getRecords())){
-            return iPage;
-        }
-        List<Long> salesLedgerIds = iPage.getRecords().stream().map(SalesLedger::getId).collect(Collectors.toList());
-        List<InvoiceLedgerDto> invoiceLedgerDtoList = invoiceLedgerMapper.invoicedTotal(salesLedgerIds);
-        if(CollectionUtils.isEmpty(invoiceLedgerDtoList)){
-            return iPage;
-        }
-        // 璁$畻鍥炴閲戦锛屽緟鍥炴閲戦
-        List<InvoiceRegistrationProduct> invoiceRegistrationProducts = invoiceRegistrationProductMapper.selectList(new LambdaQueryWrapper<InvoiceRegistrationProduct>()
-                .in(InvoiceRegistrationProduct::getSalesLedgerId, salesLedgerIds));
+        IPage<SalesLedger> iPage = salesLedgerService.selectSalesLedgerListPage(page, salesLedgerDto);
 
-        List<InvoiceLedger> invoiceLedgers = invoiceLedgerMapper.selectList(new LambdaQueryWrapper<InvoiceLedger>()
-                .in(InvoiceLedger::getInvoiceRegistrationProductId, invoiceRegistrationProducts.stream().map(InvoiceRegistrationProduct::getId).collect(Collectors.toList())));
-        List<ReceiptPayment> receiptPayments = new ArrayList<>();
-        if(!CollectionUtils.isEmpty(invoiceLedgers)){
-            receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
-                    .in(ReceiptPayment::getInvoiceLedgerId, invoiceLedgers.stream().map(InvoiceLedger::getId).collect(Collectors.toList())));
+        //  鏌ヨ缁撴灉涓虹┖,鐩存帴杩斿洖
+        if (CollectionUtils.isEmpty(iPage.getRecords())) {
+            return iPage;
         }
-        for (SalesLedger salesLedger : iPage.getRecords()) {
-            boolean existFlag = false;
-            BigDecimal noInvoiceAmountTotal = BigDecimal.ZERO;
-            BigDecimal invoiceTotal = BigDecimal.ZERO;
-            for (InvoiceLedgerDto invoiceLedgerDto : invoiceLedgerDtoList) {
-                if (salesLedger.getId().intValue() == invoiceLedgerDto.getSalesLedgerId()) {
-                    noInvoiceAmountTotal = salesLedger.getContractAmount().subtract(invoiceLedgerDto.getInvoiceTotal());
-                    invoiceTotal = invoiceLedgerDto.getInvoiceTotal();
-                    existFlag = true;
-                    if(!CollectionUtils.isEmpty(receiptPayments)){
-                        List<InvoiceRegistrationProduct> collect = invoiceRegistrationProducts.stream()
-                                .filter(item -> salesLedger.getId().equals(Long.parseLong(item.getSalesLedgerId().toString())))
-                                .collect(Collectors.toList());
-                        List<Integer> collect1 = collect.stream()
-                                .map(InvoiceRegistrationProduct::getId).collect(Collectors.toList());
-                        List<InvoiceLedger> collect2 = invoiceLedgers.stream()
-                                .filter(item -> collect1.contains(item.getInvoiceRegistrationProductId()))
-                                .collect(Collectors.toList());
-                        // 鑾峰彇宸插洖娆鹃噾棰�
-                        List<ReceiptPayment> collect3 = receiptPayments.stream()
-                                .filter(item -> collect2.stream().anyMatch(item1 -> item1.getId().equals(item.getInvoiceLedgerId())))
-                                .collect(Collectors.toList());
-                        BigDecimal receiptPaymentAmountTotal = collect3.stream().map(ReceiptPayment::getReceiptPaymentAmount)
-                                .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
-                        // 鑾峰彇寰呭洖娆鹃噾棰�
-                        BigDecimal noReceiptPaymentAmountTotal = invoiceLedgerDto.getInvoiceTotal().subtract(receiptPaymentAmountTotal);
-                        salesLedger.setReceiptPaymentAmountTotal(receiptPaymentAmountTotal);
-                        salesLedger.setNoReceiptAmount(noReceiptPaymentAmountTotal);
-                    }
-                    break;
+
+        //  鑾峰彇褰撳墠椤垫墍鏈夊彴璐﹁褰曠殑 ID 闆嗗悎
+        List<Long> salesLedgerIds = iPage.getRecords().stream().map(SalesLedger::getId).collect(Collectors.toList());
+
+        //  鏌ヨ鍙戠エ淇℃伅鐨勫凡寮�绁ㄩ噾棰�
+        List<InvoiceLedgerDto> invoiceLedgerDtoList = invoiceLedgerMapper.invoicedTotal(salesLedgerIds);
+        if (CollectionUtils.isEmpty(invoiceLedgerDtoList)) {
+            invoiceLedgerDtoList = Collections.emptyList();
+        }
+
+        //  杞崲鍙戠エ鏁版嵁, key 涓哄彴璐D, value 涓鸿鍙拌处鐨勬�诲紑绁ㄩ噾棰�
+        Map<Long, BigDecimal> invoiceTotals = invoiceLedgerDtoList.stream()
+                .filter(dto -> dto.getSalesLedgerId() != null && dto.getInvoiceTotal() != null)
+                .collect(Collectors.toMap(
+                        dto -> dto.getSalesLedgerId().longValue(),
+                        InvoiceLedgerDto::getInvoiceTotal,
+                        BigDecimal::add // 瀛樺湪閲嶅ID鎵ц绱姞
+                ));
+
+        //  鏌ヨ鍥炴/浠樻璁板綍
+        List<ReceiptPayment> receiptPayments = Collections.emptyList();
+        if (!CollectionUtils.isEmpty(salesLedgerIds)) {
+            receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
+                    .in(ReceiptPayment::getSalesLedgerId, salesLedgerIds));
+        }
+
+        //  杞崲鍥炴鏁版嵁, key 涓哄彴璐D, value 涓鸿鍙拌处鐨勬�诲洖娆鹃噾棰�
+        Map<Long, BigDecimal> receiptTotals = new HashMap<>();
+        if (!CollectionUtils.isEmpty(receiptPayments)) {
+            for (ReceiptPayment receiptPayment : receiptPayments) {
+                if (receiptPayment.getSalesLedgerId() != null && receiptPayment.getReceiptPaymentAmount() != null) {
+                    //  濡傛灉 key 瀛樺湪鍒欑浉鍔�,涓嶅瓨鍦ㄥ垯鏀惧叆
+                    receiptTotals.merge(receiptPayment.getSalesLedgerId(), receiptPayment.getReceiptPaymentAmount(), BigDecimal::add);
                 }
             }
-            if(existFlag){
-                salesLedger.setNoInvoiceAmountTotal(noInvoiceAmountTotal);
-            }else {
-                salesLedger.setNoInvoiceAmountTotal(salesLedger.getContractAmount());
-            }
-            salesLedger.setInvoiceTotal(invoiceTotal);
         }
+
+        for (SalesLedger salesLedger : iPage.getRecords()) {
+            Long ledgerId = salesLedger.getId();
+            // 鍚堝悓鎬婚噾棰�
+            BigDecimal contractAmount = salesLedger.getContractAmount() == null ? BigDecimal.ZERO : salesLedger.getContractAmount();
+            // 寮�绁ㄦ�婚鍜屽洖娆炬�婚
+            BigDecimal invoiceTotal = invoiceTotals.getOrDefault(ledgerId, BigDecimal.ZERO);
+            BigDecimal receiptPaymentAmountTotal = receiptTotals.getOrDefault(ledgerId, BigDecimal.ZERO);
+
+            //  鏈紑绁ㄩ噾棰� = 鍚堝悓閲戦 - 宸插紑绁ㄩ噾棰�
+            BigDecimal noInvoiceAmountTotal = contractAmount.subtract(invoiceTotal);
+            if (noInvoiceAmountTotal.compareTo(BigDecimal.ZERO) < 0) {
+                noInvoiceAmountTotal = BigDecimal.ZERO;
+            }
+
+            //  寰呭洖娆鹃噾棰� = 宸插紑绁ㄩ噾棰� - 宸插洖娆鹃噾棰�
+            BigDecimal noReceiptPaymentAmountTotal = invoiceTotal.subtract(receiptPaymentAmountTotal);
+            if (noReceiptPaymentAmountTotal.compareTo(BigDecimal.ZERO) < 0) {
+                noReceiptPaymentAmountTotal = BigDecimal.ZERO;
+            }
+
+            salesLedger.setNoInvoiceAmountTotal(noInvoiceAmountTotal);
+            salesLedger.setInvoiceTotal(invoiceTotal);
+            salesLedger.setReceiptPaymentAmountTotal(receiptPaymentAmountTotal);
+            salesLedger.setNoReceiptAmount(noReceiptPaymentAmountTotal);
+
+            //  濡傛灉宸茬粡鏈夎繃寮�绁ㄦ垨鍥炴鎿嶄綔,鍒欎笉鍏佽缂栬緫
+            boolean hasInvoiceOperation = invoiceTotal.compareTo(BigDecimal.ZERO) > 0;
+            boolean hasReceiptOperation = receiptPaymentAmountTotal.compareTo(BigDecimal.ZERO) > 0;
+            salesLedger.setIsEdit(!(hasInvoiceOperation || hasReceiptOperation));
+        }
+
         if (ObjectUtils.isNotEmpty(salesLedgerDto.getStatus())) {
             if (salesLedgerDto.getStatus()) {
-                iPage.getRecords().removeIf(salesLedger -> Objects.equals(salesLedger.getNoInvoiceAmountTotal(), new BigDecimal("0.00")));
+                // 娓呴櫎鎵�鏈夆�滄湭寮�绁ㄩ噾棰濃�濅负 0 鐨勮褰�
+                iPage.getRecords().removeIf(salesLedger ->
+                        Objects.equals(salesLedger.getNoInvoiceAmountTotal(), new BigDecimal("0.00")));
                 iPage.setTotal(iPage.getRecords().size());
             }
         }
diff --git a/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java b/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
index 8632313..aed72ef 100644
--- a/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
+++ b/src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
@@ -72,15 +72,14 @@
      * 鏌ヨ浜у搧淇℃伅鍒楄〃
      */
     @GetMapping("/list")
-    public AjaxResult list(SalesLedgerProduct salesLedgerProduct)
-    {
+    public AjaxResult list(SalesLedgerProduct salesLedgerProduct) {
         List<SalesLedgerProduct> list = salesLedgerProductService.selectSalesLedgerProductList(salesLedgerProduct);
         list.forEach(item -> {
-                if (item.getFutureTickets().compareTo(BigDecimal.ZERO) == 0) {
-                    item.setFutureTickets(item.getQuantity());
-                }
+            if (item.getFutureTickets().compareTo(BigDecimal.ZERO) == 0) {
+                item.setFutureTickets(BigDecimal.ZERO);
+            }
             if (item.getFutureTicketsAmount().compareTo(BigDecimal.ZERO) == 0) {
-                item.setFutureTicketsAmount(item.getTaxInclusiveTotalPrice());
+                item.setFutureTicketsAmount(BigDecimal.ZERO);
             }
 //            ProcurementPageDto procurementDto = new ProcurementPageDto();
 //            procurementDto.setSalesLedgerProductId(item.getId());
@@ -89,13 +88,13 @@
 //            BigDecimal stockQuantity = stockUtils.getStockQuantity(item.getProductModelId()).get("stockQuantity");
 
 //                ProcurementPageDtoCopy procurementDtoCopy = result.getRecords().get(0);
-                if (item.getApproveStatus() != 2) {
-                    if (item.getHasSufficientStock() == 0) {
-                        item.setApproveStatus(0);
-                    }else {
-                        item.setApproveStatus(1);
-                    }
+            if (item.getApproveStatus() != 2) {
+                if (item.getHasSufficientStock() == 0) {
+                    item.setApproveStatus(0);
+                } else {
+                    item.setApproveStatus(1);
                 }
+            }
         });
         return AjaxResult.success(list);
     }
diff --git a/src/main/java/com/ruoyi/sales/dto/StatisticsTableDto.java b/src/main/java/com/ruoyi/sales/dto/StatisticsTableDto.java
index 702bc00..e6b8ff5 100644
--- a/src/main/java/com/ruoyi/sales/dto/StatisticsTableDto.java
+++ b/src/main/java/com/ruoyi/sales/dto/StatisticsTableDto.java
@@ -21,11 +21,11 @@
     private String productCategory;
 
     @ApiModelProperty(value = "寮�濮嬫椂闂�")
-    @JsonFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM")
     private Date entryDateStart;
 
     @ApiModelProperty(value = "缁撴潫鏃堕棿")
-    @JsonFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM")
     private Date entryDateEnd;
 
 }
diff --git a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
index 3100a55..77faa01 100644
--- a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
+++ b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
@@ -69,7 +69,8 @@
             "SUM(CASE WHEN slp.approve_status = 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT sl.id) * 100), 2) AS ship_rate " +
             "FROM sales_ledger sl " +
             "LEFT JOIN sales_ledger_product slp ON sl.id = slp.sales_ledger_id " +
-            "WHERE sl.entry_date BETWEEN #{statisticsTableDto.entryDateStart} AND #{statisticsTableDto.entryDateEnd} " +
+            "WHERE sl.entry_date &gt;= DATE_FORMAT(#{statisticsTableDto.entryDateStart}, '%Y-%m-01') " +
+            "AND sl.entry_date &lt;= LAST_DAY(#{statisticsTableDto.entryDateEnd}) " +
             // 浜у搧澶х被绛涢��
             "<if test='statisticsTableDto.productCategory != null and statisticsTableDto.productCategory != \"\"'>" +
             "AND slp.product_category = #{statisticsTableDto.productCategory} " +
diff --git a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java
index 94e9892..686fc2e 100644
--- a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java
+++ b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java
@@ -11,6 +11,7 @@
 import org.apache.ibatis.annotations.Param;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
 
@@ -21,7 +22,7 @@
  * @date 2025-05-08
  */
 public interface SalesLedgerProductMapper extends MyBaseMapper<SalesLedgerProduct> {
-     List<SalesLedgerProduct> selectProduct() ;
+    List<SalesLedgerProduct> selectProduct();
 
     List<SalesLedgerProduct> selectSalesLedgerProductList(@Param("salesLedgerProduct") SalesLedgerProduct salesLedgerProduct);
 
@@ -29,9 +30,9 @@
 
     IPage<SalesLedgerProductDto> listPage(Page page, @Param("req") SalesLedgerProductDto salesLedgerProduct);
 
-    IPage<SalesLedgerProductDto> listPagePurchaseLedger(Page page,@Param("req") SalesLedgerProductDto salesLedgerProduct);
+    IPage<SalesLedgerProductDto> listPagePurchaseLedger(Page page, @Param("req") SalesLedgerProductDto salesLedgerProduct);
 
-    IPage<ProcurementBusinessSummaryDto> procurementBusinessSummaryListPage(Page page,@Param("req") ProcurementBusinessSummaryDto procurementBusinessSummaryDto);
+    IPage<ProcurementBusinessSummaryDto> procurementBusinessSummaryListPage(Page page, @Param("req") ProcurementBusinessSummaryDto procurementBusinessSummaryDto);
 
     List<LossProductModelDto> selectProductBomStructure(@Param("salesLedegerId") Long salesLedegerId);
 
@@ -39,7 +40,7 @@
 
     List<Map<String, Object>> selectRawMaterialPurchaseAnalysis();
 
-    int selectProductCountByTypeAndDate(@Param("type") Integer type, @Param("startDate") String startDate, @Param("endDate") String endDate);
+    int selectProductCountByTypeAndDate(@Param("type") Integer type, @Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate);
 
     BigDecimal selectRawMaterialExpense();
 }
diff --git a/src/main/java/com/ruoyi/sales/pojo/SalesLedger.java b/src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
index 672fe75..36751c2 100644
--- a/src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
+++ b/src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -143,5 +143,9 @@
     @TableField(exist = false)
     //鏄惁鍙戣揣(鍙拌处椤甸潰棰滆壊鎺у埗)
     private Boolean isFh;
+
+    @TableField(exist = false)
+    //鏄惁鍙紪杈�
+    private Boolean isEdit;
 }
 
diff --git a/src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java
index d1ec847..b2b5ad3 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/InvoiceRegistrationServiceImpl.java
@@ -3,7 +3,6 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -13,7 +12,10 @@
 import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
 import com.ruoyi.sales.dto.SalesLedgerDto;
 import com.ruoyi.sales.excel.InvoiceRegisAndProductExcelDto;
-import com.ruoyi.sales.mapper.*;
+import com.ruoyi.sales.mapper.InvoiceLedgerMapper;
+import com.ruoyi.sales.mapper.InvoiceRegistrationMapper;
+import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
+import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.pojo.InvoiceLedger;
 import com.ruoyi.sales.pojo.InvoiceRegistration;
 import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
@@ -85,18 +87,16 @@
                 throw new RuntimeException("閿�鍞彴璐︿骇鍝佷笉瀛樺湪锛孖D锛�" + productDatum.getId());
             }
 
-            //  璁$畻绱寮�绁�
-            BigDecimal newInvoiceNum = dbProduct.getInvoiceNum().add(currentInvoiceNum);
+            // 鏈紑绁�
+            BigDecimal noInvoiceAmount = dbProduct.getNoInvoiceAmount();
+            BigDecimal noInvoiceNum = dbProduct.getNoInvoiceNum();
 
-            BigDecimal newInvoiceAmount = dbProduct.getInvoiceAmount().add(currentInvoiceAmount);
+            // 鍓╀綑鏈紑绁�
+            BigDecimal newNoInvoiceNum = noInvoiceNum.subtract(currentInvoiceNum);
+            BigDecimal newNoInvoiceAmount = noInvoiceAmount.subtract(currentInvoiceAmount);
 
-            //  璁$畻鏈紑绁�
-            BigDecimal newNoInvoiceNum = dbProduct.getQuantity().subtract(newInvoiceNum);
 
-            BigDecimal newNoInvoiceAmount = dbProduct.getTaxInclusiveTotalPrice().subtract(newInvoiceAmount);
-
-            if (newNoInvoiceNum.compareTo(BigDecimal.ZERO) < 0
-                    || newNoInvoiceAmount.compareTo(BigDecimal.ZERO) < 0) {
+            if (newNoInvoiceAmount.compareTo(BigDecimal.ZERO) < 0) {
                 throw new RuntimeException("寮�绁ㄦ暟閲忔垨閲戦瓒呰繃鍚堝悓鎬婚噺");
             }
 
@@ -105,8 +105,6 @@
                     null,
                     new LambdaUpdateWrapper<SalesLedgerProduct>()
                             .eq(SalesLedgerProduct::getId, dbProduct.getId())
-                            .set(SalesLedgerProduct::getInvoiceNum, newInvoiceNum)
-                            .set(SalesLedgerProduct::getInvoiceAmount, newInvoiceAmount)
                             .set(SalesLedgerProduct::getNoInvoiceNum, newNoInvoiceNum)
                             .set(SalesLedgerProduct::getNoInvoiceAmount, newNoInvoiceAmount)
             );
diff --git a/src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java
index c70bbe1..010dec0 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java
@@ -59,20 +59,74 @@
 
     public AjaxResult statisticsTable(StatisticsTableDto statisticsTableDto) {
         Map<String, Object> map = new HashMap<>();
-        if (statisticsTableDto.getEntryDateStart() == null || statisticsTableDto.getEntryDateEnd() == null) {
-            Calendar calendar = Calendar.getInstance();
-            // 缁撴潫鏃堕棿榛樿鏄綋鍓嶆椂闂�
-            statisticsTableDto.setEntryDateEnd(new Date());
-            // 寮�濮嬫椂闂撮粯璁ゆ槸6涓湀鍓�
-            calendar.add(Calendar.MONTH, -6);
-            statisticsTableDto.setEntryDateStart(calendar.getTime());
+        Calendar calendar = Calendar.getInstance();
+
+        // 缁撴潫鏃堕棿榛樿鏄綋鍓嶆椂闂�
+        Date endDate = statisticsTableDto.getEntryDateEnd() != null ? statisticsTableDto.getEntryDateEnd() : new Date();
+        statisticsTableDto.setEntryDateEnd(endDate);
+
+        // 寮�濮嬫椂闂撮粯璁ゆ槸12涓湀鍓�
+        Date startDate;
+        if (statisticsTableDto.getEntryDateStart() != null) {
+            startDate = statisticsTableDto.getEntryDateStart();
+        } else {
+            calendar.setTime(endDate);
+            calendar.add(Calendar.MONTH, -11); // 鍑�11涓湀锛屽姞涓婂綋鍓嶆湀鍏�12涓湀
+            calendar.set(Calendar.DAY_OF_MONTH, 1); // 璁句负鏈堝垵
+            startDate = calendar.getTime();
         }
+        statisticsTableDto.setEntryDateStart(startDate);
+
+        // 鏌ヨ鏁版嵁搴撹幏鍙栨湁鏁版嵁鐨勬湀浠�
         List<SalesTrendDto> salesTrendDtos = salesLedgerMapper.statisticsTable(statisticsTableDto);
-        if(CollectionUtils.isEmpty(salesTrendDtos)) return AjaxResult.success(map);
-        map.put("dateList", salesTrendDtos.stream().map(SalesTrendDto::getMonth).collect(Collectors.toList()));
-        map.put("orderCountList", salesTrendDtos.stream().map(SalesTrendDto::getOrderCount).collect(Collectors.toList()));
-        map.put("salesAmountList", salesTrendDtos.stream().map(SalesTrendDto::getSalesAmount).collect(Collectors.toList()));
-        map.put("shippingRateList", salesTrendDtos.stream().map(SalesTrendDto::getShipRate).collect(Collectors.toList()));
+
+        // 鍒涘缓鏈堜唤鍒版暟鎹殑鏄犲皠
+        Map<String, SalesTrendDto> trendMap = new HashMap<>();
+        if (!CollectionUtils.isEmpty(salesTrendDtos)) {
+            for (SalesTrendDto dto : salesTrendDtos) {
+                trendMap.put(dto.getMonth(), dto);
+            }
+        }
+
+        // 鐢熸垚鏈堜唤鍒楄〃
+        List<String> dateList = new ArrayList<>();
+        List<BigDecimal> orderCountList = new ArrayList<>();
+        List<BigDecimal> salesAmountList = new ArrayList<>();
+        List<BigDecimal> shippingRateList = new ArrayList<>();
+
+        Calendar tempCalendar = Calendar.getInstance();
+        tempCalendar.setTime(startDate);
+        tempCalendar.set(Calendar.DAY_OF_MONTH, 1); // 纭繚浠庢湀鍒濆紑濮�
+
+        Calendar endCalendar = Calendar.getInstance();
+        endCalendar.setTime(endDate);
+        endCalendar.set(Calendar.DAY_OF_MONTH, 1); // 纭繚鍒版湀鏈�
+
+        // 寰幆鐢熸垚鏈堜唤鍒楄〃锛岀洿鍒拌揪鍒扮粨鏉熸湀浠�
+        while (!tempCalendar.after(endCalendar)) {
+            String monthStr = String.format("%04d-%02d", tempCalendar.get(Calendar.YEAR), tempCalendar.get(Calendar.MONTH) + 1);
+            dateList.add(monthStr);
+
+            // 鑾峰彇褰撳墠鏈堜唤鐨勬暟鎹紝濡傛灉娌℃湁鍒欎娇鐢ㄩ粯璁ゅ��
+            SalesTrendDto dto = trendMap.get(monthStr);
+            if (dto != null) {
+                orderCountList.add(new BigDecimal(dto.getOrderCount()));
+                salesAmountList.add(dto.getSalesAmount() != null ? dto.getSalesAmount() : BigDecimal.ZERO);
+                shippingRateList.add(new BigDecimal(String.valueOf(dto.getShipRate())));
+            } else {
+                orderCountList.add(BigDecimal.ZERO);
+                salesAmountList.add(BigDecimal.ZERO);
+                shippingRateList.add(BigDecimal.ZERO);
+            }
+
+            // 涓嬩竴涓湀
+            tempCalendar.add(Calendar.MONTH, 1);
+        }
+
+        map.put("dateList", dateList);
+        map.put("orderCountList", orderCountList);
+        map.put("salesAmountList", salesAmountList);
+        map.put("shippingRateList", shippingRateList);
         return AjaxResult.success(map);
     }
 }
diff --git a/src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java
index 15febe9..b667be2 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/ReceiptPaymentServiceImpl.java
@@ -79,9 +79,9 @@
                 // 澧炲姞璐㈠姟鏀跺叆璁板綍
                 AccountIncome accountIncome = new AccountIncome();
                 accountIncome.setIncomeDate(salesLedger.getEntryDate());
-                accountIncome.setIncomeType("0");
+                accountIncome.setIncomeType("3");
                 accountIncome.setCustomerName(salesLedger.getCustomerName());
-                accountIncome.setIncomeMoney(salesLedger.getContractAmount());
+                accountIncome.setIncomeMoney(receiptPayment.getReceiptPaymentAmount());
                 accountIncome.setIncomeMethod("0");
                 accountIncome.setInputTime(new Date());
                 accountIncome.setInputUser(salesLedger.getEntryPerson());
diff --git a/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
index 019320a..df94a16 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -72,6 +72,7 @@
         byId.setExpressCompany(req.getExpressCompany());
         byId.setStatus("宸插彂璐�");
         byId.setShippingCarNumber(req.getShippingCarNumber());
+        byId.setShippingDate(req.getShippingDate());
         boolean update = this.updateById(byId);
         // 杩佺Щ鏂囦欢
         if(CollectionUtils.isNotEmpty(req.getTempFileIds())){
diff --git a/src/main/java/com/ruoyi/staff/controller/HolidayApplicationController.java b/src/main/java/com/ruoyi/staff/controller/HolidayApplicationController.java
index 7ac13bd..66f1710 100644
--- a/src/main/java/com/ruoyi/staff/controller/HolidayApplicationController.java
+++ b/src/main/java/com/ruoyi/staff/controller/HolidayApplicationController.java
@@ -3,7 +3,6 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.staff.pojo.HolidayApplication;
-import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
 import com.ruoyi.staff.service.HolidayApplicationService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
diff --git a/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceLocationConfigController.java b/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceLocationConfigController.java
new file mode 100644
index 0000000..5eabe99
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceLocationConfigController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.staff.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
+import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import com.ruoyi.staff.service.PersonalAttendanceLocationConfigService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 浜哄憳鎵撳崱瑙勫垯閰嶇疆 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-11 09:41:34
+ */
+@RestController
+@RequestMapping("/personalAttendanceLocationConfig")
+@Api(tags = "浜哄憳鎵撳崱瑙勫垯閰嶇疆")
+public class PersonalAttendanceLocationConfigController {
+
+    @Autowired
+    private PersonalAttendanceLocationConfigService personalAttendanceLocationConfigService;
+
+    @ApiOperation("鏂板/淇敼浜哄憳鎵撳崱瑙勫垯閰嶇疆")
+    @PostMapping("/add")
+    public R add(@RequestBody PersonalAttendanceLocationConfig personalAttendanceLocationConfig){
+        return R.ok(personalAttendanceLocationConfigService.saveOrUpdate(personalAttendanceLocationConfig));
+    }
+
+    @ApiOperation("鍒嗛〉鏌ヨ浜哄憳鎵撳崱瑙勫垯閰嶇疆")
+    @GetMapping("/listPage")
+    public R listPage(Page page){
+        return R.ok(personalAttendanceLocationConfigService.page(page));
+    }
+
+
+    @ApiOperation("鍒犻櫎浜哄憳鎵撳崱瑙勫垯閰嶇疆")
+    @DeleteMapping("/del")
+    public R del(@RequestBody List<Integer> ids) {
+        return R.ok(personalAttendanceLocationConfigService.removeBatchByIds(ids));
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java b/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java
index 53f55fd..d6a8ce3 100644
--- a/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java
+++ b/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java
@@ -2,44 +2,53 @@
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
 import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
 import com.ruoyi.staff.service.PersonalAttendanceRecordsService;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.web.bind.annotation.*;
 
-@AllArgsConstructor
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>
+ *  鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-09 01:20:07
+ */
 @RestController
-@RequestMapping("/staff/personalAttendanceRecords")
+@RequestMapping("/personalAttendanceRecords")
+@Api(tags = "浜哄憳鎵撳崱绛惧埌")
 public class PersonalAttendanceRecordsController {
-    @Autowired
+    @Resource
     private PersonalAttendanceRecordsService personalAttendanceRecordsService;
-    /**
-     * 涓汉鑰冨嫟璁板綍鍒嗛〉鏌ヨ
-     */
+
+    @ApiOperation("鏂板鎵撳崱绛惧埌")
+    @PostMapping("")
+    public AjaxResult add(@RequestBody PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
+        return AjaxResult.success(personalAttendanceRecordsService.add(personalAttendanceRecordsDto));
+    }
+
+    @ApiOperation("鍒嗛〉鏌ヨ鎵撳崱绛惧埌")
     @GetMapping("/listPage")
-    public AjaxResult personalAttendanceRecordsListPage(Page page, PersonalAttendanceRecords personalAttendanceRecords) {
-        return AjaxResult.success(personalAttendanceRecordsService.listPage(page, personalAttendanceRecords));
+    public AjaxResult listPage(Page page, PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
+        return AjaxResult.success(personalAttendanceRecordsService.listPage(page, personalAttendanceRecordsDto));
     }
-    /**
-     * 鏂板涓汉鑰冨嫟璁板綍
-     */
-    @PostMapping("/add")
-    public AjaxResult add(@RequestBody PersonalAttendanceRecords personalAttendanceRecords) {
-        return AjaxResult.success(personalAttendanceRecordsService.save(personalAttendanceRecords));
+
+    @ApiOperation("鑾峰彇褰撳墠浜虹殑鑰冨嫟鐩稿叧鏁版嵁")
+    @GetMapping("/today")
+    public AjaxResult todayInfo(PersonalAttendanceRecordsDto personalAttendanceRecordsDto){
+        return AjaxResult.success(personalAttendanceRecordsService.todayInfo(personalAttendanceRecordsDto));
     }
-    /**
-     * 淇敼涓汉鑰冨嫟璁板綍
-     */
-    @PutMapping("/update")
-    public AjaxResult update(@RequestBody PersonalAttendanceRecords personalAttendanceRecords) {
-        return AjaxResult.success(personalAttendanceRecordsService.updateById(personalAttendanceRecords));
+
+    @ApiOperation("瀵煎嚭鎵撳崱绛惧埌")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, PersonalAttendanceRecordsDto personalAttendanceRecordsDto) {
+        personalAttendanceRecordsService.export(response, personalAttendanceRecordsDto);
     }
-    /**
-     * 鍒犻櫎涓汉鑰冨嫟璁板綍
-     */
-    @DeleteMapping("/delete/{id}")
-    public AjaxResult delete(@PathVariable("id") Long id) {
-        return AjaxResult.success(personalAttendanceRecordsService.removeById(id));
-    }
+
 }
diff --git a/src/main/java/com/ruoyi/staff/dto/PersonalAttendanceRecordsDto.java b/src/main/java/com/ruoyi/staff/dto/PersonalAttendanceRecordsDto.java
new file mode 100644
index 0000000..511390c
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/dto/PersonalAttendanceRecordsDto.java
@@ -0,0 +1,43 @@
+package com.ruoyi.staff.dto;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+@Data
+@ExcelIgnoreUnannotated
+public class PersonalAttendanceRecordsDto extends PersonalAttendanceRecords {
+    @Excel(name = "濮撳悕", sort = 3)
+    private String staffName;
+
+    @Excel(name = "宸ュ彿", sort = 4)
+    private String staffNo;
+
+    @Excel(name = "閮ㄩ棬", sort = 2)
+    private String deptName;
+
+    private Long deptId;
+
+    //鎵撳崱鐨勭粡搴�
+    private Double longitude;
+
+    //鎵撳崱鐨勭含搴�
+    private Double latitude;
+
+    //鏍囧噯涓婄彮鏃堕棿
+    @JsonFormat(pattern = "HH:mm")
+    @DateTimeFormat(pattern = "HH:mm")
+    private LocalTime startAt;
+
+    //鏍囧噯涓嬬彮鏃堕棿
+    @JsonFormat(pattern = "HH:mm")
+    @DateTimeFormat(pattern = "HH:mm")
+    private LocalTime  endAt;
+}
diff --git a/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceLocationConfigMapper.java b/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceLocationConfigMapper.java
new file mode 100644
index 0000000..e71efcd
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceLocationConfigMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.staff.mapper;
+
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 浜哄憳鎵撳崱瑙勫垯閰嶇疆 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-11 09:41:34
+ */
+@Mapper
+public interface PersonalAttendanceLocationConfigMapper extends BaseMapper<PersonalAttendanceLocationConfig> {
+
+}
diff --git a/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceRecordsMapper.java b/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceRecordsMapper.java
index 402bb45..dddd117 100644
--- a/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceRecordsMapper.java
+++ b/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceRecordsMapper.java
@@ -1,9 +1,32 @@
 package com.ruoyi.staff.mapper;
 
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
+import com.ruoyi.staff.dto.StaffOnJobDto;
 import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.staff.pojo.StaffOnJob;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * <p>
+ *  Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-09 01:20:07
+ */
 @Mapper
 public interface PersonalAttendanceRecordsMapper extends BaseMapper<PersonalAttendanceRecords> {
+    IPage<PersonalAttendanceRecordsDto> listPage(Page page, @Param("params") PersonalAttendanceRecordsDto personalAttendanceRecordsDto);
+
+    List<StaffOnJob> selectStaffWithoutAttendanceRecordBeforeTime(@Param("date") LocalDate date, @Param("entryDeadline") LocalDateTime entryDeadline);
+
+    boolean existsAttendanceRecord(@Param("staffOnJobId") Long staffOnJobId, @Param("date") LocalDate date);
 }
diff --git a/src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java b/src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java
index 5bd15e4..de8a3c0 100644
--- a/src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java
+++ b/src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java
@@ -20,6 +20,7 @@
 
     /**
      * 缁熻鎸囧畾鏃ユ湡鐨勫湪鑱屽憳宸ユ暟
+     *
      * @param date 鏃ユ湡
      * @return 鍦ㄨ亴鍛樺伐鏁�
      */
@@ -27,9 +28,18 @@
 
     /**
      * 缁熻鎸囧畾鏈堜唤鐨勬柊鍏ヨ亴鍛樺伐鏁�
+     *
      * @param monthStart 鏈堜唤寮�濮嬫棩鏈�
-     * @param monthEnd 鏈堜唤缁撴潫鏃ユ湡
+     * @param monthEnd   鏈堜唤缁撴潫鏃ユ湡
      * @return 鏂板叆鑱屽憳宸ユ暟
      */
     Integer countNewHireByMonth(@Param("monthStart") LocalDate monthStart, @Param("monthEnd") LocalDate monthEnd);
+
+    /**
+     * 鏍规嵁鍛樺伐濮撳悕鏌ヨ鍛樺伐淇℃伅
+     *
+     * @param staffName 鍛樺伐濮撳悕
+     * @return 鍛樺伐鏁版嵁
+     */
+    StaffOnJob selectStaffByNickName(String staffName);
 }
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceLocationConfig.java b/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceLocationConfig.java
new file mode 100644
index 0000000..3b677e1
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceLocationConfig.java
@@ -0,0 +1,60 @@
+package com.ruoyi.staff.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * <p>
+ * 浜哄憳鎵撳崱瑙勫垯閰嶇疆
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-11 09:41:34
+ */
+@Getter
+@Setter
+@TableName("personal_attendance_location_config")
+@ApiModel(value = "PersonalAttendanceLocationConfig瀵硅薄", description = "浜哄憳鎵撳崱瑙勫垯閰嶇疆")
+public class PersonalAttendanceLocationConfig implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty("閮ㄩ棬id")
+    private Integer sysDeptId;
+
+    @ApiModelProperty("鍦扮偣鍚嶇О")
+    private String locationName;
+
+    @ApiModelProperty("缁忓害")
+    private Double longitude;
+
+    @ApiModelProperty("绾害")
+    private Double latitude;
+
+    @ApiModelProperty("鎵撳崱鑼冨洿")
+    private Double radius;
+
+    @ApiModelProperty("涓婄彮鏃堕棿")
+    @JsonFormat(pattern = "HH:mm")
+    @DateTimeFormat(pattern = "HH:mm")
+    private LocalTime startAt;
+
+    @ApiModelProperty("涓嬬彮鏃堕棿")
+    @JsonFormat(pattern = "HH:mm")
+    @DateTimeFormat(pattern = "HH:mm")
+    private LocalTime  endAt;
+}
diff --git a/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceRecords.java b/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceRecords.java
index cbf11b7..8e64e0c 100644
--- a/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceRecords.java
+++ b/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceRecords.java
@@ -1,52 +1,84 @@
 package com.ruoyi.staff.pojo;
 
-import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.annotation.FieldFill;
+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 java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
-import lombok.Data;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import java.io.Serializable;
-import java.time.LocalDate;
-import java.time.LocalTime;
-
-@Data
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-09 01:20:07
+ */
+@Getter
+@Setter
 @TableName("personal_attendance_records")
+@ApiModel(value = "PersonalAttendanceRecords瀵硅薄", description = "")
 public class PersonalAttendanceRecords implements Serializable {
-    /**
-     * 搴忓彿
-     */
-    @TableId(type = IdType.AUTO)
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
     private Long id;
-    /**
-     * 鏃ユ湡
-     */
+
+    @ApiModelProperty("鍛樺伐鍦ㄨ亴id")
+    private Long staffOnJobId;
+
+    @ApiModelProperty("鏃ユ湡")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "鏃ユ湡", sort = 1, dateFormat = "yyyy-MM-dd")
     private LocalDate date;
-    /**
-     * 绛惧埌鏃堕棿
-     */
+
+    @ApiModelProperty("宸ヤ綔寮�濮嬫椂闂�")
     @JsonFormat(pattern = "HH:mm")
     @DateTimeFormat(pattern = "HH:mm")
-    private LocalTime checkIn;
-    /**
-     * 绛鹃��鏃堕棿
-     */
+    @Excel(name = "涓婄彮鏃堕棿", sort = 5, dateFormat = "HH:mm")
+    private LocalDateTime workStartAt;
+
+    @ApiModelProperty("宸ヤ綔缁撴潫鏃堕棿")
     @JsonFormat(pattern = "HH:mm")
     @DateTimeFormat(pattern = "HH:mm")
-    private LocalTime checkOut;
-    /**
-     * 宸ヤ綔鏃堕暱
-     */
-    private String workHours;
-    /**
-     * 鐘舵��
-     */
-    private String status;
-    /**
-     * 绉熸埛ID
-     */
+    @Excel(name = "涓嬬彮鏃堕棿", sort = 6, dateFormat = "HH:mm")
+    private LocalDateTime workEndAt;
+
+    @ApiModelProperty("宸ヤ綔鏃堕暱")
+    @Excel(name = "宸ユ椂(灏忔椂)", sort = 7)
+    private BigDecimal workHours;
+
+    @ApiModelProperty("鐘舵�� 0姝e父 1杩熷埌 2鏃╅�� 3杩熷埌鏃╅�� 4缂哄嫟")
+    @Excel(name = "鐘舵��", sort = 8,readConverterExp = "0=姝e父,1=杩熷埌,2=鏃╅��,3=杩熷埌銆佹棭閫�,4=缂哄嫟")
+    private Integer status;
+
+    @ApiModelProperty("澶囨敞")
+    @Excel(name = "澶囨敞", sort = 9)
+    private String remark;
+
+    @ApiModelProperty("绉熸埛id")
     @TableField(fill = FieldFill.INSERT)
     private Long tenantId;
+
+    @ApiModelProperty("褰曞叆鏃堕棿")
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("鏇存柊鏃堕棿")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
 }
diff --git a/src/main/java/com/ruoyi/staff/pojo/StaffOnJob.java b/src/main/java/com/ruoyi/staff/pojo/StaffOnJob.java
index 31d74b9..785b722 100644
--- a/src/main/java/com/ruoyi/staff/pojo/StaffOnJob.java
+++ b/src/main/java/com/ruoyi/staff/pojo/StaffOnJob.java
@@ -66,7 +66,7 @@
      /**
      * 閮ㄩ棬
      */
-    private Integer sysDeptId;
+    private Long sysDeptId;
 
     /**
      * 瀹跺涵浣忓潃
diff --git a/src/main/java/com/ruoyi/staff/service/PersonalAttendanceLocationConfigService.java b/src/main/java/com/ruoyi/staff/service/PersonalAttendanceLocationConfigService.java
new file mode 100644
index 0000000..14afa19
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/service/PersonalAttendanceLocationConfigService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.staff.service;
+
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 浜哄憳鎵撳崱瑙勫垯閰嶇疆 鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-11 09:41:34
+ */
+public interface PersonalAttendanceLocationConfigService extends IService<PersonalAttendanceLocationConfig> {
+
+}
diff --git a/src/main/java/com/ruoyi/staff/service/PersonalAttendanceRecordsService.java b/src/main/java/com/ruoyi/staff/service/PersonalAttendanceRecordsService.java
index c39b007..7b8cd58 100644
--- a/src/main/java/com/ruoyi/staff/service/PersonalAttendanceRecordsService.java
+++ b/src/main/java/com/ruoyi/staff/service/PersonalAttendanceRecordsService.java
@@ -2,9 +2,28 @@
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
+import com.ruoyi.staff.dto.StaffOnJobDto;
 import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.staff.pojo.StaffOnJob;
 
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>
+ *  鏈嶅姟绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-09 01:20:07
+ */
 public interface PersonalAttendanceRecordsService extends IService<PersonalAttendanceRecords> {
-    IPage listPage(Page page, PersonalAttendanceRecords personalAttendanceRecords);
+    IPage<PersonalAttendanceRecordsDto> listPage(Page page, PersonalAttendanceRecordsDto personalAttendanceRecordsDto);
+
+    int add(PersonalAttendanceRecordsDto personalAttendanceRecordsDto);
+
+    PersonalAttendanceRecordsDto todayInfo(PersonalAttendanceRecordsDto personalAttendanceRecordsDto);
+
+    void export(HttpServletResponse response, PersonalAttendanceRecordsDto personalAttendanceRecordsDto);
 }
diff --git a/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceLocationConfigServiceImpl.java b/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceLocationConfigServiceImpl.java
new file mode 100644
index 0000000..b1dffca
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceLocationConfigServiceImpl.java
@@ -0,0 +1,25 @@
+package com.ruoyi.staff.service.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
+import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
+import com.ruoyi.staff.service.PersonalAttendanceLocationConfigService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 浜哄憳鎵撳崱瑙勫垯閰嶇疆 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-11 09:41:34
+ */
+@Service
+public class PersonalAttendanceLocationConfigServiceImpl extends ServiceImpl<PersonalAttendanceLocationConfigMapper, PersonalAttendanceLocationConfig> implements PersonalAttendanceLocationConfigService {
+
+}
diff --git a/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java b/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java
index 1fc363b..b323a22 100644
--- a/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java
+++ b/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java
@@ -2,22 +2,260 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+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.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.mapper.SysDeptMapper;
+import com.ruoyi.project.system.service.ISysDictDataService;
+import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
+import com.ruoyi.staff.dto.StaffOnJobDto;
+import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
+import com.ruoyi.staff.mapper.StaffOnJobMapper;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
 import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import com.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper;
+import com.ruoyi.staff.pojo.StaffOnJob;
 import com.ruoyi.staff.service.PersonalAttendanceRecordsService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.staff.task.PersonalAttendanceRecordsTask;
+import com.ruoyi.staff.utils.LocationUtils;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import javax.servlet.http.HttpServletResponse;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+/**
+ * <p>
+ *  鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-09 01:20:07
+ */
 @Service
+@Transactional(rollbackFor = Exception.class)
 public class PersonalAttendanceRecordsServiceImpl extends ServiceImpl<PersonalAttendanceRecordsMapper, PersonalAttendanceRecords> implements PersonalAttendanceRecordsService {
     @Autowired
     private PersonalAttendanceRecordsMapper personalAttendanceRecordsMapper;
 
+    @Autowired
+    private StaffOnJobMapper staffOnJobMapper;
+
+    @Autowired
+    private PersonalAttendanceLocationConfigMapper personalAttendanceLocationConfigMapper;
+
+    @Autowired
+    private ISysDictDataService dictDataService;
+
+    @Autowired
+    private SysDeptMapper sysDeptMapper;
+
     @Override
-    public IPage listPage(Page page, PersonalAttendanceRecords personalAttendanceRecords) {
-//        return personalAttendanceRecordsMapper.ListPage(page, personalAttendanceRecords);
-        return baseMapper.selectPage(page, new QueryWrapper<>(personalAttendanceRecords));
+    public int add(PersonalAttendanceRecordsDto personalAttendanceRecordsDto) {
+        // 褰撳墠鏃堕棿
+        LocalDate currentDate = LocalDate.now();
+        LocalDateTime currentDateTime = LocalDateTime.now();
+        /*鏌ヨ鍛樺伐淇℃伅*/
+        QueryWrapper<StaffOnJob> staffQueryWrapper = new QueryWrapper<>();
+        staffQueryWrapper.eq("staff_no", SecurityUtils.getUsername());
+        staffQueryWrapper.eq("staff_state", 1);//鍦ㄨ亴
+        StaffOnJob staffOnJob = staffOnJobMapper.selectOne(staffQueryWrapper);
+        if (staffOnJob == null) {
+            throw new BaseException("褰撳墠鐢ㄦ埛娌℃湁瀵瑰簲鐨勫憳宸ヤ俊鎭�");
+        }
+        /*鍒ゆ柇鎵撳崱浣嶇疆鏄惁鍦ㄨ鍒欒寖鍥村唴*/
+        List<PersonalAttendanceLocationConfig> personalAttendanceLocationConfigs = personalAttendanceLocationConfigMapper.selectList(Wrappers.<PersonalAttendanceLocationConfig>lambdaQuery()
+                .eq(PersonalAttendanceLocationConfig::getSysDeptId, staffOnJob.getSysDeptId())
+                .orderByDesc(PersonalAttendanceLocationConfig::getId));
+        if (personalAttendanceLocationConfigs == null || personalAttendanceLocationConfigs.isEmpty()) {
+            throw new BaseException("褰撳墠閮ㄩ棬娌℃湁璁剧疆鎵撳崱瑙勫垯");
+        }
+        Double punchLongitude = personalAttendanceRecordsDto.getLongitude(); //鎵撳崱鐨勭粡搴�
+        Double punchLatitude = personalAttendanceRecordsDto.getLatitude(); // 鎵撳崱鐨勭含搴�
+        if (punchLongitude == null || punchLatitude == null) {
+            throw new BaseException("鎵撳崱澶辫触锛氭湭鑾峰彇鍒版偍鐨勪綅缃俊鎭紝璇峰紑鍚畾浣嶆潈闄�");
+        }
+        //璁$畻鎵撳崱浣嶇疆涓庤�冨嫟鐐圭殑璺濈
+        PersonalAttendanceLocationConfig locationConfig = personalAttendanceLocationConfigs.get(0);//鑾峰彇鏈�鏂扮殑涓�鏉℃暟鎹�
+        double allowedRadius = locationConfig.getRadius(); // 鍏佽鐨勮寖鍥达紙绫筹級
+        double actualDistance = LocationUtils.calculateDistance(
+                punchLatitude, punchLongitude, // 鍛樺伐鎵撳崱鐨勭粡绾害
+                locationConfig.getLatitude(), locationConfig.getLongitude() // 鑰冨嫟鐐圭殑缁忕含搴�
+        );
+        //鍒ゆ柇鏄惁鍦ㄨ寖鍥村唴
+        if (actualDistance > allowedRadius) {
+            throw new BaseException(String.format("鎵撳崱澶辫触锛氭偍褰撳墠浣嶇疆璺濈鑰冨嫟鐐�%.2f绫筹紝瓒呭嚭鍏佽鑼冨洿锛�%s绫筹級", actualDistance, allowedRadius));
+        }
+        /*鍒ゆ柇鎵撳崱鏃堕棿*/
+        // 鏍规嵁鍛樺伐ID鍜屽綋鍓嶆棩鏈熸煡璇㈡墦鍗¤褰�
+        QueryWrapper<PersonalAttendanceRecords> attendanceQueryWrapper = new QueryWrapper<>();
+        attendanceQueryWrapper.eq("staff_on_job_id", staffOnJob.getId())
+                .eq("date", currentDate);
+        PersonalAttendanceRecords attendanceRecord = personalAttendanceRecordsMapper.selectOne(attendanceQueryWrapper);
+        // 鏍规嵁鑰冨嫟鏃堕棿鍒ゆ柇杩熷埌鏃╅��
+        if (attendanceRecord == null) {
+            // 涓嶅瓨鍦ㄦ墦鍗¤褰曪紝鍒涘缓鏂拌褰�
+            PersonalAttendanceRecords personalAttendanceRecords = new PersonalAttendanceRecords();
+            personalAttendanceRecords.setStaffOnJobId(staffOnJob.getId());
+            personalAttendanceRecords.setDate(currentDate);
+            personalAttendanceRecords.setWorkStartAt(currentDateTime);
+            personalAttendanceRecords.setStatus(determineAttendanceStatus(personalAttendanceRecords, true,locationConfig));
+            personalAttendanceRecords.setRemark(personalAttendanceRecords.getRemark());
+            personalAttendanceRecords.setTenantId(staffOnJob.getTenantId());
+            return personalAttendanceRecordsMapper.insert(personalAttendanceRecords);
+        } else {
+            if (attendanceRecord.getWorkEndAt() == null) {
+                // 鏇存柊宸ヤ綔缁撴潫鏃堕棿鍜屽伐浣滄椂闀�
+                attendanceRecord.setWorkEndAt(currentDateTime);
+                // 璁$畻宸ヤ綔鏃堕暱锛堢簿纭埌鍒嗛挓锛屼繚鐣�2浣嶅皬鏁帮級
+                LocalDateTime startTime = attendanceRecord.getWorkStartAt();
+                LocalDateTime endTime = attendanceRecord.getWorkEndAt();
+                // 璁$畻涓や釜鏃堕棿涔嬮棿鐨勫垎閽熸暟
+                long totalMinutes = java.time.Duration.between(startTime, endTime).toMinutes();
+                BigDecimal workHours = BigDecimal.valueOf(totalMinutes)
+                        .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
+                attendanceRecord.setWorkHours(workHours);
+                // 鏇存柊鑰冨嫟鐘舵��
+                attendanceRecord.setStatus(determineAttendanceStatus(attendanceRecord, false,locationConfig));
+                return personalAttendanceRecordsMapper.updateById(attendanceRecord);
+            } else {
+                throw new BaseException("鎮ㄥ凡缁忔墦杩囧崱浜�,鏃犻渶閲嶅鎵撳崱!!!");
+            }
+        }
+    }
+
+    // 鏍规嵁瀹為檯鏃堕棿鍜屾槸鍚︿笂鐝椂闂村垽鏂�冨嫟鐘舵��
+    // 0 姝e父 1 杩熷埌 2 鏃╅�� 3 杩熷埌鏃╅�� 4 缂哄嫟
+    private Integer determineAttendanceStatus(PersonalAttendanceRecords attendanceRecord, boolean isStart,PersonalAttendanceLocationConfig locationConfig) {
+        //鍒ゆ柇鏄笂鐝墦鍗¤繕鏄笅鐝墦鍗�
+        LocalDateTime actualTime = isStart ? attendanceRecord.getWorkStartAt() : attendanceRecord.getWorkEndAt();
+        try {
+            // 鑾峰彇鑰冨嫟鏃堕棿閰嶇疆
+            LocalTime startAt = locationConfig.getStartAt();//涓婄彮鏃堕棿
+            LocalTime  endAt = locationConfig.getEndAt();//涓嬬彮鏃堕棿
+            LocalTime  timeConfig = isStart ? startAt : endAt;
+            // 瑙f瀽灏忔椂鍜屽垎閽�
+            int standardHour = timeConfig.getHour();
+            int standardMinute = timeConfig.getMinute();
+            // 鑾峰彇瀹為檯鏃堕棿鐨勬椂鍒�
+            int actualHour = actualTime.getHour();
+            int actualMinute = actualTime.getMinute();
+            // 鍒ゆ柇鐘舵��
+            if (isStart) {
+                // 涓婄彮鎵撳崱锛氳秴杩囨爣鍑嗘椂闂寸畻杩熷埌
+                if (actualHour > standardHour || (actualHour == standardHour && actualMinute > standardMinute)) {
+                    return 1; // 杩熷埌
+                }
+            } else {
+                // 涓嬬彮鎵撳崱锛氭棭浜庢爣鍑嗘椂闂寸畻鏃╅��
+                if (actualHour < standardHour || (actualHour == standardHour && actualMinute < standardMinute)) {
+                    if (attendanceRecord.getStatus() == 1) {
+                        return 3; // 杩熷埌鏃╅��
+                    }
+                    return 2; // 鏃╅��
+                }else if (attendanceRecord.getStatus() == 1) {
+                    return 1; // 涓嬬彮鎵撳崱姝e父浣嗘槸涓婄彮杩熷埌
+                }
+            }
+            return 0; // 姝e父
+        } catch (Exception e) {
+            // 濡傛灉鑾峰彇閰嶇疆澶辫触锛岄粯璁よ繑鍥炴甯哥姸鎬�
+            log.warn("鑾峰彇鑰冨嫟鏃堕棿閰嶇疆澶辫触锛屼娇鐢ㄩ粯璁ょ姸鎬侊細" + e.getMessage());
+            return 0;
+        }
+    }
+
+    @Override
+    public IPage<PersonalAttendanceRecordsDto> listPage(Page page, PersonalAttendanceRecordsDto personalAttendanceRecordsDto) {
+        boolean admin = SecurityUtils.isAdmin(SecurityUtils.getUserId());
+        if (!admin) {
+            QueryWrapper<StaffOnJob> staffQueryWrapper = new QueryWrapper<>();
+            staffQueryWrapper.eq("staff_no", SecurityUtils.getUsername());
+            staffQueryWrapper.eq("staff_state", 1);//鍦ㄨ亴
+            StaffOnJob staffOnJob = staffOnJobMapper.selectOne(staffQueryWrapper);
+            if (staffOnJob == null) {
+                return new Page<>(page.getCurrent(), page.getSize(), 0);
+            }
+            personalAttendanceRecordsDto.setStaffOnJobId(staffOnJob.getId());
+        }
+
+        return personalAttendanceRecordsMapper.listPage(page,personalAttendanceRecordsDto);
+    }
+
+    @Override
+    public PersonalAttendanceRecordsDto todayInfo(PersonalAttendanceRecordsDto personalAttendanceRecordsDto) {
+        // 鑾峰彇褰撳墠鏃ユ湡
+        LocalDate currentDate = LocalDate.now();
+
+        // 棣栧厛鏍规嵁鐢ㄦ埛ID鏌ヨ鍛樺伐淇℃伅
+        QueryWrapper<StaffOnJob> staffQueryWrapper = new QueryWrapper<>();
+        staffQueryWrapper.eq("staff_no", SecurityUtils.getUsername());
+        staffQueryWrapper.eq("staff_state", 1);//鍦ㄨ亴
+        StaffOnJob staffOnJob = staffOnJobMapper.selectOne(staffQueryWrapper);
+
+        if (staffOnJob == null) {
+            throw new BaseException("褰撳墠鐢ㄦ埛娌℃湁瀵瑰簲鐨勫憳宸ヤ俊鎭�");
+        }
+
+        // 鏍规嵁鍛樺伐ID鍜屽綋鍓嶆棩鏈熸煡璇㈡墦鍗¤褰�
+        QueryWrapper<PersonalAttendanceRecords> attendanceQueryWrapper = new QueryWrapper<>();
+        attendanceQueryWrapper.eq("staff_on_job_id", staffOnJob.getId())
+                .eq("date", currentDate);
+        PersonalAttendanceRecords attendanceRecord = personalAttendanceRecordsMapper.selectOne(attendanceQueryWrapper);
+
+        // 杩斿洖鍙傛暟
+        PersonalAttendanceRecordsDto resultDto = new PersonalAttendanceRecordsDto();
+
+        if (attendanceRecord != null) {
+            // 濡傛灉鏈夋墦鍗¤褰曪紝澶嶅埗鎵撳崱璁板綍淇℃伅
+            BeanUtils.copyProperties(attendanceRecord, resultDto);
+        }
+
+        // 鍛樺伐鐩稿叧淇℃伅
+        resultDto.setStaffName(staffOnJob.getStaffName());
+        resultDto.setStaffNo(staffOnJob.getStaffNo());
+        resultDto.setDeptId(staffOnJob.getSysDeptId() != null ? staffOnJob.getSysDeptId() : null);
+        SysDept dept = sysDeptMapper.selectDeptById(staffOnJob.getSysDeptId());
+        resultDto.setDeptName(dept != null ? dept.getDeptName() : null);
+        //鑾峰彇璇ュ憳宸ュ搴旂殑鎵撳崱瑙勫垯
+        List<PersonalAttendanceLocationConfig> personalAttendanceLocationConfigs = personalAttendanceLocationConfigMapper.selectList(Wrappers.<PersonalAttendanceLocationConfig>lambdaQuery()
+                .eq(PersonalAttendanceLocationConfig::getSysDeptId, staffOnJob.getSysDeptId())
+                .orderByDesc(PersonalAttendanceLocationConfig::getId));
+        if (personalAttendanceLocationConfigs.size()>0){
+            resultDto.setStartAt(personalAttendanceLocationConfigs.get(0).getStartAt());
+            resultDto.setEndAt(personalAttendanceLocationConfigs.get(0).getEndAt());
+        }
+        return resultDto;
+    }
+
+    @Override
+    public void export(HttpServletResponse response, PersonalAttendanceRecordsDto personalAttendanceRecordsDto) {
+        boolean admin = SecurityUtils.isAdmin(SecurityUtils.getUserId());
+        if (!admin) {
+            QueryWrapper<StaffOnJob> staffQueryWrapper = new QueryWrapper<>();
+            staffQueryWrapper.eq("staff_no", SecurityUtils.getUsername());
+            staffQueryWrapper.eq("staff_state", 1);//鍦ㄨ亴
+            StaffOnJob staffOnJob = staffOnJobMapper.selectOne(staffQueryWrapper);
+            if (staffOnJob == null) {
+                throw new ServiceException("娌℃湁鍛樺伐淇℃伅锛屾棤娉曞鍑鸿�冨嫟璁板綍");
+            }
+            personalAttendanceRecordsDto.setStaffOnJobId(staffOnJob.getId());
+        }
+        List<PersonalAttendanceRecordsDto> personalAttendanceRecords = personalAttendanceRecordsMapper.listPage(new Page<>(1, Integer.MAX_VALUE), personalAttendanceRecordsDto).getRecords();
+        ExcelUtil<PersonalAttendanceRecordsDto> util = new ExcelUtil<PersonalAttendanceRecordsDto>(PersonalAttendanceRecordsDto.class);
+        util.exportExcel(response, personalAttendanceRecords, "鑰冨嫟璁板綍瀵煎嚭");
     }
 }
diff --git a/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java b/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
index d7abe9b..d421345 100644
--- a/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
+++ b/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
@@ -180,7 +180,7 @@
     public void staffOnJobExport(HttpServletResponse response, StaffOnJob staffOnJob) {
         List<StaffOnJobDto> staffOnJobs = staffOnJobMapper.staffOnJobList(staffOnJob);
         ExcelUtil<StaffOnJobDto> util = new ExcelUtil<StaffOnJobDto>(StaffOnJobDto.class);
-        util.exportExcel(response, staffOnJobs, "鍦ㄨ亴鍛樺伐鍙拌处瀵煎嚭");
+        util.exportExcel(response, staffOnJobs, "鍛樺伐鍙拌处瀵煎嚭");
     }
 
     @Override
diff --git a/src/main/java/com/ruoyi/staff/task/PersonalAttendanceRecordsTask.java b/src/main/java/com/ruoyi/staff/task/PersonalAttendanceRecordsTask.java
new file mode 100644
index 0000000..9730df6
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/task/PersonalAttendanceRecordsTask.java
@@ -0,0 +1,76 @@
+package com.ruoyi.staff.task;
+
+import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import com.ruoyi.staff.pojo.StaffOnJob;
+import com.ruoyi.staff.service.PersonalAttendanceRecordsService;
+import com.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 涓汉鑰冨嫟璁板綍瀹氭椂浠诲姟
+ *
+ * @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
+ * @since 2026-02-09
+ */
+@Slf4j
+@Component
+public class PersonalAttendanceRecordsTask {
+
+    @Autowired
+    private PersonalAttendanceRecordsMapper personalAttendanceRecordsMapper;
+
+    @Autowired
+    private PersonalAttendanceRecordsService personalAttendanceRecordsService;
+
+    /**
+     * 姣忓ぉ鍑屾櫒鐢熸垚鏄ㄦ棩鐨勭己鍕よ褰�
+     * 瀹氭椂浠诲姟锛氭瘡澶╁噷鏅�1鐐规墽琛�
+     * 鎺掗櫎浠婂ぉ鍒氬叆鑱岀殑鍛樺伐
+     */
+    @Scheduled(cron = "0 0 1 * * ?")
+    public void generateAbsenceRecords() {
+        try {
+            // 鑾峰彇鏄ㄦ棩鏃ユ湡
+            LocalDate yesterday = LocalDate.now().minusDays(1);
+
+            // 鐩存帴鏌ヨ鏄ㄥぉ娌℃湁鑰冨嫟璁板綍鐨勫湪鑱屽憳宸ワ紙鎺掗櫎浠婂ぉ鍒氬叆鑱岀殑锛�
+            LocalDateTime todayStart = LocalDate.now().atStartOfDay();
+            List<StaffOnJob> staffWithoutAttendance = personalAttendanceRecordsMapper.selectStaffWithoutAttendanceRecordBeforeTime(yesterday, todayStart);
+
+            // 閬嶅巻娌℃湁鑰冨嫟璁板綍鐨勫憳宸ワ紝鐢熸垚缂哄嫟璁板綍
+            for (StaffOnJob staff : staffWithoutAttendance) {
+                try {
+                    boolean exists = personalAttendanceRecordsMapper.existsAttendanceRecord(staff.getId(), yesterday);
+                    if (exists) {
+                        continue;
+                    }
+
+                    PersonalAttendanceRecords absenceRecord = new PersonalAttendanceRecords();
+                    absenceRecord.setStaffOnJobId(staff.getId());
+                    absenceRecord.setDate(yesterday);
+                    absenceRecord.setStatus(4); // 璁剧疆鐘舵�佷负缂哄嫟
+                    absenceRecord.setRemark("绯荤粺鑷姩鐢熸垚-缂哄嫟");
+                    absenceRecord.setCreateTime(LocalDateTime.now());
+                    absenceRecord.setUpdateTime(LocalDateTime.now());
+                    absenceRecord.setTenantId(staff.getTenantId());
+                    personalAttendanceRecordsService.save(absenceRecord);
+
+                } catch (Exception e) {
+                    log.error("涓哄憳宸}鐢熸垚缂哄嫟璁板綍澶辫触锛歿}", staff.getStaffName(), e.getMessage(), e);
+                }
+            }
+
+            log.info("鏄ㄦ棩缂哄嫟璁板綍鐢熸垚瀹屾垚");
+        } catch (Exception e) {
+            log.error("鐢熸垚鏄ㄦ棩缂哄嫟璁板綍浠诲姟鎵ц澶辫触锛歿}", e.getMessage(), e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/staff/utils/LocationUtils.java b/src/main/java/com/ruoyi/staff/utils/LocationUtils.java
new file mode 100644
index 0000000..d335235
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/utils/LocationUtils.java
@@ -0,0 +1,37 @@
+package com.ruoyi.staff.utils;
+
+// 宸ュ叿绫伙細璁$畻涓や釜缁忕含搴︿箣闂寸殑璺濈锛堢悆闈㈣窛绂伙級
+public class LocationUtils {
+    private static final double EARTH_RADIUS = 6371000; // 鍦扮悆鍗婂緞锛屽崟浣嶇背
+
+    /**
+     * 璁$畻涓や釜缁忕含搴︿箣闂寸殑璺濈锛堢背锛�
+     * @param lat1 绗竴涓偣绾害
+     * @param lon1 绗竴涓偣缁忓害
+     * @param lat2 绗簩涓偣绾害
+     * @param lon2 绗簩涓偣缁忓害
+     * @return 璺濈锛堢背锛�
+     */
+    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
+        // 杞姬搴�
+        double radLat1 = Math.toRadians(lat1);
+        double radLon1 = Math.toRadians(lon1);
+        double radLat2 = Math.toRadians(lat2);
+        double radLon2 = Math.toRadians(lon2);
+
+        // 宸��
+        double deltaLat = radLat1 - radLat2;
+        double deltaLon = radLon1 - radLon2;
+
+        // 鐞冮潰璺濈鍏紡
+        double distance = 2 * Math.asin(Math.sqrt(
+                Math.pow(Math.sin(deltaLat / 2), 2) +
+                        Math.cos(radLat1) * Math.cos(radLat2) *
+                                Math.pow(Math.sin(deltaLon / 2), 2)
+        ));
+        distance = distance * EARTH_RADIUS;
+        // 淇濈暀涓や綅灏忔暟
+        distance = Math.round(distance * 100) / 100.0;
+        return distance;
+    }
+}
diff --git a/src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java b/src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
index e58db7c..0d345df 100644
--- a/src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
+++ b/src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -12,6 +12,7 @@
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
 
@@ -41,11 +42,11 @@
 
     BigDecimal selectTotal();
 
-    int selectStorageProductCountByDate(@Param("startDate") String startDate, @Param("endDate") String endDate);
+    int selectStorageProductCountByDate(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate);
 
     List<Map<String, Object>> selectDailyStockInCounts(@Param("rootCategoryId") Long rootCategoryId, @Param("startDate") String startDate, @Param("endDate") String endDate);
 
     List<Map<String, Object>> selectDailyStockOutCounts(@Param("rootCategoryId") Long rootCategoryId, @Param("startDate") String startDate, @Param("endDate") String endDate);
 
-    BigDecimal selectTotalByDate( @Param("now") LocalDate now);
+    BigDecimal selectTotalByDate(@Param("now") LocalDate now);
 }
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 40dc00c..ff56f9d 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -15,6 +15,16 @@
   captchaType: math
   # 鍗忓悓瀹℃壒缂栧彿鍓嶇紑(閰嶇疆鏂囦欢鍚庣紑鍛藉悕)
   approvalNumberPrefix: DEV
+
+  # 涓帹 Unipush 閰嶇疆
+  getui:
+    appId: PfjyAAE0FK64FaO1w2CMb1
+    appKey: zTMb831OEL6J4GK1uE3Ob4
+    masterSecret: K1GFtsv42v61tXGnF7SGE5
+    domain: https://restapi.getui.cn/v2/
+    # 绂荤嚎鎺ㄩ�佷娇鐢ㄧ殑鍖呭悕/缁勪欢鍚�
+    intentComponent: uni.app.UNI099A590/io.dcloud.PandoraEntry
+
 # 寮�鍙戠幆澧冮厤缃�
 server:
   # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
diff --git a/src/main/resources/application-khl.yml b/src/main/resources/application-khl.yml
new file mode 100644
index 0000000..c5d1ca9
--- /dev/null
+++ b/src/main/resources/application-khl.yml
@@ -0,0 +1,245 @@
+# 椤圭洰鐩稿叧閰嶇疆
+ruoyi:
+  # 鍚嶇О
+  name: RuoYi
+  # 鐗堟湰
+  version: 3.8.9
+  # 鐗堟潈骞翠唤
+  copyrightYear: 2025
+  # 鏂囦欢璺緞 绀轰緥锛� Windows閰嶇疆D:/ruoyi/uploadPath锛孡inux閰嶇疆 /home/ruoyi/uploadPath锛�
+  profile: /javaWork/product-inventory-management/file
+
+  # 鑾峰彇ip鍦板潃寮�鍏�
+  addressEnabled: false
+  # 楠岃瘉鐮佺被鍨� math 鏁板瓧璁$畻 char 瀛楃楠岃瘉
+  captchaType: math
+  # 鍗忓悓瀹℃壒缂栧彿鍓嶇紑(閰嶇疆鏂囦欢鍚庣紑鍛藉悕)
+  approvalNumberPrefix: KHL
+# 寮�鍙戠幆澧冮厤缃�
+server:
+  # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
+  port: 9214
+  servlet:
+    # 搴旂敤鐨勮闂矾寰�
+    context-path: /
+  tomcat:
+    # tomcat鐨刄RI缂栫爜
+    uri-encoding: UTF-8
+    # 杩炴帴鏁版弧鍚庣殑鎺掗槦鏁帮紝榛樿涓�100
+    accept-count: 1000
+    threads:
+      # tomcat鏈�澶х嚎绋嬫暟锛岄粯璁や负200
+      max: 800
+      # Tomcat鍚姩鍒濆鍖栫殑绾跨▼鏁帮紝榛樿鍊�10
+      min-spare: 100
+
+# 鏃ュ織閰嶇疆
+logging:
+  level:
+    com.ruoyi: warn
+    org.springframework: warn
+
+minio:
+  endpoint: http://114.132.189.42/
+  port: 7019
+  secure: false
+  accessKey: admin
+  secretKey: 12345678
+  preview-expiry: 24 # 棰勮鍦板潃榛樿24灏忔椂
+  default-bucket: jxc
+# 鐢ㄦ埛閰嶇疆
+user:
+  password:
+    # 瀵嗙爜鏈�澶ч敊璇鏁�
+    maxRetryCount: 5
+    # 瀵嗙爜閿佸畾鏃堕棿锛堥粯璁�10鍒嗛挓锛�
+    lockTime: 10
+
+# Spring閰嶇疆
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 涓诲簱鏁版嵁婧�
+      master:
+        url: jdbc:mysql://172.17.0.1:3306/product-inventory-management-khlnew?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: xd@123456..
+      # 浠庡簱鏁版嵁婧�
+      slave:
+        # 浠庢暟鎹簮寮�鍏�/榛樿鍏抽棴
+        enabled: false
+        url:
+        username:
+        password:
+      # 鍒濆杩炴帴鏁�
+      initialSize: 5
+      # 鏈�灏忚繛鎺ユ睜鏁伴噺
+      minIdle: 10
+      # 鏈�澶ц繛鎺ユ睜鏁伴噺
+      maxActive: 20
+      # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂�
+      maxWait: 60000
+      # 閰嶇疆杩炴帴瓒呮椂鏃堕棿
+      connectTimeout: 30000
+      # 閰嶇疆缃戠粶瓒呮椂鏃堕棿
+      socketTimeout: 60000
+      # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶆槸姣
+      timeBetweenEvictionRunsMillis: 60000
+      # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忕敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+      minEvictableIdleTimeMillis: 300000
+      # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�澶х敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+      maxEvictableIdleTimeMillis: 900000
+      # 閰嶇疆妫�娴嬭繛鎺ユ槸鍚︽湁鏁�
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 璁剧疆鐧藉悕鍗曪紝涓嶅~鍒欏厑璁告墍鏈夎闂�
+        allow:
+        url-pattern: /druid/*
+        # 鎺у埗鍙扮鐞嗙敤鎴峰悕鍜屽瘑鐮�
+        login-username: ruoyi
+        login-password: 123456
+      filter:
+        stat:
+          enabled: true
+          # 鎱QL璁板綍
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+  # 璧勬簮淇℃伅
+  messages:
+    # 鍥介檯鍖栬祫婧愭枃浠惰矾寰�
+    basename: i18n/messages
+  # 鏂囦欢涓婁紶
+  servlet:
+    multipart:
+      # 鍗曚釜鏂囦欢澶у皬
+      max-file-size: 1GB
+      # 璁剧疆鎬讳笂浼犵殑鏂囦欢澶у皬
+      max-request-size: 2GB
+  # 鏈嶅姟妯″潡
+  devtools:
+    restart:
+      # 鐑儴缃插紑鍏�
+      enabled: false
+  # redis 閰嶇疆
+  redis:
+    # 鍦板潃
+    #    host: 127.0.0.1
+    host: 172.17.0.1
+    # 绔彛锛岄粯璁や负6379
+    port: 6380
+    # 鏁版嵁搴撶储寮�
+    database: 0
+    # 瀵嗙爜
+    #    password: root2022!
+    password:
+
+    # 杩炴帴瓒呮椂鏃堕棿
+    timeout: 10s
+    lettuce:
+      pool:
+        # 杩炴帴姹犱腑鐨勬渶灏忕┖闂茶繛鎺�
+        min-idle: 0
+        # 杩炴帴姹犱腑鐨勬渶澶х┖闂茶繛鎺�
+        max-idle: 8
+        # 杩炴帴姹犵殑鏈�澶ф暟鎹簱杩炴帴鏁�
+        max-active: 8
+        # #杩炴帴姹犳渶澶ч樆濉炵瓑寰呮椂闂达紙浣跨敤璐熷�艰〃绀烘病鏈夐檺鍒讹級
+        max-wait: -1ms
+
+  # Quartz瀹氭椂浠诲姟閰嶇疆锛堟柊澧為儴鍒嗭級
+  quartz:
+    job-store-type: jdbc  # 浣跨敤鏁版嵁搴撳瓨鍌�
+    jdbc:
+      initialize-schema: never  # 棣栨杩愯鏃惰嚜鍔ㄥ垱寤鸿〃缁撴瀯锛屾垚鍔熷悗鏀逛负never
+      schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql  # MySQL琛ㄧ粨鏋勮剼鏈�
+    properties:
+      org:
+        quartz:
+          scheduler:
+            instanceName: RuoYiScheduler
+            instanceId: AUTO
+          jobStore:
+            class: org.quartz.impl.jdbcjobstore.JobStoreTX
+            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # MySQL閫傞厤
+            tablePrefix: qrtz_  # 琛ㄥ悕鍓嶇紑锛屼笌鑴氭湰涓�鑷�
+            isClustered: false  # 鍗曡妭鐐规ā寮忥紙闆嗙兢闇�鏀逛负true锛�
+            clusterCheckinInterval: 10000
+            txIsolationLevelSerializable: true
+          threadPool:
+            class: org.quartz.simpl.SimpleThreadPool
+            threadCount: 10  # 绾跨▼姹犲ぇ灏�
+            threadPriority: 5
+            makeThreadsDaemons: true
+          updateCheck: false  # 鍏抽棴鐗堟湰妫�鏌�
+# token閰嶇疆
+token:
+  # 浠ょ墝鑷畾涔夋爣璇�
+  header: Authorization
+  # 浠ょ墝瀵嗛挜
+  secret: abcdefghijklmnopqrstuvwxyz
+  # 浠ょ墝鏈夋晥鏈燂紙榛樿30鍒嗛挓锛�
+  expireTime: 450
+
+# MyBatis Plus閰嶇疆
+mybatis-plus:
+  # 鎼滅储鎸囧畾鍖呭埆鍚�   鏍规嵁鑷繁鐨勯」鐩潵
+  typeAliasesPackage: com.ruoyi.**.pojo
+  # 閰嶇疆mapper鐨勬壂鎻忥紝鎵惧埌鎵�鏈夌殑mapper.xml鏄犲皠鏂囦欢
+  mapperLocations: classpath*:mapper/**/*Mapper.xml
+  # 鍔犺浇鍏ㄥ眬鐨勯厤缃枃浠�
+  configLocation: classpath:mybatis/mybatis-config.xml
+  global-config:
+    enable-sql-runner: true
+    db-config:
+      id-type: auto
+
+# PageHelper鍒嗛〉鎻掍欢
+pagehelper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# Swagger閰嶇疆
+swagger:
+  # 鏄惁寮�鍚痵wagger
+  enabled: true
+  # 璇锋眰鍓嶇紑
+  pathMapping: /dev-api
+
+# 闃叉XSS鏀诲嚮
+xss:
+  # 杩囨护寮�鍏�
+  enabled: true
+  # 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
+  excludes: /system/notice
+  # 鍖归厤閾炬帴
+  urlPatterns: /system/*,/monitor/*,/tool/*
+
+# 浠g爜鐢熸垚
+gen:
+  # 浣滆��
+  author: ruoyi
+  # 榛樿鐢熸垚鍖呰矾寰� system 闇�鏀规垚鑷繁鐨勬ā鍧楀悕绉� 濡� system monitor tool
+  packageName: com.ruoyi.project.system
+  # 鑷姩鍘婚櫎琛ㄥ墠缂�锛岄粯璁ゆ槸true
+  autoRemovePre: false
+  # 琛ㄥ墠缂�锛堢敓鎴愮被鍚嶄笉浼氬寘鍚〃鍓嶇紑锛屽涓敤閫楀彿鍒嗛殧锛�
+  tablePrefix: sys_
+  # 鏄惁鍏佽鐢熸垚鏂囦欢瑕嗙洊鍒版湰鍦帮紙鑷畾涔夎矾寰勶級锛岄粯璁や笉鍏佽
+  allowOverwrite: false
+
+file:
+  temp-dir: /javaWork/product-inventory-management/file/temp/uploads
+  upload-dir: /javaWork/product-inventory-management/file/prod/uploads
\ No newline at end of file
diff --git a/src/main/resources/application-new.yml b/src/main/resources/application-new.yml
index 47f7ecd..f44dfdb 100644
--- a/src/main/resources/application-new.yml
+++ b/src/main/resources/application-new.yml
@@ -15,6 +15,16 @@
   captchaType: math
   # 鍗忓悓瀹℃壒缂栧彿鍓嶇紑(閰嶇疆鏂囦欢鍚庣紑鍛藉悕)
   approvalNumberPrefix: NEW
+
+  # 涓帹 Unipush 閰嶇疆
+  getui:
+    appId: PfjyAAE0FK64FaO1w2CMb1
+    appKey: zTMb831OEL6J4GK1uE3Ob4
+    masterSecret: K1GFtsv42v61tXGnF7SGE5
+    domain: https://restapi.getui.cn/v2/
+    # 绂荤嚎鎺ㄩ�佷娇鐢ㄧ殑鍖呭悕/缁勪欢鍚�
+    intentComponent: uni.app.UNI099A590/io.dcloud.PandoraEntry
+
 # 寮�鍙戠幆澧冮厤缃�
 server:
   # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
diff --git a/src/main/resources/application-newTest.yml b/src/main/resources/application-newTest.yml
new file mode 100644
index 0000000..4d3029c
--- /dev/null
+++ b/src/main/resources/application-newTest.yml
@@ -0,0 +1,245 @@
+# 椤圭洰鐩稿叧閰嶇疆
+ruoyi:
+  # 鍚嶇О
+  name: RuoYi
+  # 鐗堟湰
+  version: 3.8.9
+  # 鐗堟潈骞翠唤
+  copyrightYear: 2025
+  # 鏂囦欢璺緞 绀轰緥锛� Windows閰嶇疆D:/ruoyi/uploadPath锛孡inux閰嶇疆 /home/ruoyi/uploadPath锛�
+  profile: /javaWork/product-inventory-management/file
+
+  # 鑾峰彇ip鍦板潃寮�鍏�
+  addressEnabled: false
+  # 楠岃瘉鐮佺被鍨� math 鏁板瓧璁$畻 char 瀛楃楠岃瘉
+  captchaType: math
+  # 鍗忓悓瀹℃壒缂栧彿鍓嶇紑(閰嶇疆鏂囦欢鍚庣紑鍛藉悕)
+  approvalNumberPrefix: NEWTEST
+# 寮�鍙戠幆澧冮厤缃�
+server:
+  # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
+  port: 9007
+  servlet:
+    # 搴旂敤鐨勮闂矾寰�
+    context-path: /
+  tomcat:
+    # tomcat鐨刄RI缂栫爜
+    uri-encoding: UTF-8
+    # 杩炴帴鏁版弧鍚庣殑鎺掗槦鏁帮紝榛樿涓�100
+    accept-count: 1000
+    threads:
+      # tomcat鏈�澶х嚎绋嬫暟锛岄粯璁や负200
+      max: 800
+      # Tomcat鍚姩鍒濆鍖栫殑绾跨▼鏁帮紝榛樿鍊�10
+      min-spare: 100
+
+# 鏃ュ織閰嶇疆
+logging:
+  level:
+    com.ruoyi: warn
+    org.springframework: warn
+
+minio:
+  endpoint: http://114.132.189.42/
+  port: 7019
+  secure: false
+  accessKey: admin
+  secretKey: 12345678
+  preview-expiry: 24 # 棰勮鍦板潃榛樿24灏忔椂
+  default-bucket: jxc
+# 鐢ㄦ埛閰嶇疆
+user:
+  password:
+    # 瀵嗙爜鏈�澶ч敊璇鏁�
+    maxRetryCount: 5
+    # 瀵嗙爜閿佸畾鏃堕棿锛堥粯璁�10鍒嗛挓锛�
+    lockTime: 10
+
+# Spring閰嶇疆
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 涓诲簱鏁版嵁婧�
+      master:
+        url: jdbc:mysql://172.17.0.1:3306/product-inventory-management-newtest?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: xd@123456..
+      # 浠庡簱鏁版嵁婧�
+      slave:
+        # 浠庢暟鎹簮寮�鍏�/榛樿鍏抽棴
+        enabled: false
+        url:
+        username:
+        password:
+      # 鍒濆杩炴帴鏁�
+      initialSize: 5
+      # 鏈�灏忚繛鎺ユ睜鏁伴噺
+      minIdle: 10
+      # 鏈�澶ц繛鎺ユ睜鏁伴噺
+      maxActive: 20
+      # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂�
+      maxWait: 60000
+      # 閰嶇疆杩炴帴瓒呮椂鏃堕棿
+      connectTimeout: 30000
+      # 閰嶇疆缃戠粶瓒呮椂鏃堕棿
+      socketTimeout: 60000
+      # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶆槸姣
+      timeBetweenEvictionRunsMillis: 60000
+      # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忕敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+      minEvictableIdleTimeMillis: 300000
+      # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�澶х敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+      maxEvictableIdleTimeMillis: 900000
+      # 閰嶇疆妫�娴嬭繛鎺ユ槸鍚︽湁鏁�
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 璁剧疆鐧藉悕鍗曪紝涓嶅~鍒欏厑璁告墍鏈夎闂�
+        allow:
+        url-pattern: /druid/*
+        # 鎺у埗鍙扮鐞嗙敤鎴峰悕鍜屽瘑鐮�
+        login-username: ruoyi
+        login-password: 123456
+      filter:
+        stat:
+          enabled: true
+          # 鎱QL璁板綍
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+  # 璧勬簮淇℃伅
+  messages:
+    # 鍥介檯鍖栬祫婧愭枃浠惰矾寰�
+    basename: i18n/messages
+  # 鏂囦欢涓婁紶
+  servlet:
+    multipart:
+      # 鍗曚釜鏂囦欢澶у皬
+      max-file-size: 1GB
+      # 璁剧疆鎬讳笂浼犵殑鏂囦欢澶у皬
+      max-request-size: 2GB
+  # 鏈嶅姟妯″潡
+  devtools:
+    restart:
+      # 鐑儴缃插紑鍏�
+      enabled: false
+  # redis 閰嶇疆
+  redis:
+    # 鍦板潃
+    #    host: 127.0.0.1
+    host: 172.17.0.1
+    # 绔彛锛岄粯璁や负6379
+    port: 6379
+    # 鏁版嵁搴撶储寮�
+    database: 6
+    # 瀵嗙爜
+    #    password: root2022!
+    password:
+
+    # 杩炴帴瓒呮椂鏃堕棿
+    timeout: 10s
+    lettuce:
+      pool:
+        # 杩炴帴姹犱腑鐨勬渶灏忕┖闂茶繛鎺�
+        min-idle: 0
+        # 杩炴帴姹犱腑鐨勬渶澶х┖闂茶繛鎺�
+        max-idle: 8
+        # 杩炴帴姹犵殑鏈�澶ф暟鎹簱杩炴帴鏁�
+        max-active: 8
+        # #杩炴帴姹犳渶澶ч樆濉炵瓑寰呮椂闂达紙浣跨敤璐熷�艰〃绀烘病鏈夐檺鍒讹級
+        max-wait: -1ms
+
+  # Quartz瀹氭椂浠诲姟閰嶇疆锛堟柊澧為儴鍒嗭級
+  quartz:
+    job-store-type: jdbc  # 浣跨敤鏁版嵁搴撳瓨鍌�
+    jdbc:
+      initialize-schema: never  # 棣栨杩愯鏃惰嚜鍔ㄥ垱寤鸿〃缁撴瀯锛屾垚鍔熷悗鏀逛负never
+      schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql  # MySQL琛ㄧ粨鏋勮剼鏈�
+    properties:
+      org:
+        quartz:
+          scheduler:
+            instanceName: RuoYiScheduler
+            instanceId: AUTO
+          jobStore:
+            class: org.quartz.impl.jdbcjobstore.JobStoreTX
+            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # MySQL閫傞厤
+            tablePrefix: qrtz_  # 琛ㄥ悕鍓嶇紑锛屼笌鑴氭湰涓�鑷�
+            isClustered: false  # 鍗曡妭鐐规ā寮忥紙闆嗙兢闇�鏀逛负true锛�
+            clusterCheckinInterval: 10000
+            txIsolationLevelSerializable: true
+          threadPool:
+            class: org.quartz.simpl.SimpleThreadPool
+            threadCount: 10  # 绾跨▼姹犲ぇ灏�
+            threadPriority: 5
+            makeThreadsDaemons: true
+          updateCheck: false  # 鍏抽棴鐗堟湰妫�鏌�
+# token閰嶇疆
+token:
+  # 浠ょ墝鑷畾涔夋爣璇�
+  header: Authorization
+  # 浠ょ墝瀵嗛挜
+  secret: abcdefghijklmnopqrstuvwxyz
+  # 浠ょ墝鏈夋晥鏈燂紙榛樿30鍒嗛挓锛�
+  expireTime: 450
+
+# MyBatis Plus閰嶇疆
+mybatis-plus:
+  # 鎼滅储鎸囧畾鍖呭埆鍚�   鏍规嵁鑷繁鐨勯」鐩潵
+  typeAliasesPackage: com.ruoyi.**.pojo
+  # 閰嶇疆mapper鐨勬壂鎻忥紝鎵惧埌鎵�鏈夌殑mapper.xml鏄犲皠鏂囦欢
+  mapperLocations: classpath*:mapper/**/*Mapper.xml
+  # 鍔犺浇鍏ㄥ眬鐨勯厤缃枃浠�
+  configLocation: classpath:mybatis/mybatis-config.xml
+  global-config:
+    enable-sql-runner: true
+    db-config:
+      id-type: auto
+
+# PageHelper鍒嗛〉鎻掍欢
+pagehelper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# Swagger閰嶇疆
+swagger:
+  # 鏄惁寮�鍚痵wagger
+  enabled: true
+  # 璇锋眰鍓嶇紑
+  pathMapping: /dev-api
+
+# 闃叉XSS鏀诲嚮
+xss:
+  # 杩囨护寮�鍏�
+  enabled: true
+  # 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
+  excludes: /system/notice
+  # 鍖归厤閾炬帴
+  urlPatterns: /system/*,/monitor/*,/tool/*
+
+# 浠g爜鐢熸垚
+gen:
+  # 浣滆��
+  author: ruoyi
+  # 榛樿鐢熸垚鍖呰矾寰� system 闇�鏀规垚鑷繁鐨勬ā鍧楀悕绉� 濡� system monitor tool
+  packageName: com.ruoyi.project.system
+  # 鑷姩鍘婚櫎琛ㄥ墠缂�锛岄粯璁ゆ槸true
+  autoRemovePre: false
+  # 琛ㄥ墠缂�锛堢敓鎴愮被鍚嶄笉浼氬寘鍚〃鍓嶇紑锛屽涓敤閫楀彿鍒嗛殧锛�
+  tablePrefix: sys_
+  # 鏄惁鍏佽鐢熸垚鏂囦欢瑕嗙洊鍒版湰鍦帮紙鑷畾涔夎矾寰勶級锛岄粯璁や笉鍏佽
+  allowOverwrite: false
+
+file:
+  temp-dir: /javaWork/product-inventory-management/file/temp/uploads
+  upload-dir: /javaWork/product-inventory-management/file/prod/uploads
\ No newline at end of file
diff --git a/src/main/resources/mapper/account/AccountIncomeMapper.xml b/src/main/resources/mapper/account/AccountIncomeMapper.xml
index 4acb504..e4f3361 100644
--- a/src/main/resources/mapper/account/AccountIncomeMapper.xml
+++ b/src/main/resources/mapper/account/AccountIncomeMapper.xml
@@ -76,7 +76,7 @@
                IFNULL(SUM(income_money), 0)            AS amount
         FROM account_income
         WHERE income_date BETWEEN #{startDate} AND #{endDate}
-          AND business_type = 1
+#           AND business_type = 1
         GROUP BY dateStr
         ORDER BY dateStr
 
diff --git a/src/main/resources/mapper/compensationperformance/CompensationPerformanceMapper.xml b/src/main/resources/mapper/compensationperformance/CompensationPerformanceMapper.xml
index f15dd8c..a784c99 100644
--- a/src/main/resources/mapper/compensationperformance/CompensationPerformanceMapper.xml
+++ b/src/main/resources/mapper/compensationperformance/CompensationPerformanceMapper.xml
@@ -3,14 +3,35 @@
 <mapper namespace="com.ruoyi.compensationperformance.mapper.CompensationPerformanceMapper">
 
     <select id="listPage" resultType="com.ruoyi.compensationperformance.pojo.CompensationPerformance">
-        select * from compensation_performance
+        SELECT
+        cp.*,
+        soj.staff_name AS staffName,
+        sp.post_name AS postName,
+        sd.dept_name AS deptName
+        FROM compensation_performance cp
+        LEFT JOIN staff_on_job soj ON soj.id = cp.staff_id
+        LEFT JOIN sys_post sp ON sp.post_id = soj.sys_post_id
+        LEFT JOIN sys_dept sd ON sd.dept_id = soj.sys_dept_id
         <where>
-            <if test="req.name != null and req.name != ''">
-                and `name` like concat('%',#{req.name},'%')
+            <if test="staffName != null and staffName != ''">
+                AND soj.staff_name LIKE CONCAT('%', #{staffName}, '%')
             </if>
-            <if test="req.payDateStr != null and req.payDateStr != ''">
-                and pay_date like concat('%',#{req.payDateStr},'%')
+            <if test="payDateStr != null and payDateStr != ''">
+                AND DATE_FORMAT(cp.pay_date, '%Y-%m') = #{payDateStr}
             </if>
         </where>
+        ORDER BY cp.pay_date DESC, cp.id DESC
+    </select>
+
+    <select id="exportList" resultType="com.ruoyi.compensationperformance.pojo.CompensationPerformance">
+        SELECT cp.*,
+               soj.staff_name AS staffName,
+               sp.post_name   AS postName,
+               sd.dept_name   AS deptName
+        FROM compensation_performance cp
+                 LEFT JOIN staff_on_job soj ON soj.id = cp.staff_id
+                 LEFT JOIN sys_post sp ON sp.post_id = soj.sys_post_id
+                 LEFT JOIN sys_dept sd ON sd.dept_id = soj.sys_dept_id
+        ORDER BY cp.pay_date DESC, cp.id DESC
     </select>
 </mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/production/ProductProcessMapper.xml b/src/main/resources/mapper/production/ProductProcessMapper.xml
index f8ba285..5b1ac18 100644
--- a/src/main/resources/mapper/production/ProductProcessMapper.xml
+++ b/src/main/resources/mapper/production/ProductProcessMapper.xml
@@ -21,14 +21,15 @@
     <select id="calculateProductionStatistics" resultType="com.ruoyi.home.dto.processDataProductionStatisticsDto">
         SELECT
         pp.name AS processName,
-        SUM((ppo.quantity + ppo.scrap_qty) * pp.salary_quota) AS totalInput,
-        SUM(ppo.scrap_qty * pp.salary_quota) AS totalScrap,
-        SUM(ppo.quantity * pp.salary_quota) AS totalOutput
+        SUM(pi.quantity) AS totalInput,
+        SUM(distinct ppo.scrap_qty) AS totalScrap,
+        SUM(distinct (ppo.quantity - ppo.scrap_qty)) AS totalOutput
         FROM
         production_product_output ppo
         INNER JOIN production_product_main ppm ON ppo.product_main_id = ppm.id
         INNER JOIN product_process_route_item ppri ON ppm.product_process_route_item_id = ppri.id
         INNER JOIN product_process pp ON ppri.process_id = pp.id
+        INNER JOIN production_product_input pi ON pi.product_main_id = ppm.id
         <where>
             <if test="startDateTime != null">
                 AND ppo.create_time &gt;= #{startDateTime}
diff --git a/src/main/resources/mapper/production/ProductionProductInputMapper.xml b/src/main/resources/mapper/production/ProductionProductInputMapper.xml
index bc1fdcf..65e2b96 100644
--- a/src/main/resources/mapper/production/ProductionProductInputMapper.xml
+++ b/src/main/resources/mapper/production/ProductionProductInputMapper.xml
@@ -40,14 +40,39 @@
 
     <select id="selectInputStats" resultType="java.util.Map">
         SELECT
-            DATE_FORMAT(create_time, '%Y-%m-%d') as date,
-            SUM(quantity) as quantity
-        FROM
-            production_product_input
-        WHERE
-            create_time &gt;= #{startDate}
-            AND create_time &lt;= #{endDate}
+        DATE_FORMAT(ppi.create_time, '%Y-%m-%d') AS date,
+        -- 鎶ュ伐鏁伴噺 * 鏈�灏忕郴鏁�
+        SUM(ppi.quantity * IFNULL(distinct_ps.unit_quantity, 1)) AS quantity
+        FROM production_product_input ppi
+        INNER JOIN production_product_main ppm ON ppm.id = ppi.product_main_id
+        INNER JOIN product_process_route_item ppri ON ppri.id = ppm.product_process_route_item_id
+        INNER JOIN product_process_route ppr ON ppr.id = ppri.product_route_id
+        INNER JOIN product_model pm ON pm.id = ppi.product_model_id
+        INNER JOIN (
+        SELECT
+        bom_id,
+        process_id,
+        product_model_id,
+        CAST(SUBSTRING_INDEX(GROUP_CONCAT(unit_quantity ORDER BY id ASC), ',', 1) AS DECIMAL(16, 4)) AS unit_quantity
+        FROM product_structure
+        GROUP BY bom_id, process_id, product_model_id
+        ) distinct_ps ON distinct_ps.bom_id = ppr.bom_id
+        AND distinct_ps.process_id = ppri.process_id
+        AND distinct_ps.product_model_id = ppi.product_model_id
+        <where>
+            <if test="startDate != null">
+                AND ppi.create_time &gt;= #{startDate}
+            </if>
+            <if test="endDate != null">
+                AND ppi.create_time &lt;= #{endDate}
+            </if>
+        </where>
         GROUP BY
-            DATE_FORMAT(create_time, '%Y-%m-%d')
+        DATE_FORMAT(ppi.create_time, '%Y-%m-%d'),
+        pm.id,
+        pm.model
+        ORDER BY
+        date DESC,
+        pm.id ASC
     </select>
 </mapper>
diff --git a/src/main/resources/mapper/production/ProductionProductMainMapper.xml b/src/main/resources/mapper/production/ProductionProductMainMapper.xml
index fee9cdc..37e7b27 100644
--- a/src/main/resources/mapper/production/ProductionProductMainMapper.xml
+++ b/src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -18,6 +18,7 @@
         pwo.status as workOrderStatus,
         u.nick_name as nickName,
         p.product_name as productName,
+        pp.name as process,
         pm.model as productModelName,
         ppo.quantity,
         ppo.scrap_qty,
@@ -26,6 +27,8 @@
         from
         production_product_main ppm
         left join product_work_order pwo on pwo.id = ppm.work_order_id
+        left join product_process_route_item ppri on ppri.id = pwo.product_process_route_item_id
+        left join product_process pp on pp.id = ppri.process_id
         left join product_order po on po.id = pwo.product_order_id
         left join production_product_output ppo on ppm.id = ppo.product_main_id
         left join product_model pm on pm.id = ppo.product_model_id
diff --git a/src/main/resources/mapper/production/ProductionProductOutputMapper.xml b/src/main/resources/mapper/production/ProductionProductOutputMapper.xml
index f73e5e4..3b44135 100644
--- a/src/main/resources/mapper/production/ProductionProductOutputMapper.xml
+++ b/src/main/resources/mapper/production/ProductionProductOutputMapper.xml
@@ -49,7 +49,7 @@
     <select id="selectDailyOutputStats" resultType="java.util.Map">
         SELECT
             DATE_FORMAT(create_time, '%Y-%m-%d') as date,
-            SUM(quantity) as quantity
+            SUM(quantity-scrap_qty) as quantity
         FROM
             production_product_output
         WHERE
diff --git a/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml b/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
index 98c2675..f501849 100644
--- a/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
+++ b/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -9,17 +9,18 @@
         SET contract_amount = #{totalTaxInclusiveAmount}
         WHERE id = #{id}
     </update>
+
     <select id="selectPurchaseLedgerListPage" resultType="com.ruoyi.purchase.dto.PurchaseLedgerDto">
-        select
+        SELECT
         pl.id,
-        pl.purchase_contract_number ,
+        pl.purchase_contract_number,
         pl.sales_contract_no,
         pl.supplier_id,
         pl.supplier_name,
         pl.project_name,
         pl.contract_amount,
-        IFNULL(sum(tr.invoice_amount),0) as receipt_payment_amount,
-        pl.contract_amount-IFNULL(sum(tr.invoice_amount),0) AS unReceipt_payment_amount,
+        IFNULL(tr_sum.total_invoice_amount, 0) AS receipt_payment_amount,
+        pl.contract_amount - IFNULL(tr_sum.total_invoice_amount, 0) AS unReceipt_payment_amount,
         pl.entry_date,
         pl.execution_date,
         pl.recorder_id,
@@ -30,42 +31,41 @@
         pl.approval_status,
         pl.payment_method,
         pl.remarks
-        from purchase_ledger pl
-        left join sales_ledger_product slp on slp.sales_ledger_id = pl.id and slp.type=2
-        left join product_record pr on pl.id = pr.purchase_ledger_id
-        left join ticket_registration tr on tr.id = pr.ticket_registration_id
-        left join supplier_manage sm on pl.supplier_id = sm.id
+        FROM purchase_ledger pl
+        LEFT JOIN (
+        SELECT
+        purchase_ledger_id,
+        SUM(invoice_amount) AS total_invoice_amount
+        FROM ticket_registration
+        GROUP BY purchase_ledger_id
+        ) tr_sum ON pl.id = tr_sum.purchase_ledger_id
+        LEFT JOIN supplier_manage sm ON pl.supplier_id = sm.id
         <where>
-            1 = 1
             <if test="c.purchaseContractNumber != null and c.purchaseContractNumber != ''">
-               and pl.purchase_contract_number like concat('%',#{c.purchaseContractNumber},'%')
+                AND pl.purchase_contract_number LIKE CONCAT('%', #{c.purchaseContractNumber}, '%')
             </if>
             <if test="c.approvalStatus != null and c.approvalStatus != ''">
-                and pl.approval_status = #{c.approvalStatus}
+                AND pl.approval_status = #{c.approvalStatus}
             </if>
             <if test="c.supplierName != null and c.supplierName != ''">
-                and pl.supplier_name like concat('%',#{c.supplierName},'%')
+                AND pl.supplier_name LIKE CONCAT('%', #{c.supplierName}, '%')
             </if>
             <if test="c.salesContractNo != null and c.salesContractNo != ''">
-                and pl.sales_contract_no like concat('%',#{c.salesContractNo},'%')
+                AND pl.sales_contract_no LIKE CONCAT('%', #{c.salesContractNo}, '%')
             </if>
             <if test="c.projectName != null and c.projectName != ''">
-                and pl.project_name like concat('%',#{c.projectName},'%')
+                AND pl.project_name LIKE CONCAT('%', #{c.projectName}, '%')
             </if>
-            <if test="c.entryDateStart != null and c.entryDateStart != '' ">
-                AND pl.entry_date &gt;= DATE_FORMAT(#{c.entryDateStart},'%Y-%m-%d')
+            <if test="c.entryDateStart != null and c.entryDateStart != ''">
+                AND pl.entry_date &gt;= #{c.entryDateStart}
             </if>
-            <if test="c.entryDateEnd != null and c.entryDateEnd != '' ">
-                AND  pl.entry_date &lt;= DATE_FORMAT(#{c.entryDateEnd},'%Y-%m-%d')
+            <if test="c.entryDateEnd != null and c.entryDateEnd != ''">
+                AND pl.entry_date &lt;= #{c.entryDateEnd}
             </if>
         </where>
-        group by pl.id, pl.purchase_contract_number, pl.sales_contract_no, pl.supplier_name,
-        pl.project_name,pl.entry_date,
-        pl.recorder_name,
-        pl.contract_amount
-        order by pl.entry_date desc
-
+        ORDER BY pl.entry_date DESC
     </select>
+
     <select id="getPaymentRegistrationDtoById" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto">
         SELECT
             T1.id,
diff --git a/src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml b/src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml
index b15e3f9..5bda4f6 100644
--- a/src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml
+++ b/src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml
@@ -3,8 +3,29 @@
 <mapper namespace="com.ruoyi.quality.mapper.QualityUnqualifiedMapper">
     <select id="qualityUnqualifiedListPage" resultType="com.ruoyi.quality.pojo.QualityUnqualified">
         SELECT
-        *
-        FROM quality_unqualified
+        qu.id,
+        qu.inspect_type,
+        qu.inspect_state,
+        qu.check_time,
+        qu.check_name,
+        qu.product_id,
+        qu.product_name,
+        qu.unit,
+        qu.quantity,
+        qu.defective_phenomena,
+        qu.deal_result,
+        qu.deal_name,
+        qu.deal_time,
+        CASE
+        WHEN qu.model = pm.id THEN pm.model
+        ELSE qu.model
+        END AS model,
+        CASE
+        WHEN qu.model = pm.id THEN true
+        ELSE false
+        END AS method
+        FROM quality_unqualified qu
+        LEFT JOIN product_model pm ON qu.model = pm.id
         where
         1=1
         <if test="qualityUnqualified.inspectType != null ">
@@ -39,4 +60,40 @@
             AND product_name = #{qualityUnqualified.productName}
         </if>
     </select>
+    <select id="getUnqualified" resultType="com.ruoyi.quality.pojo.QualityUnqualified">
+        SELECT
+            qu.id,
+            qu.inspect_type,
+            qu.inspect_state,
+            qu.check_time,
+            qu.check_name,
+            qu.product_id,
+            qu.product_name,
+            qu.unit,
+            qu.quantity,
+            qu.defective_phenomena,
+            qu.deal_result,
+            qu.deal_name,
+            qu.deal_time,
+            CASE
+                WHEN qu.model = pm.id THEN pm.model
+                ELSE qu.model
+                END AS model,
+            CASE
+                WHEN qu.model = pm.id THEN true
+                ELSE false
+                END AS method
+        FROM quality_unqualified qu
+                 LEFT JOIN product_model pm ON qu.model = pm.id
+        where
+            1=1
+        and qu.id = #{id}
+    </select>
+    <select id="getModelId" resultType="java.lang.Long">
+        select pm.id
+        from product_model pm
+        left join product p on pm.product_id=p.id
+        where pm.model=#{model}
+          and  p.product_name=#{productName}
+    </select>
 </mapper>
diff --git a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
index 2c50787..671fcf5 100644
--- a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
+++ b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -8,23 +8,23 @@
         SELECT
         T1.*,
         CASE
-        WHEN t2.qualitity > T1.quantity THEN 1
+        WHEN (IFNULL(t2.qualitity, 0) - IFNULL(t2.locked_quantity, 0)) >= IFNULL(T1.quantity, 0) THEN 1
         ELSE 0
         END as has_sufficient_stock
         FROM
         sales_ledger_product T1
         LEFT JOIN stock_inventory t2 ON T1.product_model_id = t2.product_model_id
         <where>
-            1=1
-            <if test="salesLedgerProduct.salesLedgerId != null and salesLedgerProduct.salesLedgerId != '' ">
+            <if test="salesLedgerProduct.salesLedgerId != null">
                 AND T1.sales_ledger_id = #{salesLedgerProduct.salesLedgerId}
             </if>
-            <if test="salesLedgerProduct.type != null and salesLedgerProduct.type != '' ">
+            <if test="salesLedgerProduct.type != null">
                 AND T1.type = #{salesLedgerProduct.type}
             </if>
         </where>
         ORDER BY T1.register_date DESC
     </select>
+
     <select id="selectSalesLedgerProductByMainId" resultType="com.ruoyi.sales.pojo.SalesLedgerProduct">
         select slp.*
         from quality_inspect qi
@@ -196,11 +196,15 @@
     </select>
 
     <select id="selectProductCountByTypeAndDate" resultType="int">
-        SELECT COUNT(*)
+        SELECT IFNULL(COUNT(*), 0)
         FROM sales_ledger_product
         WHERE type = #{type}
-        AND register_date &gt;= #{startDate}
-        AND register_date &lt;= #{endDate}
+        <if test="startDate != null">
+            AND register_date &gt;= #{startDate}
+        </if>
+        <if test="endDate != null">
+            AND register_date &lt;= #{endDate}
+        </if>
     </select>
 
     <select id="selectRawMaterialExpense" resultType="java.math.BigDecimal">
diff --git a/src/main/resources/mapper/staff/PersonalAttendanceLocationConfigMapper.xml b/src/main/resources/mapper/staff/PersonalAttendanceLocationConfigMapper.xml
new file mode 100644
index 0000000..ef68e68
--- /dev/null
+++ b/src/main/resources/mapper/staff/PersonalAttendanceLocationConfigMapper.xml
@@ -0,0 +1,17 @@
+<?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.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig">
+        <id column="id" property="id" />
+        <result column="sys_dept_id" property="sysDeptId" />
+        <result column="location_name" property="locationName" />
+        <result column="longitude" property="longitude" />
+        <result column="latitude" property="latitude" />
+        <result column="radius" property="radius" />
+        <result column="start_at" property="startAt" />
+        <result column="end_at" property="endAt" />
+    </resultMap>
+
+</mapper>
diff --git a/src/main/resources/mapper/staff/PersonalAttendanceRecordsMapper.xml b/src/main/resources/mapper/staff/PersonalAttendanceRecordsMapper.xml
index 13d3513..7dbb388 100644
--- a/src/main/resources/mapper/staff/PersonalAttendanceRecordsMapper.xml
+++ b/src/main/resources/mapper/staff/PersonalAttendanceRecordsMapper.xml
@@ -1,7 +1,72 @@
-<?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" >
+<?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.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper">
 
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.staff.pojo.PersonalAttendanceRecords">
+        <id column="id" property="id" />
+        <result column="staff_on_job_id" property="staffOnJobId" />
+        <result column="date" property="date" />
+        <result column="work_start_at" property="workStartAt" />
+        <result column="work_end_at" property="workEndAt" />
+        <result column="work_hours" property="workHours" />
+        <result column="status" property="status" />
+        <result column="remark" property="remark" />
+        <result column="tenant_id" property="tenantId" />
+        <result column="create_time" property="createTime" />
+        <result column="update_time" property="updateTime" />
+    </resultMap>
 
+    <select id="listPage" resultType="com.ruoyi.staff.dto.PersonalAttendanceRecordsDto">
+        SELECT
+        personal_attendance_records.*,
+        soj.staff_name as staffName,
+        soj.staff_no as staffNo,
+        sd.dept_name as deptName
+        FROM personal_attendance_records
+        LEFT JOIN
+        staff_on_job soj ON soj.id = personal_attendance_records.staff_on_job_id
+        LEFT JOIN
+        sys_dept sd ON sd.dept_id = soj.sys_dept_id
+        where 1=1
+        <if test="params.staffOnJobId != null and params.staffOnJobId > 0">
+            AND personal_attendance_records.staff_on_job_id = #{params.staffOnJobId}
+        </if>
+        <if test="params.deptId != null and params.deptId > 0">
+            AND sd.dept_id = #{params.deptId}
+        </if>
+        <if test="params.date != null">
+            and personal_attendance_records.date &gt;= #{params.date}
+            and personal_attendance_records.date &lt; DATE_ADD(DATE(#{params.date}), INTERVAL 1 DAY)
+        </if>
+    </select>
 
-</mapper>
\ No newline at end of file
+    <!-- 鏌ヨ鎸囧畾鏃ユ湡娌℃湁鑰冨嫟璁板綍鐨勫湪鑱屽憳宸ワ紙鍦ㄦ寚瀹氭椂闂翠箣鍓嶅叆鑱岀殑锛� -->
+    <select id="selectStaffWithoutAttendanceRecordBeforeTime" resultType="com.ruoyi.staff.pojo.StaffOnJob">
+        SELECT soj.*
+        FROM staff_on_job soj
+        WHERE soj.staff_state = 1
+        AND soj.create_time &lt; #{entryDeadline}
+        AND EXISTS (
+        SELECT 1
+        FROM personal_attendance_location_config palc
+        WHERE palc.sys_dept_id = soj.sys_dept_id
+        )
+        AND NOT EXISTS (
+        SELECT 1
+        FROM personal_attendance_records par
+        WHERE par.staff_on_job_id = soj.id
+        AND par.date = #{date}
+        )
+    </select>
+
+    <!-- 妫�鏌ユ寚瀹氬憳宸ュ湪鎸囧畾鏃ユ湡鏄惁宸插瓨鍦ㄨ�冨嫟璁板綍 -->
+    <select id="existsAttendanceRecord" resultType="boolean">
+        SELECT EXISTS (
+        SELECT 1
+        FROM personal_attendance_records
+        WHERE staff_on_job_id = #{staffOnJobId}
+        AND date = #{date}
+        )
+    </select>
+</mapper>
diff --git a/src/main/resources/mapper/staff/StaffOnJobMapper.xml b/src/main/resources/mapper/staff/StaffOnJobMapper.xml
index 75ae5ef..fe35886 100644
--- a/src/main/resources/mapper/staff/StaffOnJobMapper.xml
+++ b/src/main/resources/mapper/staff/StaffOnJobMapper.xml
@@ -13,7 +13,7 @@
         sys_dept sd ON sd.dept_id = staff_on_job.sys_dept_id
         where 1=1
         <if test="staffOnJob.staffState != null">
-        AND staff_state = #{staffOnJob.staffState}
+            AND staff_state = #{staffOnJob.staffState}
         </if>
         <if test="staffOnJob.staffName != null and staffOnJob.staffName != '' ">
             AND staff_name LIKE CONCAT('%',#{staffOnJob.staffName},'%')
@@ -22,7 +22,7 @@
             AND contract_expire_time &gt;= DATE_FORMAT(#{staffOnJob.entryDateStart},'%Y-%m-%d')
         </if>
         <if test="staffOnJob.entryDateEnd != null and staffOnJob.entryDateEnd != '' ">
-            AND  contract_expire_time &lt;= DATE_FORMAT(#{staffOnJob.entryDateEnd},'%Y-%m-%d')
+            AND contract_expire_time &lt;= DATE_FORMAT(#{staffOnJob.entryDateEnd},'%Y-%m-%d')
         </if>
     </select>
     <select id="staffOnJobList" resultType="com.ruoyi.staff.dto.StaffOnJobDto">
@@ -48,7 +48,7 @@
         SELECT COUNT(*)
         FROM staff_on_job
         WHERE staff_state = 1
-        AND DATE_FORMAT(create_time, '%Y-%m-%d') &lt;= #{date}
+          AND DATE_FORMAT(create_time, '%Y-%m-%d') &lt;= #{date}
     </select>
 
     <!-- 缁熻鎸囧畾鏈堜唤鐨勬柊鍏ヨ亴鍛樺伐鏁� -->
@@ -56,6 +56,23 @@
         SELECT COUNT(*)
         FROM staff_on_job
         WHERE staff_state = 1
-        AND DATE_FORMAT(create_time, '%Y-%m-%d') BETWEEN #{monthStart} AND #{monthEnd}
+          AND DATE_FORMAT(create_time, '%Y-%m-%d') BETWEEN #{monthStart} AND #{monthEnd}
+    </select>
+
+    <select id="selectStaffByNickName" resultType="com.ruoyi.staff.pojo.StaffOnJob" parameterType="java.lang.String">
+        SELECT
+        id
+        nick_name AS staffName
+        FROM staff_on_job
+        WHERE del_flag = '0'
+        <choose>
+            <when test="staffName != null and staffName != ''">
+                AND nick_name = #{staffName}
+            </when>
+            <otherwise>
+                AND 1 = 0
+            </otherwise>
+        </choose>
+        LIMIT 1
     </select>
 </mapper>
diff --git a/src/main/resources/mapper/stock/StockInventoryMapper.xml b/src/main/resources/mapper/stock/StockInventoryMapper.xml
index 7fe1f4f..9db56f9 100644
--- a/src/main/resources/mapper/stock/StockInventoryMapper.xml
+++ b/src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -199,14 +199,16 @@
     </select>
 
     <select id="selectStorageProductCountByDate" resultType="int">
-        SELECT COUNT(*)
-        FROM (SELECT create_time
+        SELECT SUM(total_count)
+        FROM (SELECT COUNT(*) as total_count
               FROM stock_inventory
+              WHERE create_time &gt;= #{startDate}
+                AND create_time &lt;= #{endDate}
               UNION ALL
-              SELECT create_time
-              FROM stock_uninventory) combined
-        WHERE create_time &gt;= #{startDate}
-          AND create_time &lt;= #{endDate}
+              SELECT COUNT(*) as total_count
+              FROM stock_uninventory
+              WHERE create_time &gt;= #{startDate}
+                AND create_time &lt;= #{endDate}) AS combined_counts
     </select>
 
     <select id="selectDailyStockInCounts" resultType="java.util.Map">
diff --git a/src/main/resources/mapper/system/SysMenuMapper.xml b/src/main/resources/mapper/system/SysMenuMapper.xml
index aaf0cd4..20063e3 100644
--- a/src/main/resources/mapper/system/SysMenuMapper.xml
+++ b/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -85,7 +85,7 @@
 		where u.user_id = #{userId} and m.menu_type in ('M', 'C') and m.status = 0  AND ro.status = 0
 		order by m.parent_id, m.order_num
 	</select>
-	
+
 	<select id="selectMenuListByRoleId" resultType="Long">
 		select m.menu_id
 		from sys_menu m
@@ -133,7 +133,14 @@
 		<include refid="selectMenuVo"/>
 		where menu_name=#{menuName} and parent_id = #{parentId} limit 1
 	</select>
-	
+
+	<select id="selectMenuByPath" resultType="com.ruoyi.project.system.domain.SysMenu" parameterType="java.lang.String">
+        SELECT menu_id, menu_name, parent_id, path, app_component, status
+        FROM sys_menu
+        WHERE path = #{path}
+          AND status = '0' LIMIT 1
+    </select>
+
 	<update id="updateMenu" parameterType="com.ruoyi.project.system.domain.SysMenu">
 		update sys_menu
 		<set>
diff --git a/src/main/resources/mapper/system/SysNoticeMapper.xml b/src/main/resources/mapper/system/SysNoticeMapper.xml
index f1aba88..3dd5735 100644
--- a/src/main/resources/mapper/system/SysNoticeMapper.xml
+++ b/src/main/resources/mapper/system/SysNoticeMapper.xml
@@ -31,6 +31,7 @@
                sender_id,
                consignee_id,
                jump_path,
+               app_jump_path,
                tenant_id
         from sys_notice
     </sql>
@@ -75,6 +76,7 @@
         <if test="senderId != null and senderId != ''">sender_id,</if>
         <if test="consigneeId != null and consigneeId != ''">consignee_id,</if>
         <if test="jumpPath != null and jumpPath != ''">jump_path,</if>
+        <if test="appJumpPath != null and appJumpPath != ''">app_jump_path,</if>
         <if test="createBy != null and createBy != ''">create_by,</if>
         <if test="tenantId != null and tenantId != ''">tenant_id,</if>
  			create_time
@@ -87,6 +89,7 @@
         <if test="senderId != null and senderId != ''">#{senderId},</if>
         <if test="consigneeId != null and consigneeId != ''">#{consigneeId},</if>
         <if test="jumpPath != null and jumpPath != ''">#{jumpPath},</if>
+        <if test="appJumpPath != null and appJumpPath != ''">#{appJumpPath},</if>
         <if test="pathParms != null and pathParms != ''">#{queryParms},</if>
         <if test="createBy != null and createBy != ''">#{createBy},</if>
         <if test="tenantId != null and tenantId != ''">#{tenantId},</if>

--
Gitblit v1.9.3