diff --git a/wm-revenue/src/main/java/com/water/revenue/controller/InstallationController.java b/wm-revenue/src/main/java/com/water/revenue/controller/InstallationController.java new file mode 100644 index 00000000..6daf650c --- /dev/null +++ b/wm-revenue/src/main/java/com/water/revenue/controller/InstallationController.java @@ -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> preAccept(@RequestBody Map request) { + return R.ok(installationService.preAccept(request)); + } + + @Operation(summary = "工程申请") + @PutMapping("/engineering-apply") + public R> engineeringApply(@RequestBody Map request) { + String applyNo = (String) request.get("applyNo"); + return R.ok(installationService.engineeringApply(applyNo, request)); + } + + @Operation(summary = "派单") + @PutMapping("/dispatch") + public R> dispatch(@RequestBody Map 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> complete(@RequestBody Map request) { + String applyNo = (String) request.get("applyNo"); + return R.ok(installationService.complete(applyNo, request)); + } + + @Operation(summary = "查询详情") + @GetMapping("/detail") + public R> getDetail(@RequestParam String applyNo) { + return R.ok(installationService.getDetail(applyNo)); + } + + @Operation(summary = "分页列表") + @GetMapping("/list") + public R> 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 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> stats(@RequestParam(required = false) String area) { + return R.ok(installationService.stats(area)); + } +} diff --git a/wm-revenue/src/main/java/com/water/revenue/entity/InstallationApply.java b/wm-revenue/src/main/java/com/water/revenue/entity/InstallationApply.java new file mode 100644 index 00000000..c6095b0f --- /dev/null +++ b/wm-revenue/src/main/java/com/water/revenue/entity/InstallationApply.java @@ -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; +} diff --git a/wm-revenue/src/main/java/com/water/revenue/enums/InstallationStatus.java b/wm-revenue/src/main/java/com/water/revenue/enums/InstallationStatus.java new file mode 100644 index 00000000..2da3755e --- /dev/null +++ b/wm-revenue/src/main/java/com/water/revenue/enums/InstallationStatus.java @@ -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; + } +} diff --git a/wm-revenue/src/main/java/com/water/revenue/service/InstallationService.java b/wm-revenue/src/main/java/com/water/revenue/service/InstallationService.java new file mode 100644 index 00000000..1771992f --- /dev/null +++ b/wm-revenue/src/main/java/com/water/revenue/service/InstallationService.java @@ -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 preAccept(Map 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 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 engineeringApply(String applyNo, Map 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 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 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 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 complete(String applyNo, Map 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 result = new LinkedHashMap<>(); + result.put("applyNo", applyNo); + result.put("status", InstallationStatus.COMPLETED.name()); + result.put("completedTime", LocalDateTime.now().toString()); + return result; + } + + /** + * 查询详情 + */ + public Map 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 list(Map 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 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> records = jdbcTemplate.queryForList(sql.toString(), params.toArray()); + + // Total count + StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM installation_apply WHERE 1=1"); + List 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 result = new LinkedHashMap<>(); + result.put("records", records); + result.put("total", total); + result.put("page", page); + result.put("size", size); + return result; + } + + /** + * 统计 + */ + public Map stats(String area) { + StringBuilder sql = new StringBuilder( + "SELECT status, COUNT(*) as count FROM installation_apply WHERE 1=1"); + List params = new ArrayList<>(); + + if (area != null && !area.isEmpty()) { + sql.append(" AND area = ?"); + params.add(area); + } + sql.append(" GROUP BY status"); + + List> statusStats = jdbcTemplate.queryForList(sql.toString(), params.toArray()); + + Map result = new LinkedHashMap<>(); + result.put("byStatus", statusStats); + result.put("area", area); + return result; + } +} diff --git a/wm-revenue/src/main/resources/sql/installation_apply.sql b/wm-revenue/src/main/resources/sql/installation_apply.sql new file mode 100644 index 00000000..8da3069d --- /dev/null +++ b/wm-revenue/src/main/resources/sql/installation_apply.sql @@ -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='报装申请表';