Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
2025-10-10 16:14:55 +08:00
12 changed files with 136 additions and 46 deletions

View File

@ -1131,6 +1131,7 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
}
//只查施工人员
lqw.eq(SubConstructionUser::getUserRole, "0");
lqw.isNotNull(SubConstructionUser::getTeamId);
// 分页查询获取数据
Page<SubConstructionUser> constructionUserPage = this.page(pageQuery.build(), lqw);
List<SubConstructionUser> constructionUserList = constructionUserPage.getRecords();
@ -1196,7 +1197,8 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
unClockDays++;
}
}
if(ATTENDANCE_LIST.contains(clockInStatus) || ATTENDANCE_LIST.contains(clockOutStatus)){
if((clockInStatus!=null && ATTENDANCE_LIST.contains(clockInStatus))
|| (clockOutStatus!=null && ATTENDANCE_LIST.contains(clockOutStatus))){
attendanceDays++;
}

View File

@ -15,6 +15,9 @@ import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.contractor.domain.dto.contractor.SubContractorQueryReq;
import org.dromara.contractor.domain.vo.contractor.SubContractorVo;
import org.dromara.contractor.service.ISubContractorService;
import org.dromara.materials.domain.dto.materials.MatMaterialsCreateReq;
import org.dromara.materials.domain.dto.materials.MatMaterialsGisReq;
import org.dromara.materials.domain.dto.materials.MatMaterialsQueryReq;
@ -40,6 +43,8 @@ public class MatMaterialsController extends BaseController {
private final IMatMaterialsService materialsService;
private final ISubContractorService contractorService;
/**
* 查询材料列表
*/
@ -155,4 +160,13 @@ public class MatMaterialsController extends BaseController {
@PathVariable Long[] ids) {
return toAjax(materialsService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 查询分包单位列表
*/
@SaCheckPermission("materials:materials:contractorList")
@GetMapping("/contractorList")
public R<List<SubContractorVo>> contractorList(SubContractorQueryReq req) {
return R.ok(contractorService.queryList(req));
}
}

View File

@ -94,4 +94,13 @@ public class MatMaterialsInventory extends BaseEntity {
*/
private String remark;
/**
* 操作人id
*/
private Long operatorId;
/**
* 分包单位id
*/
private Long recipientId;
}

View File

@ -76,4 +76,14 @@ public class MatMaterialsInventoryCreateReq implements Serializable {
*/
private String remark;
/**
* 操作人id
*/
private Long operatorId;
/**
* 分包单位id
*/
private Long recipientId;
}

View File

@ -117,6 +117,7 @@ public class BusAttendanceController extends BaseController {
/**
* 查询项目施工人员前14天考勤状况
*/
@SaCheckPermission("project:attendance:list")
@GetMapping("/list/clockDate/twoWeek")
public R<List<BusAttendanceClockDateForTwoWeekVo>> getClockDateForTwoWeekList(Long projectId) {
return R.ok(busAttendanceService.getClockDateForTwoWeekList(projectId));
@ -124,6 +125,7 @@ public class BusAttendanceController extends BaseController {
/**
* 查询项目施工人员当天考勤状况
*/
@SaCheckPermission("project:attendance:list")
@GetMapping("/list/clockDate/today")
public R<BusAttendanceClockDateForTwoWeekVo> getTodayAttendanceData(Long projectId) {
return R.ok(busAttendanceService.getTodayAttendanceData(projectId));

View File

@ -140,4 +140,14 @@ public class BusLeave extends BaseEntity {
*/
private String auditStatus;
/**
* 时间类型 1-天 2-小时
*/
private String timeType;
/**
* 时间段类型 1-上午 2-下午
*/
private String periodType;
}

View File

@ -55,5 +55,13 @@ public class BusLeaveAddReq implements Serializable {
@NotNull(message = "项目id不能为空")
private Long projectId;
/**
* 时间类型 1-天 2-小时
*/
private String timeType;
/**
* 时间段类型 1-上午 2-下午
*/
private String periodType;
}

View File

@ -324,18 +324,16 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
//打卡范围
if (!checkInRange(req)) {
throw new ServiceException("打卡位置不在范围内", HttpStatus.BAD_REQUEST);
throw new ServiceException("打卡位置不在范围内", HttpStatus.ERROR);
}
//用户信息校验
SubConstructionUser constructionUser = constructionUserService.getBySysUserId(userId);
final String status = "1";
if (constructionUser.getStatus().equals(status)) {
throw new ServiceException("当前用户已离职", HttpStatus.BAD_REQUEST);
if ("1".equals(constructionUser.getStatus())) {
throw new ServiceException("当前用户已离职", HttpStatus.ERROR);
}
final String noClock = "1";
if (constructionUser.getClock().equals(noClock)) {
throw new ServiceException("当前用户已被禁止打卡", HttpStatus.BAD_REQUEST);
if ("1".equals(constructionUser.getClock())) {
throw new ServiceException("当前用户已被禁止打卡", HttpStatus.ERROR);
}
// 判断用户是否已经被拉黑
constructionBlacklistService.validUserInBlacklist(constructionUser.getSysUserId(), req.getProjectId());
@ -344,27 +342,27 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
try {
result = constructionUserService.faceComparison(file);
} catch (Exception e) {
throw new ServiceException("人脸识别失败,请重新识别", HttpStatus.BAD_REQUEST);
throw new ServiceException("人脸识别失败,请重新识别", HttpStatus.ERROR);
}
if (!result) {
throw new ServiceException("人脸识别失败,请重新识别", HttpStatus.BAD_REQUEST);
throw new ServiceException("人脸识别失败,请重新识别", HttpStatus.ERROR);
}
//打卡规则
BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectId(req.getProjectId());
if (busAttendanceRuleVo == null) {
throw new ServiceException("未设置打卡规则", HttpStatus.BAD_REQUEST);
throw new ServiceException("未设置打卡规则", HttpStatus.ERROR);
}
// 考勤时间
//确定考勤日期
LocalDate localDate = calculateAttendanceDate(now, busAttendanceRuleVo);
if (leaveService.isLeave(localDate, userId)) {
throw new ServiceException("当前用户正在请假中", HttpStatus.BAD_REQUEST);
}
// if (leaveService.isLeave(localDate, userId)) {
// throw new ServiceException("当前用户正在请假中", HttpStatus.ERROR);
// }
// 判断当前用户打卡状态
@ -401,7 +399,12 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
// 记录打卡坐标
attendance.setLat(req.getLat());
attendance.setLng(req.getLng());
attendance.setClockLocation(JSTUtil.getLocationName(req.getLat(), req.getLng()));
try {
attendance.setClockLocation(JSTUtil.getLocationName(req.getLat(), req.getLng()));
}catch (Exception e) {
log.error("获取打卡位置失败", e);
}
// 上传人脸照
SysOssVo upload = ossService.upload(file);
attendance.setFacePic(upload.getOssId().toString());
@ -455,7 +458,11 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
// 记录打卡坐标
attendance.setLat(req.getLat());
attendance.setLng(req.getLng());
attendance.setClockLocation(JSTUtil.getLocationName(req.getLat(), req.getLng()));
try {
attendance.setClockLocation(JSTUtil.getLocationName(req.getLat(), req.getLng()));
}catch (Exception e) {
log.error("获取打卡位置失败", e);
}
// 上传人脸照
SysOssVo upload = ossService.upload(file);
attendance.setFacePic(upload.getOssId().toString());
@ -591,6 +598,8 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
Long userId = LoginHelper.getUserId();
Long projectId = req.getProjectId();
SysUserVo sysUserVo = userService.queryById(userId);
//判断是否要求范围内打卡
BusUserProjectRelevancy relevancy = userProjectRelevancyService.getOne(Wrappers.lambdaQuery(BusUserProjectRelevancy.class)
.eq(BusUserProjectRelevancy::getUserId, userId)
@ -600,7 +609,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
throw new ServiceException("当前用户未加入项目", HttpStatus.BAD_REQUEST);
}
//判断是否是施工员 管理员返回项目全部打卡范围,施工人员返回班组打卡范围
boolean isConstruct = "1".equals(relevancy.getUserType());
boolean isConstruct = "0".equals(sysUserVo.getAppUserType());
List<Long> rangeIds = new ArrayList<>();
if (isConstruct) {
BusProjectTeamMember one = projectTeamMemberService.getOne(Wrappers.lambdaQuery(BusProjectTeamMember.class)
@ -638,7 +647,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
.toList();
if (CollUtil.isEmpty(punchRangeList)) {
throw new ServiceException(isConstruct ? "班组未配置考勤范围" : "项目未配置考勤范围", HttpStatus.BAD_REQUEST);
throw new ServiceException(isConstruct ? "班组未配置考勤范围" : "项目未配置考勤范围", HttpStatus.ERROR);
}
List<GeoPoint> matchingRange = JSTUtil.findMatchingRange(req.getLat(), req.getLng(), punchRangeList);
return matchingRange != null;
@ -870,6 +879,25 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
return checkTime.isBefore(clockOutDateTime);
}
// /**
// * 判断是否请假
// */
// private Boolean isLeave(LocalDateTime checkTime,String type,Long userId){
// // 获取当天请假数据
// LocalDate localDate = checkTim e.toLocalDate();
// LocalDateTime dateStart = LocalDateTime.of(localDate, LocalTime.MIN);
// LocalDateTime dateEnd = LocalDateTime.of(localDate, LocalTime.MAX);
//
// leaveService.isLeave()
//
//
//
//
//
//
// }
@Override
public AttendanceCountVo getAttendanceCount(AttendanceCountDto dto) {
@ -1158,15 +1186,17 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
List<Long> allUserIds = constructionUserService.list(Wrappers.<SubConstructionUser>lambdaQuery()
.eq(SubConstructionUser::getUserRole, "0")
.eq(SubConstructionUser::getProjectId,projectId)
.isNotNull(SubConstructionUser::getTeamId)
).stream().map(SubConstructionUser::getSysUserId).toList();
// 往前14天包含今天
LocalDate startDate = now.minusDays(14);
LocalDate endDate = now.minusDays(1);
List<BusAttendance> list = list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getProjectId, projectId)
.notIn(CollectionUtil.isNotEmpty(excludeUserIds),BusAttendance::getUserId, excludeUserIds)
.between(BusAttendance::getClockDate, startDate, now)
.between(BusAttendance::getClockDate, startDate, endDate)
.orderByAsc(BusAttendance::getClockDate)
);
@ -1187,7 +1217,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
List<BusAttendanceClockDateForTwoWeekVo> result = new ArrayList<>();
LocalDate currentDate = startDate;
while (!currentDate.isAfter(now)) {
while (!currentDate.isAfter(endDate)) {
Map<Long, List<BusAttendance>> userAttendanceMap = dateUserMap.getOrDefault(currentDate, new HashMap<>());
int full = 0, half = 0, absent = 0;
@ -1200,10 +1230,8 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
.filter(ATTENDANCE_LIST::contains)
.count();
if (validCount >= 2) {
if (validCount >= 1) {
full++;
} else if (validCount == 1) {
half++;
} else {
absent++;
}
@ -1214,14 +1242,6 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
vo.setAttendance(full);
vo.setHalfAttendance(half);
vo.setAbsenteeism(absent);
//如果是当天,则计算考勤率
if (currentDate.equals(now)) {
vo.setAllUserNum(allUserIds.size());
vo.setClockNum(full+half);
vo.setAttendanceRate(BigDecimalUtil.toPercentage(new BigDecimal(full+half),
new BigDecimal(allUserIds.size())));
}
result.add(vo);
currentDate = currentDate.plusDays(1);
}
@ -1243,6 +1263,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
List<Long> allUserIds = constructionUserService.list(Wrappers.<SubConstructionUser>lambdaQuery()
.eq(SubConstructionUser::getUserRole, "0")
.eq(SubConstructionUser::getProjectId,projectId)
.isNotNull(SubConstructionUser::getTeamId)
).stream().map(SubConstructionUser::getSysUserId).toList();

View File

@ -399,8 +399,10 @@ public class BusLeaveServiceImpl extends ServiceImpl<BusLeaveMapper, BusLeave>
LambdaQueryWrapper<BusLeave> wrapper = new LambdaQueryWrapper<>();
wrapper
.eq(BusLeave::getUserId, userId)
.le(BusLeave::getStartTime, newEnd) // 已有记录的开始时间 < 新记录的结束时间
.ge(BusLeave::getEndTime, newStart); // 已有记录的结束时间 > 新记录的开始时间
.lt(BusLeave::getStartTime, newEnd) // 已有记录的开始时间 < 新记录的结束时间
.gt(BusLeave::getEndTime, newStart)
.eq(BusLeave::getAuditStatus, BusinessStatusEnum.FINISH.getStatus())
; // 已有记录的结束时间 > 新记录的开始时间
// 4. 执行冲突校验
if (count(wrapper) > 0) {

View File

@ -329,10 +329,7 @@ public class BusProjectTeamMemberServiceImpl extends ServiceImpl<BusProjectTeamM
constructionUserExit.setSalaryConfirmationFile(salaryConfirmationFile);
constructionUserExit.setTeamId(constructionUser.getTeamId());
String sfzNumber = constructionUser.getSfzNumber();
if (StringUtils.isNotBlank(sfzNumber)) {
sfzNumber = idCardEncryptorUtil.decrypt(sfzNumber);
constructionUserExit.setSfzNumber(sfzNumber);
}
constructionUserExit.setSfzNumber(sfzNumber);
constructionUserExit.setEntryDate(constructionUser.getEntryDate());
constructionUserExit.setLeaveDate(new Date());
constructionUserExit.setRemark(req.getRemark());

View File

@ -149,7 +149,9 @@ public class SysUserVo implements Serializable {
*/
private List<Long> projectIds;
/**
* app用户类型 0-施工人员 1-管理人员 2-分包人员
*/
private String appUserType;
/**

View File

@ -50,6 +50,7 @@ import org.dromara.system.mapper.*;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserFileService;
import org.dromara.system.service.ISysUserService;
import org.jetbrains.annotations.NotNull;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
@ -929,7 +930,25 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
projects = projectIds;
}
Long roleId = "1".equals(appUserType)?4L:5L;
List<SysUserRole> sysUserRoles = getSysUserRoles(userId, appUserType, projects);
userRoleMapper.insertBatch(sysUserRoles);
return baseMapper.update(null,
new LambdaUpdateWrapper<SysUser>()
.set(SysUser::getAppUserType, appUserType)
.set(contractorId!=null,SysUser::getContractorId, contractorId)
.eq(SysUser::getUserId, userId)) > 0;
}
private List<SysUserRole> getSysUserRoles(Long userId, String appUserType, List<Long> projects) {
Long roleId;
if("0".equals(appUserType)){
roleId = 2L;
}else if("1".equals(appUserType)){
roleId = 4L;
}else {
roleId = 5L;
}
ArrayList<SysUserRole> sysUserRoles = new ArrayList<>();
for (Long project : projects) {
SysUserRole sysUserRole = new SysUserRole();
@ -938,13 +957,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
sysUserRole.setRoleId(roleId);
sysUserRoles.add(sysUserRole);
}
userRoleMapper.insertBatch(sysUserRoles);
return baseMapper.update(null,
new LambdaUpdateWrapper<SysUser>()
.set(SysUser::getAppUserType, appUserType)
.set(contractorId!=null,SysUser::getContractorId, contractorId)
.eq(SysUser::getUserId, userId)) > 0;
return sysUserRoles;
}
@Override