Add audit report API
This commit is contained in:
parent
c354e9e74e
commit
8dc2e4f3e7
|
|
@ -15,7 +15,7 @@
|
||||||
| 9 | GET | `/api/reports/{id}/preview` | 报告预览(图片/历史) | `src/api/report.js` | ✅ 已修正 | 返回 `ocr_result.API核验/org_exists/cma_exists`,并附带 `pages/history` 与 `status` |
|
| 9 | GET | `/api/reports/{id}/preview` | 报告预览(图片/历史) | `src/api/report.js` | ✅ 已修正 | 返回 `ocr_result.API核验/org_exists/cma_exists`,并附带 `pages/history` 与 `status` |
|
||||||
| 10 | POST | `/api/tasks` | 创建识别任务 | `src/api/report.js` | ✅ 已修正 | 支持 `product_name/testing_date/contact_phone` 等表单字段 |
|
| 10 | POST | `/api/tasks` | 创建识别任务 | `src/api/report.js` | ✅ 已修正 | 支持 `product_name/testing_date/contact_phone` 等表单字段 |
|
||||||
| 11 | POST | `/api/reports/{id}/submit` | 用户确认提交 | `src/api/report.js` | ✅ 已修正 | OCR 通过后将状态置为 `pending` 并记录历史 |
|
| 11 | POST | `/api/reports/{id}/submit` | 用户确认提交 | `src/api/report.js` | ✅ 已修正 | OCR 通过后将状态置为 `pending` 并记录历史 |
|
||||||
| 12 | POST | `/api/reports/{id}/audit` | 审核提交 | `src/api/report.js` | | |
|
| 12 | POST | `/api/reports/{id}/audit` | 审核提交 | `src/api/report.js` | ✅ 已修正 | 支持 `status/opinion/files`,保存附件并记录历史 |
|
||||||
| 13 | DELETE | `/api/reports/{id}` | 删除报告 | `src/api/report.js` | | |
|
| 13 | DELETE | `/api/reports/{id}` | 删除报告 | `src/api/report.js` | | |
|
||||||
| 14 | POST | `/api/validate-cma` | CMA 校验 | `src/api/report.js` | | |
|
| 14 | POST | `/api/validate-cma` | CMA 校验 | `src/api/report.js` | | |
|
||||||
| 15 | GET | `/api/reports/{id}/pdf` | PDF 预览 | `src/views/shibieneirong/shenhe/index.vue` | | |
|
| 15 | GET | `/api/reports/{id}/pdf` | PDF 预览 | `src/views/shibieneirong/shenhe/index.vue` | | |
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api")
|
@RequestMapping("/api")
|
||||||
|
|
@ -209,6 +210,32 @@ public class TaskController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/reports/{id}/audit")
|
||||||
|
@SaCheckRole(value = { "ADMIN", "AUDITOR" }, mode = SaMode.OR)
|
||||||
|
public ResponseEntity<?> auditReport(
|
||||||
|
@PathVariable("id") String id,
|
||||||
|
@RequestParam("status") String status,
|
||||||
|
@RequestParam(value = "opinion", required = false) String opinion,
|
||||||
|
@RequestParam(value = "files", required = false) List<MultipartFile> files) {
|
||||||
|
try {
|
||||||
|
taskService.auditReport(id, status, opinion, files);
|
||||||
|
Map<String, Object> resp = new HashMap<>();
|
||||||
|
resp.put("code", 0);
|
||||||
|
resp.put("msg", "Audited");
|
||||||
|
return ResponseEntity.ok(resp);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Map<String, Object> resp = new HashMap<>();
|
||||||
|
resp.put("code", 1);
|
||||||
|
resp.put("msg", e.getMessage());
|
||||||
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> resp = new HashMap<>();
|
||||||
|
resp.put("code", 500);
|
||||||
|
resp.put("msg", e.getMessage());
|
||||||
|
return ResponseEntity.internalServerError().body(resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/statistics")
|
@GetMapping("/statistics")
|
||||||
@SaCheckRole(value = { "ADMIN", "AUDITOR", "USER" }, mode = SaMode.OR)
|
@SaCheckRole(value = { "ADMIN", "AUDITOR", "USER" }, mode = SaMode.OR)
|
||||||
public ResponseEntity<?> getStatistics() {
|
public ResponseEntity<?> getStatistics() {
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ public class TaskService {
|
||||||
@Value("${app.file.preview-dir}")
|
@Value("${app.file.preview-dir}")
|
||||||
private String previewDir;
|
private String previewDir;
|
||||||
|
|
||||||
|
@Value("${app.file.attachment-dir}")
|
||||||
|
private String attachmentDir;
|
||||||
|
|
||||||
@Value("${app.ocr.async.enabled:false}")
|
@Value("${app.ocr.async.enabled:false}")
|
||||||
private boolean asyncOcrEnabled;
|
private boolean asyncOcrEnabled;
|
||||||
|
|
||||||
|
|
@ -559,6 +562,62 @@ public class TaskService {
|
||||||
taskRepository.save(task);
|
taskRepository.save(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void auditReport(String approvalId, String status, String opinion, List<org.springframework.web.multipart.MultipartFile> files)
|
||||||
|
throws IOException {
|
||||||
|
if (approvalId == null || approvalId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("approval_id is required");
|
||||||
|
}
|
||||||
|
if (!"compliant".equals(status) && !"non-compliant".equals(status)) {
|
||||||
|
throw new IllegalArgumentException("invalid status");
|
||||||
|
}
|
||||||
|
Task task = taskRepository.findByApprovalId(approvalId);
|
||||||
|
if (task == null) {
|
||||||
|
throw new IllegalArgumentException("Report not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
task.setStatus(status);
|
||||||
|
task.setAuditOpinion(opinion);
|
||||||
|
|
||||||
|
if (files != null && !files.isEmpty()) {
|
||||||
|
File baseDir = new File(attachmentDir, approvalId);
|
||||||
|
if (!baseDir.exists()) {
|
||||||
|
baseDir.mkdirs();
|
||||||
|
}
|
||||||
|
if (task.getAttachments() == null) {
|
||||||
|
task.setAttachments(new java.util.ArrayList<>());
|
||||||
|
}
|
||||||
|
for (org.springframework.web.multipart.MultipartFile file : files) {
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
String safeName = (originalFilename == null || originalFilename.isBlank())
|
||||||
|
? (java.util.UUID.randomUUID().toString() + ".bin")
|
||||||
|
: originalFilename;
|
||||||
|
Path target = Paths.get(baseDir.getAbsolutePath(), safeName);
|
||||||
|
Files.copy(file.getInputStream(), target);
|
||||||
|
|
||||||
|
AuditAttachment attachment = new AuditAttachment();
|
||||||
|
attachment.setFilename(safeName);
|
||||||
|
attachment.setFilepath(target.toString());
|
||||||
|
attachment.setTask(task);
|
||||||
|
task.getAttachments().add(attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AuditHistory history = new AuditHistory();
|
||||||
|
history.setAction("compliant".equals(status) ? "审核通过" : "审核不通过");
|
||||||
|
history.setOpinion(opinion == null ? "" : opinion);
|
||||||
|
history.setTask(task);
|
||||||
|
if (task.getHistories() == null) {
|
||||||
|
task.setHistories(new java.util.ArrayList<>());
|
||||||
|
}
|
||||||
|
task.getHistories().add(history);
|
||||||
|
|
||||||
|
taskRepository.save(task);
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Object> getStatistics() {
|
public Map<String, Object> getStatistics() {
|
||||||
List<String> pendingStatuses = List.of("pending", "ocr_completed");
|
List<String> pendingStatuses = List.of("pending", "ocr_completed");
|
||||||
List<String> auditedStatuses = List.of("compliant", "non-compliant");
|
List<String> auditedStatuses = List.of("compliant", "non-compliant");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue