OpController.java
5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package com.xly.web;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xly.service.AuditService;
import com.xly.service.ErpClient;
import com.xly.service.OpService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 写操作确认端点(**确定性、不经过 LLM**)—— 人在环写入闭环的执行侧。
*
* <p>用户在对话框点【确认】-> {@code /confirm} 才真正调 ERP 执行;点【取消】-> {@code /cancel}。
* v1 为同步执行(update 很快):直接调 ERP 表单更新接口,回写 ai_op_queue 状态并返回结果。
*/
@RestController
@RequestMapping("/api/agent/op")
public class OpController {
private static final Logger log = LoggerFactory.getLogger(OpController.class);
private final OpService ops;
private final ErpClient erp;
private final AuditService audit;
private final ObjectMapper mapper;
public OpController(OpService ops, ErpClient erp, AuditService audit, ObjectMapper mapper) {
this.ops = ops;
this.erp = erp;
this.audit = audit;
this.mapper = mapper;
}
/** 会话里最近一条待确认操作(前端每轮结束后轮询,用于渲染确认卡片)。 */
@GetMapping("/pending")
public Map<String, Object> pending(@RequestParam("conversationId") String conversationId) {
Map<String, Object> op = ops.pending(conversationId);
return op == null ? Map.of() : op;
}
/** 确认执行:调 ERP 更新,回写状态。 */
@PostMapping("/{id}/confirm")
public Map<String, Object> confirm(@PathVariable("id") String id) {
Map<String, Object> op = ops.get(id);
if (op == null) {
return result("failed", "找不到该操作", null);
}
if (!"draft".equals(String.valueOf(op.get("sStatus")))) {
return result(String.valueOf(op.get("sStatus")), "该操作已处理过(" + op.get("sStatus") + ")", op);
}
String uid = str(op.get("sUserId"));
String conv = str(op.get("sConversationId"));
String target = str(op.get("sTargetTable")) + "#" + str(op.get("sTargetBillId"));
String detail = str(op.get("sDescription"));
try {
String opType = str(op.get("sOpType"));
JsonNode r;
if ("create".equals(opType)) {
@SuppressWarnings("unchecked")
Map<String, Object> columns = mapper.readValue(str(op.get("sPayload")), Map.class);
r = erp.createForm(str(op.get("sTargetTable")), columns);
} else if ("delete".equals(opType)) {
r = erp.deleteForm(str(op.get("sTargetModuleId")), str(op.get("sTargetTable")), str(op.get("sTargetBillId")));
} else {
r = erp.updateForm(
str(op.get("sTargetModuleId")), str(op.get("sTargetTable")), str(op.get("sTargetBillId")),
str(op.get("sField")), str(op.get("sNewValue")));
}
int code = r.path("code").asInt(0);
if (code == 1) {
ops.setStatus(id, "executed", "操作成功");
audit.log(uid, conv, "confirm", target, detail, true, "executed");
return result("executed", "已执行:" + op.get("sDescription"), op);
}
String msg = r.path("msg").asText("执行失败");
ops.setStatus(id, "failed", msg);
audit.log(uid, conv, "confirm", target, detail, false, msg);
return result("failed", msg, op);
} catch (Exception e) {
log.warn("confirm op {} failed", id, e);
ops.setStatus(id, "failed", e.getMessage());
audit.log(uid, conv, "confirm", target, detail, false, e.getMessage());
return result("failed", "执行异常:" + e.getMessage(), op);
}
}
/** 取消。 */
@PostMapping("/{id}/cancel")
public Map<String, Object> cancel(@PathVariable("id") String id) {
Map<String, Object> op = ops.get(id);
if (op != null && "draft".equals(String.valueOf(op.get("sStatus")))) {
ops.setStatus(id, "cancelled", "用户取消");
audit.log(str(op.get("sUserId")), str(op.get("sConversationId")), "cancel",
str(op.get("sTargetTable")) + "#" + str(op.get("sTargetBillId")),
str(op.get("sDescription")), true, "cancelled");
}
return result("cancelled", "已取消", op);
}
private Map<String, Object> result(String status, String msg, Map<String, Object> op) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("status", status);
m.put("msg", msg);
if (op != null) {
m.put("opId", op.get("sId"));
m.put("description", op.get("sDescription"));
}
return m;
}
private static String str(Object o) {
return o == null ? null : o.toString();
}
}