Bläddra i källkod

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

bot_dev2 4 dagar sedan
förälder
incheckning
611d553b92

+ 76
- 0
wm-revenue/src/main/java/com/water/revenue/controller/InstallationController.java Visa fil

@@ -0,0 +1,76 @@
1
+package com.water.revenue.controller;
2
+
3
+import com.water.common.core.result.R;
4
+import com.water.revenue.service.InstallationService;
5
+import io.swagger.v3.oas.annotations.Operation;
6
+import io.swagger.v3.oas.annotations.tags.Tag;
7
+import lombok.RequiredArgsConstructor;
8
+import org.springframework.web.bind.annotation.*;
9
+
10
+import java.util.Map;
11
+
12
+@Tag(name = "报装管理")
13
+@RestController
14
+@RequestMapping("/revenue/installation")
15
+@RequiredArgsConstructor
16
+public class InstallationController {
17
+
18
+    private final InstallationService installationService;
19
+
20
+    @Operation(summary = "预受理")
21
+    @PostMapping("/pre-accept")
22
+    public R<Map<String, Object>> preAccept(@RequestBody Map<String, Object> request) {
23
+        return R.ok(installationService.preAccept(request));
24
+    }
25
+
26
+    @Operation(summary = "工程申请")
27
+    @PutMapping("/engineering-apply")
28
+    public R<Map<String, Object>> engineeringApply(@RequestBody Map<String, Object> request) {
29
+        String applyNo = (String) request.get("applyNo");
30
+        return R.ok(installationService.engineeringApply(applyNo, request));
31
+    }
32
+
33
+    @Operation(summary = "派单")
34
+    @PutMapping("/dispatch")
35
+    public R<Map<String, Object>> dispatch(@RequestBody Map<String, Object> request) {
36
+        String applyNo = (String) request.get("applyNo");
37
+        Long assigneeId = Long.parseLong(String.valueOf(request.get("assigneeId")));
38
+        String assigneeName = (String) request.get("assigneeName");
39
+        return R.ok(installationService.dispatch(applyNo, assigneeId, assigneeName));
40
+    }
41
+
42
+    @Operation(summary = "竣工确认")
43
+    @PutMapping("/complete")
44
+    public R<Map<String, Object>> complete(@RequestBody Map<String, Object> request) {
45
+        String applyNo = (String) request.get("applyNo");
46
+        return R.ok(installationService.complete(applyNo, request));
47
+    }
48
+
49
+    @Operation(summary = "查询详情")
50
+    @GetMapping("/detail")
51
+    public R<Map<String, Object>> getDetail(@RequestParam String applyNo) {
52
+        return R.ok(installationService.getDetail(applyNo));
53
+    }
54
+
55
+    @Operation(summary = "分页列表")
56
+    @GetMapping("/list")
57
+    public R<Map<String, Object>> list(@RequestParam(required = false) String area,
58
+                                        @RequestParam(required = false) String status,
59
+                                        @RequestParam(required = false) String keyword,
60
+                                        @RequestParam(defaultValue = "1") Integer page,
61
+                                        @RequestParam(defaultValue = "10") Integer size) {
62
+        Map<String, Object> query = Map.of(
63
+            "page", page, "size", size,
64
+            "area", area != null ? area : "",
65
+            "status", status != null ? status : "",
66
+            "keyword", keyword != null ? keyword : ""
67
+        );
68
+        return R.ok(installationService.list(query));
69
+    }
70
+
71
+    @Operation(summary = "统计")
72
+    @GetMapping("/stats")
73
+    public R<Map<String, Object>> stats(@RequestParam(required = false) String area) {
74
+        return R.ok(installationService.stats(area));
75
+    }
76
+}

+ 52
- 0
wm-revenue/src/main/java/com/water/revenue/entity/InstallationApply.java Visa fil

@@ -0,0 +1,52 @@
1
+package com.water.revenue.entity;
2
+
3
+import com.baomidou.mybatisplus.annotation.*;
4
+import com.water.revenue.enums.InstallationStatus;
5
+import lombok.Data;
6
+
7
+import java.math.BigDecimal;
8
+import java.time.LocalDateTime;
9
+
10
+@Data
11
+@TableName("installation_apply")
12
+public class InstallationApply {
13
+
14
+    @TableId(type = IdType.AUTO)
15
+    private Long id;
16
+
17
+    private String applyNo;
18
+
19
+    private String applicantName;
20
+
21
+    private String applicantPhone;
22
+
23
+    private String applicantIdCard;
24
+
25
+    private String address;
26
+
27
+    private String area;
28
+
29
+    private String waterUseType;
30
+
31
+    private BigDecimal pipeDiameter;
32
+
33
+    private InstallationStatus status;
34
+
35
+    private LocalDateTime applyTime;
36
+
37
+    private LocalDateTime engineeringApplyTime;
38
+
39
+    private LocalDateTime dispatchTime;
40
+
41
+    private LocalDateTime completedTime;
42
+
43
+    private Long assigneeId;
44
+
45
+    private String assigneeName;
46
+
47
+    private String remarks;
48
+
49
+    private LocalDateTime createdAt;
50
+
51
+    private LocalDateTime updatedAt;
52
+}

