FormCollectTool.java 3.4 KB
package com.xly.tool;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xly.service.FormResolverService;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * FormCollect(表单呈现)—— 在对话框里渲染一张动态表单,让用户一次填多个字段(如新增记录时)。
 *
 * <p>字段来自 ERP 配置的知识图谱({@code viw_kg_field_dict} 里该主表最常用的可填字段),
 * 前端把它们渲染成输入框;用户填完提交后,前端把「字段=值」拼成一条消息发回,agent 再走
 * proposeCreate 生成待确认提议。整套 UI 在 xlyAi 自己的聊天前端完成,无需 ERP 前端配合。
 */
@Component
public class FormCollectTool {

    private final FormResolverService resolver;
    private final JdbcTemplate jdbc;
    private final ObjectMapper mapper;

    public FormCollectTool(FormResolverService resolver, JdbcTemplate jdbc, ObjectMapper mapper) {
        this.resolver = resolver;
        this.jdbc = jdbc;
        this.mapper = mapper;
    }

    @Tool("在对话框里**渲染一张可填写的表单**,让用户一次性填写某实体的多个字段(用于新增记录时收集信息)。"
            + "调用后前端会显示表单;用户填完提交,你再据其内容用 proposeCreate 生成新增提议。")
    public String showForm(@P("实体类型,如 客户 / 物料") String entityKeyword) {
        if (entityKeyword == null || entityKeyword.isBlank()) {
            return "{\"error\":\"缺少实体类型\"}";
        }
        Map<String, Object> form = resolver.resolveMasterForm(entityKeyword.trim());
        if (form == null) {
            return "{\"error\":\"找不到「" + entityKeyword + "」的主表\"}";
        }
        String table = String.valueOf(form.get("sDataSource"));
        List<String> fields = new ArrayList<>();
        Set<String> seen = new HashSet<>();
        try {
            List<Map<String, Object>> rows = jdbc.queryForList(
                    "SELECT sChinese, sField, MAX(iFormUses) u FROM viw_kg_field_dict WHERE sTable=? " +
                            "AND sField NOT LIKE '%Id' AND sField NOT LIKE 'b%' AND sField<>'sToken' AND sField<>'sMakePerson' " +
                            "AND CHAR_LENGTH(sChinese)>=2 GROUP BY sChinese, sField ORDER BY u DESC LIMIT 10", table);
            for (Map<String, Object> r : rows) {
                Object zh = r.get("sChinese");
                if (zh != null && seen.add(zh.toString()) && fields.size() < 8) {
                    fields.add(zh.toString());
                }
            }
        } catch (Exception ignore) {
        }
        if (fields.isEmpty()) {
            return "{\"error\":\"该实体没有可填字段\"}";
        }
        Map<String, Object> out = new LinkedHashMap<>();
        out.put("formCollect", true);
        out.put("entity", entityKeyword.trim());
        out.put("fields", fields);
        out.put("message", "已在下方为你打开填写表单,请填好后点提交。");
        try {
            return mapper.writeValueAsString(out);
        } catch (Exception e) {
            return "{\"error\":\"内部错误\"}";
        }
    }
}