This commit is contained in:
2025-09-27 22:57:59 +08:00
parent 8a458ff0a4
commit ed26244cdb
12585 changed files with 1914308 additions and 3474 deletions

View File

@@ -0,0 +1,150 @@
package com.example.demo.consult;
import com.example.demo.common.AppDefaultsProperties;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@RestController
@RequestMapping("/api/consults")
public class ConsultController {
private final JdbcTemplate jdbcTemplate;
private final AppDefaultsProperties defaults;
public ConsultController(JdbcTemplate jdbcTemplate, AppDefaultsProperties defaults) {
this.jdbcTemplate = jdbcTemplate;
this.defaults = defaults;
}
@PostMapping
public ResponseEntity<?> create(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId,
@RequestHeader(name = "X-User-Id", required = false) Long userId,
@RequestBody Map<String, Object> body) {
Long sid = (shopId == null ? defaults.getShopId() : shopId);
Long uid = (userId == null ? defaults.getUserId() : userId);
if (body == null) body = new HashMap<>();
String topic = ""; // 主题字段已废弃
String message = Optional.ofNullable(body.get("message")).map(String::valueOf).orElse(null);
if (message == null || message.isBlank()) {
return ResponseEntity.badRequest().body(Map.of("message", "message required"));
}
jdbcTemplate.update("INSERT INTO consults (shop_id,user_id,topic,message,status,created_at,updated_at) VALUES (?,?,?,?, 'open', NOW(), NOW())",
sid, uid, topic, message);
Long id = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
Map<String,Object> resp = new HashMap<>();
resp.put("id", id);
return ResponseEntity.ok(resp);
}
@GetMapping("/latest")
public ResponseEntity<?> latest(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId,
@RequestHeader(name = "X-User-Id", required = false) Long userId) {
Long sid = (shopId == null ? defaults.getShopId() : shopId);
Long uid = (userId == null ? defaults.getUserId() : userId);
List<Map<String, Object>> list = jdbcTemplate.query(
"SELECT id, topic, message, status, created_at FROM consults WHERE shop_id=? AND user_id=? ORDER BY id DESC LIMIT 1",
ps -> { ps.setLong(1, sid); ps.setLong(2, uid); },
(rs, i) -> {
Map<String,Object> m = new LinkedHashMap<>();
m.put("id", rs.getLong("id"));
m.put("topic", rs.getString("topic"));
m.put("message", rs.getString("message"));
m.put("status", rs.getString("status"));
m.put("createdAt", rs.getTimestamp("created_at"));
return m;
}
);
if (list.isEmpty()) {
return ResponseEntity.ok(Collections.emptyMap());
}
Map<String,Object> latest = list.get(0);
Object idObj = latest.get("id");
Long consultId = (idObj instanceof Number) ? ((Number) idObj).longValue() : Long.valueOf(String.valueOf(idObj));
Map<String,Object> reply = jdbcTemplate.query(
"SELECT content, created_at FROM consult_replies WHERE consult_id=? ORDER BY id DESC LIMIT 1",
rs -> {
if (rs.next()) {
Map<String,Object> r = new HashMap<>();
r.put("content", rs.getString("content"));
r.put("createdAt", rs.getTimestamp("created_at"));
return r;
}
return null;
}, consultId
);
latest.put("replied", Objects.equals("resolved", String.valueOf(latest.get("status"))));
if (reply != null) {
latest.put("latestReply", reply.get("content"));
latest.put("latestReplyAt", reply.get("createdAt"));
}
return ResponseEntity.ok(latest);
}
// 兼容GET /api/consults 等同于 /api/consults/latest
@GetMapping
public ResponseEntity<?> latestAlias(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId,
@RequestHeader(name = "X-User-Id", required = false) Long userId) {
return latest(shopId, userId);
}
// 用户确认已读:查看过管理员回复后,将状态回到 open
@PutMapping("/{id}/ack")
public ResponseEntity<?> ack(@PathVariable("id") Long id,
@RequestHeader(name = "X-User-Id", required = false) Long userId) {
// 若该咨询属于该用户,则把状态改回 open仅在当前为 resolved 时)
int updated = jdbcTemplate.update(
"UPDATE consults SET status='open', updated_at=NOW() WHERE id=? AND user_id=? AND status='resolved'",
id, (userId == null ? defaults.getUserId() : userId));
Map<String,Object> body = new java.util.HashMap<>();
body.put("updated", updated);
return ResponseEntity.ok(body);
}
@GetMapping("/{id}")
public ResponseEntity<?> detail(@PathVariable("id") Long id,
@RequestHeader(name = "X-User-Id", required = false) Long userId) {
Map<String,Object> consult = jdbcTemplate.query(
"SELECT id, shop_id AS shopId, user_id AS userId, topic, message, status, created_at FROM consults WHERE id=?",
rs -> {
if (rs.next()) {
Map<String,Object> m = new LinkedHashMap<>();
m.put("id", rs.getLong("id"));
m.put("shopId", rs.getLong("shopId"));
m.put("userId", rs.getLong("userId"));
m.put("topic", rs.getString("topic"));
m.put("message", rs.getString("message"));
m.put("status", rs.getString("status"));
m.put("createdAt", rs.getTimestamp("created_at"));
return m;
}
return null;
}, id);
if (consult == null) return ResponseEntity.notFound().build();
if (userId != null) {
Object ownerObj = consult.get("userId");
Long ownerId = (ownerObj instanceof Number) ? ((Number) ownerObj).longValue() : Long.valueOf(String.valueOf(ownerObj));
if (!Objects.equals(ownerId, userId)) {
return ResponseEntity.status(403).body(Map.of("message", "forbidden"));
}
}
List<Map<String,Object>> replies = jdbcTemplate.query(
"SELECT id, user_id AS userId, content, created_at FROM consult_replies WHERE consult_id=? ORDER BY id ASC",
(rs, i) -> {
Map<String,Object> r = new LinkedHashMap<>();
r.put("id", rs.getLong("id"));
r.put("userId", rs.getLong("userId"));
r.put("content", rs.getString("content"));
r.put("createdAt", rs.getTimestamp("created_at"));
return r;
}, id);
Map<String,Object> body = new LinkedHashMap<>();
body.putAll(consult);
body.put("replies", replies);
return ResponseEntity.ok(body);
}
}