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 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 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> 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 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 latest = list.get(0); Object idObj = latest.get("id"); Long consultId = (idObj instanceof Number) ? ((Number) idObj).longValue() : Long.valueOf(String.valueOf(idObj)); Map reply = jdbcTemplate.query( "SELECT content, created_at FROM consult_replies WHERE consult_id=? ORDER BY id DESC LIMIT 1", rs -> { if (rs.next()) { Map 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 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 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 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> 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 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 body = new LinkedHashMap<>(); body.putAll(consult); body.put("replies", replies); return ResponseEntity.ok(body); } }