Przeglądaj źródła

支付申请模块前后端开发调试

yusm 1 miesiąc temu
rodzic
commit
27003ab383
21 zmienionych plików z 27639 dodań i 6545 usunięć
  1. 41 2
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/controller/FeishuInfoController.java
  2. 110 0
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/controller/PaymentApplicationController.java
  3. 161 0
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/entity/PaymentApplication.java
  4. 16 0
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/mapper/PaymentApplicationMapper.java
  5. 3 1
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/FeishuInfoService.java
  6. 0 52
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/FeishuInfoService.java~
  7. 18 0
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/PaymentApplicationService.java
  8. 266 7
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java
  9. 97 0
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/impl/PaymentApplicationServiceImpl.java
  10. 11 0
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  11. 31 0
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/resources/mapper/PaymentApplicationMapper.xml
  12. 30 0
      fhKeeper/formulahousekeeper/management-platform-yzr/src/main/resources/sql/2026-04-21.sql
  13. 83 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/demo/MonthUtils.java
  14. 11670 0
      fhKeeper/formulahousekeeper/management-workshop/workshop_print.log
  15. 1 0
      fhKeeper/formulahousekeeper/timesheet-yzr/src/i18n/en.json
  16. 1 0
      fhKeeper/formulahousekeeper/timesheet-yzr/src/i18n/zh.json
  17. 17 0
      fhKeeper/formulahousekeeper/timesheet-yzr/src/routes.js
  18. 8250 4101
      fhKeeper/formulahousekeeper/timesheet-yzr/src/views/corpreport/list.vue
  19. 2118 1089
      fhKeeper/formulahousekeeper/timesheet-yzr/src/views/expense/expense.vue
  20. 2603 0
      fhKeeper/formulahousekeeper/timesheet-yzr/src/views/paymentApplication/paymentApplication.vue
  21. 2112 1293
      fhKeeper/formulahousekeeper/timesheet-yzr/src/views/workReport/dailyReportReview.vue

+ 41 - 2
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/controller/FeishuInfoController.java

@@ -143,7 +143,7 @@ public class FeishuInfoController {
     }
 
     @RequestMapping("/refreshExpenseSheet")