+ 19
- 0
wm-revenue/src/main/java/com/water/revenue/enums/InstallationStatus.java Visa fil

@@ -0,0 +1,19 @@
1
+package com.water.revenue.enums;
2
+
3
+import lombok.Getter;
4
+
5
+@Getter
6
+public enum InstallationStatus {
7
+
8
+    PRE_ACCEPT("预受理"),
9
+    ENGINEERING_APPLY("工程申请"),
10
+    DISPATCHED("已派单"),
11
+    COMPLETED("竣工确认"),
12
+    REJECTED("已驳回");
13
+
14
+    private final String description;
15
+
16
+    InstallationStatus(String description) {
17
+        this.description = description;
18
+    }
19
+}

+ 214
- 0
wm-revenue/src/main/java/com/water/revenue/service/InstallationService.java Visa fil

@@ -0,0 +1,214 @@
1
+package com.water.revenue.service;
2
+
3
+import com.water.revenue.enums.InstallationStatus;
4
+import lombok.RequiredArgsConstructor;
5
+import lombok.extern.slf4j.Slf4j;
6
+import org.springframework.jdbc.core.JdbcTemplate;
7
+import org.springframework.stereotype.Service;
8
+
9
+import java.time.LocalDateTime;
10
+import java.util.*;
11
+
12
+@Slf4j
13
+@Service
14
+@RequiredArgsConstructor
15
+public class InstallationService {
16
+
17
+    private final JdbcTemplate jdbcTemplate;
18
+
19
+    /**
20
+     * 预受理 - 生成申请编号,状态→PRE_ACCEPT
21
+     */
22
+    public Map<String, Object> preAccept(Map<String, Object> request) {
23
+        String applyNo = "IZA-" + System.currentTimeMillis();
24
+        String applicantName = (String) request.get("applicantName");
25
+        String applicantPhone = (String) request.get("applicantPhone");
26
+        String applicantIdCard = (String) request.get("applicantIdCard");
27
+        String address = (String) request.get("address");
28
+        String area = (String) request.get("area");
29
+        String waterUseType = (String) request.get("waterUseType");
30
+        Object pipeDiameter = request.get("pipeDiameter");
31
+        String remarks = (String) request.get("remarks");
32
+
33
+        jdbcTemplate.update(
34
+            "INSERT INTO installation_apply (apply_no, applicant_name, applicant_phone, applicant_id_card, " +
35
+            "address, area, water_use_type, pipe_diameter, status, apply_time, remarks, created_at, updated_at) " +
36
+            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?, NOW(), NOW())",
37
+            applyNo, applicantName, applicantPhone, applicantIdCard,
38
+            address, area, waterUseType, pipeDiameter,
39
+            InstallationStatus.PRE_ACCEPT.name(), remarks);
40
+
41
+        log.info("Installation pre-accepted: applyNo={}, applicant={}", applyNo, applicantName);
42
+
43
+        Map<String, Object> result = new LinkedHashMap<>();
44
+        result.put("applyNo", applyNo);
45
+        result.put("status", InstallationStatus.PRE_ACCEPT.name());
46
+        result.put("applicantName", applicantName);
47
+        result.put("applyTime", LocalDateTime.now().toString());
48
+        return result;
49
+    }
50
+
51
+    /**
52
+     * 工程申请 - 状态→ENGINEERING_APPLY
53
+     */
54
+    public Map<String, Object> engineeringApply(String applyNo, Map<String, Object> engineeringInfo) {
55
+        String remarks = (String) engineeringInfo.get("remarks");
56
+        int rows = jdbcTemplate.update(
57
+            "UPDATE installation_apply SET status = ?, engineering_apply_time = NOW(), " +
58
+            "remarks = COALESCE(?, remarks), updated_at = NOW() WHERE apply_no = ?",
59
+            InstallationStatus.ENGINEERING_APPLY.name(), remarks, applyNo);
60
+
61
+        if (rows == 0) {
62
+            throw new RuntimeException("申请不存在: " + applyNo);
63
+        }
64
+        log.info("Engineering applied: applyNo={}", applyNo);
65
+
66
+        Map<String, Object> result = new LinkedHashMap<>();
67
+        result.put("applyNo", applyNo);
68
+        result.put("status", InstallationStatus.ENGINEERING_APPLY.name());
69
+        result.put("engineeringApplyTime", LocalDateTime.now().toString());
70
+        return result;
71
+    }
72
+
73
+    /**
74
+     * 派单 - 状态→DISPATCHED
75
+     */
76
+    public Map<String, Object> dispatch(String applyNo, Long assigneeId, String assigneeName) {
77
+        int rows = jdbcTemplate.update(
78
+            "UPDATE installation_apply SET status = ?, assignee_id = ?, assignee_name = ?, " +
79
+            "dispatch_time = NOW(), updated_at = NOW() WHERE apply_no = ?",
80
+            InstallationStatus.DISPATCHED.name(), assigneeId, assigneeName, applyNo);
81
+
82
+        if (rows == 0) {
83
+            throw new RuntimeException("申请不存在: " + applyNo);
84
+        }
85
+        log.info("Installation dispatched: applyNo={}, assignee={}", applyNo, assigneeName);
86
+
87
+        Map<String, Object> result = new LinkedHashMap<>();
88
+        result.put("applyNo", applyNo);
89
+        result.put("status", InstallationStatus.DISPATCHED.name());
90
+        result.put("assigneeId", assigneeId);
91
+        result.put("assigneeName", assigneeName);
92
+        result.put("dispatchTime", LocalDateTime.now().toString());
93
+        return result;
94
+    }
95
+
96
+    /**
97
+     * 竣工确认 - 状态→COMPLETED
98
+     */
99
+    public Map<String, Object> complete(String applyNo, Map<String, Object> completionInfo) {
100
+        String remarks = (String) completionInfo.get("remarks");
101
+        int rows = jdbcTemplate.update(
102
+            "UPDATE installation_apply SET status = ?, completed_time = NOW(), " +
103
+            "remarks = COALESCE(?, remarks), updated_at = NOW() WHERE apply_no = ?",
104
+            InstallationStatus.COMPLETED.name(), remarks, applyNo);
105
+
106
+        if (rows == 0) {
107
+            throw new RuntimeException("申请不存在: " + applyNo);
108
+        }
109
+        log.info("Installation completed: applyNo={}", applyNo);
110
+
111
+        Map<String, Object> result = new LinkedHashMap<>();
112
+        result.put("applyNo", applyNo);
113
+        result.put("status", InstallationStatus.COMPLETED.name());
114
+        result.put("completedTime", LocalDateTime.now().toString());
115
+        return result;
116
+    }
117
+
118
+    /**
119
+     * 查询详情
120
+     */
121
+    public Map<String, Object> getDetail(String applyNo) {
122
+        return jdbcTemplate.queryForMap(
123
+            "SELECT id, apply_no, applicant_name, applicant_phone, applicant_id_card, " +
124
+            "address, area, water_use_type, pipe_diameter, status, apply_time, " +
125
+            "engineering_apply_time, dispatch_time, completed_time, assignee_id, " +
126
+            "assignee_name, remarks, created_at, updated_at " +
127
+            "FROM installation_apply WHERE apply_no = ?",
128
+            applyNo);
129
+    }
130
+
131
+    /**
132
+     * 分页查询
133
+     */
134
+    public Map<String, Object> list(Map<String, Object> query) {
135
+        int page = query.get("page") != null ? Integer.parseInt(String.valueOf(query.get("page"))) : 1;
136
+        int size = query.get("size") != null ? Integer.parseInt(String.valueOf(query.get("size"))) : 10;
137
+        int offset = (page - 1) * size;
138
+
139
+        String area = (String) query.get("area");
140
+        String status = (String) query.get("status");
141
+        String keyword = (String) query.get("keyword");
142
+
143
+        StringBuilder sql = new StringBuilder("SELECT * FROM installation_apply WHERE 1=1");
144
+        List<Object> params = new ArrayList<>();
145
+
146
+        if (area != null && !area.isEmpty()) {
147
+            sql.append(" AND area = ?");
148
+            params.add(area);
149
+        }
150
+        if (status != null && !status.isEmpty()) {
151
+            sql.append(" AND status = ?");
152
+            params.add(status);
153
+        }
154
+        if (keyword != null && !keyword.isEmpty()) {
155
+            sql.append(" AND (applicant_name LIKE ? OR apply_no LIKE ?)");
156
+            params.add("%" + keyword + "%");
157
+            params.add("%" + keyword + "%");
158
+        }
159
+
160
+        sql.append(" ORDER BY created_at DESC LIMIT ? OFFSET ?");
161
+        params.add(size);
162
+        params.add(offset);
163
+
164
+        List<Map<String, Object>> records = jdbcTemplate.queryForList(sql.toString(), params.toArray());
165
+
166
+        // Total count
167
+        StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM installation_apply WHERE 1=1");
168
+        List<Object> countParams = new ArrayList<>();
169
+        if (area != null && !area.isEmpty()) {
170
+            countSql.append(" AND area = ?");
171
+            countParams.add(area);
172
+        }
173
+        if (status != null && !status.isEmpty()) {
174
+            countSql.append(" AND status = ?");
175
+            countParams.add(status);
176
+        }
177
+        if (keyword != null && !keyword.isEmpty()) {
178
+            countSql.append(" AND (applicant_name LIKE ? OR apply_no LIKE ?)");
179
+            countParams.add("%" + keyword + "%");
180
+            countParams.add("%" + keyword + "%");
181
+        }
182
+
183
+        Long total = jdbcTemplate.queryForObject(countSql.toString(), Long.class, countParams.toArray());
184
+
185
+        Map<String, Object> result = new LinkedHashMap<>();
186
+        result.put("records", records);
187
+        result.put("total", total);
188
+        result.put("page", page);
189
+        result.put("size", size);
190
+        return result;
191
+    }
192
+
193
+    /**
194
+     * 统计
195
+     */
196
+    public Map<String, Object> stats(String area) {
197
+        StringBuilder sql = new StringBuilder(
198
+            "SELECT status, COUNT(*) as count FROM installation_apply WHERE 1=1");
199
+        List<Object> params = new ArrayList<>();
200
+
201
+        if (area != null && !area.isEmpty()) {
202
+            sql.append(" AND area = ?");
203
+            params.add(area);
204
+        }
205
+        sql.append(" GROUP BY status");
206
+
207
+        List<Map<String, Object>> statusStats = jdbcTemplate.queryForList(sql.toString(), params.toArray());
208
+
209
+        Map<String, Object> result = new LinkedHashMap<>();
210
+        result.put("byStatus", statusStats);
211
+        result.put("area", area);
212
+        return result;
213
+    }
214
+}

