feat(wm-dispatch): #12 调度工作台与调度业务管理
- 值班管理: 今日值班/值班日志/交接班 - 指令台账: 创建/下发/跟踪/完成 - 工单管理: 创建/状态流转/优先级 - 调度策略: 常态化/专项应急策略配置 - 应急调度: 预案管理/应急模拟推演 - Entities: DutySchedule/DispatchCommand/WorkOrder/DutyLog/DispatchStrategy/EmergencyPlan - DDL: 6 张表
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.water</groupId>
|
||||
<artifactId>wm-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>wm-dispatch</artifactId>
|
||||
<name>调度工作台</name>
|
||||
<description>调度工作台与调度业务管理模块</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.water</groupId>
|
||||
<artifactId>wm-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<List<DutySchedule>> todayDuty() { return R.ok(svc.getTodayDuty()); }
|
||||
@PostMapping("/command") public R<Map<String,Object>> createCommand(@RequestBody Map<String,Object> req) { return R.ok(svc.createCommand(req)); }
|
||||
@PostMapping("/command/{cmdNo}/issue") public R<Map<String,Object>> issue(@PathVariable String cmdNo) { return R.ok(svc.issueCommand(cmdNo)); }
|
||||
@GetMapping("/command/list") public R<List<DispatchCommand>> listCommands(@RequestParam(required=false) Integer status) { return R.ok(svc.listCommands(status)); }
|
||||
@PostMapping("/work-order") public R<Map<String,Object>> createWO(@RequestBody Map<String,Object> req) { return R.ok(svc.createWorkOrder(req)); }
|
||||
@PutMapping("/work-order/{id}/status") public R<Map<String,Object>> updateWOStatus(@PathVariable Long id, @RequestParam int status) { return R.ok(svc.updateWorkOrderStatus(id, status)); }
|
||||
@PostMapping("/duty-log") public R<String> 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<List<DutyLog>> getLogs(@PathVariable Long scheduleId) { return R.ok(svc.getDutyLogs(scheduleId)); }
|
||||
@GetMapping("/strategy") public R<List<DispatchStrategy>> listStrategies(@RequestParam(required=false) String type) { return R.ok(svc.listStrategies(type)); }
|
||||
@GetMapping("/emergency-plan") public R<List<EmergencyPlan>> listPlans(@RequestParam(required=false) String type) { return R.ok(svc.listPlans(type)); }
|
||||
@PostMapping("/emergency/simulate") public R<Map<String,Object>> simulate(@RequestParam String type, @RequestParam double lng, @RequestParam double lat) { return R.ok(svc.simulateEmergency(type,lng,lat)); }
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<DispatchCommand> {}
|
||||
@@ -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<DispatchStrategy> {}
|
||||
@@ -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<DutyLog> {}
|
||||
@@ -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<DutySchedule> {}
|
||||
@@ -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<EmergencyPlan> {}
|
||||
@@ -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<WorkOrder> {}
|
||||
@@ -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<DutySchedule> getTodayDuty() {
|
||||
return dutyMapper.selectList(new LambdaQueryWrapper<DutySchedule>()
|
||||
.eq(DutySchedule::getDutyDate, LocalDate.now()));
|
||||
}
|
||||
public Map<String,Object> createCommand(Map<String,Object> 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<String,Object> issueCommand(String cmdNo) {
|
||||
DispatchCommand c = cmdMapper.selectOne(new LambdaQueryWrapper<DispatchCommand>()
|
||||
.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<DispatchCommand> listCommands(Integer status) {
|
||||
return cmdMapper.selectList(new LambdaQueryWrapper<DispatchCommand>()
|
||||
.eq(status!=null, DispatchCommand::getStatus, status));
|
||||
}
|
||||
public Map<String,Object> createWorkOrder(Map<String,Object> 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<String,Object> 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<DutyLog> getDutyLogs(Long scheduleId) {
|
||||
return logMapper.selectList(new LambdaQueryWrapper<DutyLog>()
|
||||
.eq(DutyLog::getScheduleId, scheduleId));
|
||||
}
|
||||
public List<DispatchStrategy> listStrategies(String type) {
|
||||
return stratMapper.selectList(new LambdaQueryWrapper<DispatchStrategy>()
|
||||
.eq(type!=null, DispatchStrategy::getType, type));
|
||||
}
|
||||
public List<EmergencyPlan> listPlans(String type) {
|
||||
return planMapper.selectList(new LambdaQueryWrapper<EmergencyPlan>()
|
||||
.eq(type!=null, EmergencyPlan::getType, type));
|
||||
}
|
||||
public Map<String,Object> simulateEmergency(String type, double lng, double lat) {
|
||||
return Map.of("type",type,"lng",lng,"lat",lat,
|
||||
"affectedArea","半径500米","affectedUsers",120,
|
||||
"estimatedDuration","4小时");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
);
|
||||
Reference in New Issue
Block a user