QuYueTing 4 дней назад
Родитель
Сommit
338d948e04
16 измененных файлов с 1387 добавлено и 683 удалено
  1. 36 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/FeishuInfoController.java
  2. 21 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GtemplateTaskFilesController.java
  3. 19 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  4. 71 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GtemplateTaskFiles.java
  5. 3 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserFvTime.java
  6. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/GtemplateTaskFilesMapper.java
  7. 7 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/FeishuInfoService.java
  8. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/GtemplateTaskFilesService.java
  9. 939 675
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java
  10. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/GtemplateTaskFilesServiceImpl.java
  11. 27 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  12. 26 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java
  13. 28 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java
  14. 131 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/TimeZoneConverter.java
  15. 25 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/GtemplateTaskFilesMapper.xml
  16. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserFvTimeMapper.xml

+ 36 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/FeishuInfoController.java

@@ -103,6 +103,42 @@ public class FeishuInfoController {
         return msg;
     }
 
+    @RequestMapping("/refreshCardTime")
+    public HttpRespMsg refreshCardTime(Integer companyId, String userId, String startDate, String endDate, HttpServletRequest request){
+        HttpRespMsg msg = new HttpRespMsg();
+        try {
+            FeishuInfo feishuInfo = feishuInfoService.getOne(new QueryWrapper<FeishuInfo>().eq("company_id",companyId));
+            User targetUser = null;
+            if (userId != null) {
+                targetUser = userMapper.selectById(userId);
+            }
+            msg = feishuInfoService.getCardTimeResult(feishuInfo, targetUser, startDate, endDate);
+        } catch (Exception e) {
+            e.printStackTrace();
+            msg.setError(e.getMessage());
+            return msg;
+        }
+        return msg;
+    }
+
+    @RequestMapping("/refreshLeaveSheet")
+    public HttpRespMsg refreshLeaveSheet(Integer companyId, String userId, String startDate, String endDate, HttpServletRequest request){
+        HttpRespMsg msg = new HttpRespMsg();
+        try {
+            FeishuInfo feishuInfo = feishuInfoService.getOne(new QueryWrapper<FeishuInfo>().eq("company_id",companyId));
+            User targetUser = null;
+            if (userId != null) {
+                targetUser = userMapper.selectById(userId);
+            }
+            msg = feishuInfoService.getApprovalResult(feishuInfo, targetUser, startDate, endDate);
+        } catch (Exception e) {
+            e.printStackTrace();
+            msg.setError(e.getMessage());
+            return msg;
+        }
+        return msg;
+    }
+
     /**
      * 初始化内部应用的系统数据
      * @return

+ 21 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GtemplateTaskFilesController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-11-27
+ */
+@RestController
+@RequestMapping("/gtemplate-task-files")
+public class GtemplateTaskFilesController {
+
+}
+

+ 19 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -2108,6 +2108,25 @@ public class ReportController {
                 }
             }
         }
+        //代填日报时,校验离职人员的日报日期的有效性,不能超过离职日期
+        if (targetUids != null) {
+            Report report = reportList.get(0);
+            User targetUser = targetUserList.stream().filter(t -> t.getId().equals(report.getCreatorId())).findFirst().get();
+            if (targetUser.getIsActive() == 0 && targetUser.getInactiveDate() != null) {
+                String targetDate = null;
+                if (createDate[0].contains("@")) {
+                    //取最后一个日期
+                    targetDate = createDate[0].split("@")[1];
+                } else {
+                    targetDate = createDate[0];
+                }
+                if (targetDate.compareTo(dtf.format(targetUser.getInactiveDate())) > 0) {
+                    HttpRespMsg msg = new HttpRespMsg();
+                    msg.setError("该员工于"+dtf.format(targetUser.getInactiveDate())+"离职,不可填报该日期之后的日报");
+                    return msg;
+                }
+            }
+        }
 
 
         if (createDate[0].contains("@")) {

+ 71 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GtemplateTaskFiles.java

@@ -0,0 +1,71 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-11-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class GtemplateTaskFiles extends Model<GtemplateTaskFiles> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableField("id")
+    private Integer id;
+
+    @TableField("tpl_task_id")
+    private Integer tplTaskId;
+
+    @TableField("project_id")
+    private Integer projectId;
+
+    @TableField("document_name")
+    private String documentName;
+
+    @TableField("server_name")
+    private String serverName;
+
+    @TableField("url")
+    private String url;
+
+    @TableField("indate")
+    private LocalDateTime indate;
+
+    @TableField("size")
+    private String size;
+
+    @TableField("document_type")
+    private Integer documentType;
+
+    /**
+     * 上传人id
+     */
+    @TableField("creator_id")
+    private String creatorId;
+
+    /**
+     * 上传人姓名
+     */
+    @TableField("creator_name")
+    private String creatorName;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return null;
+    }
+
+}

