From 606d0a6f3a7b47adcaa2da627a4b7d58334c134e Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期一, 20 四月 2026 14:45:12 +0800
Subject: [PATCH] 排班管理

---
 ManagementYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/specialTrain/TLineController.java |  429 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 429 insertions(+), 0 deletions(-)

diff --git a/ManagementYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/specialTrain/TLineController.java b/ManagementYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/specialTrain/TLineController.java
index 7b82789..2214c06 100644
--- a/ManagementYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/specialTrain/TLineController.java
+++ b/ManagementYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/specialTrain/TLineController.java
@@ -12,6 +12,7 @@
 import com.stylefeng.guns.core.util.SinataUtil;
 import com.stylefeng.guns.core.util.ToolUtil;
 import com.stylefeng.guns.modular.system.model.*;
+import com.stylefeng.guns.modular.system.dao.LineShiftDriverMapper;
 import com.stylefeng.guns.modular.system.service.*;
 import com.stylefeng.guns.modular.system.util.ResultUtil;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -24,7 +25,9 @@
 
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.math.BigDecimal;
@@ -67,6 +70,12 @@
     
     @Autowired
     private ITLineCompanyService itLineCompanyService;
+
+    @Autowired
+    private LineShiftDriverMapper lineShiftDriverMapper;
+
+    @Autowired
+    private ITDriverService tDriverService;
     
     /**
      * 跳转到跨城站点管理首页
@@ -420,10 +429,337 @@
                 lineCompany.setCompanyId(jsonObject.getInteger("companyId"));
                 lineCompany.setInsertTime(new Date());
                 lineCompany.setInsertUserId(ShiroKit.getUser().getId());
+                lineCompany.setAutoPlan(2);
                 itLineCompanyService.insert(lineCompany);
             }
         }
         return SUCCESS_TIP;
+    }
+
+    /**
+     * 查询线路已分配企业
+     */
+    @RequestMapping(value = "/lineCompanyList")
+    @ResponseBody
+    public Object lineCompanyList(Integer lineId) {
+        if (lineId == null) {
+            return ResultUtil.error("线路ID不能为空");
+        }
+        return ResultUtil.success(tLineService.getLineCompanyList(lineId));
+    }
+
+    /**
+     * 排班管理页面
+     */
+    @RequestMapping(value = "/schedulePage")
+    public String schedulePage(Integer lineId, Integer companyId, Model model) {
+        TLine line = tLineService.selectById(lineId);
+        TCompany company = itCompanyService.selectById(companyId);
+        TLineCompany lineCompany = itLineCompanyService.selectOne(new EntityWrapper<TLineCompany>()
+                .eq("lineId", lineId).eq("companyId", companyId));
+        model.addAttribute("lineId", lineId);
+        model.addAttribute("companyId", companyId);
+        model.addAttribute("lineName", line == null ? "" : line.getName());
+        model.addAttribute("companyName", company == null ? "" : company.getName());
+        model.addAttribute("autoPlan", lineCompany == null || lineCompany.getAutoPlan() == null ? 2 : lineCompany.getAutoPlan());
+        return PREFIX + "tLine_schedule.html";
+    }
+
+    /**
+     * 排班管理-月份数据
+     */
+    @RequestMapping(value = "/schedule/month")
+    @ResponseBody
+    public Object scheduleMonth(Integer lineId, Integer companyId, String month) {
+        try {
+            TLineCompany lineCompany = checkLineCompany(lineId, companyId);
+            if (lineCompany == null) {
+                return ResultUtil.error("线路未关联该企业");
+            }
+            if (SinataUtil.isEmpty(month)) {
+                month = new SimpleDateFormat("yyyy-MM").format(new Date());
+            }
+            SimpleDateFormat monthSdf = new SimpleDateFormat("yyyy-MM");
+            Date monthDate = monthSdf.parse(month);
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(monthDate);
+            cal.set(Calendar.DAY_OF_MONTH, 1);
+            String monthStart = new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
+            int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
+            cal.set(Calendar.DAY_OF_MONTH, maxDay);
+            String monthEnd = new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
+
+            Integer companyType = getCompanyType(companyId);
+            List<Map<String, Object>> stats = lineShiftDriverMapper.getMonthScheduleStats(lineId, monthStart, monthEnd, companyId, companyType);
+            Map<String, Integer> dayAssignMap = new HashMap<>();
+            for (Map<String, Object> stat : stats) {
+                dayAssignMap.put(String.valueOf(stat.get("dayStr")), Integer.parseInt(String.valueOf(stat.get("assignNum"))));
+            }
+            List<TLineShift> shifts = itLineShiftService.selectList(new EntityWrapper<TLineShift>().eq("lineId", lineId).ne("state", 3));
+            int totalNeed = 0;
+            for (TLineShift shift : shifts) {
+                totalNeed += (shift.getCarNum() == null ? 0 : shift.getCarNum());
+            }
+
+            List<Map<String, Object>> dayList = new ArrayList<>();
+            cal.setTime(monthDate);
+            cal.set(Calendar.DAY_OF_MONTH, 1);
+            for (int i = 1; i <= maxDay; i++) {
+                cal.set(Calendar.DAY_OF_MONTH, i);
+                String dayStr = new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
+                int assignNum = dayAssignMap.get(dayStr) == null ? 0 : dayAssignMap.get(dayStr);
+                Map<String, Object> obj = new HashMap<>();
+                obj.put("day", dayStr);
+                obj.put("assignNum", assignNum);
+                obj.put("totalNeed", totalNeed);
+                if (totalNeed <= 0) {
+                    obj.put("status", 0);
+                    obj.put("statusText", "无班次");
+                } else if (assignNum >= totalNeed) {
+                    obj.put("status", 1);
+                    obj.put("statusText", "已排班");
+                } else {
+                    obj.put("status", 2);
+                    obj.put("statusText", "未排满");
+                }
+                dayList.add(obj);
+            }
+            Map<String, Object> result = new HashMap<>();
+            result.put("month", month);
+            result.put("totalNeed", totalNeed);
+            result.put("days", dayList);
+            return ResultUtil.success(result);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return ResultUtil.runErr();
+        }
+    }
+
+    /**
+     * 排班管理-某天班次详情
+     */
+    @RequestMapping(value = "/schedule/dayDetail")
+    @ResponseBody
+    public Object scheduleDayDetail(Integer lineId, Integer companyId, String day) {
+        try {
+            TLineCompany lineCompany = checkLineCompany(lineId, companyId);
+            if (lineCompany == null) {
+                return ResultUtil.error("线路未关联该企业");
+            }
+            Integer companyType = getCompanyType(companyId);
+            List<Map<String, Object>> shiftList = lineShiftDriverMapper.getDayShiftSchedule(lineId, day, companyId, companyType);
+            for (Map<String, Object> shift : shiftList) {
+                Integer lineShiftId = Integer.valueOf(String.valueOf(shift.get("lineShiftId")));
+                List<Map<String, Object>> drivers = lineShiftDriverMapper.getDayShiftDrivers(lineShiftId, day, companyId, companyType);
+                int carNum = shift.get("carNum") == null ? 0 : Integer.parseInt(String.valueOf(shift.get("carNum")));
+                int assignNum = shift.get("assignNum") == null ? 0 : Integer.parseInt(String.valueOf(shift.get("assignNum")));
+                shift.put("drivers", drivers);
+                shift.put("remainNum", Math.max(carNum - assignNum, 0));
+                shift.put("canAdd", assignNum < carNum ? 1 : 0);
+            }
+            return ResultUtil.success(shiftList);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return ResultUtil.runErr();
+        }
+    }
+
+    /**
+     * 排班管理-可添加司机
+     */
+    @RequestMapping(value = "/schedule/drivers")
+    @ResponseBody
+    public Object scheduleDrivers(Integer lineId, Integer companyId, Integer lineShiftId, String day) {
+        try {
+            TLineCompany lineCompany = checkLineCompany(lineId, companyId);
+            if (lineCompany == null) {
+                return ResultUtil.error("线路未关联该企业");
+            }
+            Integer companyType = getCompanyType(companyId);
+            return ResultUtil.success(lineShiftDriverMapper.getAvailableDrivers(lineId, lineShiftId, day, companyId, companyType));
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return ResultUtil.runErr();
+        }
+    }
+
+    /**
+     * 排班管理-新增排班
+     */
+    @RequestMapping(value = "/schedule/add")
+    @ResponseBody
+    public Object scheduleAdd(Integer lineId, Integer companyId, Integer lineShiftId, String day, @RequestParam String driverIds) {
+        try {
+            TLineCompany lineCompany = checkLineCompany(lineId, companyId);
+            if (lineCompany == null) {
+                return ResultUtil.error("线路未关联该企业");
+            }
+            TLineShift shift = itLineShiftService.selectById(lineShiftId);
+            if (shift == null || shift.getState() == 3 || !shift.getLineId().equals(lineId)) {
+                return ResultUtil.error("班次不存在");
+            }
+            Date dayDate = parseDay(day);
+            Integer companyType = getCompanyType(companyId);
+            List<Map<String, Object>> currentDrivers = lineShiftDriverMapper.getDayShiftDrivers(lineShiftId, day, companyId, companyType);
+            int currentAssignNum = currentDrivers == null ? 0 : currentDrivers.size();
+            int carNum = shift.getCarNum() == null ? 0 : shift.getCarNum();
+            if (currentAssignNum >= carNum) {
+                return ResultUtil.error("当前班次已排满");
+            }
+
+            List<Integer> driverIdList = parseIdList(driverIds);
+            if (driverIdList.size() <= 0) {
+                return ResultUtil.error("请选择司机");
+            }
+            List<Map<String, Object>> availableDrivers = lineShiftDriverMapper.getAvailableDrivers(lineId, lineShiftId, day, companyId, companyType);
+            Map<Integer, Integer> seatMap = new HashMap<>();
+            for (Map<String, Object> driver : availableDrivers) {
+                Integer driverId = Integer.valueOf(String.valueOf(driver.get("driverId")));
+                Integer seatNum = driver.get("seatNum") == null ? 5 : Integer.valueOf(String.valueOf(driver.get("seatNum")));
+                seatMap.put(driverId, seatNum);
+            }
+            List<Integer> validDriverIds = new ArrayList<>();
+            for (Integer driverId : driverIdList) {
+                if (seatMap.containsKey(driverId)) {
+                    validDriverIds.add(driverId);
+                }
+            }
+            if (validDriverIds.size() <= 0) {
+                return ResultUtil.error("没有可添加的司机");
+            }
+            if (currentAssignNum + validDriverIds.size() > carNum) {
+                return ResultUtil.error("可排班人数不足,当前班次最多还能添加" + (carNum - currentAssignNum) + "名司机");
+            }
+
+            for (Integer driverId : validDriverIds) {
+                Integer count = lineShiftDriverMapper.countExistsSchedule(lineShiftId, driverId, day);
+                if (count != null && count > 0) {
+                    continue;
+                }
+                int seatNum = seatMap.get(driverId) == null ? 5 : seatMap.get(driverId);
+                if (seatNum <= 0) {
+                    seatNum = 5;
+                }
+                LineShiftDriver record = new LineShiftDriver();
+                record.setLineShiftId(lineShiftId);
+                record.setDriverId(driverId);
+                record.setDay(dayDate);
+                record.setTotalSeat(seatNum);
+                record.setLaveSeat(seatNum);
+                record.setLaveSeatNumber(buildSeatNoStr(seatNum));
+                record.setInserTime(new Date());
+                record.setAssignType(2);
+                lineShiftDriverMapper.insert(record);
+            }
+            return ResultUtil.success();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return ResultUtil.runErr();
+        }
+    }
+
+    /**
+     * 排班管理-删除手动排班
+     */
+    @RequestMapping(value = "/schedule/delete")
+    @ResponseBody
+    public Object scheduleDelete(Integer scheduleId, Integer lineId, Integer companyId) {
+        try {
+            TLineCompany lineCompany = checkLineCompany(lineId, companyId);
+            if (lineCompany == null) {
+                return ResultUtil.error("线路未关联该企业");
+            }
+            LineShiftDriver record = lineShiftDriverMapper.selectById(scheduleId);
+            if (record == null) {
+                return ResultUtil.error("排班记录不存在");
+            }
+            if (record.getAssignType() == null || record.getAssignType() != 2) {
+                return ResultUtil.error("仅支持删除手动排班记录");
+            }
+            TLineShift shift = itLineShiftService.selectById(record.getLineShiftId());
+            if (shift == null || !shift.getLineId().equals(lineId)) {
+                return ResultUtil.error("排班记录线路不匹配");
+            }
+            TDriver driver = tDriverService.selectById(record.getDriverId());
+            if (driver == null || !checkDriverBelongCompany(driver, companyId)) {
+                return ResultUtil.error("司机企业信息不匹配");
+            }
+            lineShiftDriverMapper.deleteById(scheduleId);
+            return ResultUtil.success();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return ResultUtil.runErr();
+        }
+    }
+
+    /**
+     * 排班管理-复制排班
+     */
+    @RequestMapping(value = "/schedule/copy")
+    @ResponseBody
+    public Object scheduleCopy(Integer lineId, Integer companyId, String sourceStart, String sourceEnd, String targetStart) {
+        try {
+            TLineCompany lineCompany = checkLineCompany(lineId, companyId);
+            if (lineCompany == null) {
+                return ResultUtil.error("线路未关联该企业");
+            }
+            Date sourceStartDate = parseDay(sourceStart);
+            Date sourceEndDate = parseDay(sourceEnd);
+            Date targetStartDate = parseDay(targetStart);
+            if (sourceEndDate.before(sourceStartDate)) {
+                return ResultUtil.error("复制结束日期不能早于开始日期");
+            }
+            Integer companyType = getCompanyType(companyId);
+            List<LineShiftDriver> sourceList = lineShiftDriverMapper.getManualSchedulesForCopy(lineId, sourceStart, sourceEnd, companyId, companyType);
+            int addNum = 0;
+            int skipNum = 0;
+            for (LineShiftDriver source : sourceList) {
+                int diff = getDayDiff(sourceStartDate, source.getDay());
+                Date targetDay = addDays(targetStartDate, diff);
+                String targetDayStr = formatDay(targetDay);
+                Integer count = lineShiftDriverMapper.countExistsSchedule(source.getLineShiftId(), source.getDriverId(), targetDayStr);
+                if (count != null && count > 0) {
+                    skipNum++;
+                    continue;
+                }
+                LineShiftDriver target = new LineShiftDriver();
+                target.setLineShiftId(source.getLineShiftId());
+                target.setDriverId(source.getDriverId());
+                target.setDay(targetDay);
+                target.setLaveSeat(source.getLaveSeat());
+                target.setLaveSeatNumber(source.getLaveSeatNumber());
+                target.setTotalSeat(source.getTotalSeat());
+                target.setInserTime(new Date());
+                target.setAssignType(2);
+                lineShiftDriverMapper.insert(target);
+                addNum++;
+            }
+            Map<String, Object> result = new HashMap<>();
+            result.put("addNum", addNum);
+            result.put("skipNum", skipNum);
+            return ResultUtil.success(result);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return ResultUtil.runErr();
+        }
+    }
+
+    /**
+     * 排班管理-保存智能排班开关
+     */
+    @RequestMapping(value = "/schedule/autoPlan")
+    @ResponseBody
+    public Object scheduleAutoPlan(Integer lineId, Integer companyId, Integer autoPlan) {
+        if (autoPlan == null || (autoPlan != 1 && autoPlan != 2)) {
+            return ResultUtil.error("智能排班参数错误");
+        }
+        TLineCompany lineCompany = checkLineCompany(lineId, companyId);
+        if (lineCompany == null) {
+            return ResultUtil.error("线路未关联该企业");
+        }
+        lineCompany.setAutoPlan(autoPlan);
+        itLineCompanyService.updateById(lineCompany);
+        return ResultUtil.success();
     }
     /**
      * 修改跨城站点管理
@@ -601,4 +937,97 @@
         return ResultUtil.success();
     }
 
+    private TLineCompany checkLineCompany(Integer lineId, Integer companyId) {
+        if (lineId == null || companyId == null) {
+            return null;
+        }
+        return itLineCompanyService.selectOne(new EntityWrapper<TLineCompany>().eq("lineId", lineId).eq("companyId", companyId));
+    }
+
+    private Integer getCompanyType(Integer companyId) {
+        TCompany company = itCompanyService.selectById(companyId);
+        return company == null ? null : company.getType();
+    }
+
+    private boolean checkDriverBelongCompany(TDriver driver, Integer companyId) {
+        if (driver == null || companyId == null) {
+            return false;
+        }
+        Integer companyType = getCompanyType(companyId);
+        if (companyType == null) {
+            return false;
+        }
+        if (companyType == 2) {
+            return driver.getCompanyId() != null && driver.getCompanyId().intValue() == companyId.intValue();
+        }
+        if (companyType == 3) {
+            return driver.getFranchiseeId() != null && driver.getFranchiseeId().intValue() == companyId.intValue();
+        }
+        return false;
+    }
+
+    private Date parseDay(String day) throws Exception {
+        return new SimpleDateFormat("yyyy-MM-dd").parse(day);
+    }
+
+    private String formatDay(Date day) {
+        return new SimpleDateFormat("yyyy-MM-dd").format(day);
+    }
+
+    private int getDayDiff(Date start, Date end) {
+        long oneDay = 24L * 60L * 60L * 1000L;
+        long startTime = start.getTime() / oneDay;
+        long endTime = end.getTime() / oneDay;
+        return (int) (endTime - startTime);
+    }
+
+    private Date addDays(Date date, int days) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        cal.add(Calendar.DAY_OF_MONTH, days);
+        return cal.getTime();
+    }
+
+    private String buildSeatNoStr(int seatNum) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 1; i <= seatNum; i++) {
+            if (i > 1) {
+                builder.append(",");
+            }
+            builder.append(i);
+        }
+        return builder.toString();
+    }
+
+    private List<Integer> parseIdList(String ids) {
+        List<Integer> list = new ArrayList<>();
+        if (SinataUtil.isEmpty(ids)) {
+            return list;
+        }
+        try {
+            if (ids.startsWith("[")) {
+                JSONArray array = JSON.parseArray(ids);
+                for (int i = 0; i < array.size(); i++) {
+                    Integer id = array.getInteger(i);
+                    if (id != null && !list.contains(id)) {
+                        list.add(id);
+                    }
+                }
+            } else {
+                String[] arr = ids.split(",");
+                for (String s : arr) {
+                    if (SinataUtil.isNotEmpty(s)) {
+                        Integer id = Integer.valueOf(s.trim());
+                        if (!list.contains(id)) {
+                            list.add(id);
+                        }
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return list;
+    }
+
 }

--
Gitblit v1.7.1