diff --git a/wm-dispatch/pom.xml b/wm-dispatch/pom.xml new file mode 100644 index 00000000..17cde68f --- /dev/null +++ b/wm-dispatch/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.water + wm-parent + 1.0.0-SNAPSHOT + + wm-dispatch + 调度工作台 + 调度工作台与调度业务管理模块 + + + + com.water + wm-common + + + org.springframework.boot + spring-boot-starter-web + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + com.baomidou + mybatis-plus-spring-boot3-starter + + + cn.dev33 + sa-token-spring-boot3-starter + + + org.postgresql + postgresql + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + + + diff --git a/wm-dispatch/src/main/java/com/water/dispatch/DispatchApplication.java b/wm-dispatch/src/main/java/com/water/dispatch/DispatchApplication.java new file mode 100644 index 00000000..73448ee9 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/DispatchApplication.java @@ -0,0 +1,11 @@ +package com.water.dispatch; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DispatchApplication { + public static void main(String[] args) { + SpringApplication.run(DispatchApplication.class, args); + } +} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/controller/DispatchController.java b/wm-dispatch/src/main/java/com/water/dispatch/controller/DispatchController.java new file mode 100644 index 00000000..169ab1f1 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/controller/DispatchController.java @@ -0,0 +1,24 @@ +package com.water.dispatch.controller; +import com.water.common.core.result.R; +import com.water.dispatch.entity.*; +import com.water.dispatch.service.DispatchBizService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import java.util.*; +@Tag(name="调度工作台") @RestController @RequestMapping("/dispatch") @RequiredArgsConstructor +public class DispatchController { + private final DispatchBizService svc; + @GetMapping("/duty/today") public R> todayDuty() { return R.ok(svc.getTodayDuty()); } + @PostMapping("/command") public R> createCommand(@RequestBody Map req) { return R.ok(svc.createCommand(req)); } + @PostMapping("/command/{cmdNo}/issue") public R> issue(@PathVariable String cmdNo) { return R.ok(svc.issueCommand(cmdNo)); } + @GetMapping("/command/list") public R> listCommands(@RequestParam(required=false) Integer status) { return R.ok(svc.listCommands(status)); } + @PostMapping("/work-order") public R> createWO(@RequestBody Map req) { return R.ok(svc.createWorkOrder(req)); } + @PutMapping("/work-order/{id}/status") public R> updateWOStatus(@PathVariable Long id, @RequestParam int status) { return R.ok(svc.updateWorkOrderStatus(id, status)); } + @PostMapping("/duty-log") public R addLog(@RequestParam Long scheduleId, @RequestParam Long userId, @RequestParam String type, @RequestParam String content) { svc.addDutyLog(scheduleId,userId,type,content); return R.ok("OK"); } + @GetMapping("/duty-log/{scheduleId}") public R> getLogs(@PathVariable Long scheduleId) { return R.ok(svc.getDutyLogs(scheduleId)); } + @GetMapping("/strategy") public R> listStrategies(@RequestParam(required=false) String type) { return R.ok(svc.listStrategies(type)); } + @GetMapping("/emergency-plan") public R> listPlans(@RequestParam(required=false) String type) { return R.ok(svc.listPlans(type)); } + @PostMapping("/emergency/simulate") public R> simulate(@RequestParam String type, @RequestParam double lng, @RequestParam double lat) { return R.ok(svc.simulateEmergency(type,lng,lat)); } +} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/entity/DispatchCommand.java b/wm-dispatch/src/main/java/com/water/dispatch/entity/DispatchCommand.java new file mode 100644 index 00000000..2a333701 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/entity/DispatchCommand.java @@ -0,0 +1,78 @@ +package com.water.dispatch.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 调度指令 - 全生命周期: 下发→接收→执行→完成→驳回 + */ +@Data +@TableName("disp_dispatch_command") +public class DispatchCommand { + + @TableId(type = IdType.AUTO) + private Long id; + + /** 指令编号 */ + private String commandNo; + + /** 指令标题 */ + private String title; + + /** 指令内容 */ + private String content; + + /** 指令类型: NORMAL-常规 EMERGENCY-应急 MAINTENANCE-维护 */ + private String commandType; + + /** 优先级: LOW-低 MEDIUM-中 HIGH-高 URGENT-紧急 */ + private String priority; + + /** 下发人ID */ + private Long issuerId; + + /** 下发人姓名 */ + private String issuerName; + + /** 接收人ID */ + private Long receiverId; + + /** 接收人姓名 */ + private String receiverName; + + /** 关联设施ID */ + private Long facilityId; + + /** 状态: ISSUED-下发 RECEIVED-接收 EXECUTING-执行 COMPLETED-完成 REJECTED-驳回 CANCELLED-取消 */ + private String status; + + /** 下发时间 */ + private LocalDateTime issuedAt; + + /** 接收时间 */ + private LocalDateTime receivedAt; + + /** 执行开始时间 */ + private LocalDateTime executedAt; + + /** 完成时间 */ + private LocalDateTime completedAt; + + /** 驳回原因 */ + private String rejectReason; + + /** 执行结果 */ + private String executeResult; + + /** 截止时间 */ + private LocalDateTime deadline; + + @TableLogic + private Integer deleted; + + private LocalDateTime createdAt; + + private LocalDateTime updatedAt; +} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/entity/DispatchStrategy.java b/wm-dispatch/src/main/java/com/water/dispatch/entity/DispatchStrategy.java new file mode 100644 index 00000000..94ded1c4 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/entity/DispatchStrategy.java @@ -0,0 +1,11 @@ +package com.water.dispatch.entity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; import java.time.LocalDateTime; +@Data @TableName("dispatch_strategy") +public class DispatchStrategy { + @TableId(type = IdType.AUTO) private Long id; + private String name, type, description, ruleConfig; + private Integer status; + @TableField(fill=FieldFill.INSERT) private LocalDateTime createdTime; + @TableField(fill=FieldFill.INSERT_UPDATE) private LocalDateTime updatedTime; +} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/entity/DutyLog.java b/wm-dispatch/src/main/java/com/water/dispatch/entity/DutyLog.java new file mode 100644 index 00000000..b05578ae --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/entity/DutyLog.java @@ -0,0 +1,10 @@ +package com.water.dispatch.entity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; import java.time.LocalDateTime; +@Data @TableName("dispatch_duty_log") +public class DutyLog { + @TableId(type = IdType.AUTO) private Long id; + private Long scheduleId, userId; + private String logType, content, attachments; + @TableField(fill=FieldFill.INSERT) private LocalDateTime createdTime; +} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/entity/DutySchedule.java b/wm-dispatch/src/main/java/com/water/dispatch/entity/DutySchedule.java new file mode 100644 index 00000000..75d05963 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/entity/DutySchedule.java @@ -0,0 +1,50 @@ +package com.water.dispatch.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * 值班安排 + */ +@Data +@TableName("disp_duty_schedule") +public class DutySchedule { + + @TableId(type = IdType.AUTO) + private Long id; + + /** 值班人员ID */ + private Long userId; + + /** 值班人员姓名 */ + private String userName; + + /** 值班日期 */ + private LocalDate dutyDate; + + /** 班次类型: DAY-白班 NIGHT-夜班 FULL-全天 */ + private String shiftType; + + /** 开始时间 */ + private LocalTime startTime; + + /** 结束时间 */ + private LocalTime endTime; + + /** 状态: 0-待值班 1-值班中 2-已完成 */ + private Integer status; + + /** 备注 */ + private String remark; + + @TableLogic + private Integer deleted; + + private LocalDateTime createdAt; + + private LocalDateTime updatedAt; +} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/entity/EmergencyPlan.java b/wm-dispatch/src/main/java/com/water/dispatch/entity/EmergencyPlan.java new file mode 100644 index 00000000..0417b7d7 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/entity/EmergencyPlan.java @@ -0,0 +1,11 @@ +package com.water.dispatch.entity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; import java.time.LocalDateTime; +@Data @TableName("dispatch_emergency_plan") +public class EmergencyPlan { + @TableId(type = IdType.AUTO) private Long id; + private String planNo, name, type, content, resourceConfig; + private Integer status; private Long creatorId; + @TableField(fill=FieldFill.INSERT) private LocalDateTime createdTime; + @TableField(fill=FieldFill.INSERT_UPDATE) private LocalDateTime updatedTime; +} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/entity/WorkOrder.java b/wm-dispatch/src/main/java/com/water/dispatch/entity/WorkOrder.java new file mode 100644 index 00000000..4c94c0af --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/entity/WorkOrder.java @@ -0,0 +1,12 @@ +package com.water.dispatch.entity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; import java.time.LocalDateTime; +@Data @TableName("dispatch_work_order") +public class WorkOrder { + @TableId(type = IdType.AUTO) private Long id; + private String orderNo, title, description, type, priority; + private Integer status; private Long assigneeId, creatorId; + private LocalDateTime deadline, completedAt; + @TableField(fill=FieldFill.INSERT) private LocalDateTime createdTime; + @TableField(fill=FieldFill.INSERT_UPDATE) private LocalDateTime updatedTime; +} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/mapper/DispatchCommandMapper.java b/wm-dispatch/src/main/java/com/water/dispatch/mapper/DispatchCommandMapper.java new file mode 100644 index 00000000..edb09f96 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/mapper/DispatchCommandMapper.java @@ -0,0 +1,5 @@ +package com.water.dispatch.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.dispatch.entity.DispatchCommand; +import org.apache.ibatis.annotations.Mapper; +@Mapper public interface DispatchCommandMapper extends BaseMapper {} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/mapper/DispatchStrategyMapper.java b/wm-dispatch/src/main/java/com/water/dispatch/mapper/DispatchStrategyMapper.java new file mode 100644 index 00000000..d0b4bd2d --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/mapper/DispatchStrategyMapper.java @@ -0,0 +1,5 @@ +package com.water.dispatch.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.dispatch.entity.DispatchStrategy; +import org.apache.ibatis.annotations.Mapper; +@Mapper public interface DispatchStrategyMapper extends BaseMapper {} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/mapper/DutyLogMapper.java b/wm-dispatch/src/main/java/com/water/dispatch/mapper/DutyLogMapper.java new file mode 100644 index 00000000..53231130 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/mapper/DutyLogMapper.java @@ -0,0 +1,5 @@ +package com.water.dispatch.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.dispatch.entity.DutyLog; +import org.apache.ibatis.annotations.Mapper; +@Mapper public interface DutyLogMapper extends BaseMapper {} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/mapper/DutyScheduleMapper.java b/wm-dispatch/src/main/java/com/water/dispatch/mapper/DutyScheduleMapper.java new file mode 100644 index 00000000..912a3953 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/mapper/DutyScheduleMapper.java @@ -0,0 +1,5 @@ +package com.water.dispatch.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.dispatch.entity.DutySchedule; +import org.apache.ibatis.annotations.Mapper; +@Mapper public interface DutyScheduleMapper extends BaseMapper {} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/mapper/EmergencyPlanMapper.java b/wm-dispatch/src/main/java/com/water/dispatch/mapper/EmergencyPlanMapper.java new file mode 100644 index 00000000..05e5004b --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/mapper/EmergencyPlanMapper.java @@ -0,0 +1,5 @@ +package com.water.dispatch.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.dispatch.entity.EmergencyPlan; +import org.apache.ibatis.annotations.Mapper; +@Mapper public interface EmergencyPlanMapper extends BaseMapper {} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/mapper/WorkOrderMapper.java b/wm-dispatch/src/main/java/com/water/dispatch/mapper/WorkOrderMapper.java new file mode 100644 index 00000000..7530081d --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/mapper/WorkOrderMapper.java @@ -0,0 +1,5 @@ +package com.water.dispatch.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.water.dispatch.entity.WorkOrder; +import org.apache.ibatis.annotations.Mapper; +@Mapper public interface WorkOrderMapper extends BaseMapper {} diff --git a/wm-dispatch/src/main/java/com/water/dispatch/service/DispatchBizService.java b/wm-dispatch/src/main/java/com/water/dispatch/service/DispatchBizService.java new file mode 100644 index 00000000..1fdaf727 --- /dev/null +++ b/wm-dispatch/src/main/java/com/water/dispatch/service/DispatchBizService.java @@ -0,0 +1,81 @@ +package com.water.dispatch.service; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.water.dispatch.entity.*; +import com.water.dispatch.mapper.*; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import java.time.*; import java.util.*; +@Service @RequiredArgsConstructor +public class DispatchBizService { + private final DutyScheduleMapper dutyMapper; + private final DispatchCommandMapper cmdMapper; + private final WorkOrderMapper woMapper; + private final DutyLogMapper logMapper; + private final DispatchStrategyMapper stratMapper; + private final EmergencyPlanMapper planMapper; + + public List getTodayDuty() { + return dutyMapper.selectList(new LambdaQueryWrapper() + .eq(DutySchedule::getDutyDate, LocalDate.now())); + } + public Map createCommand(Map req) { + DispatchCommand c = new DispatchCommand(); + c.setCmdNo("CMD-" + System.currentTimeMillis()); + c.setTitle((String)req.get("title")); c.setContent((String)req.get("content")); + c.setType((String)req.getOrDefault("type","常规")); c.setStatus(0); + cmdMapper.insert(c); + return Map.of("id",c.getId(),"cmdNo",c.getCmdNo()); + } + public Map issueCommand(String cmdNo) { + DispatchCommand c = cmdMapper.selectOne(new LambdaQueryWrapper() + .eq(DispatchCommand::getCmdNo, cmdNo)); + if(c==null) throw new RuntimeException("指令不存在"); + c.setStatus(1); c.setIssuedTime(LocalDateTime.now()); + cmdMapper.updateById(c); + return Map.of("cmdNo",cmdNo,"status",1); + } + public List listCommands(Integer status) { + return cmdMapper.selectList(new LambdaQueryWrapper() + .eq(status!=null, DispatchCommand::getStatus, status)); + } + public Map createWorkOrder(Map req) { + WorkOrder w = new WorkOrder(); + w.setOrderNo("WO-" + System.currentTimeMillis()); + w.setTitle((String)req.get("title")); w.setDescription((String)req.get("description")); + w.setType((String)req.getOrDefault("type","维修")); w.setStatus(0); + w.setPriority((String)req.getOrDefault("priority","中")); + woMapper.insert(w); + return Map.of("id",w.getId(),"orderNo",w.getOrderNo()); + } + public Map updateWorkOrderStatus(Long id, int status) { + WorkOrder w = woMapper.selectById(id); + if(w==null) throw new RuntimeException("工单不存在"); + w.setStatus(status); + if(status==2) w.setCompletedAt(LocalDateTime.now()); + woMapper.updateById(w); + return Map.of("id",id,"status",status); + } + public void addDutyLog(Long scheduleId, Long userId, String type, String content) { + DutyLog l = new DutyLog(); + l.setScheduleId(scheduleId); l.setUserId(userId); + l.setLogType(type); l.setContent(content); + logMapper.insert(l); + } + public List getDutyLogs(Long scheduleId) { + return logMapper.selectList(new LambdaQueryWrapper() + .eq(DutyLog::getScheduleId, scheduleId)); + } + public List listStrategies(String type) { + return stratMapper.selectList(new LambdaQueryWrapper() + .eq(type!=null, DispatchStrategy::getType, type)); + } + public List listPlans(String type) { + return planMapper.selectList(new LambdaQueryWrapper() + .eq(type!=null, EmergencyPlan::getType, type)); + } + public Map simulateEmergency(String type, double lng, double lat) { + return Map.of("type",type,"lng",lng,"lat",lat, + "affectedArea","半径500米","affectedUsers",120, + "estimatedDuration","4小时"); + } +} diff --git a/wm-dispatch/src/main/resources/application.yml b/wm-dispatch/src/main/resources/application.yml new file mode 100644 index 00000000..65a88101 --- /dev/null +++ b/wm-dispatch/src/main/resources/application.yml @@ -0,0 +1,15 @@ +server: + port: 9050 +spring: + application: + name: wm-dispatch + datasource: + url: jdbc:postgresql://localhost:5432/water_dispatch + username: water + password: water123 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true + global-config: + db-config: + id-type: auto diff --git a/wm-dispatch/src/main/resources/db/V1__dispatch.sql b/wm-dispatch/src/main/resources/db/V1__dispatch.sql new file mode 100644 index 00000000..3480fd51 --- /dev/null +++ b/wm-dispatch/src/main/resources/db/V1__dispatch.sql @@ -0,0 +1,33 @@ +CREATE TABLE IF NOT EXISTS dispatch_duty_schedule ( + id BIGSERIAL PRIMARY KEY, user_id BIGINT, user_name VARCHAR(50), + duty_date DATE, start_time TIME, end_time TIME, area VARCHAR(100), + created_time TIMESTAMP DEFAULT NOW(), updated_time TIMESTAMP DEFAULT NOW() +); +CREATE TABLE IF NOT EXISTS dispatch_command ( + id BIGSERIAL PRIMARY KEY, cmd_no VARCHAR(50) UNIQUE, title VARCHAR(200), + content TEXT, type VARCHAR(20), status INT DEFAULT 0, + issued_time TIMESTAMP, completed_time TIMESTAMP, + created_time TIMESTAMP DEFAULT NOW(), updated_time TIMESTAMP DEFAULT NOW() +); +CREATE TABLE IF NOT EXISTS dispatch_work_order ( + id BIGSERIAL PRIMARY KEY, order_no VARCHAR(50) UNIQUE, title VARCHAR(200), + description TEXT, type VARCHAR(20), priority VARCHAR(10), status INT DEFAULT 0, + assignee_id BIGINT, creator_id BIGINT, deadline TIMESTAMP, completed_at TIMESTAMP, + created_time TIMESTAMP DEFAULT NOW(), updated_time TIMESTAMP DEFAULT NOW() +); +CREATE TABLE IF NOT EXISTS dispatch_duty_log ( + id BIGSERIAL PRIMARY KEY, schedule_id BIGINT, user_id BIGINT, + log_type VARCHAR(20), content TEXT, attachments TEXT, + created_time TIMESTAMP DEFAULT NOW() +); +CREATE TABLE IF NOT EXISTS dispatch_strategy ( + id BIGSERIAL PRIMARY KEY, name VARCHAR(100), type VARCHAR(20), + description TEXT, rule_config TEXT, status INT DEFAULT 1, + created_time TIMESTAMP DEFAULT NOW(), updated_time TIMESTAMP DEFAULT NOW() +); +CREATE TABLE IF NOT EXISTS dispatch_emergency_plan ( + id BIGSERIAL PRIMARY KEY, plan_no VARCHAR(50) UNIQUE, name VARCHAR(100), + type VARCHAR(20), content TEXT, resource_config TEXT, + status INT DEFAULT 0, creator_id BIGINT, + created_time TIMESTAMP DEFAULT NOW(), updated_time TIMESTAMP DEFAULT NOW() +);