新增车间计算记录与数据看板

This commit is contained in:
2025-05-15 21:35:16 +08:00
parent a63afc6bfb
commit a0bc26ef3a
31 changed files with 1127 additions and 78 deletions

View File

@@ -0,0 +1,102 @@
package com.ruoyi.oa.controller;
import java.util.List;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.oa.domain.vo.OaAttendanceRecordVo;
import com.ruoyi.oa.domain.bo.OaAttendanceRecordBo;
import com.ruoyi.oa.service.IOaAttendanceRecordService;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 计算记录
*
* @author ruoyi
* @date 2025-05-15
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/oa/attendanceRecord")
public class OaAttendanceRecordController extends BaseController {
private final IOaAttendanceRecordService iOaAttendanceRecordService;
/**
* 查询计算记录列表
*/
@GetMapping("/list")
public TableDataInfo<OaAttendanceRecordVo> list(OaAttendanceRecordBo bo, PageQuery pageQuery) {
return iOaAttendanceRecordService.queryPageList(bo, pageQuery);
}
@GetMapping("/gen-list/{date}")
public R<List<String>> list(@PathVariable String date) {
return R.ok(iOaAttendanceRecordService.listGenDate(date));
}
/**
* 导出计算记录列表
*/
@PostMapping("/export")
public void export(OaAttendanceRecordBo bo, HttpServletResponse response) {
List<OaAttendanceRecordVo> list = iOaAttendanceRecordService.queryList(bo);
ExcelUtil.exportExcel(list, "计算记录", OaAttendanceRecordVo.class, response);
}
/**
* 获取计算记录详细信息
*
* @param recordId 主键
*/
@GetMapping("/{recordId}")
public R<OaAttendanceRecordVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long recordId) {
return R.ok(iOaAttendanceRecordService.queryById(recordId));
}
/**
* 新增计算记录
*/
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody OaAttendanceRecordBo bo) {
return toAjax(iOaAttendanceRecordService.insertByBo(bo));
}
/**
* 修改计算记录
*/
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody OaAttendanceRecordBo bo) {
return toAjax(iOaAttendanceRecordService.updateByBo(bo));
}
/**
* 删除计算记录
*
* @param recordIds 主键串
*/
@DeleteMapping("/{recordIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] recordIds) {
return toAjax(iOaAttendanceRecordService.deleteWithValidByIds(Arrays.asList(recordIds), true));
}
}

View File

