| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- package com.pharmacopoeia.controller;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.pharmacopoeia.config.UnifiedResponse;
- import com.pharmacopoeia.dto.*;
- import com.pharmacopoeia.entity.QuickAsk;
- import com.pharmacopoeia.service.AdminKnowledgeService;
- import org.springframework.http.ResponseEntity;
- import org.springframework.web.bind.annotation.*;
- import java.util.*;
- @UnifiedResponse
- @RestController
- @RequestMapping("/api/v1/admin/knowledge")
- public class AdminKnowledgeController {
- private final AdminKnowledgeService service;
- private final ObjectMapper mapper = new ObjectMapper();
- public AdminKnowledgeController(AdminKnowledgeService service) {
- this.service = service;
- }
- // ==================== 药品管理 ====================
- @GetMapping("/drugs")
- public ResponseEntity<Map<String, Object>> listDrugs(
- @RequestParam(required = false) String keyword,
- @RequestParam(required = false) String category,
- @RequestParam(defaultValue = "1") int page,
- @RequestParam(defaultValue = "20") int pageSize) {
- return ResponseEntity.ok(service.listDrugs(keyword, category, page, pageSize));
- }
- @GetMapping("/drugs/{drugId}")
- public ResponseEntity<Map<String, Object>> getDrug(@PathVariable String drugId) {
- return ResponseEntity.ok(service.getDrug(drugId)
- .map(d -> Map.of("data", (Object) d))
- .orElse(Map.of("message", "数据入库后可用", "drug_id", drugId)));
- }
- @PostMapping("/drugs")
- public ResponseEntity<Map<String, Object>> createDrug(@RequestBody DrugCreateRequest req) {
- return ResponseEntity.ok(service.createDrug(objectToMap(req)));
- }
- @PutMapping("/drugs/{drugId}")
- public ResponseEntity<Map<String, Object>> updateDrug(@PathVariable String drugId,
- @RequestBody DrugUpdateRequest req) {
- return ResponseEntity.ok(service.updateDrug(drugId, objectToMap(req)));
- }
- @DeleteMapping("/drugs/{drugId}")
- public ResponseEntity<Map<String, Object>> deleteDrug(@PathVariable String drugId) {
- return ResponseEntity.ok(service.deleteDrug(drugId));
- }
- @PostMapping("/drugs/import")
- public ResponseEntity<Map<String, Object>> importDrugs(@RequestBody ImportRequest req) {
- int count = parseCount(req);
- return ResponseEntity.ok(Map.of(
- "message", "导入任务已提交",
- "total", count,
- "success", 0,
- "failed", 0,
- "note", "Phase 2 实现异步批量写入 + 向量化"
- ));
- }
- @PostMapping("/drugs/reindex")
- public ResponseEntity<Map<String, Object>> reindexDrugs(@RequestBody ReindexRequest req) {
- return ResponseEntity.ok(Map.of(
- "message", "重建索引任务已提交",
- "collection", req.getCollection(),
- "drug_ids", req.getDrugIds(),
- "status", "pending",
- "note", "Phase 2 实现:重新 chunk → 向量化 → 写入 pgvector"
- ));
- }
- // ==================== 知识点管理 ====================
- @GetMapping("/knowledge-points")
- public ResponseEntity<Map<String, Object>> listKnowledgePoints(
- @RequestParam(required = false) String subject,
- @RequestParam(required = false) String chapterId,
- @RequestParam(required = false) Integer difficulty,
- @RequestParam(required = false) String frequency,
- @RequestParam(defaultValue = "1") int page,
- @RequestParam(defaultValue = "20") int pageSize) {
- return ResponseEntity.ok(service.listKnowledgePoints(subject, chapterId, difficulty, frequency, page, pageSize));
- }
- @GetMapping("/knowledge-points/{pointId}")
- public ResponseEntity<Map<String, Object>> getKnowledgePoint(@PathVariable String pointId) {
- return ResponseEntity.ok(service.getKnowledgePoint(pointId)
- .<Map<String, Object>>map(kp -> Map.of(
- "point_id", kp.getPointId(),
- "subject", kp.getSubject(),
- "title", kp.getTitle(),
- "content", kp.getContent()
- ))
- .orElse(Map.of("message", "数据入库后可用", "point_id", pointId)));
- }
- @PostMapping("/knowledge-points")
- public ResponseEntity<Map<String, Object>> createKnowledgePoint(@RequestBody KnowledgePointCreateRequest req) {
- return ResponseEntity.ok(service.createKnowledgePoint(objectToMap(req)));
- }
- @PutMapping("/knowledge-points/{pointId}")
- public ResponseEntity<Map<String, Object>> updateKnowledgePoint(@PathVariable String pointId,
- @RequestBody KnowledgePointUpdateRequest req) {
- return ResponseEntity.ok(service.updateKnowledgePoint(pointId, objectToMap(req)));
- }
- @DeleteMapping("/knowledge-points/{pointId}")
- public ResponseEntity<Map<String, Object>> deleteKnowledgePoint(@PathVariable String pointId) {
- return ResponseEntity.ok(service.deleteKnowledgePoint(pointId));
- }
- @PostMapping("/knowledge-points/import")
- public ResponseEntity<Map<String, Object>> importKnowledgePoints(@RequestBody ImportRequest req) {
- int count = parseCount(req);
- return ResponseEntity.ok(Map.of(
- "message", "导入任务已提交",
- "total", count,
- "success", 0,
- "failed", 0
- ));
- }
- // ==================== 题库管理 ====================
- @GetMapping("/questions")
- public ResponseEntity<Map<String, Object>> listQuestions(
- @RequestParam(required = false) String subject,
- @RequestParam(required = false) String chapterId,
- @RequestParam(required = false) String questionType,
- @RequestParam(required = false) Integer difficulty,
- @RequestParam(required = false) Boolean audited,
- @RequestParam(defaultValue = "1") int page,
- @RequestParam(defaultValue = "20") int pageSize) {
- return ResponseEntity.ok(service.listQuestions(subject, chapterId, questionType, difficulty, audited, page, pageSize));
- }
- @GetMapping("/questions/{questionId}")
- public ResponseEntity<Map<String, Object>> getQuestion(@PathVariable String questionId) {
- return ResponseEntity.ok(service.getQuestion(questionId)
- .<Map<String, Object>>map(q -> Map.of(
- "question_id", q.getQuestionId(),
- "content", q.getContent(),
- "answer", q.getAnswer()
- ))
- .orElse(Map.of("message", "数据入库后可用", "question_id", questionId)));
- }
- @PostMapping("/questions")
- public ResponseEntity<Map<String, Object>> createQuestion(@RequestBody QuestionCreateRequest req) {
- return ResponseEntity.ok(service.createQuestion(objectToMap(req)));
- }
- @PutMapping("/questions/{questionId}")
- public ResponseEntity<Map<String, Object>> updateQuestion(@PathVariable String questionId,
- @RequestBody QuestionUpdateRequest req) {
- return ResponseEntity.ok(service.updateQuestion(questionId, objectToMap(req)));
- }
- @DeleteMapping("/questions/{questionId}")
- public ResponseEntity<Map<String, Object>> deleteQuestion(@PathVariable String questionId) {
- return ResponseEntity.ok(service.deleteQuestion(questionId));
- }
- @PostMapping("/questions/batch-audit")
- public ResponseEntity<Map<String, Object>> batchAudit(@RequestBody BatchAuditRequest req) {
- return ResponseEntity.ok(service.batchAudit(req.getQuestionIds(), req.getAudited()));
- }
- @PostMapping("/questions/import")
- public ResponseEntity<Map<String, Object>> importQuestions(@RequestBody ImportRequest req) {
- int count = parseCount(req);
- return ResponseEntity.ok(Map.of(
- "message", "导入任务已提交",
- "total", count,
- "success", 0,
- "failed", 0
- ));
- }
- @PostMapping("/questions/generate")
- public ResponseEntity<Map<String, Object>> generateQuestions(
- @RequestParam String pointId,
- @RequestParam(defaultValue = "10") int count,
- @RequestParam(defaultValue = "A") String questionType) {
- return ResponseEntity.ok(Map.of(
- "message", "AI 出题任务已提交",
- "point_id", pointId,
- "count", count,
- "question_type", questionType,
- "status", "pending",
- "note", "Phase 2 实现:LLM 根据知识点生成题目"
- ));
- }
- // ==================== 快捷提问标签管理(管理端,需要 JWT) ====================
- @GetMapping("/quick-asks")
- public ResponseEntity<List<QuickAsk>> listAllQuickAsks() {
- return ResponseEntity.ok(service.listAllQuickAsks());
- }
- @PostMapping("/quick-asks")
- public ResponseEntity<Map<String, Object>> createQuickAsk(@RequestBody Map<String, Object> body) {
- String label = (String) body.getOrDefault("label", "");
- String question = (String) body.getOrDefault("question", label);
- int sortOrder = body.get("sort_order") instanceof Integer i ? i : 0;
- return ResponseEntity.ok(service.createQuickAsk(label, question, sortOrder));
- }
- @PutMapping("/quick-asks/{id}")
- public ResponseEntity<Map<String, Object>> updateQuickAsk(
- @PathVariable int id, @RequestBody Map<String, Object> body) {
- String label = body.containsKey("label") ? (String) body.get("label") : null;
- String question = body.containsKey("question") ? (String) body.get("question") : null;
- Integer sortOrder = body.get("sort_order") instanceof Integer i ? i : null;
- Boolean isActive = body.get("is_active") instanceof Boolean b ? b : null;
- return ResponseEntity.ok(service.updateQuickAsk(id, label, question, sortOrder, isActive));
- }
- @DeleteMapping("/quick-asks/{id}")
- public ResponseEntity<Map<String, Object>> deleteQuickAsk(@PathVariable int id) {
- return ResponseEntity.ok(service.deleteQuickAsk(id));
- }
- @PutMapping("/quick-asks/reorder")
- public ResponseEntity<Map<String, Object>> reorderQuickAsks(@RequestBody List<Map<String, Object>> items) {
- return ResponseEntity.ok(service.reorderQuickAsks(items));
- }
- @GetMapping("/quick-asks/audit-log")
- public ResponseEntity<Map<String, Object>> listQuickAskAuditLog(
- @RequestParam(defaultValue = "1") int page,
- @RequestParam(defaultValue = "20") int pageSize) {
- return ResponseEntity.ok(service.listQuickAskAuditLog(page, pageSize));
- }
- // ==================== Helpers ====================
- private int parseCount(ImportRequest req) {
- try {
- if ("json".equals(req.getFormat()) && req.getData() != null) {
- var items = mapper.readTree(req.getData());
- return items.isArray() ? items.size() : 0;
- }
- if ("csv".equals(req.getFormat()) && req.getData() != null) {
- return req.getData().split("\n").length - 1; // rough count
- }
- } catch (Exception ignored) {}
- return 0;
- }
- private Map<String, Object> objectToMap(Object obj) {
- try {
- @SuppressWarnings("unchecked")
- Map<String, Object> map = mapper.convertValue(obj, Map.class);
- return map;
- } catch (Exception e) {
- return Map.of();
- }
- }
- }
|