+ 26
- 0
wm-revenue/src/main/resources/sql/installation_apply.sql Visa fil

@@ -0,0 +1,26 @@
1
+-- 报装申请表
2
+CREATE TABLE IF NOT EXISTS installation_apply (
3
+    id              BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
4
+    apply_no        VARCHAR(64)    NOT NULL COMMENT '申请编号',
5
+    applicant_name  VARCHAR(64)    NOT NULL COMMENT '申请人姓名',
6
+    applicant_phone VARCHAR(20)    NOT NULL COMMENT '申请人电话',
7
+    applicant_id_card VARCHAR(20)  DEFAULT NULL COMMENT '申请人身份证号',
8
+    address         VARCHAR(256)   NOT NULL COMMENT '用水地址',
9
+    area            VARCHAR(64)    NOT NULL COMMENT '所属区域',
10
+    water_use_type  VARCHAR(32)    DEFAULT NULL COMMENT '用水类型(居民/商业/工业/其他)',
11
+    pipe_diameter   DECIMAL(10,2)  DEFAULT NULL COMMENT '管径(mm)',
12
+    status          VARCHAR(32)    NOT NULL DEFAULT 'PRE_ACCEPT' COMMENT '状态: PRE_ACCEPT/ENGINEERING_APPLY/DISPATCHED/COMPLETED/REJECTED',
13
+    apply_time      DATETIME       NOT NULL COMMENT '申请时间',
14
+    engineering_apply_time DATETIME DEFAULT NULL COMMENT '工程申请时间',
15
+    dispatch_time   DATETIME       DEFAULT NULL COMMENT '派单时间',
16
+    completed_time  DATETIME       DEFAULT NULL COMMENT '竣工时间',
17
+    assignee_id     BIGINT         DEFAULT NULL COMMENT '指派人ID',
18
+    assignee_name   VARCHAR(64)    DEFAULT NULL COMMENT '指派人姓名',
19
+    remarks         VARCHAR(512)   DEFAULT NULL COMMENT '备注',
20
+    created_at      DATETIME       NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
21
+    updated_at      DATETIME       NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
22
+    UNIQUE KEY uk_apply_no (apply_no),
23
+    KEY idx_area (area),
24
+    KEY idx_status (status),
25
+    KEY idx_created_at (created_at)
26
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='报装申请表';