feat(wm-revenue): #48 报装核心流程(预受理→工程申请→派单→竣工)

This commit is contained in:
2026-06-15 08:33:07 +08:00
parent e762d548b0
commit 611d553b92
5 changed files with 387 additions and 0 deletions
@@ -0,0 +1,76 @@
package com.water.revenue.controller;
import com.water.common.core.result.R;
import com.water.revenue.service.InstallationService;
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.Map;
@Tag(name = "报装管理")
@RestController
@RequestMapping("/revenue/installation")
@RequiredArgsConstructor
public class InstallationController {
private final InstallationService installationService;
@Operation(summary = "预受理")
@PostMapping("/pre-accept")
public R<Map<String, Object>> preAccept(@RequestBody Map<String, Object> request) {
return R.ok(installationService.preAccept(request));
}
@Operation(summary = "工程申请")
@PutMapping("/engineering-apply")
public R<Map<String, Object>> engineeringApply(@RequestBody Map<String, Object> request) {
String applyNo = (String) request.get("applyNo");
return R.ok(installationService.engineeringApply(applyNo, request));
}
@Operation(summary = "派单")
@PutMapping("/dispatch")
public R<Map<String, Object>> dispatch(@RequestBody Map<String, Object> request) {
String applyNo = (String) request.get("applyNo");
Long assigneeId = Long.parseLong(String.valueOf(request.get("assigneeId")));
String assigneeName = (String) request.get("assigneeName");
return R.ok(installationService.dispatch(applyNo, assigneeId, assigneeName));
}
@Operation(summary = "竣工确认")
@PutMapping("/complete")
public R<Map<String, Object>> complete(@RequestBody Map<String, Object> request) {
String applyNo = (String) request.get("applyNo");
return R.ok(installationService.complete(applyNo, request));
}
@Operation(summary = "查询详情")
@GetMapping("/detail")
public R<Map<String, Object>> getDetail(@RequestParam String applyNo) {
return R.ok(installationService.getDetail(applyNo));
}
@Operation(summary = "分页列表")
@GetMapping("/list")
public R<Map<String, Object>> list(@RequestParam(required = false) String area,
@RequestParam(required = false) String status,
@RequestParam(required = false) String keyword,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
Map<String, Object> query = Map.of(
"page", page, "size", size,
"area", area != null ? area : "",
"status", status != null ? status : "",
"keyword", keyword != null ? keyword : ""
);
return R.ok(installationService.list(query));
}
@Operation(summary = "统计")
@GetMapping("/stats")
public R<Map<String, Object>> stats(@RequestParam(required = false) String area) {
return R.ok(installationService.stats(area));
}
}
@@ -0,0 +1,52 @@
package com.water.revenue.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.water.revenue.enums.InstallationStatus;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("installation_apply")
public class InstallationApply {
@TableId(type = IdType.AUTO)
private Long id;
private String applyNo;
private String applicantName;
private String applicantPhone;
private String applicantIdCard;
private String address;
private String area;
private String waterUseType;
private BigDecimal pipeDiameter;
private InstallationStatus status;
private LocalDateTime applyTime;
private LocalDateTime engineeringApplyTime;
private LocalDateTime dispatchTime;
private LocalDateTime completedTime;
private Long assigneeId;
private String assigneeName;
private String remarks;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
@@ -0,0 +1,19 @@
package com.water.revenue.enums;
import lombok.Getter;
@Getter
public enum InstallationStatus {
PRE_ACCEPT("预受理"),
ENGINEERING_APPLY("工程申请"),
DISPATCHED("已派单"),
COMPLETED("竣工确认"),
REJECTED("已驳回");
private final String description;
InstallationStatus(String description) {
this.description = description;
}
}
@@ -0,0 +1,214 @@
package com.water.revenue.service;
import com.water.revenue.enums.InstallationStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
@Slf4j
@Service
@RequiredArgsConstructor
public class InstallationService {
private final JdbcTemplate jdbcTemplate;
/**
* 预受理 - 生成申请编号,状态→PRE_ACCEPT
*/
public Map<String, Object> preAccept(Map<String, Object> request) {
String applyNo = "IZA-" + System.currentTimeMillis();
String applicantName = (String) request.get("applicantName");
String applicantPhone = (String) request.get("applicantPhone");
String applicantIdCard = (String) request.get("applicantIdCard");
String address = (String) request.get("address");
String area = (String) request.get("area");
String waterUseType = (String) request.get("waterUseType");
Object pipeDiameter = request.get("pipeDiameter");
String remarks = (String) request.get("remarks");
jdbcTemplate.update(
"INSERT INTO installation_apply (apply_no, applicant_name, applicant_phone, applicant_id_card, " +
"address, area, water_use_type, pipe_diameter, status, apply_time, remarks, created_at, updated_at) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?, NOW(), NOW())",
applyNo, applicantName, applicantPhone, applicantIdCard,
address, area, waterUseType, pipeDiameter,
InstallationStatus.PRE_ACCEPT.name(), remarks);
log.info("Installation pre-accepted: applyNo={}, applicant={}", applyNo, applicantName);
Map<String, Object> result = new LinkedHashMap<>();
result.put("applyNo", applyNo);
result.put("status", InstallationStatus.PRE_ACCEPT.name());
result.put("applicantName", applicantName);
result.put("applyTime", LocalDateTime.now().toString());
return result;
}
/**
* 工程申请 - 状态→ENGINEERING_APPLY
*/
public Map<String, Object> engineeringApply(String applyNo, Map<String, Object> engineeringInfo) {
String remarks = (String) engineeringInfo.get("remarks");
int rows = jdbcTemplate.update(
"UPDATE installation_apply SET status = ?, engineering_apply_time = NOW(), " +
"remarks = COALESCE(?, remarks), updated_at = NOW() WHERE apply_no = ?",
InstallationStatus.ENGINEERING_APPLY.name(), remarks, applyNo);
if (rows == 0) {
throw new RuntimeException("申请不存在: " + applyNo);
}
log.info("Engineering applied: applyNo={}", applyNo);
Map<String, Object> result = new LinkedHashMap<>();
result.put("applyNo", applyNo);
result.put("status", InstallationStatus.ENGINEERING_APPLY.name());
result.put("engineeringApplyTime", LocalDateTime.now().toString());
return result;
}
/**
* 派单 - 状态→DISPATCHED
*/
public Map<String, Object> dispatch(String applyNo, Long assigneeId, String assigneeName) {
int rows = jdbcTemplate.update(
"UPDATE installation_apply SET status = ?, assignee_id = ?, assignee_name = ?, " +
"dispatch_time = NOW(), updated_at = NOW() WHERE apply_no = ?",
InstallationStatus.DISPATCHED.name(), assigneeId, assigneeName, applyNo);
if (rows == 0) {
throw new RuntimeException("申请不存在: " + applyNo);
}
log.info("Installation dispatched: applyNo={}, assignee={}", applyNo, assigneeName);
Map<String, Object> result = new LinkedHashMap<>();
result.put("applyNo", applyNo);
result.put("status", InstallationStatus.DISPATCHED.name());
result.put("assigneeId", assigneeId);
result.put("assigneeName", assigneeName);
result.put("dispatchTime", LocalDateTime.now().toString());
return result;
}
/**
* 竣工确认 - 状态→COMPLETED
*/
public Map<String, Object> complete(String applyNo, Map<String, Object> completionInfo) {
String remarks = (String) completionInfo.get("remarks");
int rows = jdbcTemplate.update(
"UPDATE installation_apply SET status = ?, completed_time = NOW(), " +
"remarks = COALESCE(?, remarks), updated_at = NOW() WHERE apply_no = ?",
InstallationStatus.COMPLETED.name(), remarks, applyNo);
if (rows == 0) {
throw new RuntimeException("申请不存在: " + applyNo);
}
log.info("Installation completed: applyNo={}", applyNo);
Map<String, Object> result = new LinkedHashMap<>();
result.put("applyNo", applyNo);
result.put("status", InstallationStatus.COMPLETED.name());
result.put("completedTime", LocalDateTime.now().toString());
return result;
}
/**
* 查询详情
*/
public Map<String, Object> getDetail(String applyNo) {
return jdbcTemplate.queryForMap(
"SELECT id, apply_no, applicant_name, applicant_phone, applicant_id_card, " +
"address, area, water_use_type, pipe_diameter, status, apply_time, " +
"engineering_apply_time, dispatch_time, completed_time, assignee_id, " +
"assignee_name, remarks, created_at, updated_at " +
"FROM installation_apply WHERE apply_no = ?",
applyNo);
}
/**
* 分页查询
*/
public Map<String, Object> list(Map<String, Object> query) {
int page = query.get("page") != null ? Integer.parseInt(String.valueOf(query.get("page"))) : 1;
int size = query.get("size") != null ? Integer.parseInt(String.valueOf(query.get("size"))) : 10;
int offset = (page - 1) * size;
String area = (String) query.get("area");
String status = (String) query.get("status");
String keyword = (String) query.get("keyword");
StringBuilder sql = new StringBuilder("SELECT * FROM installation_apply WHERE 1=1");
List<Object> params = new ArrayList<>();
if (area != null && !area.isEmpty()) {
sql.append(" AND area = ?");
params.add(area);
}
if (status != null && !status.isEmpty()) {
sql.append(" AND status = ?");
params.add(status);
}
if (keyword != null && !keyword.isEmpty()) {
sql.append(" AND (applicant_name LIKE ? OR apply_no LIKE ?)");
params.add("%" + keyword + "%");
params.add("%" + keyword + "%");
}
sql.append(" ORDER BY created_at DESC LIMIT ? OFFSET ?");
params.add(size);
params.add(offset);
List<Map<String, Object>> records = jdbcTemplate.queryForList(sql.toString(), params.toArray());
// Total count
StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM installation_apply WHERE 1=1");
List<Object> countParams = new ArrayList<>();
if (area != null && !area.isEmpty()) {
countSql.append(" AND area = ?");
countParams.add(area);
}
if (status != null && !status.isEmpty()) {
countSql.append(" AND status = ?");
countParams.add(status);
}
if (keyword != null && !keyword.isEmpty()) {
countSql.append(" AND (applicant_name LIKE ? OR apply_no LIKE ?)");
countParams.add("%" + keyword + "%");
countParams.add("%" + keyword + "%");
}
Long total = jdbcTemplate.queryForObject(countSql.toString(), Long.class, countParams.toArray());
Map<String, Object> result = new LinkedHashMap<>();
result.put("records", records);
result.put("total", total);
result.put("page", page);
result.put("size", size);
return result;
}
/**
* 统计
*/
public Map<String, Object> stats(String area) {
StringBuilder sql = new StringBuilder(
"SELECT status, COUNT(*) as count FROM installation_apply WHERE 1=1");
List<Object> params = new ArrayList<>();
if (area != null && !area.isEmpty()) {
sql.append(" AND area = ?");
params.add(area);
}
sql.append(" GROUP BY status");
List<Map<String, Object>> statusStats = jdbcTemplate.queryForList(sql.toString(), params.toArray());
Map<String, Object> result = new LinkedHashMap<>();
result.put("byStatus", statusStats);
result.put("area", area);
return result;
}
}
@@ -0,0 +1,26 @@
-- 报装申请表
CREATE TABLE IF NOT EXISTS installation_apply (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
apply_no VARCHAR(64) NOT NULL COMMENT '申请编号',
applicant_name VARCHAR(64) NOT NULL COMMENT '申请人姓名',
applicant_phone VARCHAR(20) NOT NULL COMMENT '申请人电话',
applicant_id_card VARCHAR(20) DEFAULT NULL COMMENT '申请人身份证号',
address VARCHAR(256) NOT NULL COMMENT '用水地址',
area VARCHAR(64) NOT NULL COMMENT '所属区域',
water_use_type VARCHAR(32) DEFAULT NULL COMMENT '用水类型(居民/商业/工业/其他)',
pipe_diameter DECIMAL(10,2) DEFAULT NULL COMMENT '管径(mm)',
status VARCHAR(32) NOT NULL DEFAULT 'PRE_ACCEPT' COMMENT '状态: PRE_ACCEPT/ENGINEERING_APPLY/DISPATCHED/COMPLETED/REJECTED',
apply_time DATETIME NOT NULL COMMENT '申请时间',
engineering_apply_time DATETIME DEFAULT NULL COMMENT '工程申请时间',
dispatch_time DATETIME DEFAULT NULL COMMENT '派单时间',
completed_time DATETIME DEFAULT NULL COMMENT '竣工时间',
assignee_id BIGINT DEFAULT NULL COMMENT '指派人ID',
assignee_name VARCHAR(64) DEFAULT NULL COMMENT '指派人姓名',
remarks VARCHAR(512) DEFAULT NULL COMMENT '备注',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
UNIQUE KEY uk_apply_no (apply_no),
KEY idx_area (area),
KEY idx_status (status),
KEY idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='报装申请表';