From 6cfa7d7528d4108b7d6f283507c10e02be58c0d1 Mon Sep 17 00:00:00 2001 From: hdka <823267011@qq.com> Date: Sun, 9 Mar 2025 19:04:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=87=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oa/controller/OaSalaryController.java | 8 + .../com/ruoyi/oa/domain/bo/OaSalaryBo.java | 1 + .../com/ruoyi/oa/mapper/OaSalaryMapper.java | 3 + .../ruoyi/oa/service/IOaSalaryService.java | 7 + .../oa/service/impl/OaSalaryServiceImpl.java | 326 ++++++++++++++++- .../service/impl/SysOaHolidayServiceImpl.java | 2 +- .../resources/mapper/oa/OaSalaryMapper.xml | 58 ++- ruoyi-ui/.env.development | 4 +- ruoyi-ui/src/views/oa/apply/trip/index.vue | 329 ++++++++++++++++++ 9 files changed, 713 insertions(+), 25 deletions(-) create mode 100644 ruoyi-ui/src/views/oa/apply/trip/index.vue diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaSalaryController.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaSalaryController.java index 2efe467..e073f69 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaSalaryController.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaSalaryController.java @@ -48,6 +48,14 @@ public class OaSalaryController extends BaseController { return iOaSalaryService.queryPageList(bo, pageQuery); } + /** + * 批量写入user到salary中 + */ + @GetMapping("/import") + public R importSalaryUser() { + return iOaSalaryService.importSalaryUser(); + } + /** * 导出薪资管理列表 */ diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaSalaryBo.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaSalaryBo.java index 4dce44f..8e42efc 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaSalaryBo.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaSalaryBo.java @@ -44,6 +44,7 @@ public class OaSalaryBo extends BaseEntity { */ @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd") + @NotBlank(message = "发放时间不能为空") private Date payTime; /** diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaSalaryMapper.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaSalaryMapper.java index 3557d9f..ad13f42 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaSalaryMapper.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaSalaryMapper.java @@ -18,4 +18,7 @@ import org.apache.ibatis.annotations.Param; public interface OaSalaryMapper extends BaseMapperPlus { Page selectStaffVoPage(Page build,@Param(Constants.WRAPPER) Wrapper lqw); + + + OaSalary selectVoByUserId(Long userId); } diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaSalaryService.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaSalaryService.java index fea17f3..3d9d235 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaSalaryService.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaSalaryService.java @@ -1,5 +1,6 @@ package com.ruoyi.oa.service; +import com.ruoyi.common.core.domain.R; import com.ruoyi.oa.domain.OaSalary; import com.ruoyi.oa.domain.vo.OaSalaryVo; import com.ruoyi.oa.domain.bo.OaSalaryBo; @@ -53,4 +54,10 @@ public interface IOaSalaryService { * @param bo */ void calcSalary(OaSalaryBo bo); + + /** + * 导入当月所有人的记录 + * @return + */ + R importSalaryUser(); } diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaSalaryServiceImpl.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaSalaryServiceImpl.java index 184b88d..62c5a5d 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaSalaryServiceImpl.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaSalaryServiceImpl.java @@ -1,19 +1,38 @@ package com.ruoyi.oa.service.impl; import cn.hutool.core.bean.BeanUtil; +import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.service.UserService; 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 com.ruoyi.flowable.utils.TaskUtils; +import com.ruoyi.oa.domain.OaSalaryItem; import com.ruoyi.oa.domain.vo.CalcResultVo; +import com.ruoyi.oa.domain.vo.SysOaHolidayVo; +import com.ruoyi.oa.mapper.OaSalaryItemMapper; +import com.ruoyi.oa.service.IOaSalaryItemService; +import com.ruoyi.oa.service.ISysOaHolidayService; import com.ruoyi.oa.utils.OwnHttpUtils; +import com.ruoyi.system.service.ISysDeptService; +import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysUserService; +import com.ruoyi.workflow.mapper.WfDeployFormMapper; +import com.ruoyi.workflow.service.IWfTaskService; import liquibase.pro.packaged.A; import lombok.RequiredArgsConstructor; import org.apache.catalina.User; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.repository.Deployment; +import org.flowable.task.api.TaskQuery; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.oa.domain.bo.OaSalaryBo; @@ -22,9 +41,15 @@ import com.ruoyi.oa.domain.OaSalary; import com.ruoyi.oa.mapper.OaSalaryMapper; import com.ruoyi.oa.service.IOaSalaryService; -import java.util.List; -import java.util.Map; -import java.util.Collection; +import javax.annotation.Resource; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.*; /** * 薪资管理Service业务层处理 @@ -38,9 +63,29 @@ public class OaSalaryServiceImpl implements IOaSalaryService { private final OaSalaryMapper baseMapper; + private final IWfTaskService wfTaskService; + + private final WfDeployFormMapper deployFormMapper; + + @Resource + private RepositoryService repositoryService; + + @Resource + private TaskService taskService; + + @Resource + private HistoryService historyService; + + @Autowired private ISysUserService userService; + @Autowired + private ISysOaHolidayService holidayService; + + @Autowired + private OaSalaryItemMapper salaryItemMapper; + /** * 查询薪资管理 */ @@ -59,6 +104,19 @@ public class OaSalaryServiceImpl implements IOaSalaryService { return TableDataInfo.build(result); } + @Override + public R importSalaryUser() { + SysUser sysUser = new SysUser(); + List sysUsers = userService.selectUserList(sysUser); + for (SysUser user : sysUsers) { + OaSalary oaSalary = new OaSalary(); + oaSalary.setUserId(user.getUserId()); + oaSalary.setBaseSalary(Double.valueOf(user.getLaborCost())); + oaSalary.setPayTime(new Date()); + baseMapper.insert(oaSalary); + } + return R.ok(); + } /** * 查询薪资管理列表 */ @@ -120,23 +178,279 @@ public class OaSalaryServiceImpl implements IOaSalaryService { return baseMapper.deleteBatchIds(ids) > 0; } + /** + * 计算薪资 + * @param bo + */ @Override public void calcSalary(OaSalaryBo bo) { // 1先获取对应的json路径 "/home/ubuntu/lyq/fad_oa_kqdeal/202411.json" String jsonPath = OwnHttpUtils.getJsonName(bo.getMonthStr(), bo.getFilePath()); // 2拿到所有的用户 SysUser sysUser = new SysUser(); + Date yearMonth = StringToDate(combineYearMonth(bo.getMonthStr())); List sysUsers = userService.selectUserList(sysUser); // 3遍历user列表 拿出所有的nickName分别拿到他们的json 进行第二步分析 for (SysUser user : sysUsers) { + OaSalary salary = baseMapper.selectVoByUserId(user.getUserId()); + if (salary == null) { + return; + } // 3.1 拿到一个人打卡机的记录 CalcResultVo res = OwnHttpUtils.getBaseCalc(jsonPath,user.getNickName()); - // 3.2 通过打卡机拿到的记录去和差旅表、请假申请表、假期表做比对 + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery() + .startedBy(String.valueOf(user.getUserId())) + .orderByProcessInstanceStartTime() + .desc(); + // 3.3 查询到他所有的任务 其中包括了差旅申请和请假申请的事 + List list = historicProcessInstanceQuery.list(); + for (HistoricProcessInstance historicProcessInstance : list) { + Deployment deployment = repositoryService.createDeploymentQuery() + .deploymentId(historicProcessInstance.getDeploymentId()).singleResult(); + // 这个deployment可以拿到他的分类信息 这里我需要的是 trip和absence + if (deployment.getCategory()=="absence" || deployment.getCategory()=="trip") { + TaskQuery taskQuery = taskService.createTaskQuery() + .taskCategory(deployment.getCategory()); + taskQuery.list().forEach(task -> { + Map processVariables = task.getProcessVariables(); + String startTime = String.valueOf(processVariables.get("startTime")); + String endTime = String.valueOf(processVariables.get("endTime")); + List timeRange = getDateRange(startTime, endTime); + if (deployment.getCategory().equals("absence")){ + // 这里的item为1时则为是上午 否则为下午 + Long startTimeItem = (Long) processVariables.get("startTimeItem"); + Long endTimeItem = (Long) processVariables.get("endTimeItem"); + } + // 计算缺席的某天是否请假或者出差 + List absentDates = res.getAbsentDates(); + List realDates = new ArrayList<>(); + List real05Dates = new ArrayList<>(); + for (String absentDate : absentDates) { + // 形如2024-11-01 + String fullDate = combineYearMonthAndDay(bo.getMonthStr(), absentDate); + boolean contains = timeRange.contains(fullDate); + // 如果为false 则说明此天没有请假或者出差则将其记录 + if (!contains) { + realDates.add(fullDate); + } + } + for (String real05Date : real05Dates) { + String fullDate = combineYearMonthAndDay(bo.getMonthStr(), real05Date); + boolean contains = timeRange.contains(fullDate); + if (!contains) { + real05Dates.add(fullDate); + } + } + // 这次已经将缺勤拿出来了 现在还要判断今天是否为节假日 + List realDate2 =new ArrayList<>(); + for (String realDate : realDates) { + SysOaHolidayVo sysOaHolidayVo = holidayService.queryHolidayByDate(StringToDate(realDate)); + if (sysOaHolidayVo != null && sysOaHolidayVo.getType()!=0 ) { + // 如果不为节假日则加入进去 + realDate2.add(realDate); + } + } + List real05Date2 =new ArrayList<>(); + for (String real05Date : real05Dates) { + SysOaHolidayVo sysOaHolidayVo = holidayService.queryHolidayByDate(StringToDate(real05Date)); + if (sysOaHolidayVo != null && sysOaHolidayVo.getType()!=0 ) { + // 如果不为节假日则加入进去 + real05Date2.add(real05Date); + } - // TODO 思考这里有两种情况 首先可能是车间员工他们有一个打卡表可以通过Attendence表进行比对,但是是否还会出现上下午的问题呢 - // TODO 第二种情况是职工,他们只能通过差旅报销去判断 + } + buildItemAbsent(realDate2, salary,1.0,yearMonth); + buildItemAbsent(real05Date2, salary,0.5,yearMonth); + }); + } + } + + // 3.4创建其他的item包括了好多罚金 + // 3.4.1 迟到罚金 + StringBuilder sb= new StringBuilder(); + for (String lateDate : res.getLateDates()) { + sb.append(lateDate); + sb.append(","); + } + sb.append("迟到日期"); + OaSalaryItem oaSalaryItem = new OaSalaryItem(); + oaSalaryItem.setSalaryId(salary.getSalaryId()); + oaSalaryItem.setPrice(Double.valueOf(res.getLateFee())); + oaSalaryItem.setType(4L); + oaSalaryItem.setFlag(0L); + oaSalaryItem.setReason(sb.toString()); + oaSalaryItem.setSignTime(yearMonth); + salaryItemMapper.insert(oaSalaryItem); + // 3.4.2 早退罚金 + sb= new StringBuilder(); + for (String lateDate : res.getLeaveEarly10Dates()) { + sb.append(lateDate); + sb.append(","); + } + sb.append("早退日期十分钟"); + for (String lateDate : res.getLeaveEarly30Dates()) { + sb.append(lateDate); + sb.append(","); + } + sb.append("早退日期三十分钟"); + oaSalaryItem = new OaSalaryItem(); + oaSalaryItem.setSalaryId(salary.getSalaryId()); + oaSalaryItem.setPrice(Double.valueOf(res.getLeaveEarlyFee())); + oaSalaryItem.setType(5L); + oaSalaryItem.setFlag(0L); + oaSalaryItem.setReason(sb.toString()); + oaSalaryItem.setSignTime(yearMonth); + salaryItemMapper.insert(oaSalaryItem); + // 3.4.3 打卡罚金 + sb= new StringBuilder(); + for (String lateDate : res.getLateDates()) { + sb.append(lateDate); + sb.append(","); + } + sb.append("未打卡"); + oaSalaryItem = new OaSalaryItem(); + oaSalaryItem.setSalaryId(salary.getSalaryId()); + oaSalaryItem.setPrice(Double.valueOf(res.getNotAttendanceFee())); + oaSalaryItem.setType(6L); + oaSalaryItem.setFlag(0L); + oaSalaryItem.setReason(sb.toString()); + oaSalaryItem.setSignTime(yearMonth); + salaryItemMapper.insert(oaSalaryItem); } } + + + + private void buildItemAbsent(List realDate2, OaSalary salary,Double flag,Date yearMonth) { + // 最终这个为缺勤日期 + OaSalaryItem oaSalaryItem = new OaSalaryItem(); + StringBuilder sb = new StringBuilder(); + // 接下来将他拼接成一个字符串为扣款原因矿工问题 + for (String s : realDate2) { + sb.append(s); + sb.append(","); + } + if (flag>0.5){ + sb.append("旷工整天"); + }else{ + sb.append("旷工半天"); + } + oaSalaryItem.setType(3L); + oaSalaryItem.setReason(String.valueOf(sb)); + oaSalaryItem.setPrice(2* salary.getBaseSalary()* realDate2.size()*flag); + oaSalaryItem.setFlag(0L); + oaSalaryItem.setSignTime(yearMonth); + oaSalaryItem.setSalaryId(salary.getSalaryId()); + salaryItemMapper.insert(oaSalaryItem); + } + + /** + * 获取从 startTime 到 endTime(含首尾)的所有日期列表 + * + * @param startTime 字符串格式 "yyyy-MM-dd" 的开始日期 + * @param endTime 字符串格式 "yyyy-MM-dd" 的结束日期 + * @return 日期列表,每个元素形如 "yyyy-MM-dd" + */ + public static List getDateRange(String startTime, String endTime) { + // 1. 定义解析与输出格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + try { + // 2. 解析成 LocalDate + LocalDate startDate = LocalDate.parse(startTime, formatter); + LocalDate endDate = LocalDate.parse(endTime, formatter); + + // 若开始日期大于结束日期,则抛异常(也可根据需求改成自动调换顺序) + if (startDate.isAfter(endDate)) { + throw new IllegalArgumentException("开始日期不得晚于结束日期: " + + startTime + " > " + endTime); + } + + // 3. 循环遍历日期,加入列表 + List dateList = new ArrayList<>(); + LocalDate currentDate = startDate; + while (!currentDate.isAfter(endDate)) { + // 每次加入 "yyyy-MM-dd" 格式字符串 + dateList.add(currentDate.format(formatter)); + // 加 1 天 + currentDate = currentDate.plusDays(1); + } + + return dateList; + } catch (DateTimeParseException e) { + // 如果传入的日期字符串格式不对,抛出异常或自行处理 + throw new IllegalArgumentException("日期格式错误,要求 yyyy-MM-dd", e); + } + } + + + /** + * 将形如 "202411" (yyyyMM) 和 "11-04" (MM-dd) 拼装成 "2024-11-04" (yyyy-MM-dd) + * + * @param yearMonth 形如 "202411" 的字符串 (前4位为年份, 后2位为月份) + * @param monthDay 形如 "11-04" 的字符串 (前2位为月份, 后2位为天数) + * @return 拼装好的 "yyyy-MM-dd" + */ + private String combineYearMonthAndDay(String yearMonth, String monthDay) { + // 1. 拆解第一个参数: "202411" => 年 (2024), 月 (11) + String year = yearMonth.substring(0, 4); // "2024" + String monthFromYearMonth = yearMonth.substring(4, 6); // "11" + + // 2. 拆解第二个参数: "11-04" => 月 (11), 日 (04) + String[] parts = monthDay.split("-"); + if (parts.length != 2) { + throw new IllegalArgumentException("传入的 monthDay 格式不正确, 应形如 'MM-dd'。实际传入: " + monthDay); + } + String monthFromMonthDay = parts[0]; // "11" + String day = parts[1]; // "04" + + // 3. 校验两个“月”是否一致(可选) + if (!monthFromYearMonth.equals(monthFromMonthDay)) { + throw new IllegalArgumentException("yearMonth 与 monthDay 中的 '月' 不匹配: " + + monthFromYearMonth + " != " + monthFromMonthDay); + } + + // 4. 组合成 yyyy-MM-dd 格式 + return year + "-" + monthFromYearMonth + "-" + day; + } + + /** + * 将形如 "202411" (yyyyMM) 和 "11-04" (MM-dd) 拼装成 "2024-11-04" (yyyy-MM-dd) + * + * @param yearMonth 形如 "202411" 的字符串 (前4位为年份, 后2位为月份) + * @return 拼装好的 "yyyy-MM-dd" + */ + private String combineYearMonth(String yearMonth) { + // 1. 拆解第一个参数: "202411" => 年 (2024), 月 (11) + String year = yearMonth.substring(0, 4); // "2024" + String monthFromYearMonth = yearMonth.substring(4, 6); // "11" + // 4. 组合成 yyyy-MM-dd 格式 + return year + "-" + monthFromYearMonth; + } + + private Date StringToDate(String dateStr) { + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + // 1. 先解析成 LocalDateTime + LocalDateTime localDateTime = LocalDateTime.parse(dateStr, formatter); + + // 2. 转换为 Instant(指定时区) + Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant(); + + // 3. 转换成旧版 Date + return Date.from(instant); + + } + + private String DateToString(Date date) { + // 2. 构造解析器,指定格式。例如 "yyyy-MM-dd" + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + // 3. 调用 parse() 将字符串转为 Date + + return sdf.format(date); + + } } diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/SysOaHolidayServiceImpl.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/SysOaHolidayServiceImpl.java index d0649c2..64881f7 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/SysOaHolidayServiceImpl.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/SysOaHolidayServiceImpl.java @@ -120,7 +120,7 @@ public class SysOaHolidayServiceImpl implements ISysOaHolidayService { @Override public SysOaHolidayVo queryHolidayByDate(Date date) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(SysOaHoliday::getHolidayTime, date); + lqw.like(SysOaHoliday::getHolidayTime, date); return baseMapper.selectVoOne(lqw); } diff --git a/ruoyi-oa/src/main/resources/mapper/oa/OaSalaryMapper.xml b/ruoyi-oa/src/main/resources/mapper/oa/OaSalaryMapper.xml index e76765d..ba41cda 100644 --- a/ruoyi-oa/src/main/resources/mapper/oa/OaSalaryMapper.xml +++ b/ruoyi-oa/src/main/resources/mapper/oa/OaSalaryMapper.xml @@ -21,31 +21,57 @@ + + + diff --git a/ruoyi-ui/.env.development b/ruoyi-ui/.env.development index 20b1ce2..5abea97 100644 --- a/ruoyi-ui/.env.development +++ b/ruoyi-ui/.env.development @@ -5,8 +5,8 @@ VUE_APP_TITLE = 福安德综合办公系统 ENV = 'development' # 若依管理系统/开发环境 -# VUE_APP_BASE_API = '/prod-api' -VUE_APP_BASE_API = 'http://110.41.139.73:8080' +VUE_APP_BASE_API = '/prod-api' +# VUE_APP_BASE_API = 'http://110.41.139.73:8080' # 应用访问路径 例如使用前缀 /admin/ VUE_APP_CONTEXT_PATH = '/' diff --git a/ruoyi-ui/src/views/oa/apply/trip/index.vue b/ruoyi-ui/src/views/oa/apply/trip/index.vue new file mode 100644 index 0000000..98de25a --- /dev/null +++ b/ruoyi-ui/src/views/oa/apply/trip/index.vue @@ -0,0 +1,329 @@ + + +