@@ -42,7 +42,6 @@ public class OaReportDetailController extends BaseController {
/**
* 查询设计项目汇报详情列表
*/
@SaCheckPermission("system:reportDetail:list")
@GetMapping("/list")
public TableDataInfo<OaReportDetailVo> list(OaReportDetailBo bo, PageQuery pageQuery) {
return iOaReportDetailService.queryPageList(bo, pageQuery);
@@ -51,7 +50,6 @@ public class OaReportDetailController extends BaseController {
/**
* 导出设计项目汇报详情列表
*/
@SaCheckPermission("system:reportDetail:export")
@Log(title = "设计项目汇报详情", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(OaReportDetailBo bo, HttpServletResponse response) {
@@ -64,7 +62,6 @@ public class OaReportDetailController extends BaseController {
*
* @param id 主键
*/
@SaCheckPermission("system:reportDetail:query")
@GetMapping("/{id}")
public R<OaReportDetailVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
@@ -74,7 +71,6 @@ public class OaReportDetailController extends BaseController {
/**
* 新增设计项目汇报详情
*/
@SaCheckPermission("system:reportDetail:add")
@Log(title = "设计项目汇报详情", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
@@ -85,7 +81,6 @@ public class OaReportDetailController extends BaseController {
/**
* 修改设计项目汇报详情
*/
@SaCheckPermission("system:reportDetail:edit")
@Log(title = "设计项目汇报详情", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
@@ -98,8 +93,6 @@ public class OaReportDetailController extends BaseController {
*
* @param ids 主键串
*/
@SaCheckPermission("system:reportDetail:remove")
@Log(title = "设计项目汇报详情", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {

View File

@@ -42,7 +42,6 @@ public class OaReportSummaryController extends BaseController {
/**
* 查询设计项目汇报概述列表
*/
@SaCheckPermission("system:reportSummary:list")
@GetMapping("/list")
public TableDataInfo<OaReportSummaryVo> list(OaReportSummaryBo bo, PageQuery pageQuery) {
return iOaReportSummaryService.queryPageList(bo, pageQuery);
@@ -51,7 +50,6 @@ public class OaReportSummaryController extends BaseController {
/**
* 导出设计项目汇报概述列表
*/
@SaCheckPermission("system:reportSummary:export")
@Log(title = "设计项目汇报概述", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(OaReportSummaryBo bo, HttpServletResponse response) {
@@ -64,7 +62,6 @@ public class OaReportSummaryController extends BaseController {
*
* @param id 主键
*/
@SaCheckPermission("system:reportSummary:query")
@GetMapping("/{id}")
public R<OaReportSummaryVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
@@ -74,7 +71,6 @@ public class OaReportSummaryController extends BaseController {
/**
* 新增设计项目汇报概述
*/
@SaCheckPermission("system:reportSummary:add")
@Log(title = "设计项目汇报概述", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
@@ -85,7 +81,6 @@ public class OaReportSummaryController extends BaseController {
/**
* 修改设计项目汇报概述
*/
@SaCheckPermission("system:reportSummary:edit")
@Log(title = "设计项目汇报概述", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
@@ -98,7 +93,6 @@ public class OaReportSummaryController extends BaseController {
*
* @param ids 主键串
*/
@SaCheckPermission("system:reportSummary:remove")
@Log(title = "设计项目汇报概述", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")

View File

@@ -8,6 +8,7 @@ import java.util.Arrays;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.oa.domain.LaborCostData;
import com.ruoyi.oa.domain.vo.AttendanceMonthlyCount;
import com.ruoyi.oa.domain.vo.SysUserVo;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
@@ -163,4 +164,21 @@ public class SysOaAttendanceController extends BaseController {
public R<Void> insertBatch(@Validated(AddGroup.class) @RequestBody SysOaAttendanceBo bo) {
return toAjax( iSysOaAttendanceService.insertBatch(bo));
}
@GetMapping("/data/{refDate}")
public R<List<AttendanceMonthlyCount>> selectLastSixMonthsByMonth(@PathVariable String refDate) {
return R.ok(iSysOaAttendanceService.selectLastSixMonthsByMonth(refDate));
}
@GetMapping("/data/pie/{refDate}")
public R<AttendanceMonthlyCount> selectAttendanceMonthlyCountByMonth(@PathVariable String refDate) {
return R.ok(iSysOaAttendanceService.selectAttendanceMonthlyCountByMonth(refDate));
}
@GetMapping("/data/card/{refDate}")
public R<List<AttendanceMonthlyCount>> selectMonthlyCounts(@PathVariable String refDate) {
return R.ok(iSysOaAttendanceService.selectMonthlyCounts(refDate));
}
}

View File

@@ -32,6 +32,12 @@ public class LaborCostData extends BaseEntity {
// 加班时间
private Double overtime;
// 出差次数
private Double tripTimes;
// 请假次数
private Double absenceDays;
}

View File

@@ -0,0 +1,78 @@
package com.ruoyi.oa.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import java.math.BigDecimal;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 计算记录对象 oa_attendance_record
*
* @author ruoyi
* @date 2025-05-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("oa_attendance_record")
public class OaAttendanceRecord extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 主键id
*/
@TableId(value = "record_id")
private Long recordId;
/**
* 涉及月份
*/
private Date relationMonth;
/**
* 生成时间
*/
private Date calcTime;
/**
* 统计者姓名
*/
private String nickName;
/**
* 出差天数
*/
private BigDecimal trips;
/**
* 请假次数
*/
private BigDecimal notNum;
/**
* 出勤天数
*/
private BigDecimal works;
/**
* 涉及项目
*/
private String projectIds;
/**
* 加班时长
*/
private BigDecimal overNum;
/**
* 删除标志
*/
@TableLogic
private Long delFlag;
/**
* 备注
*/
private String remark;
private Long userId;
}

View File

@@ -25,8 +25,8 @@ public class OaReportDetail extends BaseEntity {
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
@TableId(value = "detail_id")
private Long detailId;
/**
* 关联汇报概述IDoa_report_summary.id
*/

View File

@@ -27,8 +27,8 @@ public class OaReportSummary extends BaseEntity {
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
@TableId(value = "summary_id")
private Long summaryId;
/**
* 汇报标题
*/
@@ -55,4 +55,6 @@ public class OaReportSummary extends BaseEntity {
*/
private String remark;
private Long type;
}

View File

@@ -0,0 +1,86 @@
package com.ruoyi.oa.domain.bo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 计算记录业务对象 oa_attendance_record
*
* @author ruoyi
* @date 2025-05-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class OaAttendanceRecordBo extends BaseEntity {
/**
* 主键id
*/
private Long recordId;
/**
* 涉及月份
*/
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date relationMonth;
/**
* 生成时间
*/
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date calcTime;
/**
* 统计者姓名
*/
private String nickName;
/**
* 出差天数
*/
private BigDecimal trips;
/**
* 请假次数
*/
private BigDecimal notNum;
/**
* 出勤天数
*/
private BigDecimal works;
/**
* 涉及项目
*/
private String projectIds;
/**
* 加班时长
*/
private BigDecimal overNum;
/**
* 备注
*/
private String remark;
private Long userId;
}

View File

@@ -25,48 +25,41 @@ public class OaReportDetailBo extends BaseEntity {
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
private Long detailId;
/**
* 关联汇报概述IDoa_report_summary.id
*/
@NotNull(message = "关联汇报概述IDoa_report_summary.id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long summaryId;
/**
* 设备唯一编号
*/
@NotBlank(message = "设备唯一编号不能为空", groups = { AddGroup.class, EditGroup.class })
private String deviceCode;
/**
* 设备类别
*/
@NotBlank(message = "设备类别不能为空", groups = { AddGroup.class, EditGroup.class })
private String category;
/**
* 设备生产说明
*/
@NotBlank(message = "设备生产说明不能为空", groups = { AddGroup.class, EditGroup.class })
private String deviceDescription;
/**
* 汇报详情内容(含文字、图像说明等)
*/
@NotBlank(message = "汇报详情内容(含文字、图像说明等)不能为空", groups = { AddGroup.class, EditGroup.class })
private String reportDetail;
/**
* 关联图像 OSS ID 列表(逗号分隔)
*/
@NotBlank(message = "关联图像 OSS ID 列表(逗号分隔)不能为空", groups = { AddGroup.class, EditGroup.class })
private String ossIds;
/**
* 备注
*/
@NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
private String remark;

View File

@@ -27,7 +27,7 @@ public class OaReportSummaryBo extends BaseEntity {
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
private Long summaryId;
/**
* 汇报标题
@@ -59,4 +59,6 @@ public class OaReportSummaryBo extends BaseEntity {
private String remark;
private Long type;
}

View File

@@ -0,0 +1,30 @@
package com.ruoyi.oa.domain.vo;
import lombok.Data;
@Data
public class AttendanceMonthlyCount {
/** 格式:"2025-05" */
private String month;
/** 出勤次数(含出差) */
private Integer attendanceCount;
/** 请假次数 */
private Integer leaveCount;
// + getters/setters
private Long workHours;
private Long leaveHours;
private Long overtimeHours;
private Long tripHours;
private Double attendanceRate; // 出勤率01 之间)
private Integer tripCount; // 出差次数
private Integer leavePeople; // 请假人数
}

View File

@@ -0,0 +1,97 @@
package com.ruoyi.oa.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import com.ruoyi.oa.domain.LaborCostData;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 计算记录视图对象 oa_attendance_record
*
* @author ruoyi
* @date 2025-05-15
*/
@Data
@ExcelIgnoreUnannotated
public class OaAttendanceRecordVo {
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long recordId;
/**
* 涉及月份
*/
@ExcelProperty(value = "涉及月份")
private Date relationMonth;
/**
* 生成时间
*/
@ExcelProperty(value = "生成时间")
private Date calcTime;
/**
* 统计者姓名
*/
@ExcelProperty(value = "统计者姓名")
private String nickName;
/**
* 出差天数
*/
@ExcelProperty(value = "出差天数")
private BigDecimal trips;
/**
* 请假次数
*/
@ExcelProperty(value = "请假次数")
private BigDecimal notNum;
/**
* 出勤天数
*/
@ExcelProperty(value = "出勤天数")
private BigDecimal works;
/**
* 涉及项目
*/
@ExcelProperty(value = "涉及项目")
private String projectIds;
/**
* 加班时长
*/
@ExcelProperty(value = "加班时长")
private BigDecimal overNum;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
private List<SysOaAttendanceVo> attendanceList;
private Long userId;
/** ▶︎ 按项目汇总 */
private List<ProjectAttendanceSummaryVo> projectList;
private Long laborCost;
}

View File

@@ -25,7 +25,7 @@ public class OaReportDetailVo {
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
private Long detailId;
/**
* 关联汇报概述IDoa_report_summary.id

View File

@@ -27,7 +27,7 @@ public class OaReportSummaryVo {
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
private Long summaryId;
/**
* 汇报标题
@@ -65,5 +65,7 @@ public class OaReportSummaryVo {
@ExcelProperty(value = "备注")
private String remark;
private Long type;
}

View File

@@ -0,0 +1,17 @@
package com.ruoyi.oa.domain.vo;
import lombok.Data;
/** 项目维度汇总行 */
@Data
public class ProjectAttendanceSummaryVo {
private Long projectId;
private String projectName;
private String color;
private Integer workTimes; // 出勤天数
private Integer hourWorkTimes; // 工作时长h
private Integer overTime; // 加班时长h
private Integer tripDays; // 出差天数
}

View File

@@ -0,0 +1,41 @@
package com.ruoyi.oa.mapper;
import com.ruoyi.oa.domain.OaAttendanceRecord;
import com.ruoyi.oa.domain.vo.OaAttendanceRecordVo;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
* 计算记录Mapper接口
*
* @author ruoyi
* @date 2025-05-15
*/
public interface OaAttendanceRecordMapper extends BaseMapperPlus<OaAttendanceRecordMapper, OaAttendanceRecord, OaAttendanceRecordVo> {
/**
* 获取全部的生成日期
* @param date
* @return
*/
List<String> listGenDate(String date);
/**
* 获取全部相同日期数据
*
* @param date
* @param firstDay
* @return
*/
List<Long> listCommonDateRecord(@Param("date") String date, @Param("firstDay") Date firstDay);
/**
* 查询详情
* @param recordId
* @return
*/
OaAttendanceRecordVo selectVoByIdPlus(Long recordId);
}

View File

@@ -14,4 +14,7 @@ import org.apache.ibatis.annotations.Select;
public interface OaReportDetailMapper extends BaseMapperPlus<OaReportDetailMapper, OaReportDetail, OaReportDetailVo> {
@Select("SELECT url FROM sys_oss WHERE oss_id = #{ossId}")
String selectImageUrlByOssId(String ossId);
OaReportDetailVo selectVoByIdPlus(Long id);
}

View File

@@ -1,8 +1,7 @@
package com.ruoyi.oa.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.ruoyi.oa.domain.SysOaAttendance;
import com.ruoyi.oa.domain.bo.SysOaAttendanceBo;
import com.ruoyi.oa.domain.vo.AttendanceMonthlyCount;
import com.ruoyi.oa.domain.vo.SysOaAttendanceVo;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.oa.domain.vo.SysUserVo;
@@ -38,4 +37,11 @@ public interface SysOaAttendanceMapper extends BaseMapperPlus<SysOaAttendanceMap
Double getAttendanceDay(@Param("userId") Long userId,
@Param("projectId") Long projectId );
List<Long> selectNowMonthUserId(Date firstDay);
List<AttendanceMonthlyCount> selectLastSixMonthsByMonth(String refDate);
AttendanceMonthlyCount selectAttendanceMonthlyCountByMonth(String refDate);
List<AttendanceMonthlyCount> selectMonthlyCounts(String refDate);
}

View File

@@ -0,0 +1,56 @@
package com.ruoyi.oa.service;
import com.ruoyi.oa.domain.vo.OaAttendanceRecordVo;
import com.ruoyi.oa.domain.bo.OaAttendanceRecordBo;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 计算记录Service接口
*
* @author ruoyi
* @date 2025-05-15
*/
public interface IOaAttendanceRecordService {
/**
* 查询计算记录
*/
OaAttendanceRecordVo queryById(Long recordId);
/**
* 查询计算记录列表
*/
TableDataInfo<OaAttendanceRecordVo> queryPageList(OaAttendanceRecordBo bo, PageQuery pageQuery);
/**
* 查询计算记录列表
*/
List<OaAttendanceRecordVo> queryList(OaAttendanceRecordBo bo);
/**
* 新增计算记录
*/
Boolean insertByBo(OaAttendanceRecordBo bo);
/**
* 修改计算记录
*/
Boolean updateByBo(OaAttendanceRecordBo bo);
/**
* 校验并批量删除计算记录信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取某月的所有数据报告的生成日期
* @param date
* @return
*/
List<String> listGenDate(String date);
}

View File

@@ -1,6 +1,7 @@
package com.ruoyi.oa.service;
import com.ruoyi.oa.domain.LaborCostData;
import com.ruoyi.oa.domain.vo.AttendanceMonthlyCount;
import com.ruoyi.oa.domain.vo.SysOaAttendanceVo;
import com.ruoyi.oa.domain.bo.SysOaAttendanceBo;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -77,4 +78,15 @@ public interface ISysOaAttendanceService {
* @return
*/
int delOaAttendanceAll(Long day);
/**
* @param refDate
* @return
*/
List<AttendanceMonthlyCount> selectLastSixMonthsByMonth(String refDate);
AttendanceMonthlyCount selectAttendanceMonthlyCountByMonth(String refDate);
List<AttendanceMonthlyCount> selectMonthlyCounts(String refDate);
}

View File

@@ -0,0 +1,133 @@
package com.ruoyi.oa.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.ruoyi.oa.domain.bo.OaAttendanceRecordBo;
import com.ruoyi.oa.domain.vo.OaAttendanceRecordVo;
import com.ruoyi.oa.domain.OaAttendanceRecord;
import com.ruoyi.oa.mapper.OaAttendanceRecordMapper;
import com.ruoyi.oa.service.IOaAttendanceRecordService;
import java.util.*;
/**
* 计算记录Service业务层处理
*
* @author ruoyi
* @date 2025-05-15
*/
@RequiredArgsConstructor
@Service
public class OaAttendanceRecordServiceImpl implements IOaAttendanceRecordService {
private final OaAttendanceRecordMapper baseMapper;
/**
* 查询计算记录
*/
@Override
public OaAttendanceRecordVo queryById(Long recordId){
return baseMapper.selectVoByIdPlus(recordId);
}
/**
* 查询计算记录列表
*/
@Override
public TableDataInfo<OaAttendanceRecordVo> queryPageList(OaAttendanceRecordBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<OaAttendanceRecord> lqw = buildQueryWrapper(bo);
Page<OaAttendanceRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
private LambdaQueryWrapper<OaAttendanceRecord> buildQueryWrapper(OaAttendanceRecordBo bo) {
LambdaQueryWrapper<OaAttendanceRecord> lqw = Wrappers.lambdaQuery();
if (bo.getRelationMonth() != null) {
lqw.apply(
"YEAR(relation_month) = YEAR({0}) AND MONTH(relation_month) = MONTH({1})",
bo.getRelationMonth(), bo.getRelationMonth());
if (bo.getCalcTime() != null) {
// 2a) 如果前端传了 genTime就按那天精准过滤
lqw.apply("DATE(calc_time) = {0}", bo.getCalcTime());
} else {
// 2b) 如果没传 genTime就只拿该月最新一次的记录
lqw.apply(
"calc_time = (" +
"SELECT MAX(calc_time) FROM oa_attendance_record " +
"WHERE YEAR(relation_month)=YEAR({0}) AND MONTH(relation_month)=MONTH({1})" +
")",
bo.getRelationMonth(), bo.getRelationMonth()
);
}
}
return lqw;
}
/**
* 查询计算记录列表
*/
@Override
public List<OaAttendanceRecordVo> queryList(OaAttendanceRecordBo bo) {
LambdaQueryWrapper<OaAttendanceRecord> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
/**
* 新增计算记录
*/
@Override
public Boolean insertByBo(OaAttendanceRecordBo bo) {
OaAttendanceRecord add = BeanUtil.toBean(bo, OaAttendanceRecord.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setRecordId(add.getRecordId());
}
return flag;
}
/**
* 修改计算记录
*/
@Override
public Boolean updateByBo(OaAttendanceRecordBo bo) {
OaAttendanceRecord update = BeanUtil.toBean(bo, OaAttendanceRecord.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(OaAttendanceRecord entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除计算记录
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public List<String> listGenDate(String date) {
return baseMapper.listGenDate(date);
}
}

View File

@@ -88,11 +88,13 @@ public class OaProgressServiceImpl implements IOaProgressService {
OaProgress add = BeanUtil.toBean(bo, OaProgress.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
List<OaProgressDetailBo> detailList = bo.getDetailList();
for (OaProgressDetailBo detailBo : detailList) {
detailBo.setProgressId(add.getProgressId());
detailService.insertByBo(detailBo);
if(bo.getDetailList() != null && !bo.getDetailList().isEmpty()) {
for (OaProgressDetailBo detailBo : bo.getDetailList()) {
detailBo.setProgressId(add.getProgressId());
detailService.insertByBo(detailBo);
}
}
return flag;
}

View File

@@ -38,7 +38,7 @@ public class OaReportDetailServiceImpl implements IOaReportDetailService {
@Override
public OaReportDetailVo queryById(Long id){
return baseMapper.selectVoById(id);
return baseMapper.selectVoByIdPlus(id);
}
/**
@@ -119,7 +119,7 @@ public class OaReportDetailServiceImpl implements IOaReportDetailService {
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
bo.setDetailId(add.getDetailId());
}
return flag;
}

View File

@@ -78,7 +78,7 @@ public class OaReportSummaryServiceImpl implements IOaReportSummaryService {
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
bo.setSummaryId(add.getSummaryId());
}
return flag;
}

View File

@@ -8,8 +8,11 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.oa.domain.LaborCostData;
import com.ruoyi.oa.domain.OaAttendanceRecord;
import com.ruoyi.oa.domain.vo.AttendanceMonthlyCount;
import com.ruoyi.oa.domain.vo.SysOaProjectVo;
import com.ruoyi.oa.domain.vo.SysUserVo;
import com.ruoyi.oa.mapper.OaAttendanceRecordMapper;
import com.ruoyi.oa.service.ISysOaProjectService;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.system.service.ISysUserService;
@@ -23,9 +26,10 @@ import com.ruoyi.oa.domain.SysOaAttendance;
import com.ruoyi.oa.mapper.SysOaAttendanceMapper;
import com.ruoyi.oa.service.ISysOaAttendanceService;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 人员考勤Service业务层处理
@@ -49,6 +53,9 @@ public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {
@Autowired
private ISysOaProjectService projectService;
@Autowired
private OaAttendanceRecordMapper recordMapper;
/**
* 查询人员考勤
*/
@@ -84,7 +91,7 @@ public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {
lqw.eq(bo.getProjectId() != null, SysOaAttendance::getProjectId, bo.getProjectId());
lqw.eq(bo.getDayLength() != null, SysOaAttendance::getDayLength, bo.getDayLength());
lqw.eq(bo.getHour() != null, SysOaAttendance::getHour, bo.getHour());
lqw.like(bo.getCreateTime()!=null, SysOaAttendance::getCreateTime, bo.getCreateTime());
lqw.like(bo.getCreateTime() != null, SysOaAttendance::getCreateTime, bo.getCreateTime());
return lqw;
}
@@ -122,8 +129,8 @@ public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {
sysOaAttendanceVo.setProjectId(bo.getProjectId());
sysOaAttendanceVo.setCreateTime(firstDay);
sysOaAttendanceVo.setDelFlag(0L);
sysOaAttendanceVo.setDayLength(bo.getDayLength()!=null?bo.getDayLength():0);
sysOaAttendanceVo.setHour(bo.getHour()!=null?bo.getHour():0);
sysOaAttendanceVo.setDayLength(bo.getDayLength() != null ? bo.getDayLength() : 0);
sysOaAttendanceVo.setHour(bo.getHour() != null ? bo.getHour() : 0);
return baseMapper.updateDelAttendance(BeanUtil.toBean(sysOaAttendanceVo, SysOaAttendance.class)) > 0;
}
@@ -201,13 +208,29 @@ public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {
*/
@Override
public List<LaborCostData> workerCalc(Date time) {
// 查询所有的工人
List<Long> userIds = sysUserRoleMapper.selectUserIdsByRoleId(1852970465740505090L);
Date firstDay = getFirstDay(time);
Date lastDay = getLastDay(time);
// 查询所有的工人
List<Long> userIds = sysUserRoleMapper.selectUserIdsByRoleId(1852970465740505090L);
List<Long> workerIds = baseMapper.selectNowMonthUserId(firstDay);
// 合并并去重
workerIds = Stream
.concat(userIds.stream(), workerIds.stream())
.distinct()
.collect(Collectors.toList());
List<LaborCostData> costDataList = new ArrayList<>();
for (Long userId : userIds) {
// 检测当天是否生成了完全一样的数据
List<Long> recordIds = recordMapper.listCommonDateRecord(DateUtils.getDate(), firstDay);
if (!recordIds.isEmpty()) {
// 如果有重复的就删掉
recordMapper.deleteBatchIds(recordIds);
}
// 开始写入
for (Long userId : workerIds) {
SysUserVo sysUser = BeanUtil.toBean(sysUserService.selectUserByIdIncludingDel(userId), SysUserVo.class);
SysOaAttendanceVo sysOaAttendanceVo = new SysOaAttendanceVo();
sysOaAttendanceVo.setUserId(sysUser.getUserId());
@@ -218,8 +241,19 @@ public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {
Double workTimes = 0.0;
Double hourWorkTimes = 0.0;
Double overTime = 0.0;
Double tripDays = 0.0;
Double leaveCount = 0.0;
Double workDays = 0.0;
Set<Long> projSet = new HashSet<>();
for (SysOaAttendanceVo oaAttendanceVo : sysOaAttendanceVos) {
// 出差问题解决
// 出差
if (oaAttendanceVo.getProjectId() == 0) {
tripDays++;
} else if (oaAttendanceVo.getProjectId() == 1) {
leaveCount++;
}
if (oaAttendanceVo.getProjectId() != 0 && oaAttendanceVo.getProjectId() != 1) {
SysOaProjectVo sysOaProjectVo = projectService.queryById(oaAttendanceVo.getProjectId());
oaAttendanceVo.setColor(sysOaProjectVo.getColor());
@@ -228,7 +262,9 @@ public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {
projectVos.add(sysOaProjectVo);
workTimes += oaAttendanceVo.getWorkTimes();
hourWorkTimes += oaAttendanceVo.getHourWorkTimes();
overTime+=oaAttendanceVo.getOverTime();
overTime += oaAttendanceVo.getOverTime();
projSet.add(oaAttendanceVo.getProjectId());
workDays++;
}
}
// 此为所有小时计的综合
@@ -238,16 +274,43 @@ public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {
laborCostData.setAttendances(sysOaAttendanceVos);
laborCostData.setSysUser(sysUser);
laborCostData.setWorkTimes(workTimes);
laborCostData.setTripTimes(tripDays);
laborCostData.setAbsenceDays(leaveCount);
laborCostData.setHourWorkTime(hourWorkTimes);
// 加班时间
laborCostData.setOvertime(overTime);
costDataList.add(laborCostData);
// 构造并保存记录
addGenData(firstDay, sysUser, tripDays, leaveCount, workDays, projSet, overTime);
}
return costDataList;
}
private void addGenData(Date firstDay, SysUserVo sysUser, Double tripDays, Double leaveCount, Double workDays, Set<Long> projSet, Double overtimeSum) {
OaAttendanceRecord rec = new OaAttendanceRecord();
// relationMonth 只保留年月,可直接传入 firstDay其 day=1
rec.setRelationMonth(firstDay);
// calcTime 为当前时间
rec.setCalcTime(new Date());
// 当前操作人昵称
rec.setNickName(sysUser.getNickName());
rec.setUserId(sysUser.getUserId());
rec.setTrips(BigDecimal.valueOf(tripDays));
rec.setNotNum(BigDecimal.valueOf(leaveCount));
rec.setWorks(BigDecimal.valueOf(workDays));
rec.setProjectIds(
String.join(",",
projSet.stream().map(String::valueOf).toArray(String[]::new)
)
);
rec.setOverNum(BigDecimal.valueOf(overtimeSum));
rec.setRemark("自动统计生成");
recordMapper.insert(rec);
}
/**
* 删除当月某日所有人的记录
*
@@ -261,6 +324,25 @@ public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {
return baseMapper.delOaAttendanceAll(getFirstDay(now), getLastDay(now), day);
}
@Override
public List<AttendanceMonthlyCount> selectLastSixMonthsByMonth(String refDate) {
return baseMapper.selectLastSixMonthsByMonth(refDate);
}
@Override
public AttendanceMonthlyCount selectAttendanceMonthlyCountByMonth(String refDate) {
return baseMapper.selectAttendanceMonthlyCountByMonth(refDate);
}
@Override
public List<AttendanceMonthlyCount> selectMonthlyCounts(String refDate) {
return baseMapper.selectMonthlyCounts(refDate);
}
private Date getFirstDay(Date time) {
String firstDay = DateUtils.parseDateToStr("yyyy-MM-01", time);
return DateUtils.parseDate(firstDay);

View File

@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.oa.mapper.OaAttendanceRecordMapper">
<resultMap id="OaAttendanceRecordResult"
type="com.ruoyi.oa.domain.vo.OaAttendanceRecordVo">
<!-- ① 主键 -->
<id property="recordId" column="record_id"/>
<!-- ② 其他主字段 -->
<result property="userId" column="user_id"/>
<result property="relationMonth" column="relation_month"/>
<result property="calcTime" column="calc_time"/>
<result property="nickName" column="nick_name"/>
<result property="trips" column="trips"/>
<result property="notNum" column="not_num"/>
<result property="works" column="works"/>
<result property="projectIds" column="project_ids"/>
<result property="overNum" column="over_num"/>
<result property="laborCost" column="labor_cost"/>
<result property="remark" column="remark"/>
<!-- ③ ▶︎ 项目维度汇总列表 -->
<collection property="projectList"
ofType="com.ruoyi.oa.domain.vo.ProjectAttendanceSummaryVo"
javaType="list">
<result property="projectId" column="project_id"/>
<result property="projectName" column="project_name"/>
<result property="color" column="color"/>
<result property="workTimes" column="work_times"/>
<result property="hourWorkTimes" column="hour_work_times"/>
<result property="overTime" column="over_time"/>
<result property="tripDays" column="trip_days"/>
</collection>
</resultMap>
<!-- ========= 项目维度汇总查询 ========= -->
<select id="selectVoByIdPlus"
parameterType="Long"
resultMap="OaAttendanceRecordResult">
SELECT r.record_id,
r.user_id,
r.relation_month,
r.calc_time,
r.nick_name,
u.labor_cost,
r.trips,
r.not_num,
r.works,
r.project_ids,
r.over_num,
r.remark,
p.project_id,
p.project_name,
p.color,
IFNULL(m.work_times, 0) AS work_times,
IFNULL(m.hour_work_times, 0) AS hour_work_times,
IFNULL(m.over_time, 0) AS over_time,
IFNULL(m.trip_days, 0) AS trip_days
FROM oa_attendance_record r
LEFT JOIN sys_user u
ON u.user_id = r.user_id
LEFT JOIN sys_oa_project p
ON FIND_IN_SET(p.project_id, r.project_ids)
LEFT JOIN (SELECT user_id,
project_id,
DATE_FORMAT(create_time, '%Y-%m') AS relation_month,
COUNT(CASE WHEN project_id != 0 and project_id != 1 THEN 1 END) AS work_times,
SUM(CASE
WHEN project_id != 0
THEN IFNULL(hour, 0) + day_length * 8
ELSE 0 END) AS hour_work_times,
SUM(CASE
WHEN IFNULL(hour, 0) > 0
THEN (IFNULL(hour, 0)) - 8
ELSE 0 END) AS over_time,
SUM(CASE
WHEN project_id = 1
THEN day_length
ELSE 0 END) AS trip_days
FROM sys_oa_attendance
WHERE del_flag = 0
GROUP BY user_id, project_id, relation_month) m
ON m.user_id = r.user_id
AND m.project_id = p.project_id
AND m.relation_month =DATE_FORMAT( r.relation_month , '%Y-%m')
WHERE r.del_flag = 0
AND r.record_id = #{recordId}
</select>
<select id="listGenDate" resultType="java.lang.String">
select distinct calc_time
from oa_attendance_record
where YEAR(relation_month) = YEAR(#{date})
and MONTH(relation_month) = month(#{date})
and del_flag = 0
</select>
<select id="listCommonDateRecord" resultType="Long">
select record_id
from oa_attendance_record
where YEAR(calc_time) = YEAR(#{date})
and MONTH(calc_time) = month(#{date})
and DAY(calc_time) = DAY(#{date})
and YEAR(relation_month) = YEAR(#{firstDay})
and MONTH(relation_month) = month(#{firstDay})
and del_flag = 0
</select>
</mapper>

View File

@@ -5,7 +5,7 @@
<mapper namespace="com.ruoyi.oa.mapper.OaReportDetailMapper">
<resultMap type="com.ruoyi.oa.domain.OaReportDetail" id="OaReportDetailResult">
<result property="id" column="id"/>
<result property="detailId" column="detail_id"/>
<result property="summaryId" column="summary_id"/>
<result property="deviceCode" column="device_code"/>
<result property="category" column="category"/>
@@ -19,6 +19,29 @@
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectVoByIdPlus" parameterType="Long" resultType="com.ruoyi.oa.domain.vo.OaReportDetailVo">
select ord.detail_id,
summary_id,
device_code,
category,
device_description,
report_detail,
oss_ids,
create_by,
create_time,
update_by,
update_time,
del_flag,
remark,
(
SELECT GROUP_CONCAT(so.url SEPARATOR ',')
FROM sys_oss so
WHERE FIND_IN_SET(so.oss_id, ord.oss_ids) > 0
) AS images
from oa_report_detail ord
where ord.detail_id = #{id}
</select>
</mapper>

View File

@@ -5,7 +5,7 @@
<mapper namespace="com.ruoyi.oa.mapper.OaReportSummaryMapper">
<resultMap type="com.ruoyi.oa.domain.OaReportSummary" id="OaReportSummaryResult">
<result property="id" column="id"/>
<result property="summaryId" column="summary_id"/>
<result property="reportTitle" column="report_title"/>
<result property="reportDate" column="report_date"/>
<result property="reporter" column="reporter"/>
@@ -16,11 +16,12 @@
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
<result property="type" column="type"/>
</resultMap>
<select id="selectVoPageWithProject" resultType="com.ruoyi.oa.domain.vo.OaReportSummaryVo">
SELECT
s.id,
s.summary_id as summaryId,
s.report_title AS reportTitle,
s.report_date AS reportDate,
s.reporter,

View File

@@ -1,7 +1,7 @@
<?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">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.oa.mapper.SysOaAttendanceMapper">
<resultMap type="com.ruoyi.oa.domain.vo.SysOaAttendanceVo" id="SysOaAttendanceResult">
@@ -110,16 +110,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ANY_VALUE(remark) AS remark,
ANY_VALUE(del_flag) AS del_flag,
COUNT(id) AS count,
/*
1如果这条记录是按天统计 (day_length>0),就直接用 day_length。
2如果这条记录是按小时统计 (hour>0),那么就算作 1 天。
这样就不会把多日的小时相加再去整除 8。
*/
SUM(
CASE
WHEN day_length > 0 THEN day_length
WHEN hour > 0 THEN ROUND(hour / 8, 1)
WHEN day_length > 0 THEN 1
WHEN hour > 0 THEN 1
ELSE 0
END
) AS work_times,
@@ -130,20 +124,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ELSE 0
END
) AS hour_work_times,
/*
overTime如果是按小时统计且 hour>8才有加班 = (hour - 8)。
如果是 day_length 统计,则一般不会再去算小时加班(你如果有需要,也可以自己按其它规则)。
*/
SUM(
IF(hour > 8, hour - 8, 0)
) AS overTime,
/* ---------- 出差天数 (project_id = 0) ---------- */
SUM(
IF(project_id = 0, 1, 0)
) AS tripDays,
/* ---------- 请假天数 (project_id = 1) ---------- */
SUM(
IF(project_id = 1, 1, 0)
) AS absenceDays
@@ -166,10 +153,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
soa.id,soa.attendance_day,soa.project_id,soa.day_length,soa.hour,
color,
sop.project_name, sop.project_num, sop.project_type, sop.address, sop.funds, sop.functionary, sop.begin_time,
sop.finish_time, sop.delivery, sop.guarantee, sop.introduction, sop.project_grade, sop.project_status, sop.contract_id, sop.invoice_name,
sop.invoice_number, sop.invoice_address, sop.invoice_bank, sop.accessory, sop.bail,sop.is_postpone, sop.postpone_reason,sop.postpone_time
sop.finish_time, sop.delivery, sop.guarantee, sop.introduction, sop.project_grade, sop.project_status,
sop.contract_id, sop.invoice_name,
sop.invoice_number, sop.invoice_address, sop.invoice_bank, sop.accessory, sop.bail,sop.is_postpone,
sop.postpone_reason,sop.postpone_time
FROM sys_user su
left join sys_oa_attendance soa on (su.user_id = soa.user_id and (soa.create_time BETWEEN #{firstDay} AND #{lastDay}))
left join sys_oa_attendance soa on (su.user_id = soa.user_id and (soa.create_time BETWEEN #{firstDay} AND
#{lastDay}))
left join sys_oa_project sop on soa.project_id = sop.project_id
WHERE su.user_id IN
<foreach item="userId" index="index" collection="userIds"
@@ -181,7 +171,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="queryListByTime" resultMap="SysOaAttendanceResult">
SELECT id, user_id, attendance_day, project_id, day_length, hour, create_time, create_by, update_time, update_by, remark, del_flag
SELECT id,
user_id,
attendance_day,
project_id,
day_length,
hour,
create_time,
create_by,
update_time,
update_by,
remark,
del_flag
FROM sys_oa_attendance
WHERE create_time BETWEEN #{startTime} AND #{endTime}
AND user_id = #{userId}
@@ -190,18 +191,143 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<delete id="delOaAttendanceAll">
delete from sys_oa_attendance where
attendance_day = #{day}
and #{lastDay} > create_time
and create_time > #{firstDay}
delete
from sys_oa_attendance
where attendance_day = #{day}
and #{lastDay} > create_time
and create_time > #{firstDay}
</delete>
<select id="getAttendanceDay" resultType="java.lang.Double">
select sum(day_length)
from sys_oa_attendance
where user_id = #{userId} and project_id = #{projectId} and del_flag = '0'
select sum(day_length)
from sys_oa_attendance
where user_id = #{userId}
and project_id = #{projectId}
and del_flag = '0'
</select>
<select id="selectNowMonthUserId" resultType="java.lang.Long">
select distinct user_id
from sys_oa_attendance
where YEAR(create_time) = YEAR(#{firstDay})
and MONTH(create_time) = MONTH(#{firstDay})
</select>
<!-- 结果映射 -->
<resultMap id="AttendanceMonthlyCountMap" type="com.ruoyi.oa.domain.vo.AttendanceMonthlyCount">
<result column="month" property="month"/>
<result column="attendance_count" property="attendanceCount"/>
<result column="leave_count" property="leaveCount"/>
</resultMap>
<select id="selectLastSixMonthsByMonth"
resultMap="AttendanceMonthlyCountMap">
SELECT DATE_FORMAT(create_time, '%Y-%m') AS month,
SUM(CASE WHEN project_id != 1 THEN 1 ELSE 0 END) AS attendance_count,
SUM(CASE WHEN project_id = 1 THEN 1 ELSE 0 END) AS leave_count
FROM sys_oa_attendance
WHERE create_time >= DATE_FORMAT(DATE_SUB(#{refDate}, INTERVAL 6 MONTH), '%Y-%m-01')
AND IF(DATE_FORMAT(#{refDate}, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m'), NOW(),
TIMESTAMP(LAST_DAY(DATE_SUB(#{refDate}, INTERVAL 1 MONTH)), '23:59:59'))
>= create_time
AND del_flag = 0
GROUP BY month
ORDER BY month;
</select>
<select id="selectAttendanceMonthlyCountByMonth"
resultType="com.ruoyi.oa.domain.vo.AttendanceMonthlyCount">
SELECT
-- 1) project_id = 0 : 出勤 / 出差工时(天长 * 8 + 小时)
SUM(
IF(project_id != 1 and project_id != 0, IFNULL(day_length, 0) * 8 -- day_length换算成小时
+ IFNULL(hour, 0), 0)
) AS workHours,
SUM(
IF(project_id = 0,8,0)
) AS tripHours,
-- 2) project_id = 1 : 请假工时(每条记录按 8 小时计)
SUM(
IF(project_id = 1, 8, 0)
) AS leaveHours,
-- 3) 加班工时project_id = 0 情况下hour 字段超出 8 小时的部分求和
SUM(
IF(project_id != 1, GREATEST(IFNULL(hour, 0) - 8, 0), 0)
) AS overtimeHours
FROM sys_oa_attendance
WHERE del_flag = 0
AND YEAR(create_time) = YEAR(#{refDate})
and MONTH(create_time) = MONTH(#{refDate})
</select>
<select id="selectMonthlyCounts" resultType="com.ruoyi.oa.domain.vo.AttendanceMonthlyCount">
SELECT m.month,
ROUND(
COUNT(
DISTINCT CASE
WHEN a.project_id NOT IN (0, 1)
THEN CONCAT(a.user_id, '_', DATE(a.create_time))
END
)
/
NULLIF(
COUNT(
DISTINCT CASE
WHEN a.project_id != 0
THEN a.user_id
END
)
*
COUNT(
DISTINCT CASE
WHEN a.project_id != 0
THEN DATE(a.create_time)
END
),
0
),
4
) AS attendanceRate,
SUM(CASE WHEN a.project_id = 0 THEN 1 ELSE 0 END) AS tripCount,
COUNT(CASE WHEN a.project_id = 1 THEN 1 END) AS leavePeople,
SUM(CASE
WHEN a.project_id NOT IN (0, 1)
AND IFNULL(a.hour, 0) > 8
THEN IFNULL(a.hour, 0) - 8
ELSE 0
END) AS overtimeHours
FROM (SELECT DATE_FORMAT(#{refDate}, '%Y-%m') AS month,
LAST_DAY(#{refDate}) AS last_day,
CASE
WHEN DATE_FORMAT(#{refDate}, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m')
THEN DAY(#{refDate}) -- 本月:已过天数
ELSE DAY(LAST_DAY(#{refDate})) -- 历史月:整月天数
END AS days_so_far
UNION ALL
SELECT DATE_FORMAT(DATE_SUB(#{refDate}, INTERVAL 1 MONTH), '%Y-%m'),
LAST_DAY(DATE_SUB(#{refDate}, INTERVAL 1 MONTH)),
DAY(LAST_DAY(DATE_SUB(#{refDate}, INTERVAL 1 MONTH)))) m
LEFT JOIN sys_oa_attendance a
ON a.del_flag = 0
AND DATE_FORMAT(a.create_time, '%Y-%m') = m.month
AND a.create_time &lt;=
CASE
WHEN m.month = DATE_FORMAT(CURDATE(), '%Y-%m')
THEN #{refDate}
ELSE TIMESTAMP(m.last_day, '23:59:59')
END
GROUP BY m.month
ORDER BY m.month DESC; -- 本月在前,上月在后
</select>
</mapper>