-    public HttpRespMsg refreshExpenseSheet(Integer companyId, String userId, String startDate, String endDate, String ymonth, HttpServletRequest request){
+    public HttpRespMsg refreshFeishuFormData(Integer companyId, String userId, String startDate, String endDate, String ymonth,String refreshType, HttpServletRequest request){
         HttpRespMsg msg = new HttpRespMsg();
         try {
             if (ymonth != null) {
@@ -171,7 +171,46 @@ public class FeishuInfoController {
             if (userId != null) {
                 targetUser = userMapper.selectById(userId);
             }
-            msg = feishuInfoService.getExpenseFeeResult(feishuInfo, targetUser, startDate, endDate);
+            msg = feishuInfoService.refreshExpenseSheet(feishuInfo, targetUser, startDate, endDate,refreshType);
+        } catch (Exception e) {
+            e.printStackTrace();
+            msg.setError(e.getMessage());
+            return msg;
+        }
+        return msg;
+    }
+
+
+    @RequestMapping("/refreshPaymentApplication")
+    public HttpRespMsg refreshPaymentApplication(Integer companyId, String userId, String startDate, String endDate, String ymonth,String refreshType, HttpServletRequest request){
+        HttpRespMsg msg = new HttpRespMsg();
+        try {
+            if (ymonth != null) {
+                startDate = ymonth.replace("-", "") + "01";
+                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
+                //判断当前日期
+                LocalDate now = LocalDate.now();
+                DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
+                LocalDate formatDate = LocalDate.parse(startDate, dtf);
+                if (formatDate.isAfter(now)) {
+                    msg.setError("不可超过当前月");
+                } else if (now.getYear() == formatDate.getYear() && now.getMonth() == formatDate.getMonth()) {
+                    endDate = dtf.format(now);
+                } else {
+                    //计算当月的最后一天
+                    Calendar calendar = Calendar.getInstance();
+                    calendar.set(Calendar.YEAR, Integer.parseInt(ymonth.substring(0, 4)));
+                    calendar.set(Calendar.MONTH, Integer.parseInt(ymonth.substring(5, 7)) - 1);
+                    calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
+                    endDate = simpleDateFormat.format(calendar.getTime());
+                }
+            }
+            FeishuInfo feishuInfo = feishuInfoService.getOne(new QueryWrapper<FeishuInfo>().eq("company_id",companyId));
+            User targetUser = null;
+            if (userId != null) {
+                targetUser = userMapper.selectById(userId);
+            }
+            msg = feishuInfoService.refreshPaymentApplication(feishuInfo, targetUser, startDate, endDate,refreshType);
         } catch (Exception e) {
             e.printStackTrace();
             msg.setError(e.getMessage());

+ 110 - 0
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/controller/PaymentApplicationController.java

@@ -0,0 +1,110 @@
+package com.management.platform.controller;
+
+
+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.extension.plugins.pagination.Page;
+import com.github.pagehelper.util.StringUtil;
+import com.management.platform.entity.Department;
+import com.management.platform.entity.ExpenseSheet;
+import com.management.platform.entity.PaymentApplication;
+import com.management.platform.entity.User;
+import com.management.platform.entity.vo.SysRichFunction;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.DepartmentService;
+import com.management.platform.service.PaymentApplicationService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * <p>
+ * 付款申请表 前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-04-21
+ */
+@RestController
+@RequestMapping("/payment-application")
+public class PaymentApplicationController {
+
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    private PaymentApplicationService paymentApplicationService;
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private DepartmentService departmentService;
+
+    @RequestMapping("/list")
+    public HttpRespMsg list(PaymentApplication paymentApplication){
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        LambdaQueryWrapper<PaymentApplication> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(PaymentApplication::getCompanyId,companyId);
+        if(null!=paymentApplication.getDeptId()){
+            List<Integer> branchDepartment=null;
+            List<Department> departmentList=departmentService.list(new QueryWrapper<Department>().eq("company_id",companyId));
+            branchDepartment= getBranchDepartment(paymentApplication.getDeptId(), departmentList);
+            queryWrapper.in(PaymentApplication::getDeptId,branchDepartment);
+        }
+        if(null!=paymentApplication.getProjectCode()&&StringUtil.isNotEmpty(paymentApplication.getProjectCode())){
+            queryWrapper.like(PaymentApplication::getProjectCode,paymentApplication.getProjectCode());
+        }
+        if(null!=paymentApplication.getStartDate()&&null!=paymentApplication.getEndDate()&&StringUtil.isNotEmpty(paymentApplication.getStartDate())&&StringUtil.isNotEmpty(paymentApplication.getEndDate())){
+            queryWrapper.between(PaymentApplication::getPaymentDate,paymentApplication.getStartDate(),paymentApplication.getEndDate());
+        }
+        IPage<PaymentApplication> page = paymentApplicationService.page(new Page<>(paymentApplication.getPageIndex(), paymentApplication.getPageSize()), queryWrapper);
+        HashMap<String, Object> result = new HashMap<>();
+        result.put("records",page.getRecords());
+        result.put("total",page.getTotal());
+        httpRespMsg.setCode("ok");
+        httpRespMsg.setData(result);
+        return httpRespMsg;
+    }
+
+
+    @RequestMapping("/exportList")
+    public HttpRespMsg exportList(PaymentApplication paymentApplication) {
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        paymentApplication.setCompanyId(user.getCompanyId());
+        return paymentApplicationService.exportList(paymentApplication);
+    }
+
+    private List<Integer> getBranchDepartment(Integer departmentId, List<Department> departmentList) {
+        List<Integer> list = new ArrayList<>();
+        list.add(departmentId);
+        //搜到子部门进行添加
+        for (Department department : departmentList) {
+            if (departmentId.equals(department.getSuperiorId())) {
+                list.addAll(getBranchDepartment(department.getDepartmentId(), departmentList));
+            }
+        }
+        return list;
+    }
+
+    @RequestMapping("/getListByProjectCode")
+    public HttpRespMsg getListByProjectCode(String projectCode){
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        if(null!=projectCode&&StringUtil.isNotEmpty(projectCode)){
+            LambdaQueryWrapper<PaymentApplication> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(PaymentApplication::getProjectCode,projectCode);
+            List<PaymentApplication> list = paymentApplicationService.list(queryWrapper);
+            httpRespMsg.setData(list);
+        }
+        return httpRespMsg;
+    }
+}
+

+ 161 - 0
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/entity/PaymentApplication.java

@@ -0,0 +1,161 @@
+package com.management.platform.entity;
+
+import java.math.BigDecimal;
+
+import com.alibaba.excel.annotation.format.DateTimeFormat;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonAppend;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 付款申请表
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-04-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class PaymentApplication extends Model<PaymentApplication> {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 编码
+     */
+    @TableField("code")
+    private String code;
+
+    /**
+     * 提交人名称
+     */
+    @TableField("submitter_name")
+    private String submitterName;
+
+    /**
+     * 提交人ID
+     */
+    @TableField("submitter_id")
+    private String submitterId;
+
+    /**
+     * 状态
+     */
+    @TableField("status")
+    private Integer status;
+
+    /**
+     * 提交人所属部门名称
+     */
+    @TableField("submitter_dept")
+    private String submitterDept;
+
+    /**
+     * 提交人所属部门ID
+     */
+    @TableField("dept_id")
+    private Integer deptId;
+
+    /**
+     * 付款事由
+     */
+    @TableField("payment_reason")
+    private String paymentReason;
+
+    /**
+     * 付款金额
+     */
+    @TableField("payment_amount")
+    private BigDecimal paymentAmount;
+
+    /**
+     * 项目编号
+     */
+    @TableField("project_code")
+    private String projectCode;
+
+    /**
+     * 付款方式
+     */
+    @TableField("payment_method")
+    private String paymentMethod;
+
+    /**
+     * 付款日期
+     */
+    @TableField("payment_date")
+    @DateTimeFormat("yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate paymentDate;
+
+    /**
+     * 银行账户
+     */
+    @TableField("bank_account")
+    private String bankAccount;
+
+    /**
+     * 流程实例编码
+     */
+    @TableField("instance_code")
+    private String instanceCode;
+
+    /**
+     * 公司ID
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+    /**
+     * 创建时间
+     */
+    @TableField("created_at")
+    @DateTimeFormat("yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime createdAt;
+
+    /**
+     * 更新时间
+     */
+    @TableField("updated_at")
+    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updatedAt;
+
+    @TableField(exist = false)
+    private Integer pageIndex;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private String startDate;
+
+    @TableField(exist = false)
+    private String endDate;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/mapper/PaymentApplicationMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.PaymentApplication;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 付款申请表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-04-21
+ */
+public interface PaymentApplicationMapper extends BaseMapper<PaymentApplication> {
+
+}

+ 3 - 1
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/FeishuInfoService.java

@@ -48,5 +48,7 @@ public interface FeishuInfoService extends IService<FeishuInfo> {
 
     HttpRespMsg getCardTimeResult(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate);
 
-    HttpRespMsg getExpenseFeeResult(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate) throws Exception;
+    HttpRespMsg refreshExpenseSheet(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate,String refreshType) throws Exception;
+
+    HttpRespMsg refreshPaymentApplication(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate, String refreshType) throws Exception;
 }

+ 0 - 52
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/FeishuInfoService.java~

@@ -1,52 +0,0 @@
-package com.management.platform.service;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.management.platform.entity.FeishuInfo;
-import com.management.platform.entity.User;
-import com.management.platform.entity.bo.LoadTaskResultBO;
-import com.management.platform.util.HttpRespMsg;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * <p>
- *  服务类
- * </p>
- *
- * @author Seyason
- * @since 2023-02-27
- */
-public interface FeishuInfoService extends IService<FeishuInfo> {
-
-
-    String getAppAccessToken(FeishuInfo feishuInfo);
-
-    JSONObject getCorpInfo(FeishuInfo feishuInfo);
-
-    JSONObject getUserInfo(FeishuInfo feishuInfo, String feishuUserId);
-
-    Map<String,Object> getAvailableRange(FeishuInfo feishuInfo, String pageToken);
-
-    JSONArray getSubDepartmentList(FeishuInfo feishuInfo, String departmentId, String pageToken);
-
-    JSONArray getDepartmentInfo(FeishuInfo feishuInfo, String departmentId);
-
-    JSONArray getUserInfoWithDepartment(FeishuInfo feishuInfo, String feishuDeptid, String pageToken);
-
-    void batchSendCardTemplateMessage(FeishuInfo feishuInfo, List<String> userIds, String sendTypeName, List<String> templateVariableDetail) throws Exception;
-
-    void batchSendCardMessage(FeishuInfo feishuInfo, List<String> userIds, String sendTypeName, Map<String, String> templateVariableDetail, String pushUrl) throws Exception;
-
-    HttpRespMsg initSuperManager(String corpid, String name);
-
-    HttpRespMsg loadTaskResult(LoadTaskResultBO queryBO);
-
-    HttpRespMsg getApprovalResult(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate) throws Exception;
-
-    HttpRespMsg getCardTimeResult(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate);
-
-    
-}

+ 18 - 0
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/PaymentApplicationService.java

@@ -0,0 +1,18 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.PaymentApplication;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.util.HttpRespMsg;
+
+/**
+ * <p>
+ * 付款申请表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-04-21
+ */
+public interface PaymentApplicationService extends IService<PaymentApplication> {
+
+    HttpRespMsg exportList(PaymentApplication paymentApplication);
+}

+ 266 - 7
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java

@@ -78,10 +78,11 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
 
     public static final String GET_APPROVAL_INSTANCE_INFO = "https://open.feishu.cn/open-apis/approval/v4/instances/:instance_id";
 
-    public static final Map<Integer, String> EXPENSE_APPROVAL_CODE_MAP = new HashMap<>();
+    public static final Map<String, String> EXPENSE_APPROVAL_CODE_MAP = new HashMap<>();
     static {
         //医智锐科技
-        EXPENSE_APPROVAL_CODE_MAP.put(8484, "E17B8057-1847-4BA2-8DDF-BBD28C57B909");
+        EXPENSE_APPROVAL_CODE_MAP.put("ExpenseSheet", "E17B8057-1847-4BA2-8DDF-BBD28C57B909");
+        EXPENSE_APPROVAL_CODE_MAP.put("PaymentApplication", "889F8775-C221-4E77-833D-BA0D8BD085EA");
     }
 
     @Resource
@@ -115,6 +116,12 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
     private ExpenseTypeMapper expenseTypeMapper;
     @Autowired
     private ExpenseMainTypeMapper expenseMainTypeMapper;
+    @Resource
+    private PaymentApplicationMapper paymentApplicationMapper;
+    @Resource
+    private DepartmentMapper departmentMapper;
+    @Resource
+    private DepartmentFeishuMapper departmentFeishuMapper;
 
     @Override
     public String getAppAccessToken(FeishuInfo feishuInfo) {
@@ -981,7 +988,7 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
     }
 
     @Override
-    public HttpRespMsg getExpenseFeeResult(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate) throws Exception {
+    public HttpRespMsg refreshExpenseSheet(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate,String refreshType) throws Exception {
         HttpRespMsg msg = new HttpRespMsg();
         
         if (feishuInfo == null) {
@@ -1010,14 +1017,14 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
                         toDate = end;
                     }
                     System.out.println("分批查询fromDate=" + fromDate + ", toDate=" + toDate);
-                    JSONArray tmpList = getApprovalInstanceList(feishuInfo.getCompanyId(), feishuInfo.getAppId(), formatter.format(fromDate), formatter.format(toDate), userId);
+                    JSONArray tmpList = getApprovalInstanceList(feishuInfo.getCompanyId(), feishuInfo.getAppId(), formatter.format(fromDate), formatter.format(toDate), userId,refreshType);
                     if (tmpList != null && tmpList.size() > 0) {
                         instanceList.addAll(tmpList);
                     }
                 }
 
             } else{
-                instanceList = getApprovalInstanceList(feishuInfo.getCompanyId(), feishuInfo.getAppId(), startDate, endDate, userId);
+                instanceList = getApprovalInstanceList(feishuInfo.getCompanyId(), feishuInfo.getAppId(), startDate, endDate, userId,refreshType);
             }
 
 
@@ -1104,6 +1111,116 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
         
         return msg;
     }
+
+    @Override
+    public HttpRespMsg refreshPaymentApplication(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate,String refreshType) throws Exception {
+        HttpRespMsg msg = new HttpRespMsg();
+
+        if (feishuInfo == null) {
+            msg.setError("飞书信息不能为空");
+            return msg;
+        }
+
+        try {
+            // 第一步:调用GET_APPROVAL_INSTANCE_LIST获取审批实例列表
+            System.out.println("========== 开始获取支付申请审批实例列表 ==========");
+            System.out.println("开始时间: " + startDate + ", 结束时间: " + endDate);
+            String userId = targetUser == null?null:targetUser.getJobNumber();
+
+            //日期间隔如果超过30天,需要分批查询
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+            LocalDate start = LocalDate.parse(startDate, formatter);
+            LocalDate end = LocalDate.parse(endDate, formatter);
+            long daysBetween = ChronoUnit.DAYS.between(start, end);
+            JSONArray instanceList = null;
+            System.out.println("daysBetween==="+daysBetween);
+            if (daysBetween > 29) {
+                instanceList = new JSONArray();
+                for (LocalDate fromDate = start; !fromDate.isAfter(end); fromDate = fromDate.plusDays(30)) {
+                    LocalDate toDate = fromDate.plusDays(29);
+                    if (toDate.isAfter(end)) {
+                        toDate = end;
+                    }
+                    System.out.println("分批查询fromDate=" + fromDate + ", toDate=" + toDate);
+                    JSONArray tmpList = getApprovalInstanceList(feishuInfo.getCompanyId(), feishuInfo.getAppId(), formatter.format(fromDate), formatter.format(toDate), userId,refreshType);
+                    if (tmpList != null && tmpList.size() > 0) {
+                        instanceList.addAll(tmpList);
+                    }
+                }
+
+            } else{
+                instanceList = getApprovalInstanceList(feishuInfo.getCompanyId(), feishuInfo.getAppId(), startDate, endDate, userId,refreshType);
+            }
+            if (instanceList == null || instanceList.size() == 0) {
+                System.out.println("未查询到支付申请审批实例");
+                msg.setData(new JSONArray());
+                return msg;
+            }
+
+            System.out.println("查询到审批实例数量: " + instanceList.size());
+
+            // 第二步:遍历实例列表,调用GET_APPROVAL_INSTANCE_INFO获取每个实例的详情并解析存储
+            int successCount = 0;
+            int skipCount = 0;
+            int errorCount = 0;
+
+            List<String> instanceCodeList = new ArrayList<>();
+            for (int i = 0; i < instanceList.size(); i++) {
+                JSONObject instance = instanceList.getJSONObject(i).getJSONObject("instance");
+                String instanceCode = instance.getString("code");
+                instanceCodeList.add(instanceCode);
+            }
+            for (int i = 0; i < instanceList.size(); i++) {
+                JSONObject instance = instanceList.getJSONObject(i).getJSONObject("instance");
+                String instanceCode = instance.getString("code");
+
+//                System.out.println("========== 处理第 " + (i + 1) + " 个实例 ==========");
+//                System.out.println("实例ID: " + instanceCode);
+
+                try {
+
+                    // 调用接口获取实例详情
+                    JSONObject instanceDetail = getApprovalInstanceInfo(feishuInfo.getAppId(), instanceCode);
+
+                    if (instanceDetail != null) {
+                        // 解析并存储数据
+                        boolean parseResult = parseAndSavePaymentData(instanceDetail, feishuInfo.getCompanyId());
+                        if (parseResult) {
+                            successCount++;
+                            System.out.println("支付申请单处理成功。instance_code: " + instanceCode);
+                        } else {
+                            errorCount++;
+                            System.out.println("支付申请单处理失败。instance_code: " + instanceCode);
+                        }
+                    } else {
+                        errorCount++;
+                        System.out.println("获取实例详情失败,实例ID: " + instanceCode);
+                    }
+                } catch (Exception e) {
+                    errorCount++;
+                    System.out.println("处理实例异常,实例ID: " + instanceCode + ", 异常信息: " + e.getMessage());
+                    e.printStackTrace();
+                }
+            }
+
+            System.out.println("========== 支付申请单数据同步完成 ==========");
+            System.out.println("总数: " + instanceList.size() + ", 成功: " + successCount + ", 跳过: " + skipCount + ", 失败: " + errorCount);
+
+            JSONObject resultData = new JSONObject();
+            resultData.put("total", instanceList.size());
+            resultData.put("success", successCount);
+            resultData.put("skip", skipCount);
+            resultData.put("error", errorCount);
+            msg.setData(resultData);
+
+        } catch (Exception e) {
+            System.out.println("获取支付申请单数据异常: " + e.getMessage());
+            e.printStackTrace();
+            throw e;
+        }
+
+        return msg;
+    }
     
     /**
      * 解析并保存报销单数据
@@ -1318,6 +1435,148 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
             return false;
         }
     }
+
+
+
+    /**
+     * 解析并保存支付申请单数据
+     * @param instanceDetail 实例详情
+     * @param companyId 公司ID
+     * @return 是否成功
+     */
+    private boolean parseAndSavePaymentData(JSONObject instanceDetail, Integer companyId) {
+        try {
+            // 解析基本信息
+            String instanceCode = instanceDetail.getString("instance_code");
+            String userId = instanceDetail.getString("user_id");
+            String departmentId = instanceDetail.getString("department_id");
+            String serialNumber = instanceDetail.getString("serial_number");
+            String status = instanceDetail.getString("status");
+            Long startTime = instanceDetail.getLong("start_time");
+            String formStr = instanceDetail.getString("form");
+            // 根据user_id查询用户信息
+            User user = userMapper.selectOne(
+                    new QueryWrapper<User>()
+                            .eq("job_number", userId)
+                            .eq("company_id", companyId)
+            );
+
+            // 根据department_id查询部门信息
+            DepartmentFeishu departmentFeishu = departmentFeishuMapper.selectOne(new LambdaQueryWrapper<DepartmentFeishu>().eq(DepartmentFeishu::getFeishuDeptid, departmentId));
+            Department department = departmentMapper.selectOne(
+                    new QueryWrapper<Department>()
+                            .eq("feishu_deptid", departmentFeishu.getFeishuOpenDeptid())
+                            .eq("company_id", companyId)
+            );
+
+            if (user == null) {
+                System.out.println("未找到用户,job_number: " + userId);
+                return false;
+            }
+
+            // 解析form字段
+            JSONArray formArray = JSONArray.parseArray(formStr);
+
+            // 提取关键字段
+            String departmentName = null; // 提交人所属部门
+            String paymentReason = null; // 付款事由
+            Double paymentAmount = null; // 付款金额
+            String projectCode = null; // 项目编号
+            String paymentMethod = null; // 付款方式
+            String paymentDate = null; // 付款日期
+            String bankAccount = null; // 银行账户
+            DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
+            for (int i = 0; i < formArray.size(); i++) {
+                JSONObject formItem = formArray.getJSONObject(i);
+                String name = formItem.getString("name");
+
+                if ("提交人所属部门".equals(name)) {
+                    departmentName = formItem.getString("value");
+                } else if ("付款事由,需写明收款方的收款账户".equals(name)) {
+                    paymentReason = formItem.getString("value");
+                } else if ("付款金额".equals(name)) {
+                    Object valueObj = formItem.get("value");
+                    if (valueObj instanceof Number) {
+                        paymentAmount = ((Number) valueObj).doubleValue();
+                    } else if (valueObj instanceof String) {
+                        paymentAmount = Double.parseDouble((String) valueObj);
+                    }
+                } else if ("项目编号".equals(name)) {
+                    projectCode = formItem.getString("value");
+                } else if ("付款方式".equals(name)) {
+                    paymentMethod = formItem.getString("value");
+                }else if ("付款日期".equals(name)) {
+                    String dateValue = formItem.getString("value");
+                    if (!StringUtils.isEmpty(dateValue)) {
+                        try {
+                            // 解析ISO 8601格式的日期时间
+                            LocalDateTime dateTime = LocalDateTime.parse(dateValue, dateFormatter);
+                            paymentDate = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+                        } catch (Exception e) {
+                            System.out.println("日期解析失败: " + dateValue);
+                        }
+                    }
+                }else if ("银行账户".equals(name)) {
+                    JSONObject object = formItem.getJSONObject("value");
+                    String widgetAccountBankName = object.getString("widgetAccountBankName");
+                    bankAccount = object.getString("widgetAccountNumber");
+//                    JSONObject value = JSONObject.parseObject(widgetAccountBankName);
+//                    String text = value.getString("text");
+//                    bankAccount=String.valueOf(JSONObject.parseObject(text).get("bankNameZh"));
+                }
+            }
+            PaymentApplication paymentApplication = new PaymentApplication();
+            paymentApplication.setCompanyId(companyId);
+            paymentApplication.setSubmitterId(user.getId());
+            paymentApplication.setSubmitterName(user.getName());
+            paymentApplication.setInstanceCode(instanceCode);
+            paymentApplication.setSubmitterDept(department.getDepartmentName());
+            paymentApplication.setDeptId(department.getDepartmentId());
+            paymentApplication.setPaymentAmount(new BigDecimal(paymentAmount));
+            paymentApplication.setPaymentReason(paymentReason);
+            paymentApplication.setProjectCode(projectCode);
+            paymentApplication.setPaymentMethod(paymentMethod);
+            paymentApplication.setPaymentDate(LocalDate.parse(paymentDate));
+            paymentApplication.setBankAccount(bankAccount);
+
+            // 设置创建日期(从startTime转换)
+            if (startTime != null) {
+                LocalDateTime createAt = Instant.ofEpochMilli(startTime)
+                        .atZone(ZoneId.of("Asia/Shanghai"))
+                        .toLocalDateTime();
+                paymentApplication.setCreatedAt(createAt);
+            }
+            paymentApplication.setCode(serialNumber);
+            // 设置状态:根据飞书审批状态映射
+            // PENDING-待审核, APPROVED-审核通过, REJECTED-驳回, CANCELED-已撤回
+            Integer sheetStatus = 1; // 默认待审核
+            if ("APPROVED".equals(status)) {
+                sheetStatus = 0; // 审核通过
+            } else if ("REJECTED".equals(status)) {
+                sheetStatus = 2; // 驳回
+            } else if ("CANCELED".equals(status)) {
+                sheetStatus = 3; // 已撤回
+            } else if ("PENDING".equals(status)) {
+                sheetStatus = 1; // 待审核
+            }
+            paymentApplication.setStatus(sheetStatus);
+            // 插入ExpenseSheet
+            PaymentApplication oldPayment = paymentApplicationMapper.selectOne(new LambdaQueryWrapper<PaymentApplication>().eq(PaymentApplication::getCode, serialNumber));
+            if(null==oldPayment){
+                int insertResult = paymentApplicationMapper.insert(paymentApplication);
+                if (insertResult <= 0) {
+                    System.out.println("插入PaymentApplication失败");
+                    return false;
+                }
+            }
+            return true;
+
+        } catch (Exception e) {
+            System.out.println("解析并保存支付申请数据异常: " + e.getMessage());
+            e.printStackTrace();
+            return false;
+        }
+    }
     
     /**
      * 获取审批实例列表
@@ -1326,7 +1585,7 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
      * @param endDate 结束时间 格式:yyyyMMdd
      * @return 审批实例列表
      */
-    private JSONArray getApprovalInstanceList(Integer companyId, String appId, String startDate, String endDate, String userId) throws Exception {
+    private JSONArray getApprovalInstanceList(Integer companyId, String appId, String startDate, String endDate, String userId,String refreshType) throws Exception {
         JSONArray result = new JSONArray();
         
         // 将yyyyMMdd格式转换为时间戳(秒)
@@ -1339,7 +1598,7 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
         
         String url = GET_APPROVAL_INSTANCE_LIST;
         //审批表单的code
-        String approvalCode = EXPENSE_APPROVAL_CODE_MAP.get(companyId);
+        String approvalCode = EXPENSE_APPROVAL_CODE_MAP.get(refreshType);
         HttpHeaders headers = new HttpHeaders();
         MediaType type = MediaType.parseMediaType("application/json; charset=utf-8");
         headers.setContentType(type);

+ 97 - 0
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/impl/PaymentApplicationServiceImpl.java

@@ -0,0 +1,97 @@
+package com.management.platform.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.*;
+import com.management.platform.mapper.PaymentApplicationMapper;
+import com.management.platform.service.ExcelExportService;
+import com.management.platform.service.PaymentApplicationService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.util.ExcelUtil;
+import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.MessageUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 付款申请表 服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-04-21
+ */
+@Service
+public class PaymentApplicationServiceImpl extends ServiceImpl<PaymentApplicationMapper, PaymentApplication> implements PaymentApplicationService {
+
+    @Resource
+    private ExcelExportService excelExportService;
+    @Value(value = "${upload.path}")
+    private String path;
+
+    @Override
+    public HttpRespMsg exportList(PaymentApplication paymentApplication) {
+        Integer companyId = paymentApplication.getCompanyId();
+        DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        QueryWrapper<PaymentApplication> queryWrapper = new QueryWrapper<PaymentApplication>();
+        queryWrapper.eq("company_id", companyId).orderByDesc("id");
+        if (!StringUtils.isEmpty(paymentApplication.getProjectCode())) {
+            queryWrapper.like("project_code", paymentApplication.getProjectCode());
+        }
+        if (!StringUtils.isEmpty(paymentApplication.getStartDate()) && !StringUtils.isEmpty(paymentApplication.getEndDate())) {
+            queryWrapper.between("payment_date", paymentApplication.getStartDate(), paymentApplication.getEndDate());
+        }
+        if (paymentApplication.getDeptId() != null) {
+            queryWrapper.eq("dept_id", paymentApplication.getDeptId());
+        }
+        List<PaymentApplication> records = paymentApplication.selectList(queryWrapper);
+        List<List<String>> allList=new ArrayList<>();
+        List<String> titleList=new ArrayList<>();
+        titleList.add("提交人所属部门");
+        titleList.add("付款事由");
+        titleList.add("付款金额");
+        titleList.add("项目编号");
+        titleList.add("付款方式");
+        titleList.add("付款日期");
+        titleList.add("银行账户");
+        titleList.add("状态");
+
+        allList.add(titleList);
+        for (PaymentApplication record : records) {
+            ArrayList<String> itemList = new ArrayList<>();
+            Integer status = record.getStatus();
+            String statusStr="";
+            switch (status){
+                case 0:statusStr="审核通过";
+                    break;
+                case 1:statusStr="驳回";
+                    break;
+                case 2:statusStr="已撤回";
+                    break;
+                case 3:statusStr="待审核";
+                    break;
+            }
+            itemList.add(record.getSubmitterDept());
+            itemList.add(record.getPaymentReason());
+            itemList.add(String.valueOf(record.getPaymentAmount().doubleValue()));
+            itemList.add(record.getProjectCode());
+            itemList.add(record.getPaymentMethod());
+            itemList.add(df.format(record.getPaymentDate()));
+            itemList.add(record.getBankAccount());
+            itemList.add(statusStr);
+            allList.add(itemList);
+        }
+        HttpRespMsg msg = new HttpRespMsg();
+        //生成excel文件导出
+        String fileName = "支付申请单据列表"+System.currentTimeMillis();
+        String resp = ExcelUtil.exportGeneralExcelByTitleAndList(fileName , allList, path);
+        msg.data = resp;
+        return msg;
+    }
+}

+ 11 - 0
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -274,6 +274,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
 
     @Resource
     private ProjectLeaderService projectLeaderService;
+    @Resource
+    private PaymentApplicationMapper paymentApplicationMapper;
 
     @Value(value = "${upload.path}")
     private String path;
@@ -4471,10 +4473,19 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         List<ExpenseMainType> expenseMainTypes = expenseMainTypeMapper.selectList(new QueryWrapper<ExpenseMainType>().eq("company_id", companyId));
         List<ExpenseSheet> expenseSheetList = expenseSheetMapper.selectList(new QueryWrapper<ExpenseSheet>().eq("company_id", companyId).eq("status", 0));
         List<ExpenseItem> expenseItemList = expenseItemMapper.selectList(new QueryWrapper<ExpenseItem>().in("expense_id", expenseSheetList.stream().map(ExpenseSheet::getId).collect(Collectors.toList())));
+        List<String> projectCodeList = projectTask.stream().map(i -> String.valueOf(i.get("projectCode"))).distinct().collect(Collectors.toList());
+        List<PaymentApplication> paymentApplicationList = paymentApplicationMapper.selectList(new LambdaQueryWrapper<PaymentApplication>().in(PaymentApplication::getProjectCode, projectCodeList).eq(PaymentApplication::getStatus, 0));
         for (Map<String, Object> map : projectTask) {
             BigDecimal bigDecimal=new BigDecimal(0);
             List<Map<String,Object>> itemList=new ArrayList<>();
             Integer curProjectId = (Integer)map.get("id");
+            String curProjectCode = String.valueOf(map.get("projectCode"));
+            BigDecimal decimal = new BigDecimal(0);
+            List<PaymentApplication> curPaymentList = paymentApplicationList.stream().filter(i -> i.getProjectCode().equals(curProjectCode)).collect(Collectors.toList());
+            for (PaymentApplication paymentApplication : curPaymentList) {
+                decimal=decimal.add(paymentApplication.getPaymentAmount());
+            }
+            map.put("paymentApplicationAmount",decimal.doubleValue());
             for (ExpenseMainType expenseMainType : expenseMainTypes) {
                 Map<String,Object> item=new HashMap<>();
                 item.put("type",expenseMainType.getId());

+ 31 - 0
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/resources/mapper/PaymentApplicationMapper.xml

@@ -0,0 +1,31 @@
+<?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.management.platform.mapper.PaymentApplicationMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.PaymentApplication">
+        <id column="id" property="id" />
+        <result column="code" property="code" />
+        <result column="submitter_name" property="submitterName" />
+        <result column="submitter_id" property="submitterId" />
+        <result column="submitter_dept" property="submitterDept" />
+        <result column="dept_id" property="deptId" />
+        <result column="payment_reason" property="paymentReason" />
+        <result column="payment_amount" property="paymentAmount" />
+        <result column="project_code" property="projectCode" />
+        <result column="project_id" property="projectId" />
+        <result column="payment_method" property="paymentMethod" />
+        <result column="payment_date" property="paymentDate" />
+        <result column="bank_account" property="bankAccount" />
+        <result column="instance_code" property="instanceCode" />
+        <result column="company_id" property="companyId" />
+        <result column="created_at" property="createdAt" />
+        <result column="updated_at" property="updatedAt" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, code, submitter_name, submitter_id, submitter_dept, dept_id, payment_reason, payment_amount, project_code, project_id, payment_method, payment_date, bank_account, instance_code, company_id, created_at, updated_at
+    </sql>
+
+</mapper>

+ 30 - 0
fhKeeper/formulahousekeeper/management-platform-yzr/src/main/resources/sql/2026-04-21.sql

@@ -0,0 +1,30 @@
+CREATE TABLE `payment_application`  (
+  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+  `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '编码',
+  `submitter_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '提交人名称',
+  `submitter_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '提交人ID',
+  `submitter_dept` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '提交人所属部门名称',
+  `dept_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '提交人所属部门ID',
+  `payment_reason` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '付款事由',
+  `payment_amount` decimal(18, 2) NOT NULL COMMENT '付款金额',
+  `project_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '项目编号',
+  `status` int UNSIGNED NULL DEFAULT NULL COMMENT '状态',
+  `payment_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '付款方式',
+  `payment_date` date NOT NULL COMMENT '付款日期',
+  `bank_account` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '银行账户',
+  `instance_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '实例编码',
+  `company_id` int UNSIGNED NULL DEFAULT NULL COMMENT '公司ID',
+  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_code`(`code`) USING BTREE,
+  INDEX `idx_company_id`(`company_id`) USING BTREE,
+  INDEX `idx_project_code`(`project_code`) USING BTREE,
+  INDEX `idx_payment_date`(`payment_date`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '付款申请表' ROW_FORMAT = Dynamic;
+
+
+#按照顺序执行
+INSERT INTO sys_module VALUES(null,'支付申请','/paymentApplication',null,null,13,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0);
+select id from sys_module where name="支付申请";
+insert into sys_role_module values(55733,33);

+ 83 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/demo/MonthUtils.java

@@ -0,0 +1,83 @@
+package com.management.platform.demo;
+
+import java.time.*;
+import java.time.format.*;
+import java.time.temporal.*;
+import java.util.*;
+import java.util.stream.*;
+
+public class MonthUtils {
+
+    /**
+     * 获取月份信息
+     * @param yearMonthStr 格式 "yyyy-MM"(如 "2023-05")
+     * @param holidays 法定节假日列表(如 ["2023-05-01", "2023-05-02"])
+     * @return Map<String, Object> 包含月份名称、第一天、最后一天、工作日天数
+     */
+    public static Map<String, Object> getMonthInfo(String yearMonthStr, List<String> holidays) {
+        // 解析输入
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+        YearMonth yearMonth = YearMonth.parse(yearMonthStr, formatter);
+
+        // 1. 月份名称(本地化)
+        String monthName = yearMonth.getMonth().getDisplayName(TextStyle.FULL, Locale.CHINA);
+
+        // 2. 月份的第一天
+        LocalDate firstDay = yearMonth.atDay(1);
+
+        // 3. 月份的最后一天
+        LocalDate lastDay = yearMonth.atEndOfMonth();
+
+        // 4. 计算工作日天数(排除周末和法定节假日)
+        long workDays = calculateWorkDays(yearMonth, holidays);
+
+        // 返回结果
+        Map<String, Object> result = new HashMap<>();
+        result.put("monthName", monthName);  // 月份名称(如 "五月")
+        result.put("firstDay", firstDay);     // 月份第一天(LocalDate)
+        result.put("lastDay", lastDay);       // 月份最后一天(LocalDate)
+        result.put("workDays", workDays);     // 工作日天数(long)
+        return result;
+    }
+
+    /**
+     * 计算某个月的工作日天数(排除周末和法定节假日)
+     */
+    private static long calculateWorkDays(YearMonth yearMonth, List<String> holidays) {
+        // 获取月份的所有日期
+        List<LocalDate> datesInMonth = IntStream.rangeClosed(1, yearMonth.lengthOfMonth())
+                .mapToObj(day -> yearMonth.atDay(day))
+                .collect(Collectors.toList());
+
+        // 过滤:排除周末 + 法定节假日
+        return datesInMonth.stream()
+                .filter(date -> {
+                    // 1. 排除周六、周日
+                    DayOfWeek dayOfWeek = date.getDayOfWeek();
+                    if (dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY) {
+                        return false;
+                    }
+                    // 2. 排除法定节假日
+                    String dateStr = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
+                    return !holidays.contains(dateStr);
+                })
+                .count();
+    }
+
+    public static void main(String[] args) {
+        // 示例:2023年5月,假设法定节假日是 ["2023-05-01", "2023-05-02", "2023-05-03"]
+        List<String> holidays = Arrays.asList("2025-01-01",
+                "2025-01-28", "2025-01-29", "2025-01-30", "2025-01-31", "2025-02-03", "2025-02-04",
+                "2025-04-04",
+                "2025-05-01", "2025-05-02", "2025-05-05",
+                "2025-06-02",
+                "2025-10-01", "2025-10-02", "2025-10-03", "2025-10-06", "2025-10-07", "2025-10-08" );
+        Map<String, Object> monthInfo = getMonthInfo("2023-07", holidays);
+
+        // 输出结果
+        System.out.println("月份名称: " + monthInfo.get("monthName")); // 五月
+        System.out.println("第一天: " + monthInfo.get("firstDay"));    // 2023-05-01
+        System.out.println("最后一天: " + monthInfo.get("lastDay"));  // 2023-05-31
+        System.out.println("工作日天数: " + monthInfo.get("workDays")); // 23(假设5月有23个工作日)
+    }
+}

Plik diff jest za duży
+ 11670 - 0
fhKeeper/formulahousekeeper/management-workshop/workshop_print.log


+ 1 - 0
fhKeeper/formulahousekeeper/timesheet-yzr/src/i18n/en.json

@@ -20,6 +20,7 @@
     "customerManagement": "Customer management",
     "engineeringProfessionalManagement": "Engineering professional Management",
     "reimbursement": "reimbursement",
+    "paymentApplication": "payment application",
     "researchCenterManagement": "Research Center Management",
     "supplierManagement": "Supplier Management",
     "organizationalStructure": "Organizational structure",

+ 1 - 0
fhKeeper/formulahousekeeper/timesheet-yzr/src/i18n/zh.json

@@ -20,6 +20,7 @@
     "customerManagement": "客户管理",
     "engineeringProfessionalManagement": "工程专业管理",
     "reimbursement": "费用报销",
+    "paymentApplication": "支付申请",
     "researchCenterManagement": "研究中心管理",
     "supplierManagement": "供应商管理",
     "organizationalStructure": "组织架构",

+ 17 - 0
fhKeeper/formulahousekeeper/timesheet-yzr/src/routes.js

@@ -104,6 +104,9 @@ import userGrouping from './views/userGrouping/userGrouping.vue'
 // 设备管理
 import deviceManagement from './views/deviceManagement/deviceManagement'
 
+//支付申请
+import paymentApplication from './views/paymentApplication/paymentApplication.vue'
+
 Vue.use(Router)
 
 export const fixedRouter = [
@@ -429,6 +432,20 @@ export const allRouters = [//组织架构
         // 其他信息
         meta: { text: 'navigation.reimbursement' } 
     },
+
+    // 支付申请模块
+    {
+        path: '/',
+        component: Home,
+        name: '支付申请',
+        iconCls: 'iconfont firerock-iconbaoxiao',
+        leaf: true,
+        children: [
+            { path: '/paymentApplication', component: paymentApplication, name: '支付申请' }
+        ],
+        // 其他信息
+        meta: { text: 'navigation.paymentApplication' } 
+    },
     
     {
         path: '/',

Plik diff jest za duży
+ 8250 - 4101
fhKeeper/formulahousekeeper/timesheet-yzr/src/views/corpreport/list.vue


Plik diff jest za duży
+ 2118 - 1089
fhKeeper/formulahousekeeper/timesheet-yzr/src/views/expense/expense.vue


Plik diff jest za duży
+ 2603 - 0
fhKeeper/formulahousekeeper/timesheet-yzr/src/views/paymentApplication/paymentApplication.vue


Plik diff jest za duży
+ 2112 - 1293
fhKeeper/formulahousekeeper/timesheet-yzr/src/views/workReport/dailyReportReview.vue