package com.xiaopeng.maintenance.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.api.feignClient.account.XpOperationUserClient;
import com.xiaopeng.api.feignClient.maintenance.XpCheckLocationClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetOperationsClient;
import com.xiaopeng.api.model.account.XpOperationsUser;import com.xiaopeng.api.model.maintenance.*;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.utils.poi.ExcelUtil;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.maintenance.dto.ExportSchedulingDetailDto;
import com.xiaopeng.maintenance.dto.SchedulingDetailDto;
import com.xiaopeng.maintenance.dto.ShiftAttendanceDTO;
import com.xiaopeng.maintenance.mapper.XpCheckLocationMapper;
import com.xiaopeng.maintenance.mapper.XpClockInMapper;
import com.xiaopeng.maintenance.mapper.XpSchedulingDetailMapper;
import com.xiaopeng.maintenance.mapper.XpShiftMapper;
import com.xiaopeng.maintenance.service.IXpSchedulingDetailService;
import com.xiaopeng.maintenance.service.IXpSchedulingService;
import com.xiaopeng.maintenance.service.IXpShiftService;
import com.xiaopeng.maintenance.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
/**
*
* 排班明细 服务实现类
*
*
* @author mitao
* @since 2026-02-03
*/
@Service
public class XpSchedulingDetailServiceImpl extends ServiceImpl implements IXpSchedulingDetailService {
@Resource
private XpFleetClient xpFleetClient;
@Resource
private XpCheckLocationMapper xpCheckLocationMapper;
@Resource
private XpShiftMapper xpShiftMapper;
@Resource
private XpClockInMapper xpClockInMapper;
@Resource
private IXpSchedulingService xpSchedulingService;
@Resource
private IXpShiftService xpShiftService;
@Resource
private XpFleetOperationsClient xpFleetOperationsClient;
@Resource
private XpOperationUserClient xpOperationUserClient;
@Override
public ShiftAttendanceVO shiftAttendance(ShiftAttendanceDTO dto) {
// 查询用户所属车队
XpFleet xpFleet = xpFleetClient.getFleetByOperationsUserId(dto.getOperationsUserId()).getData();
if (Objects.isNull(xpFleet)) {
return null;
}
// 查询打卡地
XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(xpFleet.getLocationId());
if (Objects.isNull(xpCheckLocation)) {
return null;
}
// 查询排班明细
XpSchedulingDetail schedulingDetail = this.getOne(Wrappers.lambdaQuery(XpSchedulingDetail.class)
.likeRight(XpSchedulingDetail::getPlanTime, dto.getSchedulingDate())
.eq(XpSchedulingDetail::getFleetId, xpFleet.getId())
.last("LIMIT 1"));
if (Objects.isNull(schedulingDetail)) {
return null;
}
// 查询班次
XpShift xpShift = xpShiftMapper.selectById(schedulingDetail.getShiftId());
if (Objects.isNull(xpShift)) {
return null;
}
ShiftAttendanceVO shiftAttendanceVO = new ShiftAttendanceVO();
shiftAttendanceVO.setXpShift(xpShift);
shiftAttendanceVO.setXpCheckLocation(xpCheckLocation);
// 查询当前用户打卡信息
XpClockIn xpClockIn = xpClockInMapper.selectOne(Wrappers.lambdaQuery(XpClockIn.class)
.eq(XpClockIn::getAppUserId, dto.getOperationsUserId())
.likeRight(XpClockIn::getClockInTime, dto.getSchedulingDate())
.last("LIMIT 1"));
if (Objects.isNull(xpClockIn)) {
shiftAttendanceVO.setClockIn(false);
shiftAttendanceVO.setClockOut(false);
} else {
shiftAttendanceVO.setXpClockIn(xpClockIn);
shiftAttendanceVO.setClockIn(true);
shiftAttendanceVO.setClockOut(xpClockIn.getClockOutTime() != null);
}
return shiftAttendanceVO;
}
/**
* 排班明细分页列表
*
* @param query
* @return
*/
@Override
public PageInfo pageList(SchedulingDetailVo query) {
PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
List schedulingDetailDtos = this.baseMapper.pageList(pageInfo, query.getMonth());
LocalDate parse1 = LocalDate.parse(query.getMonth(), DateTimeFormatter.ofPattern("yyyy-MM"));
//找出月份的最大天
int dayOfMonth = parse1.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
for (SchedulingDetailDto schedulingDetailDto : schedulingDetailDtos) {
String days = schedulingDetailDto.getDays();
if (StringUtils.isNotBlank(days)) {
String[] split = days.split(",");
List list = Arrays.asList(split);
for (int i = 1; i <= dayOfMonth; i++) {
Map map1 = new HashMap<>();
for (String s : split) {
String[] split1 = s.split("_");
if (i == Integer.parseInt(split1[0])) {
map1.put("shiftId", split1[1]);
map1.put("shiftName", split1[2]);
map1.put("shiftColor", split1[3]);
break;
}
}
setEnglishDay(i, schedulingDetailDto, map1);
}
long allDay = list.stream().filter(s -> s.contains("全天")).count();
long morning = list.stream().filter(s -> s.contains("早")).count();
long midDay = list.stream().filter(s -> s.contains("中")).count();
long evening = list.stream().filter(s -> s.contains("晚")).count();
schedulingDetailDto.setAllDay(allDay);
schedulingDetailDto.setMorning(morning);
schedulingDetailDto.setMidDay(midDay);
schedulingDetailDto.setEvening(evening);
}
}
pageInfo.setRecords(schedulingDetailDtos);
return pageInfo;
}
/**
* 给每天的字段赋值
* @param day
* @param dto
* @param map
*/
private void setEnglishDay(int day, SchedulingDetailDto dto, Map map) {
switch (day) {
case 1:
dto.setOne(map);
break;
case 2:
dto.setTwo(map);
break;
case 3:
dto.setThree(map);
break;
case 4:
dto.setFour(map);
break;
case 5:
dto.setFive(map);
break;
case 6:
dto.setSix(map);
break;
case 7:
dto.setSeven(map);
break;
case 8:
dto.setEight(map);
break;
case 9:
dto.setNine(map);
break;
case 10:
dto.setTen(map);
break;
case 11:
dto.setEleven(map);
break;
case 12:
dto.setTwelve(map);
break;
case 13:
dto.setThirteen(map);
break;
case 14:
dto.setFourteen(map);
break;
case 15:
dto.setFifteen(map);
break;
case 16:
dto.setSixteen(map);
break;
case 17:
dto.setSeventeen(map);
break;
case 18:
dto.setEighteen(map);
break;
case 19:
dto.setNineteen(map);
break;
case 20:
dto.setTwenty(map);
break;
case 21:
dto.setTwentyOne(map);
break;
case 22:
dto.setTwentyTwo(map);
break;
case 23:
dto.setTwentyThree(map);
break;
case 24:
dto.setTwentyFour(map);
break;
case 25:
dto.setTwentyFive(map);
break;
case 26:
dto.setTwentySix(map);
break;
case 27:
dto.setTwentySeven(map);
break;
case 28:
dto.setTwentyEight(map);
break;
case 29:
dto.setTwentyNine(map);
break;
case 30:
dto.setThirty(map);
break;
case 31:
dto.setThirtyOne(map);
break;
}
}
/**
* 给每天的字段赋值
* @param day
* @param dto
* @param shiftName
*/
private void setEnglishDay(int day, ExportSchedulingDetailDto dto, String shiftName) {
switch (day) {
case 1:
dto.setOne(shiftName);
break;
case 2:
dto.setTwo(shiftName);
break;
case 3:
dto.setThree(shiftName);
break;
case 4:
dto.setFour(shiftName);
break;
case 5:
dto.setFive(shiftName);
break;
case 6:
dto.setSix(shiftName);
break;
case 7:
dto.setSeven(shiftName);
break;
case 8:
dto.setEight(shiftName);
break;
case 9:
dto.setNine(shiftName);
break;
case 10:
dto.setTen(shiftName);
break;
case 11:
dto.setEleven(shiftName);
break;
case 12:
dto.setTwelve(shiftName);
break;
case 13:
dto.setThirteen(shiftName);
break;
case 14:
dto.setFourteen(shiftName);
break;
case 15:
dto.setFifteen(shiftName);
break;
case 16:
dto.setSixteen(shiftName);
break;
case 17:
dto.setSeventeen(shiftName);
break;
case 18:
dto.setEighteen(shiftName);
break;
case 19:
dto.setNineteen(shiftName);
break;
case 20:
dto.setTwenty(shiftName);
break;
case 21:
dto.setTwentyOne(shiftName);
break;
case 22:
dto.setTwentyTwo(shiftName);
break;
case 23:
dto.setTwentyThree(shiftName);
break;
case 24:
dto.setTwentyFour(shiftName);
break;
case 25:
dto.setTwentyFive(shiftName);
break;
case 26:
dto.setTwentySix(shiftName);
break;
case 27:
dto.setTwentySeven(shiftName);
break;
case 28:
dto.setTwentyEight(shiftName);
break;
case 29:
dto.setTwentyNine(shiftName);
break;
case 30:
dto.setThirty(shiftName);
break;
case 31:
dto.setThirtyOne(shiftName);
break;
}
}
/**
* 保存排班明细
*
* @param vo
* @return
*/
@Override
public R saveSchedulingDetail(SaveSchedulingVo vo, Long userId) {
String month = vo.getMonth();
List list = this.list(new QueryWrapper().eq("is_deleted", 0).last(" and DATE_FORMAT(planTime,'%Y-%m') = '" + month + "'"));
//保存排班数据
XpScheduling xpScheduling = xpSchedulingService.getOne(new QueryWrapper().eq("is_deleted", 0).last(" and DATE_FORMAT(schedulingDate,'%Y-%m') = '" + month + "'"));
if(null == xpScheduling){
xpScheduling = new XpScheduling();
xpScheduling.setDeleted(false);
xpScheduling.setCreateTime(LocalDateTime.now());
xpScheduling.setUpdateTime(LocalDateTime.now());
xpScheduling.setCreateBy(userId.toString());
xpScheduling.setUpdateBy(userId.toString());
}
xpScheduling.setSchedulingDate(LocalDate.parse(month, DateTimeFormatter.ofPattern("yyyy-MM")));
xpScheduling.setCommitUserId(userId);
xpSchedulingService.saveOrUpdate(xpScheduling);
List xpShifts = xpShiftService.list(new QueryWrapper().eq("is_deleted", 0));
//构建排班明细数据
List datas = vo.getDatas();
List schedulingDetails = new ArrayList<>();
for (SaveSchedulingDetailVo data : datas) {
Long fleetId = data.getFleetId();
List days = data.getDays();
for (SaveSchedulingDetailDay day : days) {
Long shiftId = day.getShiftId();
LocalDate parse = LocalDate.parse(day.getDayTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//查询判断数据是否存在
XpSchedulingDetail schedulingDetail = list.stream().filter(s -> s.getFleetId().equals(fleetId)
&& s.getShiftId().equals(shiftId)
&& s.getPlanTime().equals(parse)
).findAny().orElse(null);
//构建存储对象
if(null == schedulingDetail){
schedulingDetail = new XpSchedulingDetail();
schedulingDetail.setCreateBy(userId.toString());
schedulingDetail.setCreateTime(LocalDateTime.now());
schedulingDetail.setUpdateBy(userId.toString());
schedulingDetail.setUpdateTime(LocalDateTime.now());
schedulingDetail.setDeleted(false);
}else{
//构建通知消息
Long old_shiftId = schedulingDetail.getShiftId();
if(!old_shiftId.equals(shiftId)){
//获取车队的所有人员
XpShift xpShift1 = xpShifts.stream().filter(s -> s.getId().equals(old_shiftId)).findAny().orElse(null);
XpShift xpShift2 = xpShifts.stream().filter(s -> s.getId().equals(shiftId)).findAny().orElse(null);
List operationsIds = xpFleetOperationsClient.getOperationsIdsByFleetId(fleetId).getData();
if(null != operationsIds && !operationsIds.isEmpty()){
List data1 = xpOperationUserClient.listByIds(operationsIds).getData();
for (XpOperationsUser xpOperationsUser : data1) {
String nickName = xpOperationsUser.getNickName();
String message = nickName + "请注意," + month + "你的排班由" + xpShift1.getShiftName() + "变更为了" + xpShift2.getShiftName() + "。详情请联系平台管理员。";
}
}
}
}
schedulingDetail.setSchedulingId(xpScheduling.getId());
schedulingDetail.setFleetId(fleetId);
schedulingDetail.setShiftId(shiftId);
XpShift xpShift = xpShifts.stream().filter(s -> s.getId().equals(shiftId)).findAny().orElse(null);
schedulingDetail.setIsAllDay(xpShift.getShiftName().contains("全天"));
schedulingDetail.setPlanTime(parse);
schedulingDetails.add(schedulingDetail);
}
}
//批量保存排班明细数据
if(schedulingDetails.isEmpty()){
this.saveOrUpdateBatch(schedulingDetails);
}
return R.ok();
}
/**
* 导出排班数据
* @param month
* @param response
*/
@Override
public void exportExcel(String month, HttpServletResponse response) {
PageInfo pageInfo = new PageInfo<>(0, 10000);
List schedulingDetailDtos = this.baseMapper.pageList(pageInfo, month);
List exportSchedulingDetailDtos = new ArrayList<>();
//获取月份的最大天数
LocalDate parse1 = LocalDate.parse(month, DateTimeFormatter.ofPattern("yyyy-MM"));
int dayOfMonth = parse1.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
//构建表头第二行数据
ExportSchedulingDetailDto exportSchedulingDetailDto = new ExportSchedulingDetailDto();
exportSchedulingDetailDto.setFleetName("");
for (int i = 1; i <= dayOfMonth; i++) {
LocalDate parse = LocalDate.parse(month + "-" + i, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
String week = "";
switch (parse.getDayOfWeek()){
case MONDAY:
week = "一";
break;
case TUESDAY:
week = "二";
break;
case WEDNESDAY:
week = "三";
break;
case THURSDAY:
week = "四";
break;
case FRIDAY:
week = "五";
break;
case SATURDAY:
week = "六";
break;
case SUNDAY:
week = "日";
break;
}
setEnglishDay(i, exportSchedulingDetailDto, week);
}
exportSchedulingDetailDto.setAllDay("全天");
exportSchedulingDetailDto.setMorning("早");
exportSchedulingDetailDto.setMidDay("中");
exportSchedulingDetailDto.setEvening("晚");
exportSchedulingDetailDtos.add(exportSchedulingDetailDto);
//构建数据部分的内容
for (SchedulingDetailDto schedulingDetailDto : schedulingDetailDtos) {
exportSchedulingDetailDto = new ExportSchedulingDetailDto();
exportSchedulingDetailDto.setFleetName(schedulingDetailDto.getFleetName());
String days = schedulingDetailDto.getDays();
if (StringUtils.isNotBlank(days)) {
String[] split = days.split(",");
List list = Arrays.asList(split);
for (int i = 1; i <= dayOfMonth; i++) {
String shiftName = "休";
for (String s : split) {
String[] split1 = s.split("_");
if (i == Integer.parseInt(split1[0])) {
shiftName = split1[2];
break;
}
}
setEnglishDay(i, exportSchedulingDetailDto, shiftName);
}
long allDay = list.stream().filter(s -> s.contains("全天")).count();
long morning = list.stream().filter(s -> s.contains("早")).count();
long midDay = list.stream().filter(s -> s.contains("中")).count();
long evening = list.stream().filter(s -> s.contains("晚")).count();
exportSchedulingDetailDto.setAllDay(allDay + "");
exportSchedulingDetailDto.setMorning(morning + "");
exportSchedulingDetailDto.setMidDay(midDay + "");
exportSchedulingDetailDto.setEvening(evening + "");
}else{
for (int i = 1; i <= 31; i++) {
String shiftName = "休";
setEnglishDay(i, exportSchedulingDetailDto, shiftName);
}
exportSchedulingDetailDto.setAllDay("0");
exportSchedulingDetailDto.setMorning("0");
exportSchedulingDetailDto.setMidDay("0");
exportSchedulingDetailDto.setEvening("0");
}
exportSchedulingDetailDtos.add(exportSchedulingDetailDto);
}
String[] split = month.split("-");
ExcelUtil excelUtil = new ExcelUtil<>(ExportSchedulingDetailDto.class);
excelUtil.exportExcel(response, exportSchedulingDetailDtos, "排班计划", "日期:" + split[0] + "年" + split[1] + "月");
}
}