+ 3 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserFvTime.java

@@ -66,6 +66,9 @@ public class UserFvTime extends Model<UserFvTime> {
     @TableField("cancel_normal")
     private Integer cancelNormal;
 
+    @TableField("ask_leave_time")
+    private Double askLeaveTime;
+
     @TableField(exist = false)
     private String name;
 

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

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.GtemplateTaskFiles;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-11-27
+ */
+public interface GtemplateTaskFilesMapper extends BaseMapper<GtemplateTaskFiles> {
+
+}

+ 7 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/FeishuInfoService.java

@@ -4,6 +4,7 @@ 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;
 
@@ -42,4 +43,10 @@ public interface FeishuInfoService extends IService<FeishuInfo> {
     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);
+
+    HttpRespMsg getExpenseFeeResult(FeishuInfo feishuInfo, User targetUser, String startDate, String endDate);
 }

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/GtemplateTaskFilesService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.GtemplateTaskFiles;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-11-27
+ */
+public interface GtemplateTaskFilesService extends IService<GtemplateTaskFiles> {
+
+}

Разница между файлами не показана из-за своего большого размера
+ 939 - 675
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java


+ 20 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/GtemplateTaskFilesServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.GtemplateTaskFiles;
+import com.management.platform.mapper.GtemplateTaskFilesMapper;
+import com.management.platform.service.GtemplateTaskFilesService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2025-11-27
+ */
+@Service
+public class GtemplateTaskFilesServiceImpl extends ServiceImpl<GtemplateTaskFilesMapper, GtemplateTaskFiles> implements GtemplateTaskFilesService {
+
+}

+ 27 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -1269,6 +1269,21 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 reportList = reportList.stream().filter(re->re.getId() == null || !ignoreIds.contains(re.getId())).collect(Collectors.toList());
             }
         }
+        //本次如果是代填日报,需要将老的日报中已驳回的删除掉
+        if (reportList.size() > 0) {
+            if (date != null && !date.contains("@")) {
+                Report oneReport = reportList.get(0);
+                if (oneReport.getId() == null && oneReport.getFillUserid() != null) {
+                    //代填的日报,需要删掉当天存在的已驳回的日报
+                    reportMapper.delete(new QueryWrapper<Report>()
+                            .eq("create_date", date)
+                            .eq("creator_id", oneReport.getCreatorId())
+                            .eq("company_id", oneReport.getCompanyId())
+                            .eq("state", 2));
+                }
+
+            }
+        }
 
         //存在按周填报的情况,需要处理一天一个汇总
         Map<LocalDate, List<Report>> groupMap = reportList.stream().collect(Collectors.groupingBy(Report::getCreateDate));
@@ -5374,6 +5389,11 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 curUserLeaveList.forEach(leave->{
                     LocalDate startDate1 = leave.getStartDate();
                     LocalDate endDate1 = leave.getEndDate();
+                    //取当天的所有请假的合计请假时长
+                    double curLeaveTime = curUserLeaveList.stream().filter(leaveSheet -> leaveSheet.getStartDate().equals(startDate1) && leaveSheet.getEndDate().equals(endDate1))
+                            .mapToDouble(LeaveSheet::getTimeHours).sum();
+                    double curLeaveDays = curUserLeaveList.stream().filter(leaveSheet -> leaveSheet.getStartDate().equals(startDate1) && leaveSheet.getEndDate().equals(endDate1))
+                            .mapToDouble(LeaveSheet::getTimeDays).sum();
                     //该范围内的都算请假
                     int i=0;
                     while(true) {
@@ -5387,11 +5407,13 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                                 //String newStr = (double)find.get().get("workingTime")+"(请假)";
                                 double leaveHours = 0.0;
                                 if (leave.getStartDate().isEqual(leave.getEndDate())) {
-                                    leaveHours = leave.getTimeHours();
+                                    leaveHours = curLeaveTime;
                                 } else {
                                     //跨天请假
-                                    leaveHours = leave.getTimeHours()/leave.getTimeDays();
+                                    leaveHours = curLeaveTime/curLeaveDays;
                                 }
+                                //将leaveHours四舍五入到1位小数
+                                leaveHours = Math.round(leaveHours*10)/10.0;
                                 String newStr = (double)find.get().get("workingTime")+"("+MessageUtils.message("leave.leave")+leaveHours+"h)";
                                 find.get().put("workingTime", newStr);
                             }
@@ -5400,10 +5422,11 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                             if (WorkDayCalculateUtils.isWorkDay(workDate)) {
                                 Map<String, Object> leaveMap = new HashMap<>();
                                 leaveMap.put("createDate", leaveDateStr);
-                                if(leave.getTimeHours() >= timeType.getAllday()){
+                                if(curLeaveTime >= timeType.getAllday()){
                                     leaveMap.put("workingTime", MessageUtils.message("leave.leaveOfDay"));
                                 } else {
-                                    leaveMap.put("workingTime", MessageUtils.message("leave.leave")+leave.getTimeHours()+"h");
+                                    curLeaveTime = Math.round(curLeaveTime*10)/10.0;
+                                    leaveMap.put("workingTime", MessageUtils.message("leave.leave")+curLeaveTime+"h");
                                 }
                                 worktimeList.add(leaveMap);
                             }

+ 26 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java

@@ -1539,7 +1539,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                                             leaveTotalMin = 0;
                                         }
                                         double leaveTotalHour = leaveTotalMin / 60 - minusRest;
-                                        if (showLog) System.out.println("重新计算请假时长:"+leaveStart+"--"+leaveEnd+", 时间间隔="+leaveTotalHour);
+//                                        if (showLog) System.out.println("重新计算请假时长:"+leaveStart+"--"+leaveEnd+", 时间间隔="+leaveTotalHour);
                                         if (ct.getAskLeaveTime() != null && ct.getAskLeaveTime() > 0) {
                                             //可能一天有多个请假单
                                             ct.setAskLeaveTime(ct.getAskLeaveTime() + leaveTotalHour);
@@ -1698,8 +1698,29 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                                         isOldFormat = true;
                                     }
                                     //获取到请假的开始时间和结束时间
+                                    String startDate = s[0];//格式:12/29
+                                    String endDate = s[2];//格式:12/31
                                     String leaveStart = s[1];
                                     String leaveEnd = isOldFormat ? s[3] : s[4];
+                                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd");
+                                    String createDate = formatter.format(ct.getCreateDate());
+
+                                    if (!startDate.equals(endDate)) {
+                                        //跨天请假的情况,需要特殊处理,重新计算开始结束时间
+                                        if (createDate.equals(startDate)) {
+                                            //当前是第一天,下班时间应该是当天下午结束时间
+                                            leaveEnd = baseAfternoonEnd;
+                                        } else if (createDate.equals(endDate)) {
+                                            //当前是中间天,应该是全天
+                                            leaveStart = baseMorningStart;
+                                            leaveEnd = baseAfternoonEnd;
+                                        } else {
+                                            //最后一天,上班时间应该是上午正常上班时间
+                                            leaveStart = baseMorningStart;
+                                        }
+                                    }
+
+                                    if (showLog) System.out.println("====请假时间=" + leaveStart + " - " + leaveEnd + ", baseAfternoonStart" + baseAfternoonStart + " baseAfternoonEnd=" + baseAfternoonEnd + " baseMorningStart=" + baseMorningStart + " baseMorningEnd=" + baseMorningEnd);
                                     //检查请假时间段是否在打卡的时间范围内
                                     if (baseMorningStart.equals(leaveStart) && baseMorningEnd.equals(leaveEnd)) {
                                         morningLeave = true;
@@ -1798,14 +1819,14 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                                     ct.setStartTime(baseMorningStart);
                                     ct.setEndTime(baseAfternoonEnd);
                                     if (showLog) System.out.println("再次校正,全天请假");
-                                } else if (morningLeave){
+                                } else if (morningLeave && ct.getAskLeaveTime() < 6.0) {//加上时长的比对,确保是半天请假
                                     ct.setAskLeaveTime(baseMorningWorkTime);
                                     ct.setWorkHours(baseAfternoonWorkTime);
                                     ct.setCardTime(baseAfternoonWorkTime);
                                     ct.setStartTime(baseAfternoonStart);
                                     ct.setEndTime(baseAfternoonEnd);
                                     if (showLog) System.out.println("再次校正,上午请假");
-                                } else if (afternoonLeave) {
+                                } else if (afternoonLeave && ct.getAskLeaveTime() < 6.0) {//加上时长的比对,确保是半天请假
                                     ct.setAskLeaveTime(baseAfternoonWorkTime);
                                     ct.setWorkHours(baseMorningWorkTime);
                                     ct.setCardTime(baseMorningWorkTime);
@@ -1903,10 +1924,12 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                         ct.setId(item.getId());
                         //之前有的时长不合法,或者新的有打卡时长
                         if (item.getWorkHours() <= 0 || hasTimeRecord) {
+                            if (showLog) System.out.println("更新考勤记录"+curUserid+", "+localDate);
                             userCorpwxTimeMapper.updateById(ct);
                         }
                     } else {
                         if (hasTimeRecord) {
+                            if (showLog) System.out.println("插入考勤记录"+curUserid+", "+localDate);
                             userCorpwxTimeMapper.insert(ct);
                         } else {
                             //调用打卡详情去获取,弥补外出打卡且时间不在自动同步范围内的情况; 仅对工作日有效

+ 28 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -112,6 +112,8 @@ public class TimingTask {
     private ProjectService projectService;
     @Resource
     private OperationRecordService operationRecordService;
+    @Resource
+    private FeishuInfoService feishuInfoService;
     @Value(value = "${upload.path}")
     private String path;
 
@@ -380,6 +382,32 @@ public class TimingTask {
         }
     }
 
+    //每天2:11 同步飞书用户前5天到未来5天时间段的请假
+    @Scheduled(cron = "0 03 9 ? * *")
+    private void synFeiShuLeaveData() {
+        if (isDev) return;
+        if (!isPrivateDeploy) return;
+        List<TimeType> timeTypeList = timeTypeMapper.selectList(new QueryWrapper<TimeType>().eq("sync_fanwei", 1));
+        List<Integer> compIds = timeTypeList.stream().map(TimeType::getCompanyId).collect(Collectors.toList());
+        if (compIds.isEmpty()) {
+            return;
+        }
+        List<FeishuInfo> feishuInfoList = feishuInfoService.list(new QueryWrapper<FeishuInfo>().in("company_id", compIds));
+        for (FeishuInfo feishuInfo : feishuInfoList) {
+            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
+            //需要修改************************************************  日期
+            LocalDateTime yesterday = LocalDateTime.now().minusDays(5);
+            String startDate = dtf.format(yesterday);
+            String endDate = dtf.format(LocalDateTime.now().plusDays(5));
+            //需要修改************************************************  日期
+            try {
+                feishuInfoService.getApprovalResult(feishuInfo, null, startDate, endDate);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
 
     //每天2:11 同步泛微用户前2天到未来30天时间段的打卡,请假,出差数据
     @Scheduled(cron = "0 11 2 ? * *")

+ 131 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/TimeZoneConverter.java

@@ -0,0 +1,131 @@
+package com.management.platform.util;
+
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.Optional;
+
+public class TimeZoneConverter {
+
+    private static final DateTimeFormatter INPUT_FORMATTER =
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+    private static final DateTimeFormatter OUTPUT_FORMATTER =
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+    private static final ZoneId TARGET_ZONE = ZoneId.of("Asia/Shanghai"); // 或者 "UTC+8"
+
+    /**
+     * 将任意时区的时间转换为东八区时间
+     *
+     * @param dateTimeStr 时间字符串,格式:yyyy-MM-dd HH:mm:ss
+     * @param timeZone 时区字符串,可能的值:
+     *                - null 或空字符串:表示UTC时区
+     *                - "UTC":UTC时区
+     *                - "Asia/Shanghai":上海时区
+     *                - "America/New_York":纽约时区
+     *                - 其他合法的时区ID
+     * @return 东八区时间字符串,格式:yyyy-MM-dd HH:mm:ss
+     * @throws IllegalArgumentException 如果时间格式或时区无效
+     */
+    public static String convertToEast8(String dateTimeStr, String timeZone) {
+        // 参数验证
+        validateInput(dateTimeStr);
+        try {
+            // 解析本地时间
+            LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr.trim(), INPUT_FORMATTER);
+
+            // 获取源时区
+            ZoneId sourceZoneId = parseTimeZone(timeZone);
+
+            // 创建带时区的时间
+            ZonedDateTime sourceZonedDateTime = localDateTime.atZone(sourceZoneId);
+
+            // 转换到目标时区(东八区)
+            ZonedDateTime targetZonedDateTime = sourceZonedDateTime.withZoneSameInstant(TARGET_ZONE);
+
+            // 格式化输出
+            return targetZonedDateTime.format(OUTPUT_FORMATTER);
+
+        } catch (DateTimeParseException e) {
+            throw new IllegalArgumentException("时间格式错误,必须为: yyyy-MM-dd HH:mm:ss", e);
+        } catch (DateTimeException e) {
+            throw new IllegalArgumentException("时区格式错误: " + timeZone, e);
+        }
+    }
+
+    /**
+     * 解析时区字符串
+     */
+    private static ZoneId parseTimeZone(String timeZone) {
+        if (timeZone == null || timeZone.trim().isEmpty()) {
+            return ZoneOffset.UTC; // 空字符串表示0时区
+        }
+
+        String tz = timeZone.trim();
+
+        // 处理一些常见别名
+        if (tz.equalsIgnoreCase("Z") ||
+                tz.equalsIgnoreCase("UTC") ||
+                tz.equalsIgnoreCase("GMT")) {
+            return ZoneOffset.UTC;
+        }
+
+        // 处理时区偏移量格式,如 +08:00, -05:00 等
+        if (tz.matches("^[+-]\\d{1,2}(:\\d{2})?$")) {
+            // 标准化偏移量格式
+            if (!tz.contains(":")) {
+                tz = tz + ":00";
+            }
+            return ZoneId.of(tz);
+        }
+
+        // 使用标准时区ID
+        return ZoneId.of(tz);
+    }
+
+    /**
+     * 输入验证
+     */
+    private static void validateInput(String dateTimeStr) {
+        if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) {
+            throw new IllegalArgumentException("时间字符串不能为空");
+        }
+
+        // 简单格式验证
+        if (!dateTimeStr.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
+            throw new IllegalArgumentException("时间格式必须为: yyyy-MM-dd HH:mm:ss");
+        }
+    }
+
+    /**
+     * 获取带有时区信息的时间字符串
+     */
+    public static String convertWithTimeZoneInfo(String dateTimeStr, String timeZone) {
+        String result = convertToEast8(dateTimeStr, timeZone);
+        return String.format("%s (东八区)", result);
+    }
+
+    // 测试示例
+    public static void main(String[] args) {
+        System.out.println("=== 时间转换示例 ===");
+
+        // 示例1: 空时区(UTC 0时区)
+//        System.out.println(convertToEast8("2025-12-12 12:12:12", ""));
+//        // 输出: 2025-12-12 20:12:12
+//
+//        // 示例2: 纽约时间转东八区
+//        System.out.println(convertToEast8("2025-12-12 12:12:12", "America/New_York"));
+        // 输出: 2025-12-13 01:12:12 (纽约比东八区晚13小时)
+
+        // 示例3: 上海时间转东八区(不变)
+        System.out.println(convertToEast8("2025-12-12 12:12:12", "Asia/Shanghai"));
+        // 输出: 2025-12-12 12:12:12
+
+        // 示例4: 使用偏移量
+//        System.out.println(convertToEast8("2025-12-12 12:12:12", "+09:00"));
+//        // 输出: 2025-12-12 11:12:12
+//
+//        // 示例5: 带详细信息
+//        System.out.println(convertWithTimeZoneInfo("2025-12-12 12:12:12", ""));
+        // 输出: 2025-12-12 20:12:12 (东八区)
+    }
+}

+ 25 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/GtemplateTaskFilesMapper.xml

@@ -0,0 +1,25 @@
+<?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.GtemplateTaskFilesMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.GtemplateTaskFiles">
+        <result column="id" property="id" />
+        <result column="tpl_task_id" property="tplTaskId" />
+        <result column="project_id" property="projectId" />
+        <result column="document_name" property="documentName" />
+        <result column="server_name" property="serverName" />
+        <result column="url" property="url" />
+        <result column="indate" property="indate" />
+        <result column="size" property="size" />
+        <result column="document_type" property="documentType" />
+        <result column="creator_id" property="creatorId" />
+        <result column="creator_name" property="creatorName" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, tpl_task_id, project_id, document_name, server_name, url, indate, size, document_type, creator_id, creator_name
+    </sql>
+
+</mapper>

+ 2 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserFvTimeMapper.xml

@@ -12,11 +12,12 @@
         <result column="end_time" property="endTime" />
         <result column="work_hours" property="workHours" />
         <result column="cancel_normal" property="cancelNormal" />
+        <result column="ask_leave_time" property="askLeaveTime" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, work_date, user_id, company_id, start_time, end_time, work_hours, cancel_normal
+        id, work_date, user_id, company_id, start_time, end_time, work_hours, cancel_normal, ask_leave_time
     </sql>
 
     <insert id="batchInsert">