备份
This commit is contained in:
@@ -48,6 +48,14 @@ public class OaSalaryController extends BaseController {
|
|||||||
return iOaSalaryService.queryPageList(bo, pageQuery);
|
return iOaSalaryService.queryPageList(bo, pageQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量写入user到salary中
|
||||||
|
*/
|
||||||
|
@GetMapping("/import")
|
||||||
|
public R<Void> importSalaryUser() {
|
||||||
|
return iOaSalaryService.importSalaryUser();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出薪资管理列表
|
* 导出薪资管理列表
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public class OaSalaryBo extends BaseEntity {
|
|||||||
*/
|
*/
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@NotBlank(message = "发放时间不能为空")
|
||||||
private Date payTime;
|
private Date payTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,4 +18,7 @@ import org.apache.ibatis.annotations.Param;
|
|||||||
public interface OaSalaryMapper extends BaseMapperPlus<OaSalaryMapper, OaSalary, OaSalaryVo> {
|
public interface OaSalaryMapper extends BaseMapperPlus<OaSalaryMapper, OaSalary, OaSalaryVo> {
|
||||||
|
|
||||||
Page<OaSalaryVo> selectStaffVoPage(Page<Object> build,@Param(Constants.WRAPPER) Wrapper<OaSalary> lqw);
|
Page<OaSalaryVo> selectStaffVoPage(Page<Object> build,@Param(Constants.WRAPPER) Wrapper<OaSalary> lqw);
|
||||||
|
|
||||||
|
|
||||||
|
OaSalary selectVoByUserId(Long userId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.ruoyi.oa.service;
|
package com.ruoyi.oa.service;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.domain.R;
|
||||||
import com.ruoyi.oa.domain.OaSalary;
|
import com.ruoyi.oa.domain.OaSalary;
|
||||||
import com.ruoyi.oa.domain.vo.OaSalaryVo;
|
import com.ruoyi.oa.domain.vo.OaSalaryVo;
|
||||||
import com.ruoyi.oa.domain.bo.OaSalaryBo;
|
import com.ruoyi.oa.domain.bo.OaSalaryBo;
|
||||||
@@ -53,4 +54,10 @@ public interface IOaSalaryService {
|
|||||||
* @param bo
|
* @param bo
|
||||||
*/
|
*/
|
||||||
void calcSalary(OaSalaryBo bo);
|
void calcSalary(OaSalaryBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入当月所有人的记录
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
R<Void> importSalaryUser();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,38 @@
|
|||||||
package com.ruoyi.oa.service.impl;
|
package com.ruoyi.oa.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
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.domain.entity.SysUser;
|
||||||
|
import com.ruoyi.common.core.service.UserService;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
import com.ruoyi.common.core.domain.PageQuery;
|
import com.ruoyi.common.core.domain.PageQuery;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
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.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.oa.utils.OwnHttpUtils;
|
||||||
|
import com.ruoyi.system.service.ISysDeptService;
|
||||||
|
import com.ruoyi.system.service.ISysRoleService;
|
||||||
import com.ruoyi.system.service.ISysUserService;
|
import com.ruoyi.system.service.ISysUserService;
|
||||||
|
import com.ruoyi.workflow.mapper.WfDeployFormMapper;
|
||||||
|
import com.ruoyi.workflow.service.IWfTaskService;
|
||||||
import liquibase.pro.packaged.A;
|
import liquibase.pro.packaged.A;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.catalina.User;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.ruoyi.oa.domain.bo.OaSalaryBo;
|
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.mapper.OaSalaryMapper;
|
||||||
import com.ruoyi.oa.service.IOaSalaryService;
|
import com.ruoyi.oa.service.IOaSalaryService;
|
||||||
|
|
||||||
import java.util.List;
|
import javax.annotation.Resource;
|
||||||
import java.util.Map;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Collection;
|
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业务层处理
|
* 薪资管理Service业务层处理
|
||||||
@@ -38,9 +63,29 @@ public class OaSalaryServiceImpl implements IOaSalaryService {
|
|||||||
|
|
||||||
private final OaSalaryMapper baseMapper;
|
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
|
@Autowired
|
||||||
private ISysUserService userService;
|
private ISysUserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysOaHolidayService holidayService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OaSalaryItemMapper salaryItemMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询薪资管理
|
* 查询薪资管理
|
||||||
*/
|
*/
|
||||||
@@ -59,6 +104,19 @@ public class OaSalaryServiceImpl implements IOaSalaryService {
|
|||||||
return TableDataInfo.build(result);
|
return TableDataInfo.build(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<Void> importSalaryUser() {
|
||||||
|
SysUser sysUser = new SysUser();
|
||||||
|
List<SysUser> 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;
|
return baseMapper.deleteBatchIds(ids) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算薪资
|
||||||
|
* @param bo
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void calcSalary(OaSalaryBo bo) {
|
public void calcSalary(OaSalaryBo bo) {
|
||||||
// 1先获取对应的json路径 "/home/ubuntu/lyq/fad_oa_kqdeal/202411.json"
|
// 1先获取对应的json路径 "/home/ubuntu/lyq/fad_oa_kqdeal/202411.json"
|
||||||
String jsonPath = OwnHttpUtils.getJsonName(bo.getMonthStr(), bo.getFilePath());
|
String jsonPath = OwnHttpUtils.getJsonName(bo.getMonthStr(), bo.getFilePath());
|
||||||
// 2拿到所有的用户
|
// 2拿到所有的用户
|
||||||
SysUser sysUser = new SysUser();
|
SysUser sysUser = new SysUser();
|
||||||
|
Date yearMonth = StringToDate(combineYearMonth(bo.getMonthStr()));
|
||||||
List<SysUser> sysUsers = userService.selectUserList(sysUser);
|
List<SysUser> sysUsers = userService.selectUserList(sysUser);
|
||||||
// 3遍历user列表 拿出所有的nickName分别拿到他们的json 进行第二步分析
|
// 3遍历user列表 拿出所有的nickName分别拿到他们的json 进行第二步分析
|
||||||
for (SysUser user : sysUsers) {
|
for (SysUser user : sysUsers) {
|
||||||
|
OaSalary salary = baseMapper.selectVoByUserId(user.getUserId());
|
||||||
|
if (salary == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 3.1 拿到一个人打卡机的记录
|
// 3.1 拿到一个人打卡机的记录
|
||||||
CalcResultVo res = OwnHttpUtils.getBaseCalc(jsonPath,user.getNickName());
|
CalcResultVo res = OwnHttpUtils.getBaseCalc(jsonPath,user.getNickName());
|
||||||
|
|
||||||
// 3.2 通过打卡机拿到的记录去和差旅表、请假申请表、假期表做比对
|
// 3.2 通过打卡机拿到的记录去和差旅表、请假申请表、假期表做比对
|
||||||
|
HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
|
||||||
|
.startedBy(String.valueOf(user.getUserId()))
|
||||||
|
.orderByProcessInstanceStartTime()
|
||||||
|
.desc();
|
||||||
|
// 3.3 查询到他所有的任务 其中包括了差旅申请和请假申请的事
|
||||||
|
List<HistoricProcessInstance> 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<String, Object> processVariables = task.getProcessVariables();
|
||||||
|
String startTime = String.valueOf(processVariables.get("startTime"));
|
||||||
|
String endTime = String.valueOf(processVariables.get("endTime"));
|
||||||
|
List<String> timeRange = getDateRange(startTime, endTime);
|
||||||
|
if (deployment.getCategory().equals("absence")){
|
||||||
|
// 这里的item为1时则为是上午 否则为下午
|
||||||
|
Long startTimeItem = (Long) processVariables.get("startTimeItem");
|
||||||
|
Long endTimeItem = (Long) processVariables.get("endTimeItem");
|
||||||
|
}
|
||||||
|
// 计算缺席的某天是否请假或者出差
|
||||||
|
List<String> absentDates = res.getAbsentDates();
|
||||||
|
List<String> realDates = new ArrayList<>();
|
||||||
|
List<String> 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<String> realDate2 =new ArrayList<>();
|
||||||
|
for (String realDate : realDates) {
|
||||||
|
SysOaHolidayVo sysOaHolidayVo = holidayService.queryHolidayByDate(StringToDate(realDate));
|
||||||
|
if (sysOaHolidayVo != null && sysOaHolidayVo.getType()!=0 ) {
|
||||||
|
// 如果不为节假日则加入进去
|
||||||
|
realDate2.add(realDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> 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<String> 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<String> 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<String> 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);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ public class SysOaHolidayServiceImpl implements ISysOaHolidayService {
|
|||||||
@Override
|
@Override
|
||||||
public SysOaHolidayVo queryHolidayByDate(Date date) {
|
public SysOaHolidayVo queryHolidayByDate(Date date) {
|
||||||
LambdaQueryWrapper<SysOaHoliday> lqw = Wrappers.lambdaQuery();
|
LambdaQueryWrapper<SysOaHoliday> lqw = Wrappers.lambdaQuery();
|
||||||
lqw.eq(SysOaHoliday::getHolidayTime, date);
|
lqw.like(SysOaHoliday::getHolidayTime, date);
|
||||||
return baseMapper.selectVoOne(lqw);
|
return baseMapper.selectVoOne(lqw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,31 +21,57 @@
|
|||||||
|
|
||||||
|
|
||||||
<select id="selectStaffVoPage" resultMap="OaSalaryResult">
|
<select id="selectStaffVoPage" resultMap="OaSalaryResult">
|
||||||
SELECT
|
SELECT
|
||||||
os.salary_id,
|
os.salary_id,
|
||||||
os.user_id,
|
os.user_id,
|
||||||
os.pay_time,
|
os.pay_time,
|
||||||
os.base_salary,
|
os.base_salary,
|
||||||
(os.base_salary * DAY(LAST_DAY(#{payTime})) +
|
(
|
||||||
COALESCE(SUM(CASE
|
os.base_salary * DAY(LAST_DAY(#{payTime}))
|
||||||
WHEN osi.flag = 1 THEN osi.price
|
+ COALESCE(SUM(
|
||||||
WHEN osi.flag = 0 AND osi.type = 3 THEN -2 * osi.price
|
CASE
|
||||||
WHEN osi.flag = 0 THEN -osi.price
|
WHEN osi.flag = 1 THEN osi.price
|
||||||
ELSE 0
|
WHEN osi.flag = 0 THEN -osi.price
|
||||||
END), 0)
|
ELSE 0
|
||||||
) AS real_salary,
|
END
|
||||||
|
), 0)
|
||||||
|
) AS real_salary,
|
||||||
osi.salary_item_id,
|
osi.salary_item_id,
|
||||||
osi.sign_time,
|
osi.sign_time,
|
||||||
su.nick_name
|
su.nick_name
|
||||||
FROM oa_salary os
|
FROM oa_salary os
|
||||||
LEFT JOIN oa_salary_item osi ON osi.salary_id = os.salary_id
|
LEFT JOIN oa_salary_item osi
|
||||||
|
ON osi.salary_id = os.salary_id
|
||||||
AND YEAR(osi.sign_time) = YEAR(#{payTime})
|
AND YEAR(osi.sign_time) = YEAR(#{payTime})
|
||||||
AND MONTH(osi.sign_time) = MONTH(#{payTime})
|
AND MONTH(osi.sign_time) = MONTH(#{payTime})
|
||||||
LEFT JOIN sys_user su on os.user_id = su.user_id
|
LEFT JOIN sys_user su ON os.user_id = su.user_id
|
||||||
WHERE YEAR(os.pay_time) = YEAR(#{payTime})
|
|
||||||
AND MONTH(os.pay_time) = MONTH(#{payTime})
|
<!-- 这里使用 <where> 标签统一管理条件 -->
|
||||||
GROUP BY os.salary_id, os.user_id, os.pay_time, os.base_salary, osi.salary_item_id, osi.type, osi.reason, osi.price, osi.sign_time;
|
<where>
|
||||||
${ew.getCustomSqlSegment}
|
YEAR(os.pay_time) = YEAR(#{payTime})
|
||||||
|
AND MONTH(os.pay_time) = MONTH(#{payTime})
|
||||||
|
|
||||||
|
<!-- 如果 ew 中带了自定义条件,就在这里追加 -->
|
||||||
|
<if test="ew != null and ew.customSqlSegment != null and ew.customSqlSegment != ''">
|
||||||
|
AND ${ew.customSqlSegment}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
|
||||||
|
GROUP BY
|
||||||
|
os.salary_id,
|
||||||
|
os.user_id,
|
||||||
|
os.pay_time,
|
||||||
|
os.base_salary,
|
||||||
|
osi.salary_item_id,
|
||||||
|
osi.type,
|
||||||
|
osi.reason,
|
||||||
|
osi.price,
|
||||||
|
osi.sign_time
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
<select id="selectVoByUserId" resultType="com.ruoyi.oa.domain.OaSalary">
|
||||||
|
select * from oa_salary where user_id = #{userId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ VUE_APP_TITLE = 福安德综合办公系统
|
|||||||
ENV = 'development'
|
ENV = 'development'
|
||||||
|
|
||||||
# 若依管理系统/开发环境
|
# 若依管理系统/开发环境
|
||||||
# VUE_APP_BASE_API = '/prod-api'
|
VUE_APP_BASE_API = '/prod-api'
|
||||||
VUE_APP_BASE_API = 'http://110.41.139.73:8080'
|
# VUE_APP_BASE_API = 'http://110.41.139.73:8080'
|
||||||
|
|
||||||
# 应用访问路径 例如使用前缀 /admin/
|
# 应用访问路径 例如使用前缀 /admin/
|
||||||
VUE_APP_CONTEXT_PATH = '/'
|
VUE_APP_CONTEXT_PATH = '/'
|
||||||
|
|||||||
329
ruoyi-ui/src/views/oa/apply/trip/index.vue
Normal file
329
ruoyi-ui/src/views/oa/apply/trip/index.vue
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||||
|
<!-- <el-form-item label="流程分类" prop="category">
|
||||||
|
<el-select v-model="queryParams.category" clearable placeholder="请选择" size="small">
|
||||||
|
<el-option
|
||||||
|
v-for="item in categoryOptions"
|
||||||
|
:key="item.categoryId"
|
||||||
|
:label="item.categoryName"
|
||||||
|
:value="item.code">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>-->
|
||||||
|
<el-form-item label="提交时间">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
style="width: 240px"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="-"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="['00:00:00', '23:59:59']"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
icon="el-icon-edit"
|
||||||
|
size="mini"
|
||||||
|
:disabled="btnLoading"
|
||||||
|
@click="handleStart"
|
||||||
|
>发起差旅申请
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="ownProcessList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center"/>
|
||||||
|
<!-- <el-table-column label="流程编号" align="center" prop="procInsId" :show-overflow-tooltip="true"/>-->
|
||||||
|
<el-table-column label="差旅详情" align="left" prop="procVars" :show-overflow-tooltip="true"/>
|
||||||
|
<!-- <el-table-column label="流程类别" align="center" prop="category" :formatter="categoryFormat" />-->
|
||||||
|
<el-table-column label="当前节点" width="150" align="center" prop="taskName"/>
|
||||||
|
<el-table-column label="提交时间" align="center" prop="createTime" width="160"/>
|
||||||
|
<el-table-column label="当前状态" align="center" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="dict.type.wf_process_status" :value="scope.row.processStatus"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="耗时" align="center" prop="duration" width="130"/>
|
||||||
|
<el-table-column label="操作" align="center" width="240" class-name="small-padding fixed-width">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-tickets"
|
||||||
|
@click="handleFlowRecord(scope.row)"
|
||||||
|
v-hasPermi="['workflow:process:query']"
|
||||||
|
>详情
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
@click="handleDelete(scope.row)"
|
||||||
|
v-if="scope.row.finishTime"
|
||||||
|
v-hasPermi="['workflow:process:remove']"
|
||||||
|
>删除
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-circle-close"
|
||||||
|
@click="handleStop(scope.row)"
|
||||||
|
v-hasPermi="['workflow:process:cancel']"
|
||||||
|
>取消
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-refresh-right"
|
||||||
|
v-hasPermi="['workflow:process:start']"
|
||||||
|
@click="handleAgain(scope.row)"
|
||||||
|
>重新发起
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-show="total>0"
|
||||||
|
:total="total"
|
||||||
|
:page.sync="queryParams.pageNum"
|
||||||
|
:limit.sync="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {listOwnProcess, stopProcess, delProcess, listProcess} from '@/api/workflow/process';
|
||||||
|
import {listAllCategory} from '@/api/workflow/category';
|
||||||
|
import {detailProcess} from '@/api/workflow/process'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Own",
|
||||||
|
dicts: ['wf_process_status'],
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 遮罩层
|
||||||
|
loading: true,
|
||||||
|
processLoading: true,
|
||||||
|
// 选中数组
|
||||||
|
ids: [],
|
||||||
|
// 非单个禁用
|
||||||
|
single: true,
|
||||||
|
// 非多个禁用
|
||||||
|
multiple: true,
|
||||||
|
// 显示搜索条件
|
||||||
|
showSearch: true,
|
||||||
|
// 总条数
|
||||||
|
total: 0,
|
||||||
|
categoryOptions: [],
|
||||||
|
processTotal: 0,
|
||||||
|
// 我发起的流程列表数据
|
||||||
|
ownProcessList: [],
|
||||||
|
// 弹出层标题
|
||||||
|
title: "",
|
||||||
|
// 是否显示弹出层
|
||||||
|
open: false,
|
||||||
|
process: {},
|
||||||
|
src: "",
|
||||||
|
definitionList: [],
|
||||||
|
// 日期范围
|
||||||
|
dateRange: [],
|
||||||
|
// 查询参数
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
processKey: undefined,
|
||||||
|
processName: undefined,
|
||||||
|
category: "trip"
|
||||||
|
},
|
||||||
|
// 表单参数
|
||||||
|
form: {},
|
||||||
|
// 表单校验
|
||||||
|
rules: {},
|
||||||
|
btnLoading:true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getCategoryList();
|
||||||
|
},
|
||||||
|
beforeRouteEnter(to, from, next) {
|
||||||
|
next(vm => {
|
||||||
|
vm.getList()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
handleStart() {
|
||||||
|
const row = this.process
|
||||||
|
this.$router.push({
|
||||||
|
path: '/workflow/process/start/' + row.deploymentId,
|
||||||
|
query: {
|
||||||
|
definitionId: row.definitionId,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 查询流程分类列表 */
|
||||||
|
getCategoryList() {
|
||||||
|
listAllCategory().then(response => this.categoryOptions = response.data)
|
||||||
|
},
|
||||||
|
/** 查询流程定义列表 */
|
||||||
|
getList() {
|
||||||
|
this.loading = true;
|
||||||
|
this.btnLoading = true;
|
||||||
|
listOwnProcess(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
|
||||||
|
listProcess(this.queryParams).then(response => {
|
||||||
|
this.process = response.rows[response.rows.length - 1];
|
||||||
|
this.btnLoading = false;
|
||||||
|
})
|
||||||
|
this.ownProcessList = response.rows;
|
||||||
|
this.total = response.total;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**流程标题搜索**/
|
||||||
|
searchList(list, str) {
|
||||||
|
let arr = [];
|
||||||
|
list.forEach((item) => {
|
||||||
|
if (item.procVars.description.indexOf(str) > -1) {
|
||||||
|
arr.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return arr;
|
||||||
|
},
|
||||||
|
|
||||||
|
//对象数组排序(文本类)
|
||||||
|
/* compare(propertyName, order) {
|
||||||
|
return function (object1, object2) {
|
||||||
|
var value1 = object1[propertyName];
|
||||||
|
var value2 = object2[propertyName];
|
||||||
|
if (order == 0) {
|
||||||
|
if (value2 < value1) {
|
||||||
|
return -1;
|
||||||
|
} else if (value2 > value1) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (order == 1) {
|
||||||
|
if (value2 > value1) {
|
||||||
|
return -1;
|
||||||
|
} else if (value2 < value1) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},*/
|
||||||
|
|
||||||
|
// 取消按钮
|
||||||
|
cancel() {
|
||||||
|
this.open = false;
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
// 表单重置
|
||||||
|
reset() {
|
||||||
|
this.form = {
|
||||||
|
id: null,
|
||||||
|
name: null,
|
||||||
|
category: null,
|
||||||
|
key: null,
|
||||||
|
tenantId: null,
|
||||||
|
deployTime: null,
|
||||||
|
derivedFrom: null,
|
||||||
|
derivedFromRoot: null,
|
||||||
|
parentDeploymentId: null,
|
||||||
|
engineVersion: null
|
||||||
|
};
|
||||||
|
this.resetForm("form");
|
||||||
|
},
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
handleQuery() {
|
||||||
|
this.queryParams.pageNum = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
resetQuery() {
|
||||||
|
this.dateRange = [];
|
||||||
|
this.resetForm("queryForm");
|
||||||
|
this.handleQuery();
|
||||||
|
},
|
||||||
|
// 多选框选中数据
|
||||||
|
handleSelectionChange(selection) {
|
||||||
|
this.ids = selection.map(item => item.procInsId);
|
||||||
|
this.single = selection.length !== 1;
|
||||||
|
this.multiple = !selection.length;
|
||||||
|
},
|
||||||
|
handleAgain(row) {
|
||||||
|
this.$router.push({
|
||||||
|
path: '/workflow/process/start/' + row.deployId,
|
||||||
|
query: {
|
||||||
|
definitionId: row.procDefId,
|
||||||
|
procInsId: row.procInsId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// console.log(row);
|
||||||
|
},
|
||||||
|
/** 取消流程申请 */
|
||||||
|
handleStop(row) {
|
||||||
|
const params = {
|
||||||
|
procInsId: row.procInsId
|
||||||
|
}
|
||||||
|
stopProcess(params).then(res => {
|
||||||
|
this.$modal.msgSuccess(res.msg);
|
||||||
|
this.getList();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 流程流转记录 */
|
||||||
|
handleFlowRecord(row) {
|
||||||
|
this.$router.push({
|
||||||
|
path: '/workflow/process/detail/' + row.procInsId,
|
||||||
|
query: {
|
||||||
|
processed: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
handleDelete(row) {
|
||||||
|
const ids = row.procInsId || this.ids;
|
||||||
|
this.$confirm('是否确认删除流程定义编号为"' + ids + '"的数据项?', "警告", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(function () {
|
||||||
|
return delProcess(ids);
|
||||||
|
}).then(() => {
|
||||||
|
this.getList();
|
||||||
|
this.$modal.msgSuccess("删除成功");
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
handleExport() {
|
||||||
|
this.download('workflow/process/ownExport', {
|
||||||
|
...this.queryParams
|
||||||
|
}, `wf_own_process_${new Date().getTime()}.xlsx`)
|
||||||
|
},
|
||||||
|
categoryFormat(row, column) {
|
||||||
|
return this.categoryOptions.find(k => k.code === row.category)?.categoryName ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user