From 2ae58a2f2d53c220c4b02d8e9f17770f63397b1e Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期四, 26 二月 2026 10:40:18 +0800
Subject: [PATCH] 人力资源模块迁移
---
src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceRecords.java | 86 ++-
src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceRecordsMapper.java | 22 +
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java | 35 +
src/main/java/com/ruoyi/staff/pojo/StaffContract.java | 1
src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java | 241 +++++++++++
src/main/java/com/ruoyi/staff/mapper/StaffLeaveMapper.java | 7
src/main/java/com/ruoyi/staff/vo/MonthlyTurnoverRateVo.java | 39 +
src/main/java/com/ruoyi/staff/controller/StaffContractController.java | 4
src/main/java/com/ruoyi/staff/dto/StaffLeaveDto.java | 10
src/main/java/com/ruoyi/staff/service/impl/StaffLeaveServiceImpl.java | 24 +
src/main/java/com/ruoyi/staff/service/AnalyticsService.java | 20 +
src/main/resources/mapper/production/ProductOrderMapper.xml | 5
src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceLocationConfigServiceImpl.java | 20 +
src/main/java/com/ruoyi/staff/controller/StaffSchedulingController.java | 1
src/main/java/com/ruoyi/staff/task/PersonalAttendanceRecordsTask.java | 75 +++
src/main/java/com/ruoyi/staff/dto/SaveStaffSchedulingDto.java | 2
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/staff/mapper/StaffContractMapper.java | 4
src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java | 28 +
src/main/java/com/ruoyi/staff/controller/AnalyticsController.java | 32 +
src/main/java/com/ruoyi/staff/controller/PersonalAttendanceLocationConfigController.java | 49 ++
src/main/java/com/ruoyi/staff/pojo/HolidayApplication.java | 1
src/main/java/com/ruoyi/staff/pojo/StaffLeave.java | 3
src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceLocationConfig.java | 59 ++
src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java | 1
src/main/java/com/ruoyi/staff/pojo/StaffOnJob.java | 2
src/main/java/com/ruoyi/staff/service/PersonalAttendanceRecordsService.java | 19
src/main/java/com/ruoyi/staff/vo/TotalTurnoverRateVo.java | 19
src/main/java/com/ruoyi/staff/service/impl/AnalyticsServiceImpl.java | 176 ++++++++
src/main/java/com/ruoyi/staff/service/PersonalAttendanceLocationConfigService.java | 16
src/main/java/com/ruoyi/staff/dto/StaffSchedulingDto.java | 1
src/main/java/com/ruoyi/staff/dto/PersonalAttendanceRecordsDto.java | 41 ++
src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java | 68 +-
35 files changed, 1,061 insertions(+), 106 deletions(-)
diff --git a/src/main/java/com/ruoyi/staff/controller/AnalyticsController.java b/src/main/java/com/ruoyi/staff/controller/AnalyticsController.java
new file mode 100644
index 0000000..cfa802c
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/controller/AnalyticsController.java
@@ -0,0 +1,32 @@
+package com.ruoyi.staff.controller;
+
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.staff.service.AnalyticsService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@RestController
+@RequestMapping("/staff/analytics")
+public class AnalyticsController {
+
+ @Resource
+ private AnalyticsService analyticsService;
+
+ @GetMapping("/reason")
+ public AjaxResult staffLeaveReasonAnalytics() {
+ return AjaxResult.success(analyticsService.staffLeaveReasonAnalytics());
+ }
+
+ @GetMapping("/monthly_turnover_rate")
+ public AjaxResult getMonthlyTurnoverRateFor12Months() {
+ return AjaxResult.success(analyticsService.getMonthlyTurnoverRateFor12Months());
+ }
+
+ @GetMapping("/total_statistic")
+ public AjaxResult getTotalStatistic() {
+ return AjaxResult.success(analyticsService.getTotalStatistic());
+ }
+}
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..fbc4fa3
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceLocationConfigController.java
@@ -0,0 +1,49 @@
+package com.ruoyi.staff.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
+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.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..8750cbf 100644
--- a/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java
+++ b/src/main/java/com/ruoyi/staff/controller/PersonalAttendanceRecordsController.java
@@ -2,44 +2,52 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
-import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
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/controller/StaffContractController.java b/src/main/java/com/ruoyi/staff/controller/StaffContractController.java
index af4c90c..3a8132c 100644
--- a/src/main/java/com/ruoyi/staff/controller/StaffContractController.java
+++ b/src/main/java/com/ruoyi/staff/controller/StaffContractController.java
@@ -5,7 +5,9 @@
import com.ruoyi.staff.pojo.StaffContract;
import com.ruoyi.staff.service.StaffContractService;
import io.swagger.annotations.Api;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
diff --git a/src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java b/src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java
index 8e3d6b6..5b5694b 100644
--- a/src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java
+++ b/src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java
@@ -16,7 +16,6 @@
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
-import javax.validation.Valid;
import java.util.List;
/**
diff --git a/src/main/java/com/ruoyi/staff/controller/StaffSchedulingController.java b/src/main/java/com/ruoyi/staff/controller/StaffSchedulingController.java
index a54096a..d4fa3b3 100644
--- a/src/main/java/com/ruoyi/staff/controller/StaffSchedulingController.java
+++ b/src/main/java/com/ruoyi/staff/controller/StaffSchedulingController.java
@@ -2,7 +2,6 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.compensationperformance.pojo.CompensationPerformance;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
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..dc81b1e
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/dto/PersonalAttendanceRecordsDto.java
@@ -0,0 +1,41 @@
+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 lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+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/dto/SaveStaffSchedulingDto.java b/src/main/java/com/ruoyi/staff/dto/SaveStaffSchedulingDto.java
index 7e57745..2bff5a5 100644
--- a/src/main/java/com/ruoyi/staff/dto/SaveStaffSchedulingDto.java
+++ b/src/main/java/com/ruoyi/staff/dto/SaveStaffSchedulingDto.java
@@ -1,12 +1,10 @@
package com.ruoyi.staff.dto;
-import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
-import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
diff --git a/src/main/java/com/ruoyi/staff/dto/StaffLeaveDto.java b/src/main/java/com/ruoyi/staff/dto/StaffLeaveDto.java
index 7cdf48a..3685410 100644
--- a/src/main/java/com/ruoyi/staff/dto/StaffLeaveDto.java
+++ b/src/main/java/com/ruoyi/staff/dto/StaffLeaveDto.java
@@ -1,11 +1,8 @@
package com.ruoyi.staff.dto;
-import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import com.ruoyi.staff.pojo.StaffLeave;
import lombok.Data;
-
-import java.util.Date;
@Data
public class StaffLeaveDto extends StaffLeave {
@@ -95,4 +92,11 @@
*/
@Excel(name = "绱ф�ヨ仈绯讳汉鐢佃瘽", sort = 15)
private String emergencyContactPhone;
+
+ private int count;
+
+ /**
+ * 绂昏亴鍘熷洜鏂囨湰
+ */
+ private String reasonText;
}
diff --git a/src/main/java/com/ruoyi/staff/dto/StaffSchedulingDto.java b/src/main/java/com/ruoyi/staff/dto/StaffSchedulingDto.java
index 727b773..a60994f 100644
--- a/src/main/java/com/ruoyi/staff/dto/StaffSchedulingDto.java
+++ b/src/main/java/com/ruoyi/staff/dto/StaffSchedulingDto.java
@@ -1,7 +1,6 @@
package com.ruoyi.staff.dto;
import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
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..bb4ed56
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceLocationConfigMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.staff.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
+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..38dce08 100644
--- a/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceRecordsMapper.java
+++ b/src/main/java/com/ruoyi/staff/mapper/PersonalAttendanceRecordsMapper.java
@@ -1,9 +1,31 @@
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.pojo.PersonalAttendanceRecords;
+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/StaffContractMapper.java b/src/main/java/com/ruoyi/staff/mapper/StaffContractMapper.java
index 9545082..1d8b83f 100644
--- a/src/main/java/com/ruoyi/staff/mapper/StaffContractMapper.java
+++ b/src/main/java/com/ruoyi/staff/mapper/StaffContractMapper.java
@@ -4,13 +4,9 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.staff.dto.StaffContractDto;
-import com.ruoyi.staff.dto.StaffOnJobDto;
import com.ruoyi.staff.pojo.StaffContract;
-import com.ruoyi.staff.pojo.StaffOnJob;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
@Mapper
public interface StaffContractMapper extends BaseMapper<StaffContract> {
diff --git a/src/main/java/com/ruoyi/staff/mapper/StaffLeaveMapper.java b/src/main/java/com/ruoyi/staff/mapper/StaffLeaveMapper.java
index e8d2854..0ba632a 100644
--- a/src/main/java/com/ruoyi/staff/mapper/StaffLeaveMapper.java
+++ b/src/main/java/com/ruoyi/staff/mapper/StaffLeaveMapper.java
@@ -4,12 +4,11 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.staff.dto.StaffLeaveDto;
-import com.ruoyi.staff.dto.StaffOnJobDto;
import com.ruoyi.staff.pojo.StaffLeave;
-import com.ruoyi.staff.pojo.StaffOnJob;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
+import java.time.LocalDate;
import java.util.List;
@@ -18,4 +17,8 @@
IPage<StaffLeaveDto> staffLeaveListPage(Page page, @Param("c") StaffLeaveDto staffLeaveDto);
List<StaffLeaveDto> staffLeaveList(@Param("c") StaffLeaveDto staffLeaveDto);
+
+ List<StaffLeaveDto> staffLeaveReasonAnalytics();
+
+ Integer countLeaveByMonth(@Param("monthStart") LocalDate monthStart, @Param("monthEnd") LocalDate monthEnd);
}
diff --git a/src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java b/src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java
index 1451487..de8a3c0 100644
--- a/src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java
+++ b/src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java
@@ -8,6 +8,7 @@
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
+import java.time.LocalDate;
import java.util.List;
@Mapper
@@ -16,4 +17,29 @@
IPage<StaffOnJobDto> staffOnJobListPage(Page page, @Param("staffOnJob") StaffOnJob staffOnJob);
List<StaffOnJobDto> staffOnJobList(@Param("staffOnJob") StaffOnJob staffOnJob);
-}
+
+ /**
+ * 缁熻鎸囧畾鏃ユ湡鐨勫湪鑱屽憳宸ユ暟
+ *
+ * @param date 鏃ユ湡
+ * @return 鍦ㄨ亴鍛樺伐鏁�
+ */
+ Integer countOnJobStaffByDate(@Param("date") LocalDate date);
+
+ /**
+ * 缁熻鎸囧畾鏈堜唤鐨勬柊鍏ヨ亴鍛樺伐鏁�
+ *
+ * @param monthStart 鏈堜唤寮�濮嬫棩鏈�
+ * @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/HolidayApplication.java b/src/main/java/com/ruoyi/staff/pojo/HolidayApplication.java
index b76893e..40ef116 100644
--- a/src/main/java/com/ruoyi/staff/pojo/HolidayApplication.java
+++ b/src/main/java/com/ruoyi/staff/pojo/HolidayApplication.java
@@ -6,7 +6,6 @@
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
-import java.time.LocalTime;
@Data
@TableName("holiday_application")
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..c4808d2
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceLocationConfig.java
@@ -0,0 +1,59 @@
+package com.ruoyi.staff.pojo;
+
+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 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.LocalTime;
+
+/**
+ * <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..e3f4bd9 100644
--- a/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceRecords.java
+++ b/src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceRecords.java
@@ -3,50 +3,78 @@
import com.baomidou.mybatisplus.annotation.*;
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.math.BigDecimal;
import java.time.LocalDate;
-import java.time.LocalTime;
+import java.time.LocalDateTime;
-@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/StaffContract.java b/src/main/java/com/ruoyi/staff/pojo/StaffContract.java
index 9b2afee..532a59e 100644
--- a/src/main/java/com/ruoyi/staff/pojo/StaffContract.java
+++ b/src/main/java/com/ruoyi/staff/pojo/StaffContract.java
@@ -4,7 +4,6 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
diff --git a/src/main/java/com/ruoyi/staff/pojo/StaffLeave.java b/src/main/java/com/ruoyi/staff/pojo/StaffLeave.java
index 3f5532c..f5d6326 100644
--- a/src/main/java/com/ruoyi/staff/pojo/StaffLeave.java
+++ b/src/main/java/com/ruoyi/staff/pojo/StaffLeave.java
@@ -3,13 +3,10 @@
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
-import java.util.Date;
@TableName("staff_leave")
@Data
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/AnalyticsService.java b/src/main/java/com/ruoyi/staff/service/AnalyticsService.java
new file mode 100644
index 0000000..ee8ff83
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/service/AnalyticsService.java
@@ -0,0 +1,20 @@
+package com.ruoyi.staff.service;
+
+import com.ruoyi.staff.dto.StaffLeaveDto;
+import com.ruoyi.staff.vo.MonthlyTurnoverRateVo;
+import com.ruoyi.staff.vo.TotalTurnoverRateVo;
+
+import java.util.List;
+
+public interface AnalyticsService {
+
+ List<StaffLeaveDto> staffLeaveReasonAnalytics();
+
+ List<MonthlyTurnoverRateVo> getMonthlyTurnoverRateFor12Months();
+
+ /**
+ * 鏌ヨ鎬绘祦鍔ㄧ巼銆佹祦澶辩巼浠ュ強鍦ㄨ亴鍛樺伐鏁�
+ * @return 鎬荤粺璁$粨鏋�
+ */
+ TotalTurnoverRateVo getTotalStatistic();
+}
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..2451cf9
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/service/PersonalAttendanceLocationConfigService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.staff.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
+
+/**
+ * <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..8b14da3 100644
--- a/src/main/java/com/ruoyi/staff/service/PersonalAttendanceRecordsService.java
+++ b/src/main/java/com/ruoyi/staff/service/PersonalAttendanceRecordsService.java
@@ -3,8 +3,25 @@
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.pojo.PersonalAttendanceRecords;
+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/AnalyticsServiceImpl.java b/src/main/java/com/ruoyi/staff/service/impl/AnalyticsServiceImpl.java
new file mode 100644
index 0000000..ff74b0f
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/service/impl/AnalyticsServiceImpl.java
@@ -0,0 +1,176 @@
+package com.ruoyi.staff.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.enums.StaffLeaveReason;
+import com.ruoyi.staff.dto.StaffLeaveDto;
+import com.ruoyi.staff.mapper.StaffLeaveMapper;
+import com.ruoyi.staff.mapper.StaffOnJobMapper;
+import com.ruoyi.staff.pojo.StaffLeave;
+import com.ruoyi.staff.service.AnalyticsService;
+import com.ruoyi.staff.vo.MonthlyTurnoverRateVo;
+import com.ruoyi.staff.vo.TotalTurnoverRateVo;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@AllArgsConstructor
+@Service
+public class AnalyticsServiceImpl extends ServiceImpl<StaffLeaveMapper, StaffLeave> implements AnalyticsService {
+ @Autowired
+ private StaffLeaveMapper staffLeaveMapper;
+
+ @Autowired
+ private StaffOnJobMapper staffOnJobMapper;
+
+ @Override
+ public List<StaffLeaveDto> staffLeaveReasonAnalytics() {
+ List<StaffLeaveDto> dbResult = staffLeaveMapper.staffLeaveReasonAnalytics();
+
+ // 鍒涘缓涓�涓狹ap鐢ㄤ簬瀛樺偍鎵�鏈夋灇涓惧師鍥犵殑鏁伴噺锛岄粯璁ゅ�间负0
+ Map<String, Integer> reasonCountMap = new HashMap<>();
+ for (StaffLeaveReason reasonEnum : StaffLeaveReason.values()) {
+ reasonCountMap.put(reasonEnum.getCode(), 0);
+ }
+
+ // 灏嗘暟鎹簱鏌ヨ缁撴灉鍚堝苟鍒癕ap涓�
+ for (StaffLeaveDto dto : dbResult) {
+ String reasonCode = dto.getReason();
+ if (reasonCountMap.containsKey(reasonCode)) {
+ reasonCountMap.put(reasonCode, dto.getCount());
+ }
+ }
+
+ // 灏哅ap杞崲涓篖ist<StaffLeaveDto>
+ List<StaffLeaveDto> result = new ArrayList<>();
+ for (StaffLeaveReason reasonEnum : StaffLeaveReason.values()) {
+ StaffLeaveDto dto = new StaffLeaveDto();
+ dto.setReason(reasonEnum.getCode());
+ dto.setCount(reasonCountMap.get(reasonEnum.getCode()));
+ dto.setReasonText(reasonEnum.getInfo());
+ result.add(dto);
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<MonthlyTurnoverRateVo> getMonthlyTurnoverRateFor12Months() {
+ List<MonthlyTurnoverRateVo> result = new ArrayList<>();
+ LocalDate now = LocalDate.now();
+ DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
+
+ // 璁$畻杩�12涓湀鐨勬暟鎹�
+ for (int i = 11; i >= 0; i--) {
+ LocalDate currentMonth = now.minusMonths(i);
+ LocalDate monthStart = currentMonth.withDayOfMonth(1);
+ LocalDate monthEnd = currentMonth.withDayOfMonth(currentMonth.lengthOfMonth());
+
+ MonthlyTurnoverRateVo vo = new MonthlyTurnoverRateVo();
+ vo.setMonth(currentMonth.format(monthFormatter));
+ vo.setMonthStartDate(monthStart);
+ vo.setMonthEndDate(monthEnd);
+
+ // 鏈堝垵鍛樺伐鏁帮紙涓婃湀鏈湪鑱屽憳宸ユ暟锛�
+ LocalDate lastMonthEnd = monthStart.minusDays(1);
+ Integer beginMonthStaffCount = staffOnJobMapper.countOnJobStaffByDate(lastMonthEnd);
+ vo.setBeginMonthStaffCount(beginMonthStaffCount != null ? beginMonthStaffCount : 0);
+
+ // 鏈堟湯鍛樺伐鏁�
+ Integer endMonthStaffCount = staffOnJobMapper.countOnJobStaffByDate(monthEnd);
+ vo.setEndMonthStaffCount(endMonthStaffCount != null ? endMonthStaffCount : 0);
+
+ // 鏈堝害鍏ヨ亴鍛樺伐鏁�
+ Integer newHireCount = staffOnJobMapper.countNewHireByMonth(monthStart, monthEnd);
+ vo.setNewHireCount(newHireCount != null ? newHireCount : 0);
+
+ // 鏈堝害绂昏亴鍛樺伐鏁�
+ Integer leaveCount = staffLeaveMapper.countLeaveByMonth(monthStart, monthEnd);
+ vo.setLeaveCount(leaveCount != null ? leaveCount : 0);
+
+ // 璁$畻褰撴湡骞冲潎鍦ㄨ亴浜烘暟 = (鏈堝垵鍛樺伐鏁� + 鏈堟湯鍛樺伐鏁�) / 2
+ Double averageStaffCount = (vo.getBeginMonthStaffCount() + vo.getEndMonthStaffCount()) / 2.0;
+
+ // 璁$畻娴佸け鐜囷細娴佸け鐜� = 鏈堝害绂昏亴鍛樺伐鏁� / 褰撴湡骞冲潎鍦ㄨ亴浜烘暟 * 100%
+ Double turnoverRate = 0.0;
+ if (averageStaffCount > 0) {
+ turnoverRate = (double) vo.getLeaveCount() / averageStaffCount * 100;
+ // 淇濈暀涓や綅灏忔暟
+ turnoverRate = Math.round(turnoverRate * 100.0) / 100.0;
+ }
+ vo.setTurnoverRate(turnoverRate);
+
+ // 璁$畻娴佸姩鐜囷細娴佸姩鐜� = (鏈堝害鍏ヨ亴鍛樺伐鏁� + 鏈堝害绂昏亴鍛樺伐鏁�) / 褰撴湡骞冲潎鍦ㄨ亴浜烘暟 * 100%
+ Double flowRate = 0.0;
+ if (averageStaffCount > 0) {
+ flowRate = (double) (vo.getNewHireCount() + vo.getLeaveCount()) / averageStaffCount * 100;
+ // 淇濈暀涓や綅灏忔暟
+ flowRate = Math.round(flowRate * 100.0) / 100.0;
+ }
+ vo.setFlowRate(flowRate);
+
+ result.add(vo);
+ }
+
+ return result;
+ }
+
+ @Override
+ public TotalTurnoverRateVo getTotalStatistic() {
+ TotalTurnoverRateVo result = new TotalTurnoverRateVo();
+ LocalDate now = LocalDate.now();
+
+ // 鑾峰彇褰撳墠鍦ㄨ亴鍛樺伐鏁�
+ Integer currentOnJobCount = staffOnJobMapper.countOnJobStaffByDate(now);
+ result.setCurrentOnJobCount(currentOnJobCount);
+
+ // 鑾峰彇鏈湀鐨勫紑濮嬪拰缁撴潫鏃ユ湡
+ LocalDate monthStartDate = now.withDayOfMonth(1);
+ LocalDate monthEndDate = now.withDayOfMonth(now.lengthOfMonth());
+
+ // 鑾峰彇鏈堝垵鍛樺伐鏁帮紙鍗充笂鏈堟湯鍛樺伐鏁帮級
+ Integer beginMonthStaffCount = staffOnJobMapper.countOnJobStaffByDate(monthStartDate.minusDays(1));
+ beginMonthStaffCount = beginMonthStaffCount != null ? beginMonthStaffCount : 0;
+
+ // 鑾峰彇鏈堟湯鍛樺伐鏁�
+ Integer endMonthStaffCount = staffOnJobMapper.countOnJobStaffByDate(monthEndDate);
+ endMonthStaffCount = endMonthStaffCount != null ? endMonthStaffCount : 0;
+
+ // 鑾峰彇鏈湀鏂板叆鑱屽憳宸ユ暟
+ Integer newHireCount = staffOnJobMapper.countNewHireByMonth(monthStartDate, monthEndDate);
+ newHireCount = newHireCount != null ? newHireCount : 0;
+
+ // 鑾峰彇鏈湀绂昏亴鍛樺伐鏁�
+ Integer leaveCount = staffLeaveMapper.countLeaveByMonth(monthStartDate, monthEndDate);
+ leaveCount = leaveCount != null ? leaveCount : 0;
+
+ // 璁$畻褰撴湡骞冲潎鍦ㄨ亴浜烘暟 = (鏈堝垵鍛樺伐鏁� + 鏈堟湯鍛樺伐鏁�) / 2
+ Double averageStaffCount = (beginMonthStaffCount + endMonthStaffCount) / 2.0;
+
+ // 璁$畻鎬绘祦鍔ㄧ巼 = (鍏ヨ亴浜烘暟 + 绂昏亴浜烘暟) / 褰撴湡骞冲潎鍦ㄨ亴浜烘暟 * 100%
+ Double totalFlowRate = 0.0;
+ if (averageStaffCount > 0) {
+ totalFlowRate = (double) (newHireCount + leaveCount) / averageStaffCount * 100;
+ // 淇濈暀涓や綅灏忔暟
+ totalFlowRate = Math.round(totalFlowRate * 100.0) / 100.0;
+ }
+ result.setTotalFlowRate(totalFlowRate);
+
+ // 璁$畻鎬绘祦澶辩巼 = 绂昏亴浜烘暟 / 褰撴湡骞冲潎鍦ㄨ亴浜烘暟 * 100%
+ Double totalTurnoverRate = 0.0;
+ if (averageStaffCount > 0) {
+ totalTurnoverRate = (double) leaveCount / averageStaffCount * 100;
+ // 淇濈暀涓や綅灏忔暟
+ totalTurnoverRate = Math.round(totalTurnoverRate * 100.0) / 100.0;
+ }
+ result.setTotalTurnoverRate(totalTurnoverRate);
+
+ return result;
+ }
+}
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..647ed78
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceLocationConfigServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.staff.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
+import com.ruoyi.staff.service.PersonalAttendanceLocationConfigService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <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..c68be3e 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,257 @@
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.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.mapper.PersonalAttendanceLocationConfigMapper;
import com.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper;
+import com.ruoyi.staff.mapper.StaffOnJobMapper;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import com.ruoyi.staff.pojo.StaffOnJob;
import com.ruoyi.staff.service.PersonalAttendanceRecordsService;
+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.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/StaffLeaveServiceImpl.java b/src/main/java/com/ruoyi/staff/service/impl/StaffLeaveServiceImpl.java
index 2d30dc5..7f124d8 100644
--- a/src/main/java/com/ruoyi/staff/service/impl/StaffLeaveServiceImpl.java
+++ b/src/main/java/com/ruoyi/staff/service/impl/StaffLeaveServiceImpl.java
@@ -5,14 +5,17 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.staff.dto.StaffLeaveDto;
import com.ruoyi.staff.mapper.StaffLeaveMapper;
import com.ruoyi.staff.mapper.StaffOnJobMapper;
+import com.ruoyi.staff.pojo.StaffLeave;
import com.ruoyi.staff.pojo.StaffOnJob;
import com.ruoyi.staff.service.StaffLeaveService;
import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import com.ruoyi.staff.pojo.StaffLeave;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
@@ -23,9 +26,14 @@
@AllArgsConstructor
@Service
public class StaffLeaveServiceImpl extends ServiceImpl<StaffLeaveMapper, StaffLeave> implements StaffLeaveService {
+ @Autowired
private StaffLeaveMapper staffLeaveMapper;
+ @Autowired
private StaffOnJobMapper staffOnJobMapper;
+
+ @Autowired
+ private SysUserMapper sysUserMapper;
//鏂板绂昏亴鍒楄〃鍒嗛〉鏌ヨ
@Override
@@ -51,11 +59,20 @@
// 鏂板绂昏亴璁板綍
StaffLeave staffLeave = new StaffLeave();
staffLeave.setStaffOnJobId(staffLeaveDto.getStaffOnJobId());
+ staffLeave.setReason(staffLeaveDto.getReason());
String reason = staffLeaveDto.getReason();
- if (!StaffLeaveReasonOther.getCode().equals(reason)){
- staffLeave.setRemark("");
+ if (StaffLeaveReasonOther.getCode().equals(reason)){
+ staffLeave.setRemark(staffLeaveDto.getRemark());
}
staffLeaveMapper.insert(staffLeave);
+
+ // 鏇存柊瀵瑰簲鐢ㄦ埛鐘舵�佷负鍋滅敤
+ // 鏍规嵁鍛樺伐缂栧彿鏌ヨ鐢ㄦ埛
+ SysUser sysUser = sysUserMapper.selectUserByUserName(staffOnJob.getStaffNo());
+ if (sysUser != null) {
+ sysUser.setStatus("1");
+ sysUserMapper.updateUser(sysUser);
+ }
// 鏇存柊绂昏亴鐘舵�佷负绂昏亴
staffOnJob.setStaffState(0);
@@ -97,6 +114,5 @@
ExcelUtil<StaffLeaveDto> util = new ExcelUtil<StaffLeaveDto>(StaffLeaveDto.class);
util.exportExcel(response, staffLeaves, "鍛樺伐绂昏亴瀵煎嚭");
}
-
}
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 6fb0cd0..9e9a4dc 100644
--- a/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
+++ b/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
@@ -21,30 +21,37 @@
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.AllArgsConstructor;
-
import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
-import java.io.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
@AllArgsConstructor
@Service
public class StaffOnJobServiceImpl extends ServiceImpl<StaffOnJobMapper, StaffOnJob> implements IStaffOnJobService {
-
+ @Autowired
private StaffOnJobMapper staffOnJobMapper;
-
+ @Autowired
private SysPostMapper sysPostMapper;
+ @Autowired
private StaffContractMapper staffContractMapper;
+ @Autowired
private StaffLeaveMapper staffLeaveMapper;
@@ -66,6 +73,7 @@
}
// 鍒涘缓鍏ヨ亴鏁版嵁
staffOnJobPrams.setContractExpireTime(staffOnJobPrams.getContractEndTime());
+ staffOnJobPrams.setStaffState(1);
staffOnJobMapper.insert(staffOnJobPrams);
// 鍒涘缓鍚堝悓璁板綍
@@ -87,7 +95,7 @@
throw new BaseException("缂栧彿涓�"+staffOnJobParams.getStaffNo()+"鐨勫憳宸ヤ笉瀛樺湪,鏃犳硶鏇存柊!!!");
}
- String[] ignoreProperties = {"id"};//鎺掗櫎id灞炴��
+ String[] ignoreProperties = {"id"};//鎺掗櫎鏇存柊灞炴��
// 鑾峰彇鏈�鏂板悎鍚屾暟鎹紝骞朵笖鏇存柊
StaffContract contract = staffContractMapper.selectOne(Wrappers.<StaffContract>lambdaQuery()
@@ -100,9 +108,8 @@
}
// 鏇存柊鍛樺伐鏁版嵁
- BeanUtils.copyProperties(staffOnJobParams,job,ignoreProperties);
- job.setContractExpireTime(staffOnJobParams.getContractEndTime());
- return staffOnJobMapper.updateById(job);
+ staffOnJobParams.setContractExpireTime(staffOnJobParams.getContractEndTime());
+ return staffOnJobMapper.updateById(staffOnJobParams);
}
//鍒犻櫎鍏ヨ亴
@@ -152,8 +159,12 @@
StaffOnJobDto staffOnJobDto = new StaffOnJobDto();
BeanUtils.copyProperties(staffOnJob, staffOnJobDto);
// 鏌ヨ宀椾綅鍚嶇О
- SysPost post = sysPostMapper.selectPostById((long) staffOnJob.getSysPostId());
- staffOnJobDto.setPostName(post.getPostName());
+ if (staffOnJob.getSysPostId() != null) {
+ SysPost post = sysPostMapper.selectPostById(staffOnJob.getSysPostId().longValue());
+ if (post != null) {
+ staffOnJobDto.setPostName(post.getPostName());
+ }
+ }
// 鏌ヨ鍚堝悓淇℃伅
StaffContract contract = staffContractMapper.selectOne(Wrappers.<StaffContract>lambdaQuery()
@@ -173,7 +184,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..d3a8cd0
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/task/PersonalAttendanceRecordsTask.java
@@ -0,0 +1,75 @@
+package com.ruoyi.staff.task;
+
+import com.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper;
+import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
+import com.ruoyi.staff.pojo.StaffOnJob;
+import com.ruoyi.staff.service.PersonalAttendanceRecordsService;
+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.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/staff/vo/MonthlyTurnoverRateVo.java b/src/main/java/com/ruoyi/staff/vo/MonthlyTurnoverRateVo.java
new file mode 100644
index 0000000..90f9c69
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/vo/MonthlyTurnoverRateVo.java
@@ -0,0 +1,39 @@
+package com.ruoyi.staff.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+/**
+ * 鏈堝害鍛樺伐娴佸姩鐜囧拰娴佸け鐜囩粺璁O
+ */
+@Data
+public class MonthlyTurnoverRateVo {
+ @ApiModelProperty("鏈堜唤")
+ private String month;
+
+ @ApiModelProperty("鏈堝垵鍛樺伐鏁�")
+ private Integer beginMonthStaffCount;
+
+ @ApiModelProperty("鏈堟湯鍛樺伐鏁�")
+ private Integer endMonthStaffCount;
+
+ @ApiModelProperty("鏈堝害鍏ヨ亴鍛樺伐鏁�")
+ private Integer newHireCount;
+
+ @ApiModelProperty("鏈堝害绂昏亴鍛樺伐鏁�")
+ private Integer leaveCount;
+
+ @ApiModelProperty("娴佸け鐜�(%)")
+ private Double turnoverRate;
+
+ @ApiModelProperty("娴佸姩鐜�(%)")
+ private Double flowRate;
+
+ @ApiModelProperty("鏈堜唤寮�濮嬫棩鏈�")
+ private LocalDate monthStartDate;
+
+ @ApiModelProperty("鏈堜唤缁撴潫鏃ユ湡")
+ private LocalDate monthEndDate;
+}
diff --git a/src/main/java/com/ruoyi/staff/vo/TotalTurnoverRateVo.java b/src/main/java/com/ruoyi/staff/vo/TotalTurnoverRateVo.java
new file mode 100644
index 0000000..49d2f42
--- /dev/null
+++ b/src/main/java/com/ruoyi/staff/vo/TotalTurnoverRateVo.java
@@ -0,0 +1,19 @@
+package com.ruoyi.staff.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 鍛樺伐鎬绘祦鍔ㄧ巼銆佹祦澶辩巼鍙婂湪鑱屽憳宸ユ暟缁熻VO
+ */
+@Data
+public class TotalTurnoverRateVo {
+ @ApiModelProperty("鎬绘祦鍔ㄧ巼(%)")
+ private Double totalFlowRate;
+
+ @ApiModelProperty("鎬绘祦澶辩巼(%)")
+ private Double totalTurnoverRate;
+
+ @ApiModelProperty("褰撳墠鍦ㄨ亴鍛樺伐鏁�")
+ private Integer currentOnJobCount;
+}
diff --git a/src/main/resources/mapper/production/ProductOrderMapper.xml b/src/main/resources/mapper/production/ProductOrderMapper.xml
index 6fb143a..4c2b1f8 100644
--- a/src/main/resources/mapper/production/ProductOrderMapper.xml
+++ b/src/main/resources/mapper/production/ProductOrderMapper.xml
@@ -31,9 +31,6 @@
<if test="c.salesContractNo != null and c.salesContractNo != ''">
and sl.sales_contract_no like concat('%',#{c.salesContractNo},'%')
</if>
- <if test="c.customerName != null and c.customerName != ''">
- and sl.customer_name like concat('%',#{c.customerName},'%')
- </if>
<if test="c.productCategory != null and c.productCategory != ''">
and slp.product_category like concat('%',#{c.productCategory},'%')
</if>
@@ -46,7 +43,7 @@
</where>
</select>
<select id="productMainByOrderId" resultType="com.ruoyi.production.dto.ProductOrderDto">
- select po.*,
+ select po.*,F
pwo.work_order_no,
pwo.report_work,
pwo.status,
--
Gitblit v1